blob: 910583121fb72012d9ee399c45613af3cca7a98a [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
paul718e3742002-12-13 20:15:29 +000024#include "prefix.h"
25#include "filter.h"
26#include "log.h"
27#include "thread.h"
28#include "memory.h"
29#include "if.h"
30#include "stream.h"
31#include "table.h"
32#include "command.h"
33#include "sockopt.h"
34#include "distribute.h"
35#include "plist.h"
36#include "routemap.h"
hasso0750d212003-05-24 21:41:49 +000037#include "if_rmap.h"
paul27d47aa2003-11-17 09:04:53 +000038#include "privs.h"
paul718e3742002-12-13 20:15:29 +000039
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
hassoa94434b2003-05-25 17:10:12 +000043#include "ripngd/ripng_nexthop.h"
paul718e3742002-12-13 20:15:29 +000044
45/* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48struct ripng *ripng = NULL;
49
50enum
51{
52 ripng_all_route,
53 ripng_changed_route,
paul718e3742002-12-13 20:15:29 +000054};
55
paul27d47aa2003-11-17 09:04:53 +000056extern struct zebra_privs_t ripngd_privs;
57
paul718e3742002-12-13 20:15:29 +000058/* Prototypes. */
59void
hassoa94434b2003-05-25 17:10:12 +000060ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
paul718e3742002-12-13 20:15:29 +000061
62int
63ripng_triggered_update (struct thread *);
64
65/* RIPng next hop specification. */
66struct ripng_nexthop
67{
68 enum ripng_nexthop_type
69 {
70 RIPNG_NEXTHOP_UNSPEC,
71 RIPNG_NEXTHOP_ADDRESS
72 } flag;
73 struct in6_addr address;
74};
paul718e3742002-12-13 20:15:29 +000075
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static int
hassoa94434b2003-05-25 17:10:12 +000077ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
paul718e3742002-12-13 20:15:29 +000082/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
David Lamparter6b0655a2014-06-04 06:53:35 +020098
paul718e3742002-12-13 20:15:29 +000099/* Create ripng socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100100static int
paul718e3742002-12-13 20:15:29 +0000101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't make ripng socket");
111 return sock;
112 }
113
114 ret = setsockopt_so_recvbuf (sock, 8096);
115 if (ret < 0)
116 return ret;
117 ret = setsockopt_ipv6_pktinfo (sock, 1);
118 if (ret < 0)
119 return ret;
Stephen Hemminger6d0732c2011-09-28 14:23:35 +0400120#ifdef IPTOS_PREC_INTERNETCONTROL
121 ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
122 if (ret < 0)
123 return ret;
124#endif
paul718e3742002-12-13 20:15:29 +0000125 ret = setsockopt_ipv6_multicast_hops (sock, 255);
126 if (ret < 0)
127 return ret;
128 ret = setsockopt_ipv6_multicast_loop (sock, 0);
129 if (ret < 0)
130 return ret;
131 ret = setsockopt_ipv6_hoplimit (sock, 1);
132 if (ret < 0)
133 return ret;
134
135 memset (&ripaddr, 0, sizeof (ripaddr));
136 ripaddr.sin6_family = AF_INET6;
137#ifdef SIN6_LEN
138 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
139#endif /* SIN6_LEN */
140 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
141
paul27d47aa2003-11-17 09:04:53 +0000142 if (ripngd_privs.change (ZPRIVS_RAISE))
143 zlog_err ("ripng_make_socket: could not raise privs");
144
paul718e3742002-12-13 20:15:29 +0000145 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
146 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000147 {
ajs6099b3b2004-11-20 02:06:59 +0000148 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000149 if (ripngd_privs.change (ZPRIVS_LOWER))
150 zlog_err ("ripng_make_socket: could not lower privs");
151 return ret;
152 }
153 if (ripngd_privs.change (ZPRIVS_LOWER))
154 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000155 return sock;
156}
157
158/* Send RIPng packet. */
159int
160ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
161 struct interface *ifp)
162{
163 int ret;
164 struct msghdr msg;
165 struct iovec iov;
166 struct cmsghdr *cmsgptr;
167 char adata [256];
168 struct in6_pktinfo *pkt;
169 struct sockaddr_in6 addr;
170
hassoa94434b2003-05-25 17:10:12 +0000171 if (IS_RIPNG_DEBUG_SEND) {
172 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000173 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000174 zlog_debug (" send interface %s", ifp->name);
175 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000176 }
paul718e3742002-12-13 20:15:29 +0000177
178 memset (&addr, 0, sizeof (struct sockaddr_in6));
179 addr.sin6_family = AF_INET6;
180#ifdef SIN6_LEN
181 addr.sin6_len = sizeof (struct sockaddr_in6);
182#endif /* SIN6_LEN */
183 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
184
185 /* When destination is specified. */
186 if (to != NULL)
187 {
188 addr.sin6_addr = to->sin6_addr;
189 addr.sin6_port = to->sin6_port;
190 }
191 else
192 {
193 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
194 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
195 }
196
197 msg.msg_name = (void *) &addr;
198 msg.msg_namelen = sizeof (struct sockaddr_in6);
199 msg.msg_iov = &iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = (void *) adata;
202 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
203
204 iov.iov_base = buf;
205 iov.iov_len = bufsize;
206
207 cmsgptr = (struct cmsghdr *)adata;
208 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
209 cmsgptr->cmsg_level = IPPROTO_IPV6;
210 cmsgptr->cmsg_type = IPV6_PKTINFO;
211
212 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
213 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
214 pkt->ipi6_ifindex = ifp->ifindex;
215
216 ret = sendmsg (ripng->sock, &msg, 0);
217
hassoa94434b2003-05-25 17:10:12 +0000218 if (ret < 0) {
219 if (to)
220 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000221 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000222 else
ajs6099b3b2004-11-20 02:06:59 +0000223 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000224 }
paul718e3742002-12-13 20:15:29 +0000225
226 return ret;
227}
228
229/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100230static int
paul718e3742002-12-13 20:15:29 +0000231ripng_recv_packet (int sock, u_char *buf, int bufsize,
Paul Jakma9099f9b2016-01-18 10:12:10 +0000232 struct sockaddr_in6 *from, ifindex_t *ifindex,
paul718e3742002-12-13 20:15:29 +0000233 int *hoplimit)
234{
235 int ret;
236 struct msghdr msg;
237 struct iovec iov;
238 struct cmsghdr *cmsgptr;
David Lamparterab90fc02015-03-03 09:07:25 +0100239 struct in6_addr dst = { .s6_addr = { 0 } };
paul718e3742002-12-13 20:15:29 +0000240
241 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
242 point I can't determine size of cmsghdr */
243 char adata[1024];
244
245 /* Fill in message and iovec. */
246 msg.msg_name = (void *) from;
247 msg.msg_namelen = sizeof (struct sockaddr_in6);
248 msg.msg_iov = &iov;
249 msg.msg_iovlen = 1;
250 msg.msg_control = (void *) adata;
251 msg.msg_controllen = sizeof adata;
252 iov.iov_base = buf;
253 iov.iov_len = bufsize;
254
255 /* If recvmsg fail return minus value. */
256 ret = recvmsg (sock, &msg, 0);
257 if (ret < 0)
258 return ret;
259
ajsb99760a2005-01-04 16:24:43 +0000260 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000261 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
262 {
263 /* I want interface index which this packet comes from. */
264 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265 cmsgptr->cmsg_type == IPV6_PKTINFO)
266 {
267 struct in6_pktinfo *ptr;
268
269 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270 *ifindex = ptr->ipi6_ifindex;
271 dst = ptr->ipi6_addr;
272
273 if (*ifindex == 0)
274 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275 }
276
277 /* Incoming packet's multicast hop limit. */
278 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemminger5eb9d112009-12-10 15:52:33 +0300280 {
281 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282 *hoplimit = *phoplimit;
283 }
paul718e3742002-12-13 20:15:29 +0000284 }
285
286 /* Hoplimit check shold be done when destination address is
287 multicast address. */
288 if (! IN6_IS_ADDR_MULTICAST (&dst))
289 *hoplimit = -1;
290
291 return ret;
292}
293
294/* Dump rip packet */
295void
hasso7a1d5832004-10-08 06:32:23 +0000296ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000297{
298 caddr_t lim;
299 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000300 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000301
302 /* Set command string. */
303 if (packet->command == RIPNG_REQUEST)
304 command_str = "request";
305 else if (packet->command == RIPNG_RESPONSE)
306 command_str = "response";
307 else
308 command_str = "unknown";
309
310 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000311 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000312 sndrcv, command_str, packet->version, size);
313
314 /* Dump each routing table entry. */
315 rte = packet->rte;
316
317 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318 {
319 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000320 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000321 else
ajsc6106812004-12-08 19:51:16 +0000322 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000323 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000324 rte->metric, ntohs (rte->tag));
325 }
326}
327
328/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100329static void
paul718e3742002-12-13 20:15:29 +0000330ripng_nexthop_rte (struct rte *rte,
331 struct sockaddr_in6 *from,
332 struct ripng_nexthop *nexthop)
333{
334 char buf[INET6_BUFSIZ];
335
336 /* Logging before checking RTE. */
337 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000338 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000339 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000340
341 /* RFC2080 2.1.1 Next Hop:
342 The route tag and prefix length in the next hop RTE must be
343 set to zero on sending and ignored on receiption. */
344 if (ntohs (rte->tag) != 0)
345 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000346 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000347
348 if (rte->prefixlen != 0)
349 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000350 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000351
352 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353 next hop RTE indicates that the next hop address should be the
354 originator of the RIPng advertisement. An address specified as a
355 next hop must be a link-local address. */
356 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357 {
358 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359 memset (&nexthop->address, 0, sizeof (struct in6_addr));
360 return;
361 }
362
363 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364 {
365 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367 return;
368 }
369
370 /* The purpose of the next hop RTE is to eliminate packets being
371 routed through extra hops in the system. It is particularly useful
372 when RIPng is not being run on all of the routers on a network.
373 Note that next hop RTE is "advisory". That is, if the provided
374 information is ignored, a possibly sub-optimal, but absolutely
375 valid, route may be taken. If the received next hop address is not
376 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
377 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000378 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000379 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382 memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384 return;
385}
386
387/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100388static int
paul718e3742002-12-13 20:15:29 +0000389ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390{
paul1eb8ef22005-04-07 07:30:20 +0000391 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000392 struct connected *connected;
393 struct prefix *p;
394
paul1eb8ef22005-04-07 07:30:20 +0000395 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396 {
397 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000398
paul1eb8ef22005-04-07 07:30:20 +0000399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
paul718e3742002-12-13 20:15:29 +0000404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100408static int
paul718e3742002-12-13 20:15:29 +0000409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
paul718e3742002-12-13 20:15:29 +0000423 /* Unlock route_node. */
Feng Lue97c31a2015-05-22 11:39:53 +0200424 listnode_delete (rp->info, rinfo);
425 if (list_isempty ((struct list *)rp->info))
426 {
427 list_free (rp->info);
428 rp->info = NULL;
429 route_unlock_node (rp);
430 }
paul718e3742002-12-13 20:15:29 +0000431
432 /* Free RIPng routing information. */
433 ripng_info_free (rinfo);
434
435 return 0;
436}
437
Feng Lue97c31a2015-05-22 11:39:53 +0200438static void ripng_timeout_update (struct ripng_info *rinfo);
439
440/* Add new route to the ECMP list.
Feng Lu72855b12015-05-22 11:39:54 +0200441 * RETURN: the new entry added in the list, or NULL if it is not the first
442 * entry and ECMP is not allowed.
Feng Lue97c31a2015-05-22 11:39:53 +0200443 */
444struct ripng_info *
445ripng_ecmp_add (struct ripng_info *rinfo_new)
446{
447 struct route_node *rp = rinfo_new->rp;
448 struct ripng_info *rinfo = NULL;
449 struct list *list = NULL;
450
451 if (rp->info == NULL)
452 rp->info = list_new ();
453 list = (struct list *)rp->info;
454
Feng Lu72855b12015-05-22 11:39:54 +0200455 /* If ECMP is not allowed and some entry already exists in the list,
456 * do nothing. */
457 if (listcount (list) && !ripng->ecmp)
458 return NULL;
459
Feng Lue97c31a2015-05-22 11:39:53 +0200460 rinfo = ripng_info_new ();
461 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
462 listnode_add (list, rinfo);
463
464 if (ripng_route_rte (rinfo))
465 {
466 ripng_timeout_update (rinfo);
467 ripng_zebra_ipv6_add (rp);
468 }
469
470 ripng_aggregate_increment (rp, rinfo);
471
472 /* Set the route change flag on the first entry. */
473 rinfo = listgetdata (listhead (list));
474 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
475
476 /* Signal the output process to trigger an update. */
477 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
478
479 return rinfo;
480}
481
482/* Replace the ECMP list with the new route.
483 * RETURN: the new entry added in the list
484 */
485struct ripng_info *
486ripng_ecmp_replace (struct ripng_info *rinfo_new)
487{
488 struct route_node *rp = rinfo_new->rp;
489 struct list *list = (struct list *)rp->info;
490 struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
491 struct listnode *node = NULL, *nextnode = NULL;
492
493 if (list == NULL || listcount (list) == 0)
494 return ripng_ecmp_add (rinfo_new);
495
496 /* Get the first entry */
497 rinfo = listgetdata (listhead (list));
498
499 /* Learnt route replaced by a local one. Delete it from zebra. */
500 if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
501 if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
502 ripng_zebra_ipv6_delete (rp);
503
504 if (rinfo->metric != RIPNG_METRIC_INFINITY)
505 ripng_aggregate_decrement_list (rp, list);
506
507 /* Re-use the first entry, and delete the others. */
508 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
509 if (tmp_rinfo != rinfo)
510 {
511 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
512 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
513 list_delete_node (list, node);
514 ripng_info_free (tmp_rinfo);
515 }
516
517 RIPNG_TIMER_OFF (rinfo->t_timeout);
518 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
519 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
520
521 if (ripng_route_rte (rinfo))
522 {
523 ripng_timeout_update (rinfo);
524 /* The ADD message implies an update. */
525 ripng_zebra_ipv6_add (rp);
526 }
527
528 ripng_aggregate_increment (rp, rinfo);
529
530 /* Set the route change flag. */
531 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
532
533 /* Signal the output process to trigger an update. */
534 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
535
536 return rinfo;
537}
538
539/* Delete one route from the ECMP list.
540 * RETURN:
541 * null - the entry is freed, and other entries exist in the list
542 * the entry - the entry is the last one in the list; its metric is set
543 * to INFINITY, and the garbage collector is started for it
544 */
545struct ripng_info *
546ripng_ecmp_delete (struct ripng_info *rinfo)
547{
548 struct route_node *rp = rinfo->rp;
549 struct list *list = (struct list *)rp->info;
550
551 RIPNG_TIMER_OFF (rinfo->t_timeout);
552
553 if (rinfo->metric != RIPNG_METRIC_INFINITY)
554 ripng_aggregate_decrement (rp, rinfo);
555
556 if (listcount (list) > 1)
557 {
558 /* Some other ECMP entries still exist. Just delete this entry. */
559 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
560 listnode_delete (list, rinfo);
561 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
562 /* The ADD message implies the update. */
563 ripng_zebra_ipv6_add (rp);
564 ripng_info_free (rinfo);
565 rinfo = NULL;
566 }
567 else
568 {
569 assert (rinfo == listgetdata (listhead (list)));
570
571 /* This is the only entry left in the list. We must keep it in
572 * the list for garbage collection time, with INFINITY metric. */
573
574 rinfo->metric = RIPNG_METRIC_INFINITY;
575 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
576 ripng_garbage_collect, ripng->garbage_time);
577
578 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
579 ripng_zebra_ipv6_delete (rp);
580 }
581
582 /* Set the route change flag on the first entry. */
583 rinfo = listgetdata (listhead (list));
584 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
585
586 /* Signal the output process to trigger an update. */
587 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
588
589 return rinfo;
590}
591
paul718e3742002-12-13 20:15:29 +0000592/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100593static int
paul718e3742002-12-13 20:15:29 +0000594ripng_timeout (struct thread *t)
595{
Feng Lue97c31a2015-05-22 11:39:53 +0200596 ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
paul718e3742002-12-13 20:15:29 +0000597 return 0;
598}
599
Paul Jakma6ac29a52008-08-15 13:45:30 +0100600static void
paul718e3742002-12-13 20:15:29 +0000601ripng_timeout_update (struct ripng_info *rinfo)
602{
603 if (rinfo->metric != RIPNG_METRIC_INFINITY)
604 {
605 RIPNG_TIMER_OFF (rinfo->t_timeout);
606 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
607 }
608}
609
Paul Jakma6ac29a52008-08-15 13:45:30 +0100610static int
Matthieu Boutier543e7912014-09-10 16:50:44 +0200611ripng_filter (int ripng_distribute, struct prefix_ipv6 *p,
612 struct ripng_interface *ri)
hassoa94434b2003-05-25 17:10:12 +0000613{
614 struct distribute *dist;
615 struct access_list *alist;
616 struct prefix_list *plist;
Matthieu Boutier543e7912014-09-10 16:50:44 +0200617 int distribute = ripng_distribute == RIPNG_FILTER_OUT ?
Matthieu Boutierdf2ef242014-09-10 16:50:45 +0200618 DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN;
Matthieu Boutier543e7912014-09-10 16:50:44 +0200619 const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
hassoa94434b2003-05-25 17:10:12 +0000620
621 /* Input distribute-list filtering. */
Matthieu Boutier543e7912014-09-10 16:50:44 +0200622 if (ri->list[ripng_distribute])
hassoa94434b2003-05-25 17:10:12 +0000623 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200624 if (access_list_apply (ri->list[ripng_distribute],
hassoa94434b2003-05-25 17:10:12 +0000625 (struct prefix *) p) == FILTER_DENY)
626 {
627 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200628 zlog_debug ("%s/%d filtered by distribute %s",
629 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000630 return -1;
631 }
632 }
Matthieu Boutier543e7912014-09-10 16:50:44 +0200633 if (ri->prefix[ripng_distribute])
hassoa94434b2003-05-25 17:10:12 +0000634 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200635 if (prefix_list_apply (ri->prefix[ripng_distribute],
hassoa94434b2003-05-25 17:10:12 +0000636 (struct prefix *) p) == PREFIX_DENY)
637 {
638 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200639 zlog_debug ("%s/%d filtered by prefix-list %s",
640 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000641 return -1;
642 }
643 }
644
645 /* All interface filter check. */
646 dist = distribute_lookup (NULL);
647 if (dist)
648 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200649 if (dist->list[distribute])
hassoa94434b2003-05-25 17:10:12 +0000650 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200651 alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
652
hassoa94434b2003-05-25 17:10:12 +0000653 if (alist)
654 {
655 if (access_list_apply (alist,
656 (struct prefix *) p) == FILTER_DENY)
657 {
658 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200659 zlog_debug ("%s/%d filtered by distribute %s",
660 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000661 return -1;
662 }
663 }
664 }
Matthieu Boutier543e7912014-09-10 16:50:44 +0200665 if (dist->prefix[distribute])
hassoa94434b2003-05-25 17:10:12 +0000666 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200667 plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
668
hassoa94434b2003-05-25 17:10:12 +0000669 if (plist)
670 {
671 if (prefix_list_apply (plist,
672 (struct prefix *) p) == PREFIX_DENY)
673 {
674 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200675 zlog_debug ("%s/%d filtered by prefix-list %s",
676 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000677 return -1;
678 }
679 }
680 }
681 }
682 return 0;
683}
684
paul718e3742002-12-13 20:15:29 +0000685/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100686static void
paul718e3742002-12-13 20:15:29 +0000687ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
688 struct ripng_nexthop *ripng_nexthop,
689 struct interface *ifp)
690{
hassoa94434b2003-05-25 17:10:12 +0000691 int ret;
paul718e3742002-12-13 20:15:29 +0000692 struct prefix_ipv6 p;
693 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200694 struct ripng_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000695 struct ripng_interface *ri;
696 struct in6_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000697 int same = 0;
Feng Lue97c31a2015-05-22 11:39:53 +0200698 struct list *list = NULL;
699 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000700
701 /* Make prefix structure. */
702 memset (&p, 0, sizeof (struct prefix_ipv6));
703 p.family = AF_INET6;
704 /* p.prefix = rte->addr; */
705 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
706 p.prefixlen = rte->prefixlen;
707
708 /* Make sure mask is applied. */
709 /* XXX We have to check the prefix is valid or not before call
710 apply_mask_ipv6. */
711 apply_mask_ipv6 (&p);
712
713 /* Apply input filters. */
714 ri = ifp->info;
715
Matthieu Boutier543e7912014-09-10 16:50:44 +0200716 ret = ripng_filter (RIPNG_FILTER_IN, &p, ri);
hassoa94434b2003-05-25 17:10:12 +0000717 if (ret < 0)
718 return;
paul718e3742002-12-13 20:15:29 +0000719
Feng Lue97c31a2015-05-22 11:39:53 +0200720 memset (&newinfo, 0, sizeof (newinfo));
721 newinfo.type = ZEBRA_ROUTE_RIPNG;
722 newinfo.sub_type = RIPNG_ROUTE_RTE;
723 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
724 newinfo.nexthop = ripng_nexthop->address;
725 else
726 newinfo.nexthop = from->sin6_addr;
727 newinfo.from = from->sin6_addr;
728 newinfo.ifindex = ifp->ifindex;
729 newinfo.metric = rte->metric;
730 newinfo.metric_out = rte->metric; /* XXX */
731 newinfo.tag = ntohs (rte->tag); /* XXX */
732
paul718e3742002-12-13 20:15:29 +0000733 /* Modify entry. */
734 if (ri->routemap[RIPNG_FILTER_IN])
735 {
736 int ret;
paul718e3742002-12-13 20:15:29 +0000737
738 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
739 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
740
741 if (ret == RMAP_DENYMATCH)
742 {
743 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000744 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000745 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000746 return;
747 }
748
hassoa94434b2003-05-25 17:10:12 +0000749 /* Get back the object */
750 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
751 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
752 /* the nexthop get changed by the routemap */
753 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
754 ripng_nexthop->address = newinfo.nexthop;
755 else
756 ripng_nexthop->address = in6addr_any;
757 }
758 } else {
759 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
760 /* the nexthop get changed by the routemap */
761 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
762 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
763 ripng_nexthop->address = newinfo.nexthop;
764 }
765 }
766 }
767 rte->tag = htons(newinfo.tag_out); /* XXX */
768 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000769 }
770
hassoa94434b2003-05-25 17:10:12 +0000771 /* Once the entry has been validated, update the metric by
772 * adding the cost of the network on wich the message
773 * arrived. If the result is greater than infinity, use infinity
774 * (RFC2453 Sec. 3.9.2)
775 **/
776
777 /* Zebra ripngd can handle offset-list in. */
778 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
779
780 /* If offset-list does not modify the metric use interface's
781 * one. */
782 if (! ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000783 rte->metric += ifp->metric ? ifp->metric : 1;
hassoa94434b2003-05-25 17:10:12 +0000784
785 if (rte->metric > RIPNG_METRIC_INFINITY)
786 rte->metric = RIPNG_METRIC_INFINITY;
787
paul718e3742002-12-13 20:15:29 +0000788 /* Set nexthop pointer. */
789 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
790 nexthop = &ripng_nexthop->address;
791 else
792 nexthop = &from->sin6_addr;
793
794 /* Lookup RIPng routing table. */
795 rp = route_node_get (ripng->table, (struct prefix *) &p);
796
Feng Lue97c31a2015-05-22 11:39:53 +0200797 newinfo.rp = rp;
798 newinfo.nexthop = *nexthop;
799 newinfo.metric = rte->metric;
800 newinfo.tag = ntohs (rte->tag);
801
802 /* Check to see whether there is already RIPng route on the table. */
803 if ((list = rp->info) != NULL)
804 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
805 {
806 /* Need to compare with redistributed entry or local entry */
807 if (!ripng_route_rte (rinfo))
808 break;
809
810 if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
811 IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
812 break;
813
814 if (!listnextnode (node))
815 {
816 /* Not found in the list */
817
818 if (rte->metric > rinfo->metric)
819 {
820 /* New route has a greater metric. Discard it. */
821 route_unlock_node (rp);
822 return;
823 }
824
825 if (rte->metric < rinfo->metric)
826 /* New route has a smaller metric. Replace the ECMP list
827 * with the new one in below. */
828 break;
829
830 /* Metrics are same. Keep "rinfo" null and the new route
831 * is added in the ECMP list in below. */
832 }
833 }
834
hassoa94434b2003-05-25 17:10:12 +0000835 if (rinfo)
836 {
837 /* Redistributed route check. */
838 if (rinfo->type != ZEBRA_ROUTE_RIPNG
839 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200840 {
841 route_unlock_node (rp);
842 return;
843 }
hassoa94434b2003-05-25 17:10:12 +0000844
845 /* Local static route. */
846 if (rinfo->type == ZEBRA_ROUTE_RIPNG
847 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
848 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
849 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200850 {
851 route_unlock_node (rp);
852 return;
853 }
hassoa94434b2003-05-25 17:10:12 +0000854 }
855
Feng Lue97c31a2015-05-22 11:39:53 +0200856 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000857 {
858 /* Now, check to see whether there is already an explicit route
859 for the destination prefix. If there is no such route, add
860 this route to the routing table, unless the metric is
861 infinity (there is no point in adding a route which
862 unusable). */
863 if (rte->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200864 ripng_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000865 }
866 else
867 {
paul718e3742002-12-13 20:15:29 +0000868 /* If there is an existing route, compare the next hop address
869 to the address of the router from which the datagram came.
870 If this datagram is from the same router as the existing
871 route, reinitialize the timeout. */
872 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
873 && (rinfo->ifindex == ifp->ifindex));
874
paul718e3742002-12-13 20:15:29 +0000875 /* Next, compare the metrics. If the datagram is from the same
876 router as the existing route, and the new metric is different
877 than the old one; or, if the new metric is lower than the old
878 one; do the following actions: */
879 if ((same && rinfo->metric != rte->metric) ||
880 rte->metric < rinfo->metric)
881 {
Feng Lue97c31a2015-05-22 11:39:53 +0200882 if (listcount (list) == 1)
883 {
884 if (newinfo.metric != RIPNG_METRIC_INFINITY)
885 ripng_ecmp_replace (&newinfo);
886 else
887 ripng_ecmp_delete (rinfo);
888 }
889 else
890 {
891 if (newinfo.metric < rinfo->metric)
892 ripng_ecmp_replace (&newinfo);
893 else /* newinfo.metric > rinfo->metric */
894 ripng_ecmp_delete (rinfo);
895 }
paul718e3742002-12-13 20:15:29 +0000896 }
Feng Lue97c31a2015-05-22 11:39:53 +0200897 else /* same & no change */
898 ripng_timeout_update (rinfo);
899
paul718e3742002-12-13 20:15:29 +0000900 /* Unlock tempolary lock of the route. */
901 route_unlock_node (rp);
902 }
903}
904
905/* Add redistributed route to RIPng table. */
906void
907ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +0000908 ifindex_t ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000909{
910 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200911 struct ripng_info *rinfo = NULL, newinfo;
912 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +0000913
914 /* Redistribute route */
915 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
916 return;
917 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
918 return;
919
920 rp = route_node_get (ripng->table, (struct prefix *) p);
paul718e3742002-12-13 20:15:29 +0000921
Feng Lue97c31a2015-05-22 11:39:53 +0200922 memset (&newinfo, 0, sizeof (struct ripng_info));
923 newinfo.type = type;
924 newinfo.sub_type = sub_type;
925 newinfo.ifindex = ifindex;
926 newinfo.metric = 1;
927 newinfo.rp = rp;
928 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
929 newinfo.nexthop = *nexthop;
930
931 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +0000932 {
Feng Lue97c31a2015-05-22 11:39:53 +0200933 rinfo = listgetdata (listhead (list));
934
hassoa94434b2003-05-25 17:10:12 +0000935 if (rinfo->type == ZEBRA_ROUTE_CONNECT
936 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
937 && rinfo->metric != RIPNG_METRIC_INFINITY) {
938 route_unlock_node (rp);
939 return;
940 }
941
942 /* Manually configured RIPng route check.
943 * They have the precedence on all the other entries.
944 **/
945 if (rinfo->type == ZEBRA_ROUTE_RIPNG
946 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
947 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
948 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
949 (sub_type != RIPNG_ROUTE_DEFAULT))) {
950 route_unlock_node (rp);
951 return;
952 }
953 }
hassoa94434b2003-05-25 17:10:12 +0000954
Feng Lue97c31a2015-05-22 11:39:53 +0200955 rinfo = ripng_ecmp_replace (&newinfo);
paul718e3742002-12-13 20:15:29 +0000956 route_unlock_node (rp);
957 }
Feng Lue97c31a2015-05-22 11:39:53 +0200958 else
959 rinfo = ripng_ecmp_add (&newinfo);
hassoa94434b2003-05-25 17:10:12 +0000960
961 if (IS_RIPNG_DEBUG_EVENT) {
962 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +0000963 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000964 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +0000965 ifindex2ifname(ifindex));
966 else
ajsc6106812004-12-08 19:51:16 +0000967 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000968 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +0000969 ifindex2ifname(ifindex));
970 }
971
972 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000973}
974
975/* Delete redistributed route to RIPng table. */
976void
977ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +0000978 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +0000979{
980 struct route_node *rp;
981 struct ripng_info *rinfo;
982
983 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
984 return;
985 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
986 return;
987
988 rp = route_node_lookup (ripng->table, (struct prefix *) p);
989
990 if (rp)
991 {
Feng Lue97c31a2015-05-22 11:39:53 +0200992 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +0000993
Feng Lue97c31a2015-05-22 11:39:53 +0200994 if (list != NULL && listcount (list) != 0)
995 {
996 rinfo = listgetdata (listhead (list));
997 if (rinfo != NULL
998 && rinfo->type == type
999 && rinfo->sub_type == sub_type
1000 && rinfo->ifindex == ifindex)
1001 {
1002 /* Perform poisoned reverse. */
1003 rinfo->metric = RIPNG_METRIC_INFINITY;
1004 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1005 ripng_garbage_collect, ripng->garbage_time);
1006 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001007
Feng Lue97c31a2015-05-22 11:39:53 +02001008 /* Aggregate count decrement. */
1009 ripng_aggregate_decrement (rp, rinfo);
hassoa94434b2003-05-25 17:10:12 +00001010
Feng Lue97c31a2015-05-22 11:39:53 +02001011 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001012
Feng Lue97c31a2015-05-22 11:39:53 +02001013 if (IS_RIPNG_DEBUG_EVENT)
1014 zlog_debug ("Poisone %s/%d on the interface %s with an "
1015 "infinity metric [delete]",
1016 inet6_ntoa (p->prefix), p->prefixlen,
1017 ifindex2ifname (ifindex));
1018
1019 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1020 }
1021 }
1022 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001023 }
1024}
1025
1026/* Withdraw redistributed route. */
1027void
1028ripng_redistribute_withdraw (int type)
1029{
1030 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001031 struct ripng_info *rinfo = NULL;
1032 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001033
hassoa94434b2003-05-25 17:10:12 +00001034 if (!ripng)
1035 return;
1036
paul718e3742002-12-13 20:15:29 +00001037 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001038 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00001039 {
Feng Lue97c31a2015-05-22 11:39:53 +02001040 rinfo = listgetdata (listhead (list));
hassoa94434b2003-05-25 17:10:12 +00001041 if ((rinfo->type == type)
1042 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001043 {
hassoa94434b2003-05-25 17:10:12 +00001044 /* Perform poisoned reverse. */
1045 rinfo->metric = RIPNG_METRIC_INFINITY;
1046 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1047 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001048 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001049
hassoa94434b2003-05-25 17:10:12 +00001050 /* Aggregate count decrement. */
1051 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001052
hassoa94434b2003-05-25 17:10:12 +00001053 rinfo->flags |= RIPNG_RTF_CHANGED;
1054
1055 if (IS_RIPNG_DEBUG_EVENT) {
1056 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1057
ajsc6106812004-12-08 19:51:16 +00001058 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001059 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001060 ifindex2ifname(rinfo->ifindex));
1061 }
1062
1063 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001064 }
1065 }
1066}
1067
1068/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001069static void
paul718e3742002-12-13 20:15:29 +00001070ripng_response_process (struct ripng_packet *packet, int size,
1071 struct sockaddr_in6 *from, struct interface *ifp,
1072 int hoplimit)
1073{
1074 caddr_t lim;
1075 struct rte *rte;
1076 struct ripng_nexthop nexthop;
1077
1078 /* RFC2080 2.4.2 Response Messages:
1079 The Response must be ignored if it is not from the RIPng port. */
1080 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1081 {
1082 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001083 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001084 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001085 return;
1086 }
1087
1088 /* The datagram's IPv6 source address should be checked to see
1089 whether the datagram is from a valid neighbor; the source of the
1090 datagram must be a link-local address. */
1091 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1092 {
1093 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001094 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001095 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001096 return;
1097 }
1098
1099 /* It is also worth checking to see whether the response is from one
1100 of the router's own addresses. Interfaces on broadcast networks
1101 may receive copies of their own multicasts immediately. If a
1102 router processes its own output as new input, confusion is likely,
1103 and such datagrams must be ignored. */
1104 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1105 {
1106 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001107 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001108 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001109 return;
1110 }
1111
1112 /* As an additional check, periodic advertisements must have their
1113 hop counts set to 255, and inbound, multicast packets sent from the
1114 RIPng port (i.e. periodic advertisement or triggered update
1115 packets) must be examined to ensure that the hop count is 255. */
1116 if (hoplimit >= 0 && hoplimit != 255)
1117 {
1118 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001119 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001120 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001121 return;
1122 }
1123
hassoa94434b2003-05-25 17:10:12 +00001124 /* Update RIPng peer. */
1125 ripng_peer_update (from, packet->version);
1126
paul718e3742002-12-13 20:15:29 +00001127 /* Reset nexthop. */
1128 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1129 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1130
1131 /* Set RTE pointer. */
1132 rte = packet->rte;
1133
1134 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1135 {
1136 /* First of all, we have to check this RTE is next hop RTE or
1137 not. Next hop RTE is completely different with normal RTE so
1138 we need special treatment. */
1139 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1140 {
1141 ripng_nexthop_rte (rte, from, &nexthop);
1142 continue;
1143 }
1144
1145 /* RTE information validation. */
1146
1147 /* - is the destination prefix valid (e.g., not a multicast
1148 prefix and not a link-local address) A link-local address
1149 should never be present in an RTE. */
1150 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1151 {
1152 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001153 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001154 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001155 continue;
1156 }
1157 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1158 {
1159 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001160 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001161 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001162 continue;
1163 }
1164 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1165 {
1166 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001167 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001168 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001169 continue;
1170 }
1171
1172 /* - is the prefix length valid (i.e., between 0 and 128,
1173 inclusive) */
1174 if (rte->prefixlen > 128)
1175 {
1176 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001177 inet6_ntoa (rte->addr), rte->prefixlen,
1178 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001179 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001180 continue;
1181 }
1182
1183 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1184 if (! (rte->metric >= 1 && rte->metric <= 16))
1185 {
1186 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001187 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001188 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001189 continue;
1190 }
1191
hassoa94434b2003-05-25 17:10:12 +00001192 /* Vincent: XXX Should we compute the direclty reachable nexthop
1193 * for our RIPng network ?
1194 **/
paul718e3742002-12-13 20:15:29 +00001195
1196 /* Routing table updates. */
1197 ripng_route_process (rte, from, &nexthop, ifp);
1198 }
1199}
1200
1201/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001202static void
paul718e3742002-12-13 20:15:29 +00001203ripng_request_process (struct ripng_packet *packet,int size,
1204 struct sockaddr_in6 *from, struct interface *ifp)
1205{
1206 caddr_t lim;
1207 struct rte *rte;
1208 struct prefix_ipv6 p;
1209 struct route_node *rp;
1210 struct ripng_info *rinfo;
1211 struct ripng_interface *ri;
1212
hassoa94434b2003-05-25 17:10:12 +00001213 /* Does not reponse to the requests on the loopback interfaces */
1214 if (if_is_loopback (ifp))
1215 return;
1216
paul718e3742002-12-13 20:15:29 +00001217 /* Check RIPng process is enabled on this interface. */
1218 ri = ifp->info;
1219 if (! ri->running)
1220 return;
1221
1222 /* When passive interface is specified, suppress responses */
1223 if (ri->passive)
1224 return;
1225
hassoa94434b2003-05-25 17:10:12 +00001226 /* RIPng peer update. */
1227 ripng_peer_update (from, packet->version);
1228
paul718e3742002-12-13 20:15:29 +00001229 lim = ((caddr_t) packet) + size;
1230 rte = packet->rte;
1231
1232 /* The Request is processed entry by entry. If there are no
1233 entries, no response is given. */
1234 if (lim == (caddr_t) rte)
1235 return;
1236
1237 /* There is one special case. If there is exactly one entry in the
1238 request, and it has a destination prefix of zero, a prefix length
1239 of zero, and a metric of infinity (i.e., 16), then this is a
1240 request to send the entire routing table. In that case, a call
1241 is made to the output process to send the routing table to the
1242 requesting address/port. */
1243 if (lim == ((caddr_t) (rte + 1)) &&
1244 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1245 rte->prefixlen == 0 &&
1246 rte->metric == RIPNG_METRIC_INFINITY)
1247 {
1248 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001249 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001250 }
1251 else
1252 {
1253 /* Except for this special case, processing is quite simple.
1254 Examine the list of RTEs in the Request one by one. For each
1255 entry, look up the destination in the router's routing
1256 database and, if there is a route, put that route's metric in
1257 the metric field of the RTE. If there is no explicit route
1258 to the specified destination, put infinity in the metric
1259 field. Once all the entries have been filled in, change the
1260 command from Request to Response and send the datagram back
1261 to the requestor. */
1262 memset (&p, 0, sizeof (struct prefix_ipv6));
1263 p.family = AF_INET6;
1264
1265 for (; ((caddr_t) rte) < lim; rte++)
1266 {
1267 p.prefix = rte->addr;
1268 p.prefixlen = rte->prefixlen;
1269 apply_mask_ipv6 (&p);
1270
1271 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1272
1273 if (rp)
1274 {
Feng Lue97c31a2015-05-22 11:39:53 +02001275 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001276 rte->metric = rinfo->metric;
1277 route_unlock_node (rp);
1278 }
1279 else
1280 rte->metric = RIPNG_METRIC_INFINITY;
1281 }
1282 packet->command = RIPNG_RESPONSE;
1283
1284 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1285 }
1286}
1287
1288/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001289static int
paul718e3742002-12-13 20:15:29 +00001290ripng_read (struct thread *thread)
1291{
1292 int len;
1293 int sock;
1294 struct sockaddr_in6 from;
1295 struct ripng_packet *packet;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001296 ifindex_t ifindex = 0;
paul718e3742002-12-13 20:15:29 +00001297 struct interface *ifp;
1298 int hoplimit = -1;
1299
1300 /* Check ripng is active and alive. */
1301 assert (ripng != NULL);
1302 assert (ripng->sock >= 0);
1303
1304 /* Fetch thread data and set read pointer to empty for event
1305 managing. `sock' sould be same as ripng->sock. */
1306 sock = THREAD_FD (thread);
1307 ripng->t_read = NULL;
1308
1309 /* Add myself to the next event. */
1310 ripng_event (RIPNG_READ, sock);
1311
1312 /* Read RIPng packet. */
1313 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1314 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1315 &hoplimit);
1316 if (len < 0)
1317 {
ajs6099b3b2004-11-20 02:06:59 +00001318 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001319 return len;
1320 }
1321
1322 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1323 (4)) must be multiple size of one RTE size (20). */
1324 if (((len - 4) % 20) != 0)
1325 {
1326 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001327 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001328 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001329 return 0;
1330 }
1331
1332 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1333 ifp = if_lookup_by_index (ifindex);
1334
1335 /* RIPng packet received. */
1336 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001337 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001338 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001339 ifp ? ifp->name : "unknown");
1340
1341 /* Logging before packet checking. */
1342 if (IS_RIPNG_DEBUG_RECV)
1343 ripng_packet_dump (packet, len, "RECV");
1344
1345 /* Packet comes from unknown interface. */
1346 if (ifp == NULL)
1347 {
1348 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1349 return 0;
1350 }
1351
1352 /* Packet version mismatch checking. */
1353 if (packet->version != ripng->version)
1354 {
1355 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1356 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001357 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001358 return 0;
1359 }
1360
1361 /* Process RIPng packet. */
1362 switch (packet->command)
1363 {
1364 case RIPNG_REQUEST:
1365 ripng_request_process (packet, len, &from, ifp);
1366 break;
1367 case RIPNG_RESPONSE:
1368 ripng_response_process (packet, len, &from, ifp, hoplimit);
1369 break;
1370 default:
1371 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001372 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001373 break;
1374 }
1375 return 0;
1376}
1377
1378/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001379static void
1380ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001381{
1382 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001383 struct ripng_info *rinfo = NULL;
1384 struct list *list = NULL;
1385 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001386
1387 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001388 if ((list = rp->info) != NULL)
1389 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1390 {
1391 UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1392 /* This flag can be set only on the first entry. */
1393 break;
1394 }
paul718e3742002-12-13 20:15:29 +00001395}
1396
1397/* Regular update of RIPng route. Send all routing formation to RIPng
1398 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001399static int
paul718e3742002-12-13 20:15:29 +00001400ripng_update (struct thread *t)
1401{
hasso52dc7ee2004-09-23 19:18:23 +00001402 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001403 struct interface *ifp;
1404 struct ripng_interface *ri;
1405
1406 /* Clear update timer thread. */
1407 ripng->t_update = NULL;
1408
1409 /* Logging update event. */
1410 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001411 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001412
1413 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001414 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001415 {
paul718e3742002-12-13 20:15:29 +00001416 ri = ifp->info;
1417
1418 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1419 continue;
1420
1421 if (! ri->running)
1422 continue;
1423
1424 /* When passive interface is specified, suppress announce to the
1425 interface. */
1426 if (ri->passive)
1427 continue;
1428
1429#if RIPNG_ADVANCED
1430 if (ri->ri_send == RIPNG_SEND_OFF)
1431 {
1432 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001433 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001434 "[Event] RIPng send to if %d is suppressed by config",
1435 ifp->ifindex);
1436 continue;
1437 }
1438#endif /* RIPNG_ADVANCED */
1439
hassoa94434b2003-05-25 17:10:12 +00001440 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001441 }
1442
1443 /* Triggered updates may be suppressed if a regular update is due by
1444 the time the triggered update would be sent. */
1445 if (ripng->t_triggered_interval)
1446 {
1447 thread_cancel (ripng->t_triggered_interval);
1448 ripng->t_triggered_interval = NULL;
1449 }
1450 ripng->trigger = 0;
1451
1452 /* Reset flush event. */
1453 ripng_event (RIPNG_UPDATE_EVENT, 0);
1454
1455 return 0;
1456}
1457
1458/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001459static int
paul718e3742002-12-13 20:15:29 +00001460ripng_triggered_interval (struct thread *t)
1461{
1462 ripng->t_triggered_interval = NULL;
1463
1464 if (ripng->trigger)
1465 {
1466 ripng->trigger = 0;
1467 ripng_triggered_update (t);
1468 }
1469 return 0;
1470}
1471
1472/* Execute triggered update. */
1473int
1474ripng_triggered_update (struct thread *t)
1475{
hasso52dc7ee2004-09-23 19:18:23 +00001476 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001477 struct interface *ifp;
1478 struct ripng_interface *ri;
1479 int interval;
1480
1481 ripng->t_triggered_update = NULL;
1482
1483 /* Cancel interval timer. */
1484 if (ripng->t_triggered_interval)
1485 {
1486 thread_cancel (ripng->t_triggered_interval);
1487 ripng->t_triggered_interval = NULL;
1488 }
1489 ripng->trigger = 0;
1490
1491 /* Logging triggered update. */
1492 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001493 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001494
1495 /* Split Horizon processing is done when generating triggered
1496 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001497 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001498 {
paul718e3742002-12-13 20:15:29 +00001499 ri = ifp->info;
1500
1501 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1502 continue;
1503
1504 if (! ri->running)
1505 continue;
1506
1507 /* When passive interface is specified, suppress announce to the
1508 interface. */
1509 if (ri->passive)
1510 continue;
1511
hassoa94434b2003-05-25 17:10:12 +00001512 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001513 }
1514
1515 /* Once all of the triggered updates have been generated, the route
1516 change flags should be cleared. */
1517 ripng_clear_changed_flag ();
1518
1519 /* After a triggered update is sent, a timer should be set for a
1520 random interval between 1 and 5 seconds. If other changes that
1521 would trigger updates occur before the timer expires, a single
1522 update is triggered when the timer expires. */
1523 interval = (random () % 5) + 1;
1524
1525 ripng->t_triggered_interval =
1526 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1527
1528 return 0;
1529}
1530
1531/* Write routing table entry to the stream and return next index of
1532 the routing table entry in the stream. */
1533int
1534ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001535 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001536{
1537 /* RIPng packet header. */
1538 if (num == 0)
1539 {
1540 stream_putc (s, RIPNG_RESPONSE);
1541 stream_putc (s, RIPNG_V1);
1542 stream_putw (s, 0);
1543 }
1544
1545 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001546 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001547 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001548 else
hassoc9e52be2004-09-26 16:09:34 +00001549 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001550 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001551 if (p)
1552 stream_putc (s, p->prefixlen);
1553 else
1554 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001555 stream_putc (s, metric);
1556
1557 return ++num;
1558}
1559
1560/* Send RESPONSE message to specified destination. */
1561void
1562ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001563 int route_type)
paul718e3742002-12-13 20:15:29 +00001564{
1565 int ret;
paul718e3742002-12-13 20:15:29 +00001566 struct route_node *rp;
1567 struct ripng_info *rinfo;
1568 struct ripng_interface *ri;
1569 struct ripng_aggregate *aggregate;
1570 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001571 struct list * ripng_rte_list;
Feng Lue97c31a2015-05-22 11:39:53 +02001572 struct list *list = NULL;
1573 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001574
hassoa94434b2003-05-25 17:10:12 +00001575 if (IS_RIPNG_DEBUG_EVENT) {
1576 if (to)
ajsc6106812004-12-08 19:51:16 +00001577 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001578 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001579 else
ajsc6106812004-12-08 19:51:16 +00001580 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001581 }
paul718e3742002-12-13 20:15:29 +00001582
paul718e3742002-12-13 20:15:29 +00001583 /* Get RIPng interface. */
1584 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001585
1586 ripng_rte_list = ripng_rte_new();
1587
paul718e3742002-12-13 20:15:29 +00001588 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1589 {
Feng Lue97c31a2015-05-22 11:39:53 +02001590 if ((list = rp->info) != NULL &&
1591 (rinfo = listgetdata (listhead (list))) != NULL &&
1592 rinfo->suppress == 0)
paul718e3742002-12-13 20:15:29 +00001593 {
hassoa94434b2003-05-25 17:10:12 +00001594 /* If no route-map are applied, the RTE will be these following
1595 * informations.
1596 */
paul718e3742002-12-13 20:15:29 +00001597 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001598 rinfo->metric_out = rinfo->metric;
1599 rinfo->tag_out = rinfo->tag;
1600 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1601 /* In order to avoid some local loops,
1602 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1603 * otherwise set it to 0. The nexthop should not be propagated
1604 * beyond the local broadcast/multicast area in order
1605 * to avoid an IGP multi-level recursive look-up.
1606 */
1607 if (rinfo->ifindex == ifp->ifindex)
1608 rinfo->nexthop_out = rinfo->nexthop;
1609
1610 /* Apply output filters. */
Matthieu Boutier543e7912014-09-10 16:50:44 +02001611 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
hassoa94434b2003-05-25 17:10:12 +00001612 if (ret < 0)
1613 continue;
paul718e3742002-12-13 20:15:29 +00001614
1615 /* Changed route only output. */
1616 if (route_type == ripng_changed_route &&
1617 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1618 continue;
1619
1620 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001621 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1622 {
1623 /* We perform split horizon for RIPng routes. */
Feng Lue97c31a2015-05-22 11:39:53 +02001624 int suppress = 0;
1625 struct ripng_info *tmp_rinfo = NULL;
1626
1627 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1628 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1629 tmp_rinfo->ifindex == ifp->ifindex)
1630 {
1631 suppress = 1;
1632 break;
1633 }
1634 if (suppress)
hassoa94434b2003-05-25 17:10:12 +00001635 continue;
1636 }
paul718e3742002-12-13 20:15:29 +00001637
1638 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001639 rinfo->metric_set = 0;
1640 /* nexthop_out,
1641 * metric_out
1642 * and tag_out are already initialized.
1643 */
paul718e3742002-12-13 20:15:29 +00001644
hassoa94434b2003-05-25 17:10:12 +00001645 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001646 if (ri->routemap[RIPNG_FILTER_OUT])
1647 {
1648 int ret;
paul718e3742002-12-13 20:15:29 +00001649
1650 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1651 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001652 rinfo);
paul718e3742002-12-13 20:15:29 +00001653
1654 if (ret == RMAP_DENYMATCH)
1655 {
1656 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001657 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001658 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001659 continue;
paul718e3742002-12-13 20:15:29 +00001660 }
1661
paul718e3742002-12-13 20:15:29 +00001662 }
1663
hassoa94434b2003-05-25 17:10:12 +00001664 /* Redistribute route-map. */
1665 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001666 {
hassoa94434b2003-05-25 17:10:12 +00001667 int ret;
1668
1669 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1670 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001671 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001672
1673 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001674 {
hassoa94434b2003-05-25 17:10:12 +00001675 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001676 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001677 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001678 continue;
paul718e3742002-12-13 20:15:29 +00001679 }
hassoa94434b2003-05-25 17:10:12 +00001680 }
paul718e3742002-12-13 20:15:29 +00001681
hassoa94434b2003-05-25 17:10:12 +00001682 /* When the route-map does not set metric. */
1683 if (! rinfo->metric_set)
1684 {
1685 /* If the redistribute metric is set. */
1686 if (ripng->route_map[rinfo->type].metric_config
1687 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001688 {
hassoa94434b2003-05-25 17:10:12 +00001689 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1690 }
1691 else
1692 {
1693 /* If the route is not connected or localy generated
1694 one, use default-metric value */
1695 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1696 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001697 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001698 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001699 }
1700 }
1701
hassoa94434b2003-05-25 17:10:12 +00001702 /* Apply offset-list */
1703 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1704 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001705
hassoa94434b2003-05-25 17:10:12 +00001706 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1707 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1708
1709 /* Perform split-horizon with poisoned reverse
1710 * for RIPng routes.
1711 **/
1712 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
Feng Lue97c31a2015-05-22 11:39:53 +02001713 struct ripng_info *tmp_rinfo = NULL;
1714
1715 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1716 if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1717 tmp_rinfo->ifindex == ifp->ifindex)
1718 rinfo->metric_out = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +00001719 }
1720
1721 /* Add RTE to the list */
1722 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001723 }
hassoa94434b2003-05-25 17:10:12 +00001724
1725 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001726 if ((aggregate = rp->aggregate) != NULL &&
1727 aggregate->count > 0 &&
1728 aggregate->suppress == 0)
1729 {
hassoa94434b2003-05-25 17:10:12 +00001730 /* If no route-map are applied, the RTE will be these following
1731 * informations.
1732 */
paul718e3742002-12-13 20:15:29 +00001733 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001734 aggregate->metric_set = 0;
1735 aggregate->metric_out = aggregate->metric;
1736 aggregate->tag_out = aggregate->tag;
1737 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001738
1739 /* Apply output filters.*/
Matthieu Boutier543e7912014-09-10 16:50:44 +02001740 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
hassoa94434b2003-05-25 17:10:12 +00001741 if (ret < 0)
1742 continue;
paul718e3742002-12-13 20:15:29 +00001743
hassoa94434b2003-05-25 17:10:12 +00001744 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001745 if (ri->routemap[RIPNG_FILTER_OUT])
1746 {
1747 int ret;
1748 struct ripng_info newinfo;
1749
hassoa94434b2003-05-25 17:10:12 +00001750 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001751 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001752 /* the nexthop is :: */
1753 newinfo.metric = aggregate->metric;
1754 newinfo.metric_out = aggregate->metric_out;
1755 newinfo.tag = aggregate->tag;
1756 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001757
1758 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1759 (struct prefix *) p, RMAP_RIPNG,
1760 &newinfo);
1761
1762 if (ret == RMAP_DENYMATCH)
1763 {
1764 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001765 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001766 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001767 continue;
paul718e3742002-12-13 20:15:29 +00001768 }
1769
hassoa94434b2003-05-25 17:10:12 +00001770 aggregate->metric_out = newinfo.metric_out;
1771 aggregate->tag_out = newinfo.tag_out;
1772 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1773 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001774 }
1775
hassoa94434b2003-05-25 17:10:12 +00001776 /* There is no redistribute routemap for the aggregated RTE */
1777
paul718e3742002-12-13 20:15:29 +00001778 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001779 /* XXX, vincent, in order to increase time convergence,
1780 * it should be announced if a child has changed.
1781 */
paul718e3742002-12-13 20:15:29 +00001782 if (route_type == ripng_changed_route)
1783 continue;
1784
hassoa94434b2003-05-25 17:10:12 +00001785 /* Apply offset-list */
1786 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1787 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001788
hassoa94434b2003-05-25 17:10:12 +00001789 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1790 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1791
1792 /* Add RTE to the list */
1793 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001794 }
1795
1796 }
paul718e3742002-12-13 20:15:29 +00001797
hassoa94434b2003-05-25 17:10:12 +00001798 /* Flush the list */
1799 ripng_rte_send(ripng_rte_list, ifp, to);
1800 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001801}
1802
1803/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001804static int
1805ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001806{
1807 /* ripng should be NULL. */
1808 assert (ripng == NULL);
1809
1810 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001811 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001812
1813 /* Default version and timer values. */
1814 ripng->version = RIPNG_V1;
1815 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1816 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1817 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1818 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1819
1820 /* Make buffer. */
1821 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1822 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1823
1824 /* Initialize RIPng routig table. */
1825 ripng->table = route_table_init ();
1826 ripng->route = route_table_init ();
1827 ripng->aggregate = route_table_init ();
1828
1829 /* Make socket. */
1830 ripng->sock = ripng_make_socket ();
1831 if (ripng->sock < 0)
1832 return ripng->sock;
1833
1834 /* Threads. */
1835 ripng_event (RIPNG_READ, ripng->sock);
1836 ripng_event (RIPNG_UPDATE_EVENT, 1);
1837
1838 return 0;
1839}
1840
hassoa94434b2003-05-25 17:10:12 +00001841/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001842int
1843ripng_request (struct interface *ifp)
1844{
1845 struct rte *rte;
1846 struct ripng_packet ripng_packet;
1847
hassoa94434b2003-05-25 17:10:12 +00001848 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1849 if (if_is_loopback(ifp))
1850 return 0;
1851
1852 /* If interface is down, don't send RIP packet. */
1853 if (! if_is_up (ifp))
1854 return 0;
1855
paul718e3742002-12-13 20:15:29 +00001856 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001857 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001858
1859 memset (&ripng_packet, 0, sizeof (ripng_packet));
1860 ripng_packet.command = RIPNG_REQUEST;
1861 ripng_packet.version = RIPNG_V1;
1862 rte = ripng_packet.rte;
1863 rte->metric = RIPNG_METRIC_INFINITY;
1864
1865 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1866 NULL, ifp);
1867}
1868
David Lamparter6b0655a2014-06-04 06:53:35 +02001869
Paul Jakma6ac29a52008-08-15 13:45:30 +01001870static int
paul718e3742002-12-13 20:15:29 +00001871ripng_update_jitter (int time)
1872{
Donald Sharpf31bab42015-06-19 19:26:19 -04001873 return ((random () % (time + 1)) - (time / 2));
paul718e3742002-12-13 20:15:29 +00001874}
1875
1876void
1877ripng_event (enum ripng_event event, int sock)
1878{
paul718e3742002-12-13 20:15:29 +00001879 int jitter = 0;
1880
1881 switch (event)
1882 {
1883 case RIPNG_READ:
1884 if (!ripng->t_read)
1885 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1886 break;
1887 case RIPNG_UPDATE_EVENT:
1888 if (ripng->t_update)
1889 {
1890 thread_cancel (ripng->t_update);
1891 ripng->t_update = NULL;
1892 }
1893 /* Update timer jitter. */
1894 jitter = ripng_update_jitter (ripng->update_time);
1895
1896 ripng->t_update =
1897 thread_add_timer (master, ripng_update, NULL,
1898 sock ? 2 : ripng->update_time + jitter);
1899 break;
1900 case RIPNG_TRIGGERED_UPDATE:
1901 if (ripng->t_triggered_interval)
1902 ripng->trigger = 1;
1903 else if (! ripng->t_triggered_update)
1904 ripng->t_triggered_update =
1905 thread_add_event (master, ripng_triggered_update, NULL, 0);
1906 break;
1907 default:
1908 break;
1909 }
1910}
David Lamparter6b0655a2014-06-04 06:53:35 +02001911
paul718e3742002-12-13 20:15:29 +00001912
paul718e3742002-12-13 20:15:29 +00001913/* Print out routes update time. */
1914static void
1915ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1916{
paul718e3742002-12-13 20:15:29 +00001917 time_t clock;
1918 struct tm *tm;
1919#define TIME_BUF 25
1920 char timebuf [TIME_BUF];
1921 struct thread *thread;
1922
paul718e3742002-12-13 20:15:29 +00001923 if ((thread = rinfo->t_timeout) != NULL)
1924 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001925 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001926 tm = gmtime (&clock);
1927 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1928 vty_out (vty, "%5s", timebuf);
1929 }
1930 else if ((thread = rinfo->t_garbage_collect) != NULL)
1931 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001932 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001933 tm = gmtime (&clock);
1934 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1935 vty_out (vty, "%5s", timebuf);
1936 }
1937}
1938
Paul Jakma6ac29a52008-08-15 13:45:30 +01001939static char *
hassoa94434b2003-05-25 17:10:12 +00001940ripng_route_subtype_print (struct ripng_info *rinfo)
1941{
1942 static char str[3];
1943 memset(str, 0, 3);
1944
1945 if (rinfo->suppress)
1946 strcat(str, "S");
1947
1948 switch (rinfo->sub_type)
1949 {
1950 case RIPNG_ROUTE_RTE:
1951 strcat(str, "n");
1952 break;
1953 case RIPNG_ROUTE_STATIC:
1954 strcat(str, "s");
1955 break;
1956 case RIPNG_ROUTE_DEFAULT:
1957 strcat(str, "d");
1958 break;
1959 case RIPNG_ROUTE_REDISTRIBUTE:
1960 strcat(str, "r");
1961 break;
1962 case RIPNG_ROUTE_INTERFACE:
1963 strcat(str, "i");
1964 break;
1965 default:
1966 strcat(str, "?");
1967 break;
1968 }
1969
1970 return str;
1971}
1972
paul718e3742002-12-13 20:15:29 +00001973DEFUN (show_ipv6_ripng,
1974 show_ipv6_ripng_cmd,
1975 "show ipv6 ripng",
1976 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001977 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001978 "Show RIPng routes\n")
1979{
1980 struct route_node *rp;
1981 struct ripng_info *rinfo;
1982 struct ripng_aggregate *aggregate;
1983 struct prefix_ipv6 *p;
Feng Lue97c31a2015-05-22 11:39:53 +02001984 struct list *list = NULL;
1985 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001986 int len;
1987
hassoa94434b2003-05-25 17:10:12 +00001988 if (! ripng)
1989 return CMD_SUCCESS;
1990
paul718e3742002-12-13 20:15:29 +00001991 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00001992 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
1993 "Sub-codes:%s"
1994 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
1995 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
1996 " Network Next Hop Via Metric Tag Time%s",
1997 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00001998 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1999
2000 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2001 {
2002 if ((aggregate = rp->aggregate) != NULL)
2003 {
2004 p = (struct prefix_ipv6 *) &rp->p;
2005
2006#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002007 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002008 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002009 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002010#else
hassoa94434b2003-05-25 17:10:12 +00002011 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002012 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002013#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002014 vty_out (vty, "%s", VTY_NEWLINE);
2015 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002016
hassoa94434b2003-05-25 17:10:12 +00002017 vty_out (vty, "%*s", 28, " ");
2018 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002019 aggregate->tag,
2020 VTY_NEWLINE);
2021 }
2022
Feng Lue97c31a2015-05-22 11:39:53 +02002023 if ((list = rp->info) != NULL)
2024 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00002025 {
2026 p = (struct prefix_ipv6 *) &rp->p;
2027
2028#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002029 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2030 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002031 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002032 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002033 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002034#else
ajsf52d13c2005-10-01 17:38:06 +00002035 len = vty_out (vty, "%c(%s) %s/%d ",
2036 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002037 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002038 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002039#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002040 vty_out (vty, "%s", VTY_NEWLINE);
2041 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002042 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002043
hassoa94434b2003-05-25 17:10:12 +00002044 len = 28 - len;
2045 if (len > 0)
2046 len = vty_out (vty, "%*s", len, " ");
2047
2048 /* from */
2049 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2050 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2051 {
2052 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2053 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2054 {
2055 len = vty_out (vty, "kill");
2056 } else
2057 len = vty_out (vty, "self");
2058
2059 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002060 if (len > 0)
2061 vty_out (vty, "%*s", len, " ");
2062
hassoa94434b2003-05-25 17:10:12 +00002063 vty_out (vty, " %2d %3d ",
2064 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002065
hassoa94434b2003-05-25 17:10:12 +00002066 /* time */
2067 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2068 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2069 {
2070 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002071 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002072 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2073 {
2074 /* poisonous reversed routes (gc) */
2075 ripng_vty_out_uptime (vty, rinfo);
2076 }
paul718e3742002-12-13 20:15:29 +00002077
2078 vty_out (vty, "%s", VTY_NEWLINE);
2079 }
2080 }
2081
2082 return CMD_SUCCESS;
2083}
2084
hassoa94434b2003-05-25 17:10:12 +00002085DEFUN (show_ipv6_ripng_status,
2086 show_ipv6_ripng_status_cmd,
2087 "show ipv6 ripng status",
2088 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002089 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002090 "Show RIPng routes\n"
2091 "IPv6 routing protocol process parameters and statistics\n")
2092{
hasso52dc7ee2004-09-23 19:18:23 +00002093 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002094 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002095
2096 if (! ripng)
2097 return CMD_SUCCESS;
2098
2099 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2100 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2101 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002102 vty_out (vty, " next due in %lu seconds%s",
2103 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002104 VTY_NEWLINE);
2105 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2106 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2107 VTY_NEWLINE);
2108
2109 /* Filtering status show. */
2110 config_show_distribute (vty);
2111
2112 /* Default metric information. */
2113 vty_out (vty, " Default redistribution metric is %d%s",
2114 ripng->default_metric, VTY_NEWLINE);
2115
2116 /* Redistribute information. */
2117 vty_out (vty, " Redistributing:");
2118 ripng_redistribute_write (vty, 0);
2119 vty_out (vty, "%s", VTY_NEWLINE);
2120
2121 vty_out (vty, " Default version control: send version %d,", ripng->version);
2122 vty_out (vty, " receive version %d %s", ripng->version,
2123 VTY_NEWLINE);
2124
2125 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2126
paul1eb8ef22005-04-07 07:30:20 +00002127 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002128 {
2129 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002130
hassoa94434b2003-05-25 17:10:12 +00002131 ri = ifp->info;
2132
2133 if (ri->enable_network || ri->enable_interface)
2134 {
2135
2136 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2137 ripng->version,
2138 ripng->version,
2139 VTY_NEWLINE);
2140 }
2141 }
2142
2143 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2144 ripng_network_write (vty, 0);
2145
2146 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2147 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2148 ripng_peer_display (vty);
2149
2150 return CMD_SUCCESS;
2151}
2152
paul718e3742002-12-13 20:15:29 +00002153DEFUN (router_ripng,
2154 router_ripng_cmd,
2155 "router ripng",
2156 "Enable a routing process\n"
2157 "Make RIPng instance command\n")
2158{
2159 int ret;
2160
2161 vty->node = RIPNG_NODE;
2162
2163 if (!ripng)
2164 {
2165 ret = ripng_create ();
2166
2167 /* Notice to user we couldn't create RIPng. */
2168 if (ret < 0)
2169 {
2170 zlog_warn ("can't create RIPng");
2171 return CMD_WARNING;
2172 }
2173 }
2174
2175 return CMD_SUCCESS;
2176}
2177
hassoa94434b2003-05-25 17:10:12 +00002178DEFUN (no_router_ripng,
2179 no_router_ripng_cmd,
2180 "no router ripng",
2181 NO_STR
2182 "Enable a routing process\n"
2183 "Make RIPng instance command\n")
2184{
2185 if(ripng)
2186 ripng_clean();
2187 return CMD_SUCCESS;
2188}
2189
paul718e3742002-12-13 20:15:29 +00002190DEFUN (ripng_route,
2191 ripng_route_cmd,
2192 "route IPV6ADDR",
2193 "Static route setup\n"
2194 "Set static RIPng route announcement\n")
2195{
2196 int ret;
2197 struct prefix_ipv6 p;
2198 struct route_node *rp;
2199
2200 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2201 if (ret <= 0)
2202 {
2203 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2204 return CMD_WARNING;
2205 }
2206 apply_mask_ipv6 (&p);
2207
2208 rp = route_node_get (ripng->route, (struct prefix *) &p);
2209 if (rp->info)
2210 {
2211 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2212 route_unlock_node (rp);
2213 return CMD_WARNING;
2214 }
2215 rp->info = (void *)1;
2216
hassoa94434b2003-05-25 17:10:12 +00002217 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002218
2219 return CMD_SUCCESS;
2220}
2221
2222DEFUN (no_ripng_route,
2223 no_ripng_route_cmd,
2224 "no route IPV6ADDR",
2225 NO_STR
2226 "Static route setup\n"
2227 "Delete static RIPng route announcement\n")
2228{
2229 int ret;
2230 struct prefix_ipv6 p;
2231 struct route_node *rp;
2232
2233 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2234 if (ret <= 0)
2235 {
2236 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2237 return CMD_WARNING;
2238 }
2239 apply_mask_ipv6 (&p);
2240
2241 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2242 if (! rp)
2243 {
2244 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2245 return CMD_WARNING;
2246 }
2247
2248 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2249 route_unlock_node (rp);
2250
2251 rp->info = NULL;
2252 route_unlock_node (rp);
2253
2254 return CMD_SUCCESS;
2255}
2256
2257DEFUN (ripng_aggregate_address,
2258 ripng_aggregate_address_cmd,
2259 "aggregate-address X:X::X:X/M",
2260 "Set aggregate RIPng route announcement\n"
2261 "Aggregate network\n")
2262{
2263 int ret;
2264 struct prefix p;
2265 struct route_node *node;
2266
2267 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2268 if (ret <= 0)
2269 {
2270 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2271 return CMD_WARNING;
2272 }
2273
2274 /* Check aggregate alredy exist or not. */
2275 node = route_node_get (ripng->aggregate, &p);
2276 if (node->info)
2277 {
2278 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2279 route_unlock_node (node);
2280 return CMD_WARNING;
2281 }
2282 node->info = (void *)1;
2283
2284 ripng_aggregate_add (&p);
2285
2286 return CMD_SUCCESS;
2287}
2288
2289DEFUN (no_ripng_aggregate_address,
2290 no_ripng_aggregate_address_cmd,
2291 "no aggregate-address X:X::X:X/M",
2292 NO_STR
2293 "Delete aggregate RIPng route announcement\n"
2294 "Aggregate network")
2295{
2296 int ret;
2297 struct prefix p;
2298 struct route_node *rn;
2299
2300 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2301 if (ret <= 0)
2302 {
2303 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2304 return CMD_WARNING;
2305 }
2306
2307 rn = route_node_lookup (ripng->aggregate, &p);
2308 if (! rn)
2309 {
2310 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2311 return CMD_WARNING;
2312 }
2313 route_unlock_node (rn);
2314 rn->info = NULL;
2315 route_unlock_node (rn);
2316
2317 ripng_aggregate_delete (&p);
2318
2319 return CMD_SUCCESS;
2320}
2321
2322DEFUN (ripng_default_metric,
2323 ripng_default_metric_cmd,
2324 "default-metric <1-16>",
2325 "Set a metric of redistribute routes\n"
2326 "Default metric\n")
2327{
2328 if (ripng)
2329 {
2330 ripng->default_metric = atoi (argv[0]);
2331 }
2332 return CMD_SUCCESS;
2333}
2334
2335DEFUN (no_ripng_default_metric,
2336 no_ripng_default_metric_cmd,
2337 "no default-metric",
2338 NO_STR
2339 "Set a metric of redistribute routes\n"
2340 "Default metric\n")
2341{
2342 if (ripng)
2343 {
2344 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2345 }
2346 return CMD_SUCCESS;
2347}
2348
2349ALIAS (no_ripng_default_metric,
2350 no_ripng_default_metric_val_cmd,
2351 "no default-metric <1-16>",
2352 NO_STR
2353 "Set a metric of redistribute routes\n"
2354 "Default metric\n")
2355
2356#if 0
2357/* RIPng update timer setup. */
2358DEFUN (ripng_update_timer,
2359 ripng_update_timer_cmd,
2360 "update-timer SECOND",
2361 "Set RIPng update timer in seconds\n"
2362 "Seconds\n")
2363{
2364 unsigned long update;
2365 char *endptr = NULL;
2366
2367 update = strtoul (argv[0], &endptr, 10);
2368 if (update == ULONG_MAX || *endptr != '\0')
2369 {
2370 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2371 return CMD_WARNING;
2372 }
2373
2374 ripng->update_time = update;
2375
2376 ripng_event (RIPNG_UPDATE_EVENT, 0);
2377 return CMD_SUCCESS;
2378}
2379
2380DEFUN (no_ripng_update_timer,
2381 no_ripng_update_timer_cmd,
2382 "no update-timer SECOND",
2383 NO_STR
2384 "Unset RIPng update timer in seconds\n"
2385 "Seconds\n")
2386{
2387 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2388 ripng_event (RIPNG_UPDATE_EVENT, 0);
2389 return CMD_SUCCESS;
2390}
2391
2392/* RIPng timeout timer setup. */
2393DEFUN (ripng_timeout_timer,
2394 ripng_timeout_timer_cmd,
2395 "timeout-timer SECOND",
2396 "Set RIPng timeout timer in seconds\n"
2397 "Seconds\n")
2398{
2399 unsigned long timeout;
2400 char *endptr = NULL;
2401
2402 timeout = strtoul (argv[0], &endptr, 10);
2403 if (timeout == ULONG_MAX || *endptr != '\0')
2404 {
2405 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2406 return CMD_WARNING;
2407 }
2408
2409 ripng->timeout_time = timeout;
2410
2411 return CMD_SUCCESS;
2412}
2413
2414DEFUN (no_ripng_timeout_timer,
2415 no_ripng_timeout_timer_cmd,
2416 "no timeout-timer SECOND",
2417 NO_STR
2418 "Unset RIPng timeout timer in seconds\n"
2419 "Seconds\n")
2420{
2421 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2422 return CMD_SUCCESS;
2423}
2424
2425/* RIPng garbage timer setup. */
2426DEFUN (ripng_garbage_timer,
2427 ripng_garbage_timer_cmd,
2428 "garbage-timer SECOND",
2429 "Set RIPng garbage timer in seconds\n"
2430 "Seconds\n")
2431{
2432 unsigned long garbage;
2433 char *endptr = NULL;
2434
2435 garbage = strtoul (argv[0], &endptr, 10);
2436 if (garbage == ULONG_MAX || *endptr != '\0')
2437 {
2438 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2439 return CMD_WARNING;
2440 }
2441
2442 ripng->garbage_time = garbage;
2443
2444 return CMD_SUCCESS;
2445}
2446
2447DEFUN (no_ripng_garbage_timer,
2448 no_ripng_garbage_timer_cmd,
2449 "no garbage-timer SECOND",
2450 NO_STR
2451 "Unset RIPng garbage timer in seconds\n"
2452 "Seconds\n")
2453{
2454 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2455 return CMD_SUCCESS;
2456}
2457#endif /* 0 */
2458
2459DEFUN (ripng_timers,
2460 ripng_timers_cmd,
2461 "timers basic <0-65535> <0-65535> <0-65535>",
2462 "RIPng timers setup\n"
2463 "Basic timer\n"
2464 "Routing table update timer value in second. Default is 30.\n"
2465 "Routing information timeout timer. Default is 180.\n"
2466 "Garbage collection timer. Default is 120.\n")
2467{
2468 unsigned long update;
2469 unsigned long timeout;
2470 unsigned long garbage;
paul718e3742002-12-13 20:15:29 +00002471
Ulrich Weber69898802011-11-17 21:35:08 +04002472 VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2473 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2474 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
paul718e3742002-12-13 20:15:29 +00002475
2476 /* Set each timer value. */
2477 ripng->update_time = update;
2478 ripng->timeout_time = timeout;
2479 ripng->garbage_time = garbage;
2480
2481 /* Reset update timer thread. */
2482 ripng_event (RIPNG_UPDATE_EVENT, 0);
2483
2484 return CMD_SUCCESS;
2485}
2486
2487DEFUN (no_ripng_timers,
2488 no_ripng_timers_cmd,
2489 "no timers basic",
2490 NO_STR
2491 "RIPng timers setup\n"
2492 "Basic timer\n")
2493{
2494 /* Set each timer value to the default. */
2495 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2496 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2497 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2498
2499 /* Reset update timer thread. */
2500 ripng_event (RIPNG_UPDATE_EVENT, 0);
2501
2502 return CMD_SUCCESS;
2503}
2504
hassoa94434b2003-05-25 17:10:12 +00002505ALIAS (no_ripng_timers,
2506 no_ripng_timers_val_cmd,
2507 "no timers basic <0-65535> <0-65535> <0-65535>",
2508 NO_STR
2509 "RIPng timers setup\n"
2510 "Basic timer\n"
2511 "Routing table update timer value in second. Default is 30.\n"
2512 "Routing information timeout timer. Default is 180.\n"
2513 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002514
2515DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2516 "show ipv6 protocols",
2517 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002518 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002519 "Routing protocol information")
2520{
2521 if (! ripng)
2522 return CMD_SUCCESS;
2523
2524 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2525
2526 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2527 ripng->update_time, 0,
2528 VTY_NEWLINE);
2529
2530 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2531 ripng->timeout_time,
2532 ripng->garbage_time,
2533 VTY_NEWLINE);
2534
2535 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2536 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2537
2538 return CMD_SUCCESS;
2539}
2540
2541/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002542DEFUN (ripng_default_information_originate,
2543 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002544 "default-information originate",
2545 "Default route information\n"
2546 "Distribute default route\n")
2547{
2548 struct prefix_ipv6 p;
2549
hassoa94434b2003-05-25 17:10:12 +00002550 if (! ripng ->default_information) {
2551 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002552
hassoa94434b2003-05-25 17:10:12 +00002553 str2prefix_ipv6 ("::/0", &p);
2554 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2555 }
paul718e3742002-12-13 20:15:29 +00002556
2557 return CMD_SUCCESS;
2558}
2559
paula2c62832003-04-23 17:01:31 +00002560DEFUN (no_ripng_default_information_originate,
2561 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002562 "no default-information originate",
2563 NO_STR
2564 "Default route information\n"
2565 "Distribute default route\n")
2566{
2567 struct prefix_ipv6 p;
2568
hassoa94434b2003-05-25 17:10:12 +00002569 if (ripng->default_information) {
2570 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002571
hassoa94434b2003-05-25 17:10:12 +00002572 str2prefix_ipv6 ("::/0", &p);
2573 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2574 }
paul718e3742002-12-13 20:15:29 +00002575
2576 return CMD_SUCCESS;
2577}
2578
Feng Lu72855b12015-05-22 11:39:54 +02002579/* Update ECMP routes to zebra when ECMP is disabled. */
2580static void
2581ripng_ecmp_disable (void)
2582{
2583 struct route_node *rp;
2584 struct ripng_info *rinfo, *tmp_rinfo;
2585 struct list *list;
2586 struct listnode *node, *nextnode;
2587
2588 if (!ripng)
2589 return;
2590
2591 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2592 if ((list = rp->info) != NULL && listcount (list) > 1)
2593 {
2594 rinfo = listgetdata (listhead (list));
2595 if (!ripng_route_rte (rinfo))
2596 continue;
2597
2598 /* Drop all other entries, except the first one. */
2599 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
2600 if (tmp_rinfo != rinfo)
2601 {
2602 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
2603 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
2604 list_delete_node (list, node);
2605 ripng_info_free (tmp_rinfo);
2606 }
2607
2608 /* Update zebra. */
2609 ripng_zebra_ipv6_add (rp);
2610
2611 /* Set the route change flag. */
2612 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
2613
2614 /* Signal the output process to trigger an update. */
2615 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
2616 }
2617}
2618
2619DEFUN (ripng_allow_ecmp,
2620 ripng_allow_ecmp_cmd,
2621 "allow-ecmp",
2622 "Allow Equal Cost MultiPath\n")
2623{
2624 if (ripng->ecmp)
2625 {
2626 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2627 return CMD_WARNING;
2628 }
2629
2630 ripng->ecmp = 1;
2631 zlog_info ("ECMP is enabled.");
2632 return CMD_SUCCESS;
2633}
2634
2635DEFUN (no_ripng_allow_ecmp,
2636 no_ripng_allow_ecmp_cmd,
2637 "no allow-ecmp",
2638 NO_STR
2639 "Allow Equal Cost MultiPath\n")
2640{
2641 if (!ripng->ecmp)
2642 {
2643 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2644 return CMD_WARNING;
2645 }
2646
2647 ripng->ecmp = 0;
2648 zlog_info ("ECMP is disabled.");
2649 ripng_ecmp_disable ();
2650 return CMD_SUCCESS;
2651}
2652
paul718e3742002-12-13 20:15:29 +00002653/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002654static int
paul718e3742002-12-13 20:15:29 +00002655ripng_config_write (struct vty *vty)
2656{
hassoa94434b2003-05-25 17:10:12 +00002657 int ripng_network_write (struct vty *, int);
2658 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002659 int write = 0;
2660 struct route_node *rp;
2661
2662 if (ripng)
2663 {
2664
2665 /* RIPng router. */
2666 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2667
2668 if (ripng->default_information)
2669 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2670
hassoa94434b2003-05-25 17:10:12 +00002671 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002672
2673 /* RIPng default metric configuration */
2674 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2675 vty_out (vty, " default-metric %d%s",
2676 ripng->default_metric, VTY_NEWLINE);
2677
hassoa94434b2003-05-25 17:10:12 +00002678 ripng_redistribute_write (vty, 1);
2679
2680 /* RIP offset-list configuration. */
2681 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002682
2683 /* RIPng aggregate routes. */
2684 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2685 if (rp->info != NULL)
2686 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002687 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002688 rp->p.prefixlen,
2689
2690 VTY_NEWLINE);
2691
Feng Lu72855b12015-05-22 11:39:54 +02002692 /* ECMP configuration. */
2693 if (ripng->ecmp)
2694 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
2695
paul718e3742002-12-13 20:15:29 +00002696 /* RIPng static routes. */
2697 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2698 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002699 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002700 rp->p.prefixlen,
2701 VTY_NEWLINE);
2702
2703 /* RIPng timers configuration. */
2704 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2705 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2706 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2707 {
2708 vty_out (vty, " timers basic %ld %ld %ld%s",
2709 ripng->update_time,
2710 ripng->timeout_time,
2711 ripng->garbage_time,
2712 VTY_NEWLINE);
2713 }
2714#if 0
2715 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2716 vty_out (vty, " update-timer %d%s", ripng->update_time,
2717 VTY_NEWLINE);
2718 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2719 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2720 VTY_NEWLINE);
2721 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2722 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2723 VTY_NEWLINE);
2724#endif /* 0 */
2725
2726 write += config_write_distribute (vty);
2727
2728 write += config_write_if_rmap (vty);
2729
2730 write++;
2731 }
2732 return write;
2733}
2734
2735/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002736static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002737{
2738 RIPNG_NODE,
2739 "%s(config-router)# ",
2740 1,
2741};
2742
Paul Jakma6ac29a52008-08-15 13:45:30 +01002743static void
paul718e3742002-12-13 20:15:29 +00002744ripng_distribute_update (struct distribute *dist)
2745{
2746 struct interface *ifp;
2747 struct ripng_interface *ri;
2748 struct access_list *alist;
2749 struct prefix_list *plist;
2750
2751 if (! dist->ifname)
2752 return;
2753
2754 ifp = if_lookup_by_name (dist->ifname);
2755 if (ifp == NULL)
2756 return;
2757
2758 ri = ifp->info;
2759
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002760 if (dist->list[DISTRIBUTE_V6_IN])
paul718e3742002-12-13 20:15:29 +00002761 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002762 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_IN]);
paul718e3742002-12-13 20:15:29 +00002763 if (alist)
2764 ri->list[RIPNG_FILTER_IN] = alist;
2765 else
2766 ri->list[RIPNG_FILTER_IN] = NULL;
2767 }
2768 else
2769 ri->list[RIPNG_FILTER_IN] = NULL;
2770
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002771 if (dist->list[DISTRIBUTE_V6_OUT])
paul718e3742002-12-13 20:15:29 +00002772 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002773 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_OUT]);
paul718e3742002-12-13 20:15:29 +00002774 if (alist)
2775 ri->list[RIPNG_FILTER_OUT] = alist;
2776 else
2777 ri->list[RIPNG_FILTER_OUT] = NULL;
2778 }
2779 else
2780 ri->list[RIPNG_FILTER_OUT] = NULL;
2781
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002782 if (dist->prefix[DISTRIBUTE_V6_IN])
paul718e3742002-12-13 20:15:29 +00002783 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002784 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_IN]);
paul718e3742002-12-13 20:15:29 +00002785 if (plist)
2786 ri->prefix[RIPNG_FILTER_IN] = plist;
2787 else
2788 ri->prefix[RIPNG_FILTER_IN] = NULL;
2789 }
2790 else
2791 ri->prefix[RIPNG_FILTER_IN] = NULL;
2792
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002793 if (dist->prefix[DISTRIBUTE_V6_OUT])
paul718e3742002-12-13 20:15:29 +00002794 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002795 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_OUT]);
paul718e3742002-12-13 20:15:29 +00002796 if (plist)
2797 ri->prefix[RIPNG_FILTER_OUT] = plist;
2798 else
2799 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2800 }
2801 else
2802 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2803}
hassoa94434b2003-05-25 17:10:12 +00002804
paul718e3742002-12-13 20:15:29 +00002805void
2806ripng_distribute_update_interface (struct interface *ifp)
2807{
2808 struct distribute *dist;
2809
2810 dist = distribute_lookup (ifp->name);
2811 if (dist)
2812 ripng_distribute_update (dist);
2813}
2814
2815/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002816static void
hassoc9e52be2004-09-26 16:09:34 +00002817ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002818{
2819 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002820 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002821
paul1eb8ef22005-04-07 07:30:20 +00002822 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2823 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002824}
hassoc9e52be2004-09-26 16:09:34 +00002825
Paul Jakma6ac29a52008-08-15 13:45:30 +01002826static void
hassoc9e52be2004-09-26 16:09:34 +00002827ripng_distribute_update_all_wrapper (struct access_list *notused)
2828{
2829 ripng_distribute_update_all(NULL);
2830}
David Lamparter6b0655a2014-06-04 06:53:35 +02002831
hassoa94434b2003-05-25 17:10:12 +00002832/* delete all the added ripng routes. */
2833void
2834ripng_clean()
2835{
2836 int i;
2837 struct route_node *rp;
2838 struct ripng_info *rinfo;
Feng Lue97c31a2015-05-22 11:39:53 +02002839 struct ripng_aggregate *aggregate;
2840 struct list *list = NULL;
2841 struct listnode *listnode = NULL;
hassoa94434b2003-05-25 17:10:12 +00002842
2843 if (ripng) {
2844 /* Clear RIPng routes */
Feng Lue97c31a2015-05-22 11:39:53 +02002845 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2846 {
2847 if ((list = rp->info) != NULL)
2848 {
2849 rinfo = listgetdata (listhead (list));
2850 if (ripng_route_rte (rinfo))
2851 ripng_zebra_ipv6_delete (rp);
hassoa94434b2003-05-25 17:10:12 +00002852
Feng Lue97c31a2015-05-22 11:39:53 +02002853 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2854 {
2855 RIPNG_TIMER_OFF (rinfo->t_timeout);
2856 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2857 ripng_info_free (rinfo);
2858 }
2859 list_delete (list);
2860 rp->info = NULL;
2861 route_unlock_node (rp);
2862 }
hassoa94434b2003-05-25 17:10:12 +00002863
Feng Lue97c31a2015-05-22 11:39:53 +02002864 if ((aggregate = rp->aggregate) != NULL)
2865 {
2866 ripng_aggregate_free (aggregate);
2867 rp->aggregate = NULL;
2868 route_unlock_node (rp);
2869 }
hassoa94434b2003-05-25 17:10:12 +00002870 }
2871
2872 /* Cancel the RIPng timers */
2873 RIPNG_TIMER_OFF (ripng->t_update);
2874 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2875 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2876
2877 /* Cancel the read thread */
2878 if (ripng->t_read) {
2879 thread_cancel (ripng->t_read);
2880 ripng->t_read = NULL;
2881 }
2882
2883 /* Close the RIPng socket */
2884 if (ripng->sock >= 0) {
2885 close(ripng->sock);
2886 ripng->sock = -1;
2887 }
2888
2889 /* Static RIPng route configuration. */
2890 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2891 if (rp->info) {
2892 rp->info = NULL;
2893 route_unlock_node (rp);
2894 }
2895
2896 /* RIPng aggregated prefixes */
2897 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2898 if (rp->info) {
2899 rp->info = NULL;
2900 route_unlock_node (rp);
2901 }
2902
2903 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2904 if (ripng->route_map[i].name)
2905 free (ripng->route_map[i].name);
2906
2907 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2908 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2909 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2910
2911 XFREE (MTYPE_RIPNG, ripng);
2912 ripng = NULL;
2913 } /* if (ripng) */
2914
2915 ripng_clean_network();
2916 ripng_passive_interface_clean ();
2917 ripng_offset_clean ();
2918 ripng_interface_clean ();
2919 ripng_redistribute_clean ();
2920}
2921
2922/* Reset all values to the default settings. */
2923void
2924ripng_reset ()
2925{
2926 /* Call ripd related reset functions. */
2927 ripng_debug_reset ();
2928 ripng_route_map_reset ();
2929
2930 /* Call library reset functions. */
2931 vty_reset ();
2932 access_list_reset ();
2933 prefix_list_reset ();
2934
2935 distribute_list_reset ();
2936
2937 ripng_interface_reset ();
2938
2939 ripng_zclient_reset ();
2940}
paul718e3742002-12-13 20:15:29 +00002941
Paul Jakma6ac29a52008-08-15 13:45:30 +01002942static void
paul718e3742002-12-13 20:15:29 +00002943ripng_if_rmap_update (struct if_rmap *if_rmap)
2944{
2945 struct interface *ifp;
2946 struct ripng_interface *ri;
2947 struct route_map *rmap;
2948
2949 ifp = if_lookup_by_name (if_rmap->ifname);
2950 if (ifp == NULL)
2951 return;
2952
2953 ri = ifp->info;
2954
2955 if (if_rmap->routemap[IF_RMAP_IN])
2956 {
2957 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2958 if (rmap)
2959 ri->routemap[IF_RMAP_IN] = rmap;
2960 else
2961 ri->routemap[IF_RMAP_IN] = NULL;
2962 }
2963 else
2964 ri->routemap[RIPNG_FILTER_IN] = NULL;
2965
2966 if (if_rmap->routemap[IF_RMAP_OUT])
2967 {
2968 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2969 if (rmap)
2970 ri->routemap[IF_RMAP_OUT] = rmap;
2971 else
2972 ri->routemap[IF_RMAP_OUT] = NULL;
2973 }
2974 else
2975 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2976}
2977
2978void
2979ripng_if_rmap_update_interface (struct interface *ifp)
2980{
2981 struct if_rmap *if_rmap;
2982
2983 if_rmap = if_rmap_lookup (ifp->name);
2984 if (if_rmap)
2985 ripng_if_rmap_update (if_rmap);
2986}
2987
Paul Jakma6ac29a52008-08-15 13:45:30 +01002988static void
paul718e3742002-12-13 20:15:29 +00002989ripng_routemap_update_redistribute (void)
2990{
2991 int i;
2992
2993 if (ripng)
2994 {
2995 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2996 {
2997 if (ripng->route_map[i].name)
2998 ripng->route_map[i].map =
2999 route_map_lookup_by_name (ripng->route_map[i].name);
3000 }
3001 }
3002}
3003
Paul Jakma6ac29a52008-08-15 13:45:30 +01003004static void
hasso98b718a2004-10-11 12:57:57 +00003005ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00003006{
3007 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00003008 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003009
paul1eb8ef22005-04-07 07:30:20 +00003010 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
3011 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003012
3013 ripng_routemap_update_redistribute ();
3014}
3015
3016/* Initialize ripng structure and set commands. */
3017void
3018ripng_init ()
3019{
3020 /* Randomize. */
Donald Sharpf31bab42015-06-19 19:26:19 -04003021 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00003022
3023 /* Install RIPNG_NODE. */
3024 install_node (&cmd_ripng_node, ripng_config_write);
3025
3026 /* Install ripng commands. */
3027 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003028 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003029
3030 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003031 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003032
3033 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003034 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00003035
3036 install_default (RIPNG_NODE);
3037 install_element (RIPNG_NODE, &ripng_route_cmd);
3038 install_element (RIPNG_NODE, &no_ripng_route_cmd);
3039 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3040 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3041
3042 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3043 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
3044 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
3045
3046 install_element (RIPNG_NODE, &ripng_timers_cmd);
3047 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00003048 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00003049#if 0
3050 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3051 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3052 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3053 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3054 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3055 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3056#endif /* 0 */
3057
paula2c62832003-04-23 17:01:31 +00003058 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3059 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00003060
Feng Lu72855b12015-05-22 11:39:54 +02003061 install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
3062 install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
3063
paul718e3742002-12-13 20:15:29 +00003064 ripng_if_init ();
3065 ripng_debug_init ();
3066
3067 /* Access list install. */
3068 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003069 access_list_add_hook (ripng_distribute_update_all_wrapper);
3070 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003071
3072 /* Prefix list initialize.*/
3073 prefix_list_init ();
3074 prefix_list_add_hook (ripng_distribute_update_all);
3075 prefix_list_delete_hook (ripng_distribute_update_all);
3076
3077 /* Distribute list install. */
3078 distribute_list_init (RIPNG_NODE);
3079 distribute_list_add_hook (ripng_distribute_update);
3080 distribute_list_delete_hook (ripng_distribute_update);
3081
3082 /* Route-map for interface. */
3083 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003084 ripng_offset_init ();
3085
paul718e3742002-12-13 20:15:29 +00003086 route_map_add_hook (ripng_routemap_update);
3087 route_map_delete_hook (ripng_routemap_update);
3088
hasso0750d212003-05-24 21:41:49 +00003089 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003090 if_rmap_hook_add (ripng_if_rmap_update);
3091 if_rmap_hook_delete (ripng_if_rmap_update);
3092}