blob: 97a1392817733a099d39da3c1d8e99c48a71351b [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,
232 struct sockaddr_in6 *from, unsigned int *ifindex,
233 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
hassoa94434b2003-05-25 17:10:12 +0000611ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
612{
613 struct distribute *dist;
614 struct access_list *alist;
615 struct prefix_list *plist;
616
617 /* Input distribute-list filtering. */
618 if (ri->list[RIPNG_FILTER_IN])
619 {
620 if (access_list_apply (ri->list[RIPNG_FILTER_IN],
621 (struct prefix *) p) == FILTER_DENY)
622 {
623 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000624 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000625 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000626 return -1;
627 }
628 }
629 if (ri->prefix[RIPNG_FILTER_IN])
630 {
631 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
632 (struct prefix *) p) == PREFIX_DENY)
633 {
634 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000635 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000636 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000637 return -1;
638 }
639 }
640
641 /* All interface filter check. */
642 dist = distribute_lookup (NULL);
643 if (dist)
644 {
645 if (dist->list[DISTRIBUTE_IN])
646 {
647 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
648
649 if (alist)
650 {
651 if (access_list_apply (alist,
652 (struct prefix *) p) == FILTER_DENY)
653 {
654 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000655 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000656 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000657 return -1;
658 }
659 }
660 }
661 if (dist->prefix[DISTRIBUTE_IN])
662 {
663 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
664
665 if (plist)
666 {
667 if (prefix_list_apply (plist,
668 (struct prefix *) p) == PREFIX_DENY)
669 {
670 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000671 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000672 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000673 return -1;
674 }
675 }
676 }
677 }
678 return 0;
679}
680
Paul Jakma6ac29a52008-08-15 13:45:30 +0100681static int
hassoa94434b2003-05-25 17:10:12 +0000682ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
683{
684 struct distribute *dist;
685 struct access_list *alist;
686 struct prefix_list *plist;
687
688 if (ri->list[RIPNG_FILTER_OUT])
689 {
690 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
691 (struct prefix *) p) == FILTER_DENY)
692 {
693 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000694 zlog_debug ("%s/%d is filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000695 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000696 return -1;
697 }
698 }
699 if (ri->prefix[RIPNG_FILTER_OUT])
700 {
701 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
702 (struct prefix *) p) == PREFIX_DENY)
703 {
704 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000705 zlog_debug ("%s/%d is filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000706 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000707 return -1;
708 }
709 }
710
711 /* All interface filter check. */
712 dist = distribute_lookup (NULL);
713 if (dist)
714 {
715 if (dist->list[DISTRIBUTE_OUT])
716 {
717 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
718
719 if (alist)
720 {
721 if (access_list_apply (alist,
722 (struct prefix *) p) == FILTER_DENY)
723 {
724 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000725 zlog_debug ("%s/%d filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000726 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000727 return -1;
728 }
729 }
730 }
731 if (dist->prefix[DISTRIBUTE_OUT])
732 {
733 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
734
735 if (plist)
736 {
737 if (prefix_list_apply (plist,
738 (struct prefix *) p) == PREFIX_DENY)
739 {
740 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000741 zlog_debug ("%s/%d filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000742 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000743 return -1;
744 }
745 }
746 }
747 }
748 return 0;
749}
750
paul718e3742002-12-13 20:15:29 +0000751/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100752static void
paul718e3742002-12-13 20:15:29 +0000753ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
754 struct ripng_nexthop *ripng_nexthop,
755 struct interface *ifp)
756{
hassoa94434b2003-05-25 17:10:12 +0000757 int ret;
paul718e3742002-12-13 20:15:29 +0000758 struct prefix_ipv6 p;
759 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200760 struct ripng_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000761 struct ripng_interface *ri;
762 struct in6_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000763 int same = 0;
Feng Lue97c31a2015-05-22 11:39:53 +0200764 struct list *list = NULL;
765 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000766
767 /* Make prefix structure. */
768 memset (&p, 0, sizeof (struct prefix_ipv6));
769 p.family = AF_INET6;
770 /* p.prefix = rte->addr; */
771 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
772 p.prefixlen = rte->prefixlen;
773
774 /* Make sure mask is applied. */
775 /* XXX We have to check the prefix is valid or not before call
776 apply_mask_ipv6. */
777 apply_mask_ipv6 (&p);
778
779 /* Apply input filters. */
780 ri = ifp->info;
781
hassoa94434b2003-05-25 17:10:12 +0000782 ret = ripng_incoming_filter (&p, ri);
783 if (ret < 0)
784 return;
paul718e3742002-12-13 20:15:29 +0000785
Feng Lue97c31a2015-05-22 11:39:53 +0200786 memset (&newinfo, 0, sizeof (newinfo));
787 newinfo.type = ZEBRA_ROUTE_RIPNG;
788 newinfo.sub_type = RIPNG_ROUTE_RTE;
789 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
790 newinfo.nexthop = ripng_nexthop->address;
791 else
792 newinfo.nexthop = from->sin6_addr;
793 newinfo.from = from->sin6_addr;
794 newinfo.ifindex = ifp->ifindex;
795 newinfo.metric = rte->metric;
796 newinfo.metric_out = rte->metric; /* XXX */
797 newinfo.tag = ntohs (rte->tag); /* XXX */
798
paul718e3742002-12-13 20:15:29 +0000799 /* Modify entry. */
800 if (ri->routemap[RIPNG_FILTER_IN])
801 {
802 int ret;
paul718e3742002-12-13 20:15:29 +0000803
804 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
805 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
806
807 if (ret == RMAP_DENYMATCH)
808 {
809 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000810 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000811 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000812 return;
813 }
814
hassoa94434b2003-05-25 17:10:12 +0000815 /* Get back the object */
816 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
817 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
818 /* the nexthop get changed by the routemap */
819 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
820 ripng_nexthop->address = newinfo.nexthop;
821 else
822 ripng_nexthop->address = in6addr_any;
823 }
824 } else {
825 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
826 /* the nexthop get changed by the routemap */
827 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
828 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
829 ripng_nexthop->address = newinfo.nexthop;
830 }
831 }
832 }
833 rte->tag = htons(newinfo.tag_out); /* XXX */
834 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000835 }
836
hassoa94434b2003-05-25 17:10:12 +0000837 /* Once the entry has been validated, update the metric by
838 * adding the cost of the network on wich the message
839 * arrived. If the result is greater than infinity, use infinity
840 * (RFC2453 Sec. 3.9.2)
841 **/
842
843 /* Zebra ripngd can handle offset-list in. */
844 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
845
846 /* If offset-list does not modify the metric use interface's
847 * one. */
848 if (! ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000849 rte->metric += ifp->metric ? ifp->metric : 1;
hassoa94434b2003-05-25 17:10:12 +0000850
851 if (rte->metric > RIPNG_METRIC_INFINITY)
852 rte->metric = RIPNG_METRIC_INFINITY;
853
paul718e3742002-12-13 20:15:29 +0000854 /* Set nexthop pointer. */
855 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
856 nexthop = &ripng_nexthop->address;
857 else
858 nexthop = &from->sin6_addr;
859
860 /* Lookup RIPng routing table. */
861 rp = route_node_get (ripng->table, (struct prefix *) &p);
862
Feng Lue97c31a2015-05-22 11:39:53 +0200863 newinfo.rp = rp;
864 newinfo.nexthop = *nexthop;
865 newinfo.metric = rte->metric;
866 newinfo.tag = ntohs (rte->tag);
867
868 /* Check to see whether there is already RIPng route on the table. */
869 if ((list = rp->info) != NULL)
870 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
871 {
872 /* Need to compare with redistributed entry or local entry */
873 if (!ripng_route_rte (rinfo))
874 break;
875
876 if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
877 IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
878 break;
879
880 if (!listnextnode (node))
881 {
882 /* Not found in the list */
883
884 if (rte->metric > rinfo->metric)
885 {
886 /* New route has a greater metric. Discard it. */
887 route_unlock_node (rp);
888 return;
889 }
890
891 if (rte->metric < rinfo->metric)
892 /* New route has a smaller metric. Replace the ECMP list
893 * with the new one in below. */
894 break;
895
896 /* Metrics are same. Keep "rinfo" null and the new route
897 * is added in the ECMP list in below. */
898 }
899 }
900
hassoa94434b2003-05-25 17:10:12 +0000901 if (rinfo)
902 {
903 /* Redistributed route check. */
904 if (rinfo->type != ZEBRA_ROUTE_RIPNG
905 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200906 {
907 route_unlock_node (rp);
908 return;
909 }
hassoa94434b2003-05-25 17:10:12 +0000910
911 /* Local static route. */
912 if (rinfo->type == ZEBRA_ROUTE_RIPNG
913 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
914 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
915 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200916 {
917 route_unlock_node (rp);
918 return;
919 }
hassoa94434b2003-05-25 17:10:12 +0000920 }
921
Feng Lue97c31a2015-05-22 11:39:53 +0200922 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000923 {
924 /* Now, check to see whether there is already an explicit route
925 for the destination prefix. If there is no such route, add
926 this route to the routing table, unless the metric is
927 infinity (there is no point in adding a route which
928 unusable). */
929 if (rte->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200930 ripng_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000931 }
932 else
933 {
paul718e3742002-12-13 20:15:29 +0000934 /* If there is an existing route, compare the next hop address
935 to the address of the router from which the datagram came.
936 If this datagram is from the same router as the existing
937 route, reinitialize the timeout. */
938 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
939 && (rinfo->ifindex == ifp->ifindex));
940
paul718e3742002-12-13 20:15:29 +0000941 /* Next, compare the metrics. If the datagram is from the same
942 router as the existing route, and the new metric is different
943 than the old one; or, if the new metric is lower than the old
944 one; do the following actions: */
945 if ((same && rinfo->metric != rte->metric) ||
946 rte->metric < rinfo->metric)
947 {
Feng Lue97c31a2015-05-22 11:39:53 +0200948 if (listcount (list) == 1)
949 {
950 if (newinfo.metric != RIPNG_METRIC_INFINITY)
951 ripng_ecmp_replace (&newinfo);
952 else
953 ripng_ecmp_delete (rinfo);
954 }
955 else
956 {
957 if (newinfo.metric < rinfo->metric)
958 ripng_ecmp_replace (&newinfo);
959 else /* newinfo.metric > rinfo->metric */
960 ripng_ecmp_delete (rinfo);
961 }
paul718e3742002-12-13 20:15:29 +0000962 }
Feng Lue97c31a2015-05-22 11:39:53 +0200963 else /* same & no change */
964 ripng_timeout_update (rinfo);
965
paul718e3742002-12-13 20:15:29 +0000966 /* Unlock tempolary lock of the route. */
967 route_unlock_node (rp);
968 }
969}
970
971/* Add redistributed route to RIPng table. */
972void
973ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +0000974 unsigned int ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000975{
976 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200977 struct ripng_info *rinfo = NULL, newinfo;
978 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +0000979
980 /* Redistribute route */
981 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
982 return;
983 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
984 return;
985
986 rp = route_node_get (ripng->table, (struct prefix *) p);
paul718e3742002-12-13 20:15:29 +0000987
Feng Lue97c31a2015-05-22 11:39:53 +0200988 memset (&newinfo, 0, sizeof (struct ripng_info));
989 newinfo.type = type;
990 newinfo.sub_type = sub_type;
991 newinfo.ifindex = ifindex;
992 newinfo.metric = 1;
993 newinfo.rp = rp;
994 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
995 newinfo.nexthop = *nexthop;
996
997 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +0000998 {
Feng Lue97c31a2015-05-22 11:39:53 +0200999 rinfo = listgetdata (listhead (list));
1000
hassoa94434b2003-05-25 17:10:12 +00001001 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1002 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
1003 && rinfo->metric != RIPNG_METRIC_INFINITY) {
1004 route_unlock_node (rp);
1005 return;
1006 }
1007
1008 /* Manually configured RIPng route check.
1009 * They have the precedence on all the other entries.
1010 **/
1011 if (rinfo->type == ZEBRA_ROUTE_RIPNG
1012 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
1013 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
1014 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
1015 (sub_type != RIPNG_ROUTE_DEFAULT))) {
1016 route_unlock_node (rp);
1017 return;
1018 }
1019 }
hassoa94434b2003-05-25 17:10:12 +00001020
Feng Lue97c31a2015-05-22 11:39:53 +02001021 rinfo = ripng_ecmp_replace (&newinfo);
paul718e3742002-12-13 20:15:29 +00001022 route_unlock_node (rp);
1023 }
Feng Lue97c31a2015-05-22 11:39:53 +02001024 else
1025 rinfo = ripng_ecmp_add (&newinfo);
hassoa94434b2003-05-25 17:10:12 +00001026
1027 if (IS_RIPNG_DEBUG_EVENT) {
1028 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +00001029 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001030 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001031 ifindex2ifname(ifindex));
1032 else
ajsc6106812004-12-08 19:51:16 +00001033 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001034 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001035 ifindex2ifname(ifindex));
1036 }
1037
1038 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001039}
1040
1041/* Delete redistributed route to RIPng table. */
1042void
1043ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1044 unsigned int ifindex)
1045{
1046 struct route_node *rp;
1047 struct ripng_info *rinfo;
1048
1049 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1050 return;
1051 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1052 return;
1053
1054 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1055
1056 if (rp)
1057 {
Feng Lue97c31a2015-05-22 11:39:53 +02001058 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001059
Feng Lue97c31a2015-05-22 11:39:53 +02001060 if (list != NULL && listcount (list) != 0)
1061 {
1062 rinfo = listgetdata (listhead (list));
1063 if (rinfo != NULL
1064 && rinfo->type == type
1065 && rinfo->sub_type == sub_type
1066 && rinfo->ifindex == ifindex)
1067 {
1068 /* Perform poisoned reverse. */
1069 rinfo->metric = RIPNG_METRIC_INFINITY;
1070 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1071 ripng_garbage_collect, ripng->garbage_time);
1072 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001073
Feng Lue97c31a2015-05-22 11:39:53 +02001074 /* Aggregate count decrement. */
1075 ripng_aggregate_decrement (rp, rinfo);
hassoa94434b2003-05-25 17:10:12 +00001076
Feng Lue97c31a2015-05-22 11:39:53 +02001077 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001078
Feng Lue97c31a2015-05-22 11:39:53 +02001079 if (IS_RIPNG_DEBUG_EVENT)
1080 zlog_debug ("Poisone %s/%d on the interface %s with an "
1081 "infinity metric [delete]",
1082 inet6_ntoa (p->prefix), p->prefixlen,
1083 ifindex2ifname (ifindex));
1084
1085 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1086 }
1087 }
1088 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001089 }
1090}
1091
1092/* Withdraw redistributed route. */
1093void
1094ripng_redistribute_withdraw (int type)
1095{
1096 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001097 struct ripng_info *rinfo = NULL;
1098 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001099
hassoa94434b2003-05-25 17:10:12 +00001100 if (!ripng)
1101 return;
1102
paul718e3742002-12-13 20:15:29 +00001103 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001104 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00001105 {
Feng Lue97c31a2015-05-22 11:39:53 +02001106 rinfo = listgetdata (listhead (list));
hassoa94434b2003-05-25 17:10:12 +00001107 if ((rinfo->type == type)
1108 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001109 {
hassoa94434b2003-05-25 17:10:12 +00001110 /* Perform poisoned reverse. */
1111 rinfo->metric = RIPNG_METRIC_INFINITY;
1112 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1113 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001114 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001115
hassoa94434b2003-05-25 17:10:12 +00001116 /* Aggregate count decrement. */
1117 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001118
hassoa94434b2003-05-25 17:10:12 +00001119 rinfo->flags |= RIPNG_RTF_CHANGED;
1120
1121 if (IS_RIPNG_DEBUG_EVENT) {
1122 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1123
ajsc6106812004-12-08 19:51:16 +00001124 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001125 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001126 ifindex2ifname(rinfo->ifindex));
1127 }
1128
1129 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001130 }
1131 }
1132}
1133
1134/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001135static void
paul718e3742002-12-13 20:15:29 +00001136ripng_response_process (struct ripng_packet *packet, int size,
1137 struct sockaddr_in6 *from, struct interface *ifp,
1138 int hoplimit)
1139{
1140 caddr_t lim;
1141 struct rte *rte;
1142 struct ripng_nexthop nexthop;
1143
1144 /* RFC2080 2.4.2 Response Messages:
1145 The Response must be ignored if it is not from the RIPng port. */
1146 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1147 {
1148 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001149 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001150 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001151 return;
1152 }
1153
1154 /* The datagram's IPv6 source address should be checked to see
1155 whether the datagram is from a valid neighbor; the source of the
1156 datagram must be a link-local address. */
1157 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1158 {
1159 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001160 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001161 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001162 return;
1163 }
1164
1165 /* It is also worth checking to see whether the response is from one
1166 of the router's own addresses. Interfaces on broadcast networks
1167 may receive copies of their own multicasts immediately. If a
1168 router processes its own output as new input, confusion is likely,
1169 and such datagrams must be ignored. */
1170 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1171 {
1172 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001173 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001174 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001175 return;
1176 }
1177
1178 /* As an additional check, periodic advertisements must have their
1179 hop counts set to 255, and inbound, multicast packets sent from the
1180 RIPng port (i.e. periodic advertisement or triggered update
1181 packets) must be examined to ensure that the hop count is 255. */
1182 if (hoplimit >= 0 && hoplimit != 255)
1183 {
1184 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001185 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001186 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001187 return;
1188 }
1189
hassoa94434b2003-05-25 17:10:12 +00001190 /* Update RIPng peer. */
1191 ripng_peer_update (from, packet->version);
1192
paul718e3742002-12-13 20:15:29 +00001193 /* Reset nexthop. */
1194 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1195 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1196
1197 /* Set RTE pointer. */
1198 rte = packet->rte;
1199
1200 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1201 {
1202 /* First of all, we have to check this RTE is next hop RTE or
1203 not. Next hop RTE is completely different with normal RTE so
1204 we need special treatment. */
1205 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1206 {
1207 ripng_nexthop_rte (rte, from, &nexthop);
1208 continue;
1209 }
1210
1211 /* RTE information validation. */
1212
1213 /* - is the destination prefix valid (e.g., not a multicast
1214 prefix and not a link-local address) A link-local address
1215 should never be present in an RTE. */
1216 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1217 {
1218 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001219 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001220 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001221 continue;
1222 }
1223 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1224 {
1225 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001226 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001227 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001228 continue;
1229 }
1230 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1231 {
1232 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001233 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001234 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001235 continue;
1236 }
1237
1238 /* - is the prefix length valid (i.e., between 0 and 128,
1239 inclusive) */
1240 if (rte->prefixlen > 128)
1241 {
1242 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001243 inet6_ntoa (rte->addr), rte->prefixlen,
1244 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001245 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001246 continue;
1247 }
1248
1249 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1250 if (! (rte->metric >= 1 && rte->metric <= 16))
1251 {
1252 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001253 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001254 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001255 continue;
1256 }
1257
hassoa94434b2003-05-25 17:10:12 +00001258 /* Vincent: XXX Should we compute the direclty reachable nexthop
1259 * for our RIPng network ?
1260 **/
paul718e3742002-12-13 20:15:29 +00001261
1262 /* Routing table updates. */
1263 ripng_route_process (rte, from, &nexthop, ifp);
1264 }
1265}
1266
1267/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001268static void
paul718e3742002-12-13 20:15:29 +00001269ripng_request_process (struct ripng_packet *packet,int size,
1270 struct sockaddr_in6 *from, struct interface *ifp)
1271{
1272 caddr_t lim;
1273 struct rte *rte;
1274 struct prefix_ipv6 p;
1275 struct route_node *rp;
1276 struct ripng_info *rinfo;
1277 struct ripng_interface *ri;
1278
hassoa94434b2003-05-25 17:10:12 +00001279 /* Does not reponse to the requests on the loopback interfaces */
1280 if (if_is_loopback (ifp))
1281 return;
1282
paul718e3742002-12-13 20:15:29 +00001283 /* Check RIPng process is enabled on this interface. */
1284 ri = ifp->info;
1285 if (! ri->running)
1286 return;
1287
1288 /* When passive interface is specified, suppress responses */
1289 if (ri->passive)
1290 return;
1291
hassoa94434b2003-05-25 17:10:12 +00001292 /* RIPng peer update. */
1293 ripng_peer_update (from, packet->version);
1294
paul718e3742002-12-13 20:15:29 +00001295 lim = ((caddr_t) packet) + size;
1296 rte = packet->rte;
1297
1298 /* The Request is processed entry by entry. If there are no
1299 entries, no response is given. */
1300 if (lim == (caddr_t) rte)
1301 return;
1302
1303 /* There is one special case. If there is exactly one entry in the
1304 request, and it has a destination prefix of zero, a prefix length
1305 of zero, and a metric of infinity (i.e., 16), then this is a
1306 request to send the entire routing table. In that case, a call
1307 is made to the output process to send the routing table to the
1308 requesting address/port. */
1309 if (lim == ((caddr_t) (rte + 1)) &&
1310 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1311 rte->prefixlen == 0 &&
1312 rte->metric == RIPNG_METRIC_INFINITY)
1313 {
1314 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001315 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001316 }
1317 else
1318 {
1319 /* Except for this special case, processing is quite simple.
1320 Examine the list of RTEs in the Request one by one. For each
1321 entry, look up the destination in the router's routing
1322 database and, if there is a route, put that route's metric in
1323 the metric field of the RTE. If there is no explicit route
1324 to the specified destination, put infinity in the metric
1325 field. Once all the entries have been filled in, change the
1326 command from Request to Response and send the datagram back
1327 to the requestor. */
1328 memset (&p, 0, sizeof (struct prefix_ipv6));
1329 p.family = AF_INET6;
1330
1331 for (; ((caddr_t) rte) < lim; rte++)
1332 {
1333 p.prefix = rte->addr;
1334 p.prefixlen = rte->prefixlen;
1335 apply_mask_ipv6 (&p);
1336
1337 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1338
1339 if (rp)
1340 {
Feng Lue97c31a2015-05-22 11:39:53 +02001341 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001342 rte->metric = rinfo->metric;
1343 route_unlock_node (rp);
1344 }
1345 else
1346 rte->metric = RIPNG_METRIC_INFINITY;
1347 }
1348 packet->command = RIPNG_RESPONSE;
1349
1350 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1351 }
1352}
1353
1354/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001355static int
paul718e3742002-12-13 20:15:29 +00001356ripng_read (struct thread *thread)
1357{
1358 int len;
1359 int sock;
1360 struct sockaddr_in6 from;
1361 struct ripng_packet *packet;
David Lamparter6ed810d2015-04-21 10:13:07 +02001362 unsigned int ifindex = 0;
paul718e3742002-12-13 20:15:29 +00001363 struct interface *ifp;
1364 int hoplimit = -1;
1365
1366 /* Check ripng is active and alive. */
1367 assert (ripng != NULL);
1368 assert (ripng->sock >= 0);
1369
1370 /* Fetch thread data and set read pointer to empty for event
1371 managing. `sock' sould be same as ripng->sock. */
1372 sock = THREAD_FD (thread);
1373 ripng->t_read = NULL;
1374
1375 /* Add myself to the next event. */
1376 ripng_event (RIPNG_READ, sock);
1377
1378 /* Read RIPng packet. */
1379 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1380 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1381 &hoplimit);
1382 if (len < 0)
1383 {
ajs6099b3b2004-11-20 02:06:59 +00001384 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001385 return len;
1386 }
1387
1388 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1389 (4)) must be multiple size of one RTE size (20). */
1390 if (((len - 4) % 20) != 0)
1391 {
1392 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001393 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001394 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001395 return 0;
1396 }
1397
1398 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1399 ifp = if_lookup_by_index (ifindex);
1400
1401 /* RIPng packet received. */
1402 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001403 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001404 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001405 ifp ? ifp->name : "unknown");
1406
1407 /* Logging before packet checking. */
1408 if (IS_RIPNG_DEBUG_RECV)
1409 ripng_packet_dump (packet, len, "RECV");
1410
1411 /* Packet comes from unknown interface. */
1412 if (ifp == NULL)
1413 {
1414 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1415 return 0;
1416 }
1417
1418 /* Packet version mismatch checking. */
1419 if (packet->version != ripng->version)
1420 {
1421 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1422 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001423 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001424 return 0;
1425 }
1426
1427 /* Process RIPng packet. */
1428 switch (packet->command)
1429 {
1430 case RIPNG_REQUEST:
1431 ripng_request_process (packet, len, &from, ifp);
1432 break;
1433 case RIPNG_RESPONSE:
1434 ripng_response_process (packet, len, &from, ifp, hoplimit);
1435 break;
1436 default:
1437 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001438 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001439 break;
1440 }
1441 return 0;
1442}
1443
1444/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001445static void
1446ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001447{
1448 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001449 struct ripng_info *rinfo = NULL;
1450 struct list *list = NULL;
1451 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001452
1453 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001454 if ((list = rp->info) != NULL)
1455 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1456 {
1457 UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1458 /* This flag can be set only on the first entry. */
1459 break;
1460 }
paul718e3742002-12-13 20:15:29 +00001461}
1462
1463/* Regular update of RIPng route. Send all routing formation to RIPng
1464 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001465static int
paul718e3742002-12-13 20:15:29 +00001466ripng_update (struct thread *t)
1467{
hasso52dc7ee2004-09-23 19:18:23 +00001468 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001469 struct interface *ifp;
1470 struct ripng_interface *ri;
1471
1472 /* Clear update timer thread. */
1473 ripng->t_update = NULL;
1474
1475 /* Logging update event. */
1476 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001477 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001478
1479 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001480 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001481 {
paul718e3742002-12-13 20:15:29 +00001482 ri = ifp->info;
1483
1484 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1485 continue;
1486
1487 if (! ri->running)
1488 continue;
1489
1490 /* When passive interface is specified, suppress announce to the
1491 interface. */
1492 if (ri->passive)
1493 continue;
1494
1495#if RIPNG_ADVANCED
1496 if (ri->ri_send == RIPNG_SEND_OFF)
1497 {
1498 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001499 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001500 "[Event] RIPng send to if %d is suppressed by config",
1501 ifp->ifindex);
1502 continue;
1503 }
1504#endif /* RIPNG_ADVANCED */
1505
hassoa94434b2003-05-25 17:10:12 +00001506 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001507 }
1508
1509 /* Triggered updates may be suppressed if a regular update is due by
1510 the time the triggered update would be sent. */
1511 if (ripng->t_triggered_interval)
1512 {
1513 thread_cancel (ripng->t_triggered_interval);
1514 ripng->t_triggered_interval = NULL;
1515 }
1516 ripng->trigger = 0;
1517
1518 /* Reset flush event. */
1519 ripng_event (RIPNG_UPDATE_EVENT, 0);
1520
1521 return 0;
1522}
1523
1524/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001525static int
paul718e3742002-12-13 20:15:29 +00001526ripng_triggered_interval (struct thread *t)
1527{
1528 ripng->t_triggered_interval = NULL;
1529
1530 if (ripng->trigger)
1531 {
1532 ripng->trigger = 0;
1533 ripng_triggered_update (t);
1534 }
1535 return 0;
1536}
1537
1538/* Execute triggered update. */
1539int
1540ripng_triggered_update (struct thread *t)
1541{
hasso52dc7ee2004-09-23 19:18:23 +00001542 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001543 struct interface *ifp;
1544 struct ripng_interface *ri;
1545 int interval;
1546
1547 ripng->t_triggered_update = NULL;
1548
1549 /* Cancel interval timer. */
1550 if (ripng->t_triggered_interval)
1551 {
1552 thread_cancel (ripng->t_triggered_interval);
1553 ripng->t_triggered_interval = NULL;
1554 }
1555 ripng->trigger = 0;
1556
1557 /* Logging triggered update. */
1558 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001559 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001560
1561 /* Split Horizon processing is done when generating triggered
1562 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001563 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001564 {
paul718e3742002-12-13 20:15:29 +00001565 ri = ifp->info;
1566
1567 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1568 continue;
1569
1570 if (! ri->running)
1571 continue;
1572
1573 /* When passive interface is specified, suppress announce to the
1574 interface. */
1575 if (ri->passive)
1576 continue;
1577
hassoa94434b2003-05-25 17:10:12 +00001578 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001579 }
1580
1581 /* Once all of the triggered updates have been generated, the route
1582 change flags should be cleared. */
1583 ripng_clear_changed_flag ();
1584
1585 /* After a triggered update is sent, a timer should be set for a
1586 random interval between 1 and 5 seconds. If other changes that
1587 would trigger updates occur before the timer expires, a single
1588 update is triggered when the timer expires. */
1589 interval = (random () % 5) + 1;
1590
1591 ripng->t_triggered_interval =
1592 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1593
1594 return 0;
1595}
1596
1597/* Write routing table entry to the stream and return next index of
1598 the routing table entry in the stream. */
1599int
1600ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001601 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001602{
1603 /* RIPng packet header. */
1604 if (num == 0)
1605 {
1606 stream_putc (s, RIPNG_RESPONSE);
1607 stream_putc (s, RIPNG_V1);
1608 stream_putw (s, 0);
1609 }
1610
1611 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001612 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001613 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001614 else
hassoc9e52be2004-09-26 16:09:34 +00001615 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001616 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001617 if (p)
1618 stream_putc (s, p->prefixlen);
1619 else
1620 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001621 stream_putc (s, metric);
1622
1623 return ++num;
1624}
1625
1626/* Send RESPONSE message to specified destination. */
1627void
1628ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001629 int route_type)
paul718e3742002-12-13 20:15:29 +00001630{
1631 int ret;
paul718e3742002-12-13 20:15:29 +00001632 struct route_node *rp;
1633 struct ripng_info *rinfo;
1634 struct ripng_interface *ri;
1635 struct ripng_aggregate *aggregate;
1636 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001637 struct list * ripng_rte_list;
Feng Lue97c31a2015-05-22 11:39:53 +02001638 struct list *list = NULL;
1639 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001640
hassoa94434b2003-05-25 17:10:12 +00001641 if (IS_RIPNG_DEBUG_EVENT) {
1642 if (to)
ajsc6106812004-12-08 19:51:16 +00001643 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001644 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001645 else
ajsc6106812004-12-08 19:51:16 +00001646 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001647 }
paul718e3742002-12-13 20:15:29 +00001648
paul718e3742002-12-13 20:15:29 +00001649 /* Get RIPng interface. */
1650 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001651
1652 ripng_rte_list = ripng_rte_new();
1653
paul718e3742002-12-13 20:15:29 +00001654 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1655 {
Feng Lue97c31a2015-05-22 11:39:53 +02001656 if ((list = rp->info) != NULL &&
1657 (rinfo = listgetdata (listhead (list))) != NULL &&
1658 rinfo->suppress == 0)
paul718e3742002-12-13 20:15:29 +00001659 {
hassoa94434b2003-05-25 17:10:12 +00001660 /* If no route-map are applied, the RTE will be these following
1661 * informations.
1662 */
paul718e3742002-12-13 20:15:29 +00001663 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001664 rinfo->metric_out = rinfo->metric;
1665 rinfo->tag_out = rinfo->tag;
1666 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1667 /* In order to avoid some local loops,
1668 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1669 * otherwise set it to 0. The nexthop should not be propagated
1670 * beyond the local broadcast/multicast area in order
1671 * to avoid an IGP multi-level recursive look-up.
1672 */
1673 if (rinfo->ifindex == ifp->ifindex)
1674 rinfo->nexthop_out = rinfo->nexthop;
1675
1676 /* Apply output filters. */
1677 ret = ripng_outgoing_filter (p, ri);
1678 if (ret < 0)
1679 continue;
paul718e3742002-12-13 20:15:29 +00001680
1681 /* Changed route only output. */
1682 if (route_type == ripng_changed_route &&
1683 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1684 continue;
1685
1686 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001687 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1688 {
1689 /* We perform split horizon for RIPng routes. */
Feng Lue97c31a2015-05-22 11:39:53 +02001690 int suppress = 0;
1691 struct ripng_info *tmp_rinfo = NULL;
1692
1693 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1694 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1695 tmp_rinfo->ifindex == ifp->ifindex)
1696 {
1697 suppress = 1;
1698 break;
1699 }
1700 if (suppress)
hassoa94434b2003-05-25 17:10:12 +00001701 continue;
1702 }
paul718e3742002-12-13 20:15:29 +00001703
1704 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001705 rinfo->metric_set = 0;
1706 /* nexthop_out,
1707 * metric_out
1708 * and tag_out are already initialized.
1709 */
paul718e3742002-12-13 20:15:29 +00001710
hassoa94434b2003-05-25 17:10:12 +00001711 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001712 if (ri->routemap[RIPNG_FILTER_OUT])
1713 {
1714 int ret;
paul718e3742002-12-13 20:15:29 +00001715
1716 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1717 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001718 rinfo);
paul718e3742002-12-13 20:15:29 +00001719
1720 if (ret == RMAP_DENYMATCH)
1721 {
1722 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001723 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001724 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001725 continue;
paul718e3742002-12-13 20:15:29 +00001726 }
1727
paul718e3742002-12-13 20:15:29 +00001728 }
1729
hassoa94434b2003-05-25 17:10:12 +00001730 /* Redistribute route-map. */
1731 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001732 {
hassoa94434b2003-05-25 17:10:12 +00001733 int ret;
1734
1735 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1736 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001737 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001738
1739 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001740 {
hassoa94434b2003-05-25 17:10:12 +00001741 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001742 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001743 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001744 continue;
paul718e3742002-12-13 20:15:29 +00001745 }
hassoa94434b2003-05-25 17:10:12 +00001746 }
paul718e3742002-12-13 20:15:29 +00001747
hassoa94434b2003-05-25 17:10:12 +00001748 /* When the route-map does not set metric. */
1749 if (! rinfo->metric_set)
1750 {
1751 /* If the redistribute metric is set. */
1752 if (ripng->route_map[rinfo->type].metric_config
1753 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001754 {
hassoa94434b2003-05-25 17:10:12 +00001755 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1756 }
1757 else
1758 {
1759 /* If the route is not connected or localy generated
1760 one, use default-metric value */
1761 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1762 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001763 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001764 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001765 }
1766 }
1767
hassoa94434b2003-05-25 17:10:12 +00001768 /* Apply offset-list */
1769 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1770 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001771
hassoa94434b2003-05-25 17:10:12 +00001772 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1773 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1774
1775 /* Perform split-horizon with poisoned reverse
1776 * for RIPng routes.
1777 **/
1778 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
Feng Lue97c31a2015-05-22 11:39:53 +02001779 struct ripng_info *tmp_rinfo = NULL;
1780
1781 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1782 if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1783 tmp_rinfo->ifindex == ifp->ifindex)
1784 rinfo->metric_out = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +00001785 }
1786
1787 /* Add RTE to the list */
1788 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001789 }
hassoa94434b2003-05-25 17:10:12 +00001790
1791 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001792 if ((aggregate = rp->aggregate) != NULL &&
1793 aggregate->count > 0 &&
1794 aggregate->suppress == 0)
1795 {
hassoa94434b2003-05-25 17:10:12 +00001796 /* If no route-map are applied, the RTE will be these following
1797 * informations.
1798 */
paul718e3742002-12-13 20:15:29 +00001799 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001800 aggregate->metric_set = 0;
1801 aggregate->metric_out = aggregate->metric;
1802 aggregate->tag_out = aggregate->tag;
1803 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001804
1805 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001806 ret = ripng_outgoing_filter (p, ri);
1807 if (ret < 0)
1808 continue;
paul718e3742002-12-13 20:15:29 +00001809
hassoa94434b2003-05-25 17:10:12 +00001810 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001811 if (ri->routemap[RIPNG_FILTER_OUT])
1812 {
1813 int ret;
1814 struct ripng_info newinfo;
1815
hassoa94434b2003-05-25 17:10:12 +00001816 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001817 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001818 /* the nexthop is :: */
1819 newinfo.metric = aggregate->metric;
1820 newinfo.metric_out = aggregate->metric_out;
1821 newinfo.tag = aggregate->tag;
1822 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001823
1824 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1825 (struct prefix *) p, RMAP_RIPNG,
1826 &newinfo);
1827
1828 if (ret == RMAP_DENYMATCH)
1829 {
1830 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001831 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001832 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001833 continue;
paul718e3742002-12-13 20:15:29 +00001834 }
1835
hassoa94434b2003-05-25 17:10:12 +00001836 aggregate->metric_out = newinfo.metric_out;
1837 aggregate->tag_out = newinfo.tag_out;
1838 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1839 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001840 }
1841
hassoa94434b2003-05-25 17:10:12 +00001842 /* There is no redistribute routemap for the aggregated RTE */
1843
paul718e3742002-12-13 20:15:29 +00001844 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001845 /* XXX, vincent, in order to increase time convergence,
1846 * it should be announced if a child has changed.
1847 */
paul718e3742002-12-13 20:15:29 +00001848 if (route_type == ripng_changed_route)
1849 continue;
1850
hassoa94434b2003-05-25 17:10:12 +00001851 /* Apply offset-list */
1852 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1853 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001854
hassoa94434b2003-05-25 17:10:12 +00001855 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1856 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1857
1858 /* Add RTE to the list */
1859 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001860 }
1861
1862 }
paul718e3742002-12-13 20:15:29 +00001863
hassoa94434b2003-05-25 17:10:12 +00001864 /* Flush the list */
1865 ripng_rte_send(ripng_rte_list, ifp, to);
1866 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001867}
1868
1869/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001870static int
1871ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001872{
1873 /* ripng should be NULL. */
1874 assert (ripng == NULL);
1875
1876 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001877 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001878
1879 /* Default version and timer values. */
1880 ripng->version = RIPNG_V1;
1881 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1882 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1883 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1884 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1885
1886 /* Make buffer. */
1887 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1888 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1889
1890 /* Initialize RIPng routig table. */
1891 ripng->table = route_table_init ();
1892 ripng->route = route_table_init ();
1893 ripng->aggregate = route_table_init ();
1894
1895 /* Make socket. */
1896 ripng->sock = ripng_make_socket ();
1897 if (ripng->sock < 0)
1898 return ripng->sock;
1899
1900 /* Threads. */
1901 ripng_event (RIPNG_READ, ripng->sock);
1902 ripng_event (RIPNG_UPDATE_EVENT, 1);
1903
1904 return 0;
1905}
1906
hassoa94434b2003-05-25 17:10:12 +00001907/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001908int
1909ripng_request (struct interface *ifp)
1910{
1911 struct rte *rte;
1912 struct ripng_packet ripng_packet;
1913
hassoa94434b2003-05-25 17:10:12 +00001914 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1915 if (if_is_loopback(ifp))
1916 return 0;
1917
1918 /* If interface is down, don't send RIP packet. */
1919 if (! if_is_up (ifp))
1920 return 0;
1921
paul718e3742002-12-13 20:15:29 +00001922 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001923 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001924
1925 memset (&ripng_packet, 0, sizeof (ripng_packet));
1926 ripng_packet.command = RIPNG_REQUEST;
1927 ripng_packet.version = RIPNG_V1;
1928 rte = ripng_packet.rte;
1929 rte->metric = RIPNG_METRIC_INFINITY;
1930
1931 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1932 NULL, ifp);
1933}
1934
David Lamparter6b0655a2014-06-04 06:53:35 +02001935
Paul Jakma6ac29a52008-08-15 13:45:30 +01001936static int
paul718e3742002-12-13 20:15:29 +00001937ripng_update_jitter (int time)
1938{
Donald Sharpf31bab42015-06-19 19:26:19 -04001939 return ((random () % (time + 1)) - (time / 2));
paul718e3742002-12-13 20:15:29 +00001940}
1941
1942void
1943ripng_event (enum ripng_event event, int sock)
1944{
paul718e3742002-12-13 20:15:29 +00001945 int jitter = 0;
1946
1947 switch (event)
1948 {
1949 case RIPNG_READ:
1950 if (!ripng->t_read)
1951 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1952 break;
1953 case RIPNG_UPDATE_EVENT:
1954 if (ripng->t_update)
1955 {
1956 thread_cancel (ripng->t_update);
1957 ripng->t_update = NULL;
1958 }
1959 /* Update timer jitter. */
1960 jitter = ripng_update_jitter (ripng->update_time);
1961
1962 ripng->t_update =
1963 thread_add_timer (master, ripng_update, NULL,
1964 sock ? 2 : ripng->update_time + jitter);
1965 break;
1966 case RIPNG_TRIGGERED_UPDATE:
1967 if (ripng->t_triggered_interval)
1968 ripng->trigger = 1;
1969 else if (! ripng->t_triggered_update)
1970 ripng->t_triggered_update =
1971 thread_add_event (master, ripng_triggered_update, NULL, 0);
1972 break;
1973 default:
1974 break;
1975 }
1976}
David Lamparter6b0655a2014-06-04 06:53:35 +02001977
paul718e3742002-12-13 20:15:29 +00001978
paul718e3742002-12-13 20:15:29 +00001979/* Print out routes update time. */
1980static void
1981ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1982{
paul718e3742002-12-13 20:15:29 +00001983 time_t clock;
1984 struct tm *tm;
1985#define TIME_BUF 25
1986 char timebuf [TIME_BUF];
1987 struct thread *thread;
1988
paul718e3742002-12-13 20:15:29 +00001989 if ((thread = rinfo->t_timeout) != NULL)
1990 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001991 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001992 tm = gmtime (&clock);
1993 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1994 vty_out (vty, "%5s", timebuf);
1995 }
1996 else if ((thread = rinfo->t_garbage_collect) != NULL)
1997 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001998 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001999 tm = gmtime (&clock);
2000 strftime (timebuf, TIME_BUF, "%M:%S", tm);
2001 vty_out (vty, "%5s", timebuf);
2002 }
2003}
2004
Paul Jakma6ac29a52008-08-15 13:45:30 +01002005static char *
hassoa94434b2003-05-25 17:10:12 +00002006ripng_route_subtype_print (struct ripng_info *rinfo)
2007{
2008 static char str[3];
2009 memset(str, 0, 3);
2010
2011 if (rinfo->suppress)
2012 strcat(str, "S");
2013
2014 switch (rinfo->sub_type)
2015 {
2016 case RIPNG_ROUTE_RTE:
2017 strcat(str, "n");
2018 break;
2019 case RIPNG_ROUTE_STATIC:
2020 strcat(str, "s");
2021 break;
2022 case RIPNG_ROUTE_DEFAULT:
2023 strcat(str, "d");
2024 break;
2025 case RIPNG_ROUTE_REDISTRIBUTE:
2026 strcat(str, "r");
2027 break;
2028 case RIPNG_ROUTE_INTERFACE:
2029 strcat(str, "i");
2030 break;
2031 default:
2032 strcat(str, "?");
2033 break;
2034 }
2035
2036 return str;
2037}
2038
paul718e3742002-12-13 20:15:29 +00002039DEFUN (show_ipv6_ripng,
2040 show_ipv6_ripng_cmd,
2041 "show ipv6 ripng",
2042 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002043 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002044 "Show RIPng routes\n")
2045{
2046 struct route_node *rp;
2047 struct ripng_info *rinfo;
2048 struct ripng_aggregate *aggregate;
2049 struct prefix_ipv6 *p;
Feng Lue97c31a2015-05-22 11:39:53 +02002050 struct list *list = NULL;
2051 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002052 int len;
2053
hassoa94434b2003-05-25 17:10:12 +00002054 if (! ripng)
2055 return CMD_SUCCESS;
2056
paul718e3742002-12-13 20:15:29 +00002057 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00002058 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2059 "Sub-codes:%s"
2060 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2061 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2062 " Network Next Hop Via Metric Tag Time%s",
2063 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002064 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2065
2066 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2067 {
2068 if ((aggregate = rp->aggregate) != NULL)
2069 {
2070 p = (struct prefix_ipv6 *) &rp->p;
2071
2072#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002073 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002074 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002075 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002076#else
hassoa94434b2003-05-25 17:10:12 +00002077 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002078 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002079#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002080 vty_out (vty, "%s", VTY_NEWLINE);
2081 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002082
hassoa94434b2003-05-25 17:10:12 +00002083 vty_out (vty, "%*s", 28, " ");
2084 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002085 aggregate->tag,
2086 VTY_NEWLINE);
2087 }
2088
Feng Lue97c31a2015-05-22 11:39:53 +02002089 if ((list = rp->info) != NULL)
2090 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00002091 {
2092 p = (struct prefix_ipv6 *) &rp->p;
2093
2094#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002095 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2096 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002097 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002098 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002099 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002100#else
ajsf52d13c2005-10-01 17:38:06 +00002101 len = vty_out (vty, "%c(%s) %s/%d ",
2102 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002103 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002104 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002105#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002106 vty_out (vty, "%s", VTY_NEWLINE);
2107 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002108 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002109
hassoa94434b2003-05-25 17:10:12 +00002110 len = 28 - len;
2111 if (len > 0)
2112 len = vty_out (vty, "%*s", len, " ");
2113
2114 /* from */
2115 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2116 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2117 {
2118 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2119 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2120 {
2121 len = vty_out (vty, "kill");
2122 } else
2123 len = vty_out (vty, "self");
2124
2125 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002126 if (len > 0)
2127 vty_out (vty, "%*s", len, " ");
2128
hassoa94434b2003-05-25 17:10:12 +00002129 vty_out (vty, " %2d %3d ",
2130 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002131
hassoa94434b2003-05-25 17:10:12 +00002132 /* time */
2133 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2134 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2135 {
2136 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002137 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002138 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2139 {
2140 /* poisonous reversed routes (gc) */
2141 ripng_vty_out_uptime (vty, rinfo);
2142 }
paul718e3742002-12-13 20:15:29 +00002143
2144 vty_out (vty, "%s", VTY_NEWLINE);
2145 }
2146 }
2147
2148 return CMD_SUCCESS;
2149}
2150
hassoa94434b2003-05-25 17:10:12 +00002151DEFUN (show_ipv6_ripng_status,
2152 show_ipv6_ripng_status_cmd,
2153 "show ipv6 ripng status",
2154 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002155 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002156 "Show RIPng routes\n"
2157 "IPv6 routing protocol process parameters and statistics\n")
2158{
hasso52dc7ee2004-09-23 19:18:23 +00002159 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002160 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002161
2162 if (! ripng)
2163 return CMD_SUCCESS;
2164
2165 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2166 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2167 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002168 vty_out (vty, " next due in %lu seconds%s",
2169 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002170 VTY_NEWLINE);
2171 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2172 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2173 VTY_NEWLINE);
2174
2175 /* Filtering status show. */
2176 config_show_distribute (vty);
2177
2178 /* Default metric information. */
2179 vty_out (vty, " Default redistribution metric is %d%s",
2180 ripng->default_metric, VTY_NEWLINE);
2181
2182 /* Redistribute information. */
2183 vty_out (vty, " Redistributing:");
2184 ripng_redistribute_write (vty, 0);
2185 vty_out (vty, "%s", VTY_NEWLINE);
2186
2187 vty_out (vty, " Default version control: send version %d,", ripng->version);
2188 vty_out (vty, " receive version %d %s", ripng->version,
2189 VTY_NEWLINE);
2190
2191 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2192
paul1eb8ef22005-04-07 07:30:20 +00002193 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002194 {
2195 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002196
hassoa94434b2003-05-25 17:10:12 +00002197 ri = ifp->info;
2198
2199 if (ri->enable_network || ri->enable_interface)
2200 {
2201
2202 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2203 ripng->version,
2204 ripng->version,
2205 VTY_NEWLINE);
2206 }
2207 }
2208
2209 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2210 ripng_network_write (vty, 0);
2211
2212 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2213 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2214 ripng_peer_display (vty);
2215
2216 return CMD_SUCCESS;
2217}
2218
paul718e3742002-12-13 20:15:29 +00002219DEFUN (router_ripng,
2220 router_ripng_cmd,
2221 "router ripng",
2222 "Enable a routing process\n"
2223 "Make RIPng instance command\n")
2224{
2225 int ret;
2226
2227 vty->node = RIPNG_NODE;
2228
2229 if (!ripng)
2230 {
2231 ret = ripng_create ();
2232
2233 /* Notice to user we couldn't create RIPng. */
2234 if (ret < 0)
2235 {
2236 zlog_warn ("can't create RIPng");
2237 return CMD_WARNING;
2238 }
2239 }
2240
2241 return CMD_SUCCESS;
2242}
2243
hassoa94434b2003-05-25 17:10:12 +00002244DEFUN (no_router_ripng,
2245 no_router_ripng_cmd,
2246 "no router ripng",
2247 NO_STR
2248 "Enable a routing process\n"
2249 "Make RIPng instance command\n")
2250{
2251 if(ripng)
2252 ripng_clean();
2253 return CMD_SUCCESS;
2254}
2255
paul718e3742002-12-13 20:15:29 +00002256DEFUN (ripng_route,
2257 ripng_route_cmd,
2258 "route IPV6ADDR",
2259 "Static route setup\n"
2260 "Set static RIPng route announcement\n")
2261{
2262 int ret;
2263 struct prefix_ipv6 p;
2264 struct route_node *rp;
2265
2266 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2267 if (ret <= 0)
2268 {
2269 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2270 return CMD_WARNING;
2271 }
2272 apply_mask_ipv6 (&p);
2273
2274 rp = route_node_get (ripng->route, (struct prefix *) &p);
2275 if (rp->info)
2276 {
2277 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2278 route_unlock_node (rp);
2279 return CMD_WARNING;
2280 }
2281 rp->info = (void *)1;
2282
hassoa94434b2003-05-25 17:10:12 +00002283 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002284
2285 return CMD_SUCCESS;
2286}
2287
2288DEFUN (no_ripng_route,
2289 no_ripng_route_cmd,
2290 "no route IPV6ADDR",
2291 NO_STR
2292 "Static route setup\n"
2293 "Delete static RIPng route announcement\n")
2294{
2295 int ret;
2296 struct prefix_ipv6 p;
2297 struct route_node *rp;
2298
2299 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2300 if (ret <= 0)
2301 {
2302 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2303 return CMD_WARNING;
2304 }
2305 apply_mask_ipv6 (&p);
2306
2307 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2308 if (! rp)
2309 {
2310 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2311 return CMD_WARNING;
2312 }
2313
2314 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2315 route_unlock_node (rp);
2316
2317 rp->info = NULL;
2318 route_unlock_node (rp);
2319
2320 return CMD_SUCCESS;
2321}
2322
2323DEFUN (ripng_aggregate_address,
2324 ripng_aggregate_address_cmd,
2325 "aggregate-address X:X::X:X/M",
2326 "Set aggregate RIPng route announcement\n"
2327 "Aggregate network\n")
2328{
2329 int ret;
2330 struct prefix p;
2331 struct route_node *node;
2332
2333 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2334 if (ret <= 0)
2335 {
2336 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2337 return CMD_WARNING;
2338 }
2339
2340 /* Check aggregate alredy exist or not. */
2341 node = route_node_get (ripng->aggregate, &p);
2342 if (node->info)
2343 {
2344 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2345 route_unlock_node (node);
2346 return CMD_WARNING;
2347 }
2348 node->info = (void *)1;
2349
2350 ripng_aggregate_add (&p);
2351
2352 return CMD_SUCCESS;
2353}
2354
2355DEFUN (no_ripng_aggregate_address,
2356 no_ripng_aggregate_address_cmd,
2357 "no aggregate-address X:X::X:X/M",
2358 NO_STR
2359 "Delete aggregate RIPng route announcement\n"
2360 "Aggregate network")
2361{
2362 int ret;
2363 struct prefix p;
2364 struct route_node *rn;
2365
2366 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2367 if (ret <= 0)
2368 {
2369 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2370 return CMD_WARNING;
2371 }
2372
2373 rn = route_node_lookup (ripng->aggregate, &p);
2374 if (! rn)
2375 {
2376 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2377 return CMD_WARNING;
2378 }
2379 route_unlock_node (rn);
2380 rn->info = NULL;
2381 route_unlock_node (rn);
2382
2383 ripng_aggregate_delete (&p);
2384
2385 return CMD_SUCCESS;
2386}
2387
2388DEFUN (ripng_default_metric,
2389 ripng_default_metric_cmd,
2390 "default-metric <1-16>",
2391 "Set a metric of redistribute routes\n"
2392 "Default metric\n")
2393{
2394 if (ripng)
2395 {
2396 ripng->default_metric = atoi (argv[0]);
2397 }
2398 return CMD_SUCCESS;
2399}
2400
2401DEFUN (no_ripng_default_metric,
2402 no_ripng_default_metric_cmd,
2403 "no default-metric",
2404 NO_STR
2405 "Set a metric of redistribute routes\n"
2406 "Default metric\n")
2407{
2408 if (ripng)
2409 {
2410 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2411 }
2412 return CMD_SUCCESS;
2413}
2414
2415ALIAS (no_ripng_default_metric,
2416 no_ripng_default_metric_val_cmd,
2417 "no default-metric <1-16>",
2418 NO_STR
2419 "Set a metric of redistribute routes\n"
2420 "Default metric\n")
2421
2422#if 0
2423/* RIPng update timer setup. */
2424DEFUN (ripng_update_timer,
2425 ripng_update_timer_cmd,
2426 "update-timer SECOND",
2427 "Set RIPng update timer in seconds\n"
2428 "Seconds\n")
2429{
2430 unsigned long update;
2431 char *endptr = NULL;
2432
2433 update = strtoul (argv[0], &endptr, 10);
2434 if (update == ULONG_MAX || *endptr != '\0')
2435 {
2436 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2437 return CMD_WARNING;
2438 }
2439
2440 ripng->update_time = update;
2441
2442 ripng_event (RIPNG_UPDATE_EVENT, 0);
2443 return CMD_SUCCESS;
2444}
2445
2446DEFUN (no_ripng_update_timer,
2447 no_ripng_update_timer_cmd,
2448 "no update-timer SECOND",
2449 NO_STR
2450 "Unset RIPng update timer in seconds\n"
2451 "Seconds\n")
2452{
2453 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2454 ripng_event (RIPNG_UPDATE_EVENT, 0);
2455 return CMD_SUCCESS;
2456}
2457
2458/* RIPng timeout timer setup. */
2459DEFUN (ripng_timeout_timer,
2460 ripng_timeout_timer_cmd,
2461 "timeout-timer SECOND",
2462 "Set RIPng timeout timer in seconds\n"
2463 "Seconds\n")
2464{
2465 unsigned long timeout;
2466 char *endptr = NULL;
2467
2468 timeout = strtoul (argv[0], &endptr, 10);
2469 if (timeout == ULONG_MAX || *endptr != '\0')
2470 {
2471 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2472 return CMD_WARNING;
2473 }
2474
2475 ripng->timeout_time = timeout;
2476
2477 return CMD_SUCCESS;
2478}
2479
2480DEFUN (no_ripng_timeout_timer,
2481 no_ripng_timeout_timer_cmd,
2482 "no timeout-timer SECOND",
2483 NO_STR
2484 "Unset RIPng timeout timer in seconds\n"
2485 "Seconds\n")
2486{
2487 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2488 return CMD_SUCCESS;
2489}
2490
2491/* RIPng garbage timer setup. */
2492DEFUN (ripng_garbage_timer,
2493 ripng_garbage_timer_cmd,
2494 "garbage-timer SECOND",
2495 "Set RIPng garbage timer in seconds\n"
2496 "Seconds\n")
2497{
2498 unsigned long garbage;
2499 char *endptr = NULL;
2500
2501 garbage = strtoul (argv[0], &endptr, 10);
2502 if (garbage == ULONG_MAX || *endptr != '\0')
2503 {
2504 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2505 return CMD_WARNING;
2506 }
2507
2508 ripng->garbage_time = garbage;
2509
2510 return CMD_SUCCESS;
2511}
2512
2513DEFUN (no_ripng_garbage_timer,
2514 no_ripng_garbage_timer_cmd,
2515 "no garbage-timer SECOND",
2516 NO_STR
2517 "Unset RIPng garbage timer in seconds\n"
2518 "Seconds\n")
2519{
2520 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2521 return CMD_SUCCESS;
2522}
2523#endif /* 0 */
2524
2525DEFUN (ripng_timers,
2526 ripng_timers_cmd,
2527 "timers basic <0-65535> <0-65535> <0-65535>",
2528 "RIPng timers setup\n"
2529 "Basic timer\n"
2530 "Routing table update timer value in second. Default is 30.\n"
2531 "Routing information timeout timer. Default is 180.\n"
2532 "Garbage collection timer. Default is 120.\n")
2533{
2534 unsigned long update;
2535 unsigned long timeout;
2536 unsigned long garbage;
paul718e3742002-12-13 20:15:29 +00002537
Ulrich Weber69898802011-11-17 21:35:08 +04002538 VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2539 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2540 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
paul718e3742002-12-13 20:15:29 +00002541
2542 /* Set each timer value. */
2543 ripng->update_time = update;
2544 ripng->timeout_time = timeout;
2545 ripng->garbage_time = garbage;
2546
2547 /* Reset update timer thread. */
2548 ripng_event (RIPNG_UPDATE_EVENT, 0);
2549
2550 return CMD_SUCCESS;
2551}
2552
2553DEFUN (no_ripng_timers,
2554 no_ripng_timers_cmd,
2555 "no timers basic",
2556 NO_STR
2557 "RIPng timers setup\n"
2558 "Basic timer\n")
2559{
2560 /* Set each timer value to the default. */
2561 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2562 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2563 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2564
2565 /* Reset update timer thread. */
2566 ripng_event (RIPNG_UPDATE_EVENT, 0);
2567
2568 return CMD_SUCCESS;
2569}
2570
hassoa94434b2003-05-25 17:10:12 +00002571ALIAS (no_ripng_timers,
2572 no_ripng_timers_val_cmd,
2573 "no timers basic <0-65535> <0-65535> <0-65535>",
2574 NO_STR
2575 "RIPng timers setup\n"
2576 "Basic timer\n"
2577 "Routing table update timer value in second. Default is 30.\n"
2578 "Routing information timeout timer. Default is 180.\n"
2579 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002580
2581DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2582 "show ipv6 protocols",
2583 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002584 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002585 "Routing protocol information")
2586{
2587 if (! ripng)
2588 return CMD_SUCCESS;
2589
2590 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2591
2592 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2593 ripng->update_time, 0,
2594 VTY_NEWLINE);
2595
2596 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2597 ripng->timeout_time,
2598 ripng->garbage_time,
2599 VTY_NEWLINE);
2600
2601 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2602 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2603
2604 return CMD_SUCCESS;
2605}
2606
2607/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002608DEFUN (ripng_default_information_originate,
2609 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002610 "default-information originate",
2611 "Default route information\n"
2612 "Distribute default route\n")
2613{
2614 struct prefix_ipv6 p;
2615
hassoa94434b2003-05-25 17:10:12 +00002616 if (! ripng ->default_information) {
2617 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002618
hassoa94434b2003-05-25 17:10:12 +00002619 str2prefix_ipv6 ("::/0", &p);
2620 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2621 }
paul718e3742002-12-13 20:15:29 +00002622
2623 return CMD_SUCCESS;
2624}
2625
paula2c62832003-04-23 17:01:31 +00002626DEFUN (no_ripng_default_information_originate,
2627 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002628 "no default-information originate",
2629 NO_STR
2630 "Default route information\n"
2631 "Distribute default route\n")
2632{
2633 struct prefix_ipv6 p;
2634
hassoa94434b2003-05-25 17:10:12 +00002635 if (ripng->default_information) {
2636 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002637
hassoa94434b2003-05-25 17:10:12 +00002638 str2prefix_ipv6 ("::/0", &p);
2639 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2640 }
paul718e3742002-12-13 20:15:29 +00002641
2642 return CMD_SUCCESS;
2643}
2644
Feng Lu72855b12015-05-22 11:39:54 +02002645/* Update ECMP routes to zebra when ECMP is disabled. */
2646static void
2647ripng_ecmp_disable (void)
2648{
2649 struct route_node *rp;
2650 struct ripng_info *rinfo, *tmp_rinfo;
2651 struct list *list;
2652 struct listnode *node, *nextnode;
2653
2654 if (!ripng)
2655 return;
2656
2657 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2658 if ((list = rp->info) != NULL && listcount (list) > 1)
2659 {
2660 rinfo = listgetdata (listhead (list));
2661 if (!ripng_route_rte (rinfo))
2662 continue;
2663
2664 /* Drop all other entries, except the first one. */
2665 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
2666 if (tmp_rinfo != rinfo)
2667 {
2668 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
2669 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
2670 list_delete_node (list, node);
2671 ripng_info_free (tmp_rinfo);
2672 }
2673
2674 /* Update zebra. */
2675 ripng_zebra_ipv6_add (rp);
2676
2677 /* Set the route change flag. */
2678 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
2679
2680 /* Signal the output process to trigger an update. */
2681 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
2682 }
2683}
2684
2685DEFUN (ripng_allow_ecmp,
2686 ripng_allow_ecmp_cmd,
2687 "allow-ecmp",
2688 "Allow Equal Cost MultiPath\n")
2689{
2690 if (ripng->ecmp)
2691 {
2692 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2693 return CMD_WARNING;
2694 }
2695
2696 ripng->ecmp = 1;
2697 zlog_info ("ECMP is enabled.");
2698 return CMD_SUCCESS;
2699}
2700
2701DEFUN (no_ripng_allow_ecmp,
2702 no_ripng_allow_ecmp_cmd,
2703 "no allow-ecmp",
2704 NO_STR
2705 "Allow Equal Cost MultiPath\n")
2706{
2707 if (!ripng->ecmp)
2708 {
2709 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2710 return CMD_WARNING;
2711 }
2712
2713 ripng->ecmp = 0;
2714 zlog_info ("ECMP is disabled.");
2715 ripng_ecmp_disable ();
2716 return CMD_SUCCESS;
2717}
2718
paul718e3742002-12-13 20:15:29 +00002719/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002720static int
paul718e3742002-12-13 20:15:29 +00002721ripng_config_write (struct vty *vty)
2722{
hassoa94434b2003-05-25 17:10:12 +00002723 int ripng_network_write (struct vty *, int);
2724 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002725 int write = 0;
2726 struct route_node *rp;
2727
2728 if (ripng)
2729 {
2730
2731 /* RIPng router. */
2732 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2733
2734 if (ripng->default_information)
2735 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2736
hassoa94434b2003-05-25 17:10:12 +00002737 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002738
2739 /* RIPng default metric configuration */
2740 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2741 vty_out (vty, " default-metric %d%s",
2742 ripng->default_metric, VTY_NEWLINE);
2743
hassoa94434b2003-05-25 17:10:12 +00002744 ripng_redistribute_write (vty, 1);
2745
2746 /* RIP offset-list configuration. */
2747 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002748
2749 /* RIPng aggregate routes. */
2750 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2751 if (rp->info != NULL)
2752 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002753 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002754 rp->p.prefixlen,
2755
2756 VTY_NEWLINE);
2757
Feng Lu72855b12015-05-22 11:39:54 +02002758 /* ECMP configuration. */
2759 if (ripng->ecmp)
2760 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
2761
paul718e3742002-12-13 20:15:29 +00002762 /* RIPng static routes. */
2763 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2764 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002765 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002766 rp->p.prefixlen,
2767 VTY_NEWLINE);
2768
2769 /* RIPng timers configuration. */
2770 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2771 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2772 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2773 {
2774 vty_out (vty, " timers basic %ld %ld %ld%s",
2775 ripng->update_time,
2776 ripng->timeout_time,
2777 ripng->garbage_time,
2778 VTY_NEWLINE);
2779 }
2780#if 0
2781 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2782 vty_out (vty, " update-timer %d%s", ripng->update_time,
2783 VTY_NEWLINE);
2784 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2785 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2786 VTY_NEWLINE);
2787 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2788 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2789 VTY_NEWLINE);
2790#endif /* 0 */
2791
2792 write += config_write_distribute (vty);
2793
2794 write += config_write_if_rmap (vty);
2795
2796 write++;
2797 }
2798 return write;
2799}
2800
2801/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002802static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002803{
2804 RIPNG_NODE,
2805 "%s(config-router)# ",
2806 1,
2807};
2808
Paul Jakma6ac29a52008-08-15 13:45:30 +01002809static void
paul718e3742002-12-13 20:15:29 +00002810ripng_distribute_update (struct distribute *dist)
2811{
2812 struct interface *ifp;
2813 struct ripng_interface *ri;
2814 struct access_list *alist;
2815 struct prefix_list *plist;
2816
2817 if (! dist->ifname)
2818 return;
2819
2820 ifp = if_lookup_by_name (dist->ifname);
2821 if (ifp == NULL)
2822 return;
2823
2824 ri = ifp->info;
2825
2826 if (dist->list[DISTRIBUTE_IN])
2827 {
2828 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2829 if (alist)
2830 ri->list[RIPNG_FILTER_IN] = alist;
2831 else
2832 ri->list[RIPNG_FILTER_IN] = NULL;
2833 }
2834 else
2835 ri->list[RIPNG_FILTER_IN] = NULL;
2836
2837 if (dist->list[DISTRIBUTE_OUT])
2838 {
2839 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2840 if (alist)
2841 ri->list[RIPNG_FILTER_OUT] = alist;
2842 else
2843 ri->list[RIPNG_FILTER_OUT] = NULL;
2844 }
2845 else
2846 ri->list[RIPNG_FILTER_OUT] = NULL;
2847
2848 if (dist->prefix[DISTRIBUTE_IN])
2849 {
2850 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2851 if (plist)
2852 ri->prefix[RIPNG_FILTER_IN] = plist;
2853 else
2854 ri->prefix[RIPNG_FILTER_IN] = NULL;
2855 }
2856 else
2857 ri->prefix[RIPNG_FILTER_IN] = NULL;
2858
2859 if (dist->prefix[DISTRIBUTE_OUT])
2860 {
2861 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2862 if (plist)
2863 ri->prefix[RIPNG_FILTER_OUT] = plist;
2864 else
2865 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2866 }
2867 else
2868 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2869}
hassoa94434b2003-05-25 17:10:12 +00002870
paul718e3742002-12-13 20:15:29 +00002871void
2872ripng_distribute_update_interface (struct interface *ifp)
2873{
2874 struct distribute *dist;
2875
2876 dist = distribute_lookup (ifp->name);
2877 if (dist)
2878 ripng_distribute_update (dist);
2879}
2880
2881/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002882static void
hassoc9e52be2004-09-26 16:09:34 +00002883ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002884{
2885 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002886 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002887
paul1eb8ef22005-04-07 07:30:20 +00002888 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2889 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002890}
hassoc9e52be2004-09-26 16:09:34 +00002891
Paul Jakma6ac29a52008-08-15 13:45:30 +01002892static void
hassoc9e52be2004-09-26 16:09:34 +00002893ripng_distribute_update_all_wrapper (struct access_list *notused)
2894{
2895 ripng_distribute_update_all(NULL);
2896}
David Lamparter6b0655a2014-06-04 06:53:35 +02002897
hassoa94434b2003-05-25 17:10:12 +00002898/* delete all the added ripng routes. */
2899void
2900ripng_clean()
2901{
2902 int i;
2903 struct route_node *rp;
2904 struct ripng_info *rinfo;
Feng Lue97c31a2015-05-22 11:39:53 +02002905 struct ripng_aggregate *aggregate;
2906 struct list *list = NULL;
2907 struct listnode *listnode = NULL;
hassoa94434b2003-05-25 17:10:12 +00002908
2909 if (ripng) {
2910 /* Clear RIPng routes */
Feng Lue97c31a2015-05-22 11:39:53 +02002911 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2912 {
2913 if ((list = rp->info) != NULL)
2914 {
2915 rinfo = listgetdata (listhead (list));
2916 if (ripng_route_rte (rinfo))
2917 ripng_zebra_ipv6_delete (rp);
hassoa94434b2003-05-25 17:10:12 +00002918
Feng Lue97c31a2015-05-22 11:39:53 +02002919 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2920 {
2921 RIPNG_TIMER_OFF (rinfo->t_timeout);
2922 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2923 ripng_info_free (rinfo);
2924 }
2925 list_delete (list);
2926 rp->info = NULL;
2927 route_unlock_node (rp);
2928 }
hassoa94434b2003-05-25 17:10:12 +00002929
Feng Lue97c31a2015-05-22 11:39:53 +02002930 if ((aggregate = rp->aggregate) != NULL)
2931 {
2932 ripng_aggregate_free (aggregate);
2933 rp->aggregate = NULL;
2934 route_unlock_node (rp);
2935 }
hassoa94434b2003-05-25 17:10:12 +00002936 }
2937
2938 /* Cancel the RIPng timers */
2939 RIPNG_TIMER_OFF (ripng->t_update);
2940 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2941 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2942
2943 /* Cancel the read thread */
2944 if (ripng->t_read) {
2945 thread_cancel (ripng->t_read);
2946 ripng->t_read = NULL;
2947 }
2948
2949 /* Close the RIPng socket */
2950 if (ripng->sock >= 0) {
2951 close(ripng->sock);
2952 ripng->sock = -1;
2953 }
2954
2955 /* Static RIPng route configuration. */
2956 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2957 if (rp->info) {
2958 rp->info = NULL;
2959 route_unlock_node (rp);
2960 }
2961
2962 /* RIPng aggregated prefixes */
2963 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2964 if (rp->info) {
2965 rp->info = NULL;
2966 route_unlock_node (rp);
2967 }
2968
2969 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2970 if (ripng->route_map[i].name)
2971 free (ripng->route_map[i].name);
2972
2973 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2974 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2975 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2976
2977 XFREE (MTYPE_RIPNG, ripng);
2978 ripng = NULL;
2979 } /* if (ripng) */
2980
2981 ripng_clean_network();
2982 ripng_passive_interface_clean ();
2983 ripng_offset_clean ();
2984 ripng_interface_clean ();
2985 ripng_redistribute_clean ();
2986}
2987
2988/* Reset all values to the default settings. */
2989void
2990ripng_reset ()
2991{
2992 /* Call ripd related reset functions. */
2993 ripng_debug_reset ();
2994 ripng_route_map_reset ();
2995
2996 /* Call library reset functions. */
2997 vty_reset ();
2998 access_list_reset ();
2999 prefix_list_reset ();
3000
3001 distribute_list_reset ();
3002
3003 ripng_interface_reset ();
3004
3005 ripng_zclient_reset ();
3006}
paul718e3742002-12-13 20:15:29 +00003007
Paul Jakma6ac29a52008-08-15 13:45:30 +01003008static void
paul718e3742002-12-13 20:15:29 +00003009ripng_if_rmap_update (struct if_rmap *if_rmap)
3010{
3011 struct interface *ifp;
3012 struct ripng_interface *ri;
3013 struct route_map *rmap;
3014
3015 ifp = if_lookup_by_name (if_rmap->ifname);
3016 if (ifp == NULL)
3017 return;
3018
3019 ri = ifp->info;
3020
3021 if (if_rmap->routemap[IF_RMAP_IN])
3022 {
3023 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3024 if (rmap)
3025 ri->routemap[IF_RMAP_IN] = rmap;
3026 else
3027 ri->routemap[IF_RMAP_IN] = NULL;
3028 }
3029 else
3030 ri->routemap[RIPNG_FILTER_IN] = NULL;
3031
3032 if (if_rmap->routemap[IF_RMAP_OUT])
3033 {
3034 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3035 if (rmap)
3036 ri->routemap[IF_RMAP_OUT] = rmap;
3037 else
3038 ri->routemap[IF_RMAP_OUT] = NULL;
3039 }
3040 else
3041 ri->routemap[RIPNG_FILTER_OUT] = NULL;
3042}
3043
3044void
3045ripng_if_rmap_update_interface (struct interface *ifp)
3046{
3047 struct if_rmap *if_rmap;
3048
3049 if_rmap = if_rmap_lookup (ifp->name);
3050 if (if_rmap)
3051 ripng_if_rmap_update (if_rmap);
3052}
3053
Paul Jakma6ac29a52008-08-15 13:45:30 +01003054static void
paul718e3742002-12-13 20:15:29 +00003055ripng_routemap_update_redistribute (void)
3056{
3057 int i;
3058
3059 if (ripng)
3060 {
3061 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3062 {
3063 if (ripng->route_map[i].name)
3064 ripng->route_map[i].map =
3065 route_map_lookup_by_name (ripng->route_map[i].name);
3066 }
3067 }
3068}
3069
Paul Jakma6ac29a52008-08-15 13:45:30 +01003070static void
hasso98b718a2004-10-11 12:57:57 +00003071ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00003072{
3073 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00003074 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003075
paul1eb8ef22005-04-07 07:30:20 +00003076 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
3077 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003078
3079 ripng_routemap_update_redistribute ();
3080}
3081
3082/* Initialize ripng structure and set commands. */
3083void
3084ripng_init ()
3085{
3086 /* Randomize. */
Donald Sharpf31bab42015-06-19 19:26:19 -04003087 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00003088
3089 /* Install RIPNG_NODE. */
3090 install_node (&cmd_ripng_node, ripng_config_write);
3091
3092 /* Install ripng commands. */
3093 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003094 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003095
3096 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003097 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003098
3099 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003100 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00003101
3102 install_default (RIPNG_NODE);
3103 install_element (RIPNG_NODE, &ripng_route_cmd);
3104 install_element (RIPNG_NODE, &no_ripng_route_cmd);
3105 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3106 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3107
3108 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3109 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
3110 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
3111
3112 install_element (RIPNG_NODE, &ripng_timers_cmd);
3113 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00003114 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00003115#if 0
3116 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3117 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3118 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3119 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3120 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3121 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3122#endif /* 0 */
3123
paula2c62832003-04-23 17:01:31 +00003124 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3125 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00003126
Feng Lu72855b12015-05-22 11:39:54 +02003127 install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
3128 install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
3129
paul718e3742002-12-13 20:15:29 +00003130 ripng_if_init ();
3131 ripng_debug_init ();
3132
3133 /* Access list install. */
3134 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003135 access_list_add_hook (ripng_distribute_update_all_wrapper);
3136 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003137
3138 /* Prefix list initialize.*/
3139 prefix_list_init ();
3140 prefix_list_add_hook (ripng_distribute_update_all);
3141 prefix_list_delete_hook (ripng_distribute_update_all);
3142
3143 /* Distribute list install. */
3144 distribute_list_init (RIPNG_NODE);
3145 distribute_list_add_hook (ripng_distribute_update);
3146 distribute_list_delete_hook (ripng_distribute_update);
3147
3148 /* Route-map for interface. */
3149 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003150 ripng_offset_init ();
3151
paul718e3742002-12-13 20:15:29 +00003152 route_map_add_hook (ripng_routemap_update);
3153 route_map_delete_hook (ripng_routemap_update);
3154
hasso0750d212003-05-24 21:41:49 +00003155 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003156 if_rmap_hook_add (ripng_if_rmap_update);
3157 if_rmap_hook_delete (ripng_if_rmap_update);
3158}