blob: 824b3a4c3ceca3f205bceb0be5892d641fa59120 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
paul718e3742002-12-13 20:15:29 +000024#include "prefix.h"
25#include "filter.h"
26#include "log.h"
27#include "thread.h"
28#include "memory.h"
29#include "if.h"
30#include "stream.h"
31#include "table.h"
32#include "command.h"
33#include "sockopt.h"
34#include "distribute.h"
35#include "plist.h"
36#include "routemap.h"
hasso0750d212003-05-24 21:41:49 +000037#include "if_rmap.h"
paul27d47aa2003-11-17 09:04:53 +000038#include "privs.h"
paul718e3742002-12-13 20:15:29 +000039
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
hassoa94434b2003-05-25 17:10:12 +000043#include "ripngd/ripng_nexthop.h"
paul718e3742002-12-13 20:15:29 +000044
45/* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48struct ripng *ripng = NULL;
49
50enum
51{
52 ripng_all_route,
53 ripng_changed_route,
paul718e3742002-12-13 20:15:29 +000054};
55
paul27d47aa2003-11-17 09:04:53 +000056extern struct zebra_privs_t ripngd_privs;
57
paul718e3742002-12-13 20:15:29 +000058/* Prototypes. */
59void
hassoa94434b2003-05-25 17:10:12 +000060ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
paul718e3742002-12-13 20:15:29 +000061
62int
63ripng_triggered_update (struct thread *);
64
65/* RIPng next hop specification. */
66struct ripng_nexthop
67{
68 enum ripng_nexthop_type
69 {
70 RIPNG_NEXTHOP_UNSPEC,
71 RIPNG_NEXTHOP_ADDRESS
72 } flag;
73 struct in6_addr address;
74};
paul718e3742002-12-13 20:15:29 +000075
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static int
hassoa94434b2003-05-25 17:10:12 +000077ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
paul718e3742002-12-13 20:15:29 +000082/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
David Lamparter6b0655a2014-06-04 06:53:35 +020098
paul718e3742002-12-13 20:15:29 +000099/* Create ripng socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100100static int
paul718e3742002-12-13 20:15:29 +0000101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't make ripng socket");
111 return sock;
112 }
113
114 ret = setsockopt_so_recvbuf (sock, 8096);
115 if (ret < 0)
116 return ret;
117 ret = setsockopt_ipv6_pktinfo (sock, 1);
118 if (ret < 0)
119 return ret;
Stephen Hemminger6d0732c2011-09-28 14:23:35 +0400120#ifdef IPTOS_PREC_INTERNETCONTROL
121 ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
122 if (ret < 0)
123 return ret;
124#endif
paul718e3742002-12-13 20:15:29 +0000125 ret = setsockopt_ipv6_multicast_hops (sock, 255);
126 if (ret < 0)
127 return ret;
128 ret = setsockopt_ipv6_multicast_loop (sock, 0);
129 if (ret < 0)
130 return ret;
131 ret = setsockopt_ipv6_hoplimit (sock, 1);
132 if (ret < 0)
133 return ret;
134
135 memset (&ripaddr, 0, sizeof (ripaddr));
136 ripaddr.sin6_family = AF_INET6;
137#ifdef SIN6_LEN
138 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
139#endif /* SIN6_LEN */
140 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
141
paul27d47aa2003-11-17 09:04:53 +0000142 if (ripngd_privs.change (ZPRIVS_RAISE))
143 zlog_err ("ripng_make_socket: could not raise privs");
144
paul718e3742002-12-13 20:15:29 +0000145 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
146 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000147 {
ajs6099b3b2004-11-20 02:06:59 +0000148 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000149 if (ripngd_privs.change (ZPRIVS_LOWER))
150 zlog_err ("ripng_make_socket: could not lower privs");
151 return ret;
152 }
153 if (ripngd_privs.change (ZPRIVS_LOWER))
154 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000155 return sock;
156}
157
158/* Send RIPng packet. */
159int
160ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
161 struct interface *ifp)
162{
163 int ret;
164 struct msghdr msg;
165 struct iovec iov;
166 struct cmsghdr *cmsgptr;
167 char adata [256];
168 struct in6_pktinfo *pkt;
169 struct sockaddr_in6 addr;
170
hassoa94434b2003-05-25 17:10:12 +0000171 if (IS_RIPNG_DEBUG_SEND) {
172 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000173 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000174 zlog_debug (" send interface %s", ifp->name);
175 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000176 }
paul718e3742002-12-13 20:15:29 +0000177
178 memset (&addr, 0, sizeof (struct sockaddr_in6));
179 addr.sin6_family = AF_INET6;
180#ifdef SIN6_LEN
181 addr.sin6_len = sizeof (struct sockaddr_in6);
182#endif /* SIN6_LEN */
183 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
184
185 /* When destination is specified. */
186 if (to != NULL)
187 {
188 addr.sin6_addr = to->sin6_addr;
189 addr.sin6_port = to->sin6_port;
190 }
191 else
192 {
193 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
194 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
195 }
196
197 msg.msg_name = (void *) &addr;
198 msg.msg_namelen = sizeof (struct sockaddr_in6);
199 msg.msg_iov = &iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = (void *) adata;
202 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
203
204 iov.iov_base = buf;
205 iov.iov_len = bufsize;
206
207 cmsgptr = (struct cmsghdr *)adata;
208 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
209 cmsgptr->cmsg_level = IPPROTO_IPV6;
210 cmsgptr->cmsg_type = IPV6_PKTINFO;
211
212 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
213 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
214 pkt->ipi6_ifindex = ifp->ifindex;
215
216 ret = sendmsg (ripng->sock, &msg, 0);
217
hassoa94434b2003-05-25 17:10:12 +0000218 if (ret < 0) {
219 if (to)
220 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000221 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000222 else
ajs6099b3b2004-11-20 02:06:59 +0000223 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000224 }
paul718e3742002-12-13 20:15:29 +0000225
226 return ret;
227}
228
229/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100230static int
paul718e3742002-12-13 20:15:29 +0000231ripng_recv_packet (int sock, u_char *buf, int bufsize,
Paul Jakma9099f9b2016-01-18 10:12:10 +0000232 struct sockaddr_in6 *from, ifindex_t *ifindex,
paul718e3742002-12-13 20:15:29 +0000233 int *hoplimit)
234{
235 int ret;
236 struct msghdr msg;
237 struct iovec iov;
238 struct cmsghdr *cmsgptr;
David Lamparterab90fc02015-03-03 09:07:25 +0100239 struct in6_addr dst = { .s6_addr = { 0 } };
paul718e3742002-12-13 20:15:29 +0000240
241 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
242 point I can't determine size of cmsghdr */
243 char adata[1024];
244
245 /* Fill in message and iovec. */
246 msg.msg_name = (void *) from;
247 msg.msg_namelen = sizeof (struct sockaddr_in6);
248 msg.msg_iov = &iov;
249 msg.msg_iovlen = 1;
250 msg.msg_control = (void *) adata;
251 msg.msg_controllen = sizeof adata;
252 iov.iov_base = buf;
253 iov.iov_len = bufsize;
254
255 /* If recvmsg fail return minus value. */
256 ret = recvmsg (sock, &msg, 0);
257 if (ret < 0)
258 return ret;
259
ajsb99760a2005-01-04 16:24:43 +0000260 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000261 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
262 {
263 /* I want interface index which this packet comes from. */
264 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265 cmsgptr->cmsg_type == IPV6_PKTINFO)
266 {
267 struct in6_pktinfo *ptr;
268
269 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270 *ifindex = ptr->ipi6_ifindex;
271 dst = ptr->ipi6_addr;
272
273 if (*ifindex == 0)
274 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275 }
276
277 /* Incoming packet's multicast hop limit. */
278 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemminger5eb9d112009-12-10 15:52:33 +0300280 {
281 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282 *hoplimit = *phoplimit;
283 }
paul718e3742002-12-13 20:15:29 +0000284 }
285
286 /* Hoplimit check shold be done when destination address is
287 multicast address. */
288 if (! IN6_IS_ADDR_MULTICAST (&dst))
289 *hoplimit = -1;
290
291 return ret;
292}
293
294/* Dump rip packet */
295void
hasso7a1d5832004-10-08 06:32:23 +0000296ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000297{
298 caddr_t lim;
299 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000300 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000301
302 /* Set command string. */
303 if (packet->command == RIPNG_REQUEST)
304 command_str = "request";
305 else if (packet->command == RIPNG_RESPONSE)
306 command_str = "response";
307 else
308 command_str = "unknown";
309
310 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000311 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000312 sndrcv, command_str, packet->version, size);
313
314 /* Dump each routing table entry. */
315 rte = packet->rte;
316
317 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318 {
319 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000320 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000321 else
ajsc6106812004-12-08 19:51:16 +0000322 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000323 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000324 rte->metric, ntohs (rte->tag));
325 }
326}
327
328/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100329static void
paul718e3742002-12-13 20:15:29 +0000330ripng_nexthop_rte (struct rte *rte,
331 struct sockaddr_in6 *from,
332 struct ripng_nexthop *nexthop)
333{
334 char buf[INET6_BUFSIZ];
335
336 /* Logging before checking RTE. */
337 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000338 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000339 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000340
341 /* RFC2080 2.1.1 Next Hop:
342 The route tag and prefix length in the next hop RTE must be
343 set to zero on sending and ignored on receiption. */
344 if (ntohs (rte->tag) != 0)
345 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000346 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000347
348 if (rte->prefixlen != 0)
349 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000350 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000351
352 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353 next hop RTE indicates that the next hop address should be the
354 originator of the RIPng advertisement. An address specified as a
355 next hop must be a link-local address. */
356 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357 {
358 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359 memset (&nexthop->address, 0, sizeof (struct in6_addr));
360 return;
361 }
362
363 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364 {
365 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367 return;
368 }
369
370 /* The purpose of the next hop RTE is to eliminate packets being
371 routed through extra hops in the system. It is particularly useful
372 when RIPng is not being run on all of the routers on a network.
373 Note that next hop RTE is "advisory". That is, if the provided
374 information is ignored, a possibly sub-optimal, but absolutely
375 valid, route may be taken. If the received next hop address is not
376 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
377 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000378 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000379 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382 memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384 return;
385}
386
387/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100388static int
paul718e3742002-12-13 20:15:29 +0000389ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390{
paul1eb8ef22005-04-07 07:30:20 +0000391 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000392 struct connected *connected;
393 struct prefix *p;
394
paul1eb8ef22005-04-07 07:30:20 +0000395 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396 {
397 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000398
paul1eb8ef22005-04-07 07:30:20 +0000399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
paul718e3742002-12-13 20:15:29 +0000404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100408static int
paul718e3742002-12-13 20:15:29 +0000409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
paul718e3742002-12-13 20:15:29 +0000423 /* Unlock route_node. */
Feng Lue97c31a2015-05-22 11:39:53 +0200424 listnode_delete (rp->info, rinfo);
425 if (list_isempty ((struct list *)rp->info))
426 {
427 list_free (rp->info);
428 rp->info = NULL;
429 route_unlock_node (rp);
430 }
paul718e3742002-12-13 20:15:29 +0000431
432 /* Free RIPng routing information. */
433 ripng_info_free (rinfo);
434
435 return 0;
436}
437
Feng Lue97c31a2015-05-22 11:39:53 +0200438static void ripng_timeout_update (struct ripng_info *rinfo);
439
440/* Add new route to the ECMP list.
Feng Lu72855b12015-05-22 11:39:54 +0200441 * RETURN: the new entry added in the list, or NULL if it is not the first
442 * entry and ECMP is not allowed.
Feng Lue97c31a2015-05-22 11:39:53 +0200443 */
444struct ripng_info *
445ripng_ecmp_add (struct ripng_info *rinfo_new)
446{
447 struct route_node *rp = rinfo_new->rp;
448 struct ripng_info *rinfo = NULL;
449 struct list *list = NULL;
450
451 if (rp->info == NULL)
452 rp->info = list_new ();
453 list = (struct list *)rp->info;
454
Feng Lu72855b12015-05-22 11:39:54 +0200455 /* If ECMP is not allowed and some entry already exists in the list,
456 * do nothing. */
457 if (listcount (list) && !ripng->ecmp)
458 return NULL;
459
Feng Lue97c31a2015-05-22 11:39:53 +0200460 rinfo = ripng_info_new ();
461 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
462 listnode_add (list, rinfo);
463
464 if (ripng_route_rte (rinfo))
465 {
466 ripng_timeout_update (rinfo);
467 ripng_zebra_ipv6_add (rp);
468 }
469
470 ripng_aggregate_increment (rp, rinfo);
471
472 /* Set the route change flag on the first entry. */
473 rinfo = listgetdata (listhead (list));
474 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
475
476 /* Signal the output process to trigger an update. */
477 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
478
479 return rinfo;
480}
481
482/* Replace the ECMP list with the new route.
483 * RETURN: the new entry added in the list
484 */
485struct ripng_info *
486ripng_ecmp_replace (struct ripng_info *rinfo_new)
487{
488 struct route_node *rp = rinfo_new->rp;
489 struct list *list = (struct list *)rp->info;
490 struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
491 struct listnode *node = NULL, *nextnode = NULL;
492
493 if (list == NULL || listcount (list) == 0)
494 return ripng_ecmp_add (rinfo_new);
495
496 /* Get the first entry */
497 rinfo = listgetdata (listhead (list));
498
499 /* Learnt route replaced by a local one. Delete it from zebra. */
500 if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
501 if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
502 ripng_zebra_ipv6_delete (rp);
503
504 if (rinfo->metric != RIPNG_METRIC_INFINITY)
505 ripng_aggregate_decrement_list (rp, list);
506
507 /* Re-use the first entry, and delete the others. */
508 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
509 if (tmp_rinfo != rinfo)
510 {
511 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
512 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
513 list_delete_node (list, node);
514 ripng_info_free (tmp_rinfo);
515 }
516
517 RIPNG_TIMER_OFF (rinfo->t_timeout);
518 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
519 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
520
521 if (ripng_route_rte (rinfo))
522 {
523 ripng_timeout_update (rinfo);
524 /* The ADD message implies an update. */
525 ripng_zebra_ipv6_add (rp);
526 }
527
528 ripng_aggregate_increment (rp, rinfo);
529
530 /* Set the route change flag. */
531 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
532
533 /* Signal the output process to trigger an update. */
534 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
535
536 return rinfo;
537}
538
539/* Delete one route from the ECMP list.
540 * RETURN:
541 * null - the entry is freed, and other entries exist in the list
542 * the entry - the entry is the last one in the list; its metric is set
543 * to INFINITY, and the garbage collector is started for it
544 */
545struct ripng_info *
546ripng_ecmp_delete (struct ripng_info *rinfo)
547{
548 struct route_node *rp = rinfo->rp;
549 struct list *list = (struct list *)rp->info;
550
551 RIPNG_TIMER_OFF (rinfo->t_timeout);
552
553 if (rinfo->metric != RIPNG_METRIC_INFINITY)
554 ripng_aggregate_decrement (rp, rinfo);
555
556 if (listcount (list) > 1)
557 {
558 /* Some other ECMP entries still exist. Just delete this entry. */
559 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
560 listnode_delete (list, rinfo);
561 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
562 /* The ADD message implies the update. */
563 ripng_zebra_ipv6_add (rp);
564 ripng_info_free (rinfo);
565 rinfo = NULL;
566 }
567 else
568 {
569 assert (rinfo == listgetdata (listhead (list)));
570
571 /* This is the only entry left in the list. We must keep it in
572 * the list for garbage collection time, with INFINITY metric. */
573
574 rinfo->metric = RIPNG_METRIC_INFINITY;
575 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
576 ripng_garbage_collect, ripng->garbage_time);
577
578 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
579 ripng_zebra_ipv6_delete (rp);
580 }
581
582 /* Set the route change flag on the first entry. */
583 rinfo = listgetdata (listhead (list));
584 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
585
586 /* Signal the output process to trigger an update. */
587 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
588
589 return rinfo;
590}
591
paul718e3742002-12-13 20:15:29 +0000592/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100593static int
paul718e3742002-12-13 20:15:29 +0000594ripng_timeout (struct thread *t)
595{
Feng Lue97c31a2015-05-22 11:39:53 +0200596 ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
paul718e3742002-12-13 20:15:29 +0000597 return 0;
598}
599
Paul Jakma6ac29a52008-08-15 13:45:30 +0100600static void
paul718e3742002-12-13 20:15:29 +0000601ripng_timeout_update (struct ripng_info *rinfo)
602{
603 if (rinfo->metric != RIPNG_METRIC_INFINITY)
604 {
605 RIPNG_TIMER_OFF (rinfo->t_timeout);
606 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
607 }
608}
609
Paul Jakma6ac29a52008-08-15 13:45:30 +0100610static int
Matthieu Boutier543e7912014-09-10 16:50:44 +0200611ripng_filter (int ripng_distribute, struct prefix_ipv6 *p,
612 struct ripng_interface *ri)
hassoa94434b2003-05-25 17:10:12 +0000613{
614 struct distribute *dist;
615 struct access_list *alist;
616 struct prefix_list *plist;
Matthieu Boutier543e7912014-09-10 16:50:44 +0200617 int distribute = ripng_distribute == RIPNG_FILTER_OUT ?
Matthieu Boutierdf2ef242014-09-10 16:50:45 +0200618 DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN;
Matthieu Boutier543e7912014-09-10 16:50:44 +0200619 const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
hassoa94434b2003-05-25 17:10:12 +0000620
621 /* Input distribute-list filtering. */
Matthieu Boutier543e7912014-09-10 16:50:44 +0200622 if (ri->list[ripng_distribute])
hassoa94434b2003-05-25 17:10:12 +0000623 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200624 if (access_list_apply (ri->list[ripng_distribute],
hassoa94434b2003-05-25 17:10:12 +0000625 (struct prefix *) p) == FILTER_DENY)
626 {
627 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200628 zlog_debug ("%s/%d filtered by distribute %s",
629 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000630 return -1;
631 }
632 }
Matthieu Boutier543e7912014-09-10 16:50:44 +0200633 if (ri->prefix[ripng_distribute])
hassoa94434b2003-05-25 17:10:12 +0000634 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200635 if (prefix_list_apply (ri->prefix[ripng_distribute],
hassoa94434b2003-05-25 17:10:12 +0000636 (struct prefix *) p) == PREFIX_DENY)
637 {
638 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200639 zlog_debug ("%s/%d filtered by prefix-list %s",
640 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000641 return -1;
642 }
643 }
644
645 /* All interface filter check. */
646 dist = distribute_lookup (NULL);
647 if (dist)
648 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200649 if (dist->list[distribute])
hassoa94434b2003-05-25 17:10:12 +0000650 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200651 alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
652
hassoa94434b2003-05-25 17:10:12 +0000653 if (alist)
654 {
655 if (access_list_apply (alist,
656 (struct prefix *) p) == FILTER_DENY)
657 {
658 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200659 zlog_debug ("%s/%d filtered by distribute %s",
660 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000661 return -1;
662 }
663 }
664 }
Matthieu Boutier543e7912014-09-10 16:50:44 +0200665 if (dist->prefix[distribute])
hassoa94434b2003-05-25 17:10:12 +0000666 {
Matthieu Boutier543e7912014-09-10 16:50:44 +0200667 plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
668
hassoa94434b2003-05-25 17:10:12 +0000669 if (plist)
670 {
671 if (prefix_list_apply (plist,
672 (struct prefix *) p) == PREFIX_DENY)
673 {
674 if (IS_RIPNG_DEBUG_PACKET)
Matthieu Boutier543e7912014-09-10 16:50:44 +0200675 zlog_debug ("%s/%d filtered by prefix-list %s",
676 inet6_ntoa (p->prefix), p->prefixlen, inout);
hassoa94434b2003-05-25 17:10:12 +0000677 return -1;
678 }
679 }
680 }
681 }
682 return 0;
683}
684
paul718e3742002-12-13 20:15:29 +0000685/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100686static void
paul718e3742002-12-13 20:15:29 +0000687ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
688 struct ripng_nexthop *ripng_nexthop,
689 struct interface *ifp)
690{
hassoa94434b2003-05-25 17:10:12 +0000691 int ret;
paul718e3742002-12-13 20:15:29 +0000692 struct prefix_ipv6 p;
693 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200694 struct ripng_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000695 struct ripng_interface *ri;
696 struct in6_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000697 int same = 0;
Feng Lue97c31a2015-05-22 11:39:53 +0200698 struct list *list = NULL;
699 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000700
701 /* Make prefix structure. */
702 memset (&p, 0, sizeof (struct prefix_ipv6));
703 p.family = AF_INET6;
704 /* p.prefix = rte->addr; */
705 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
706 p.prefixlen = rte->prefixlen;
707
708 /* Make sure mask is applied. */
709 /* XXX We have to check the prefix is valid or not before call
710 apply_mask_ipv6. */
711 apply_mask_ipv6 (&p);
712
713 /* Apply input filters. */
714 ri = ifp->info;
715
Matthieu Boutier543e7912014-09-10 16:50:44 +0200716 ret = ripng_filter (RIPNG_FILTER_IN, &p, ri);
hassoa94434b2003-05-25 17:10:12 +0000717 if (ret < 0)
718 return;
paul718e3742002-12-13 20:15:29 +0000719
Feng Lue97c31a2015-05-22 11:39:53 +0200720 memset (&newinfo, 0, sizeof (newinfo));
721 newinfo.type = ZEBRA_ROUTE_RIPNG;
722 newinfo.sub_type = RIPNG_ROUTE_RTE;
723 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
724 newinfo.nexthop = ripng_nexthop->address;
725 else
726 newinfo.nexthop = from->sin6_addr;
727 newinfo.from = from->sin6_addr;
728 newinfo.ifindex = ifp->ifindex;
729 newinfo.metric = rte->metric;
730 newinfo.metric_out = rte->metric; /* XXX */
731 newinfo.tag = ntohs (rte->tag); /* XXX */
732
paul718e3742002-12-13 20:15:29 +0000733 /* Modify entry. */
734 if (ri->routemap[RIPNG_FILTER_IN])
735 {
736 int ret;
paul718e3742002-12-13 20:15:29 +0000737
738 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
739 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
740
741 if (ret == RMAP_DENYMATCH)
742 {
743 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000744 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000745 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000746 return;
747 }
748
hassoa94434b2003-05-25 17:10:12 +0000749 /* Get back the object */
750 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
751 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
752 /* the nexthop get changed by the routemap */
753 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
754 ripng_nexthop->address = newinfo.nexthop;
755 else
756 ripng_nexthop->address = in6addr_any;
757 }
758 } else {
759 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
760 /* the nexthop get changed by the routemap */
761 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
762 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
763 ripng_nexthop->address = newinfo.nexthop;
764 }
765 }
766 }
767 rte->tag = htons(newinfo.tag_out); /* XXX */
768 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000769 }
770
hassoa94434b2003-05-25 17:10:12 +0000771 /* Once the entry has been validated, update the metric by
772 * adding the cost of the network on wich the message
773 * arrived. If the result is greater than infinity, use infinity
774 * (RFC2453 Sec. 3.9.2)
775 **/
776
777 /* Zebra ripngd can handle offset-list in. */
778 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
779
780 /* If offset-list does not modify the metric use interface's
781 * one. */
782 if (! ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000783 rte->metric += ifp->metric ? ifp->metric : 1;
hassoa94434b2003-05-25 17:10:12 +0000784
785 if (rte->metric > RIPNG_METRIC_INFINITY)
786 rte->metric = RIPNG_METRIC_INFINITY;
787
paul718e3742002-12-13 20:15:29 +0000788 /* Set nexthop pointer. */
789 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
790 nexthop = &ripng_nexthop->address;
791 else
792 nexthop = &from->sin6_addr;
793
794 /* Lookup RIPng routing table. */
795 rp = route_node_get (ripng->table, (struct prefix *) &p);
796
Feng Lue97c31a2015-05-22 11:39:53 +0200797 newinfo.rp = rp;
798 newinfo.nexthop = *nexthop;
799 newinfo.metric = rte->metric;
800 newinfo.tag = ntohs (rte->tag);
801
802 /* Check to see whether there is already RIPng route on the table. */
803 if ((list = rp->info) != NULL)
804 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
805 {
806 /* Need to compare with redistributed entry or local entry */
807 if (!ripng_route_rte (rinfo))
808 break;
809
810 if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
811 IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
812 break;
813
814 if (!listnextnode (node))
815 {
816 /* Not found in the list */
817
818 if (rte->metric > rinfo->metric)
819 {
820 /* New route has a greater metric. Discard it. */
821 route_unlock_node (rp);
822 return;
823 }
824
825 if (rte->metric < rinfo->metric)
826 /* New route has a smaller metric. Replace the ECMP list
827 * with the new one in below. */
828 break;
829
830 /* Metrics are same. Keep "rinfo" null and the new route
831 * is added in the ECMP list in below. */
832 }
833 }
834
hassoa94434b2003-05-25 17:10:12 +0000835 if (rinfo)
836 {
837 /* Redistributed route check. */
838 if (rinfo->type != ZEBRA_ROUTE_RIPNG
839 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200840 {
841 route_unlock_node (rp);
842 return;
843 }
hassoa94434b2003-05-25 17:10:12 +0000844
845 /* Local static route. */
846 if (rinfo->type == ZEBRA_ROUTE_RIPNG
847 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
848 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
849 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200850 {
851 route_unlock_node (rp);
852 return;
853 }
hassoa94434b2003-05-25 17:10:12 +0000854 }
855
Feng Lue97c31a2015-05-22 11:39:53 +0200856 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000857 {
858 /* Now, check to see whether there is already an explicit route
859 for the destination prefix. If there is no such route, add
860 this route to the routing table, unless the metric is
861 infinity (there is no point in adding a route which
862 unusable). */
863 if (rte->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200864 ripng_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000865 }
866 else
867 {
paul718e3742002-12-13 20:15:29 +0000868 /* If there is an existing route, compare the next hop address
869 to the address of the router from which the datagram came.
870 If this datagram is from the same router as the existing
871 route, reinitialize the timeout. */
872 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
873 && (rinfo->ifindex == ifp->ifindex));
874
paul718e3742002-12-13 20:15:29 +0000875 /* Next, compare the metrics. If the datagram is from the same
876 router as the existing route, and the new metric is different
877 than the old one; or, if the new metric is lower than the old
878 one; do the following actions: */
879 if ((same && rinfo->metric != rte->metric) ||
880 rte->metric < rinfo->metric)
881 {
Feng Lue97c31a2015-05-22 11:39:53 +0200882 if (listcount (list) == 1)
883 {
884 if (newinfo.metric != RIPNG_METRIC_INFINITY)
885 ripng_ecmp_replace (&newinfo);
886 else
887 ripng_ecmp_delete (rinfo);
888 }
889 else
890 {
891 if (newinfo.metric < rinfo->metric)
892 ripng_ecmp_replace (&newinfo);
893 else /* newinfo.metric > rinfo->metric */
894 ripng_ecmp_delete (rinfo);
895 }
paul718e3742002-12-13 20:15:29 +0000896 }
Feng Lue97c31a2015-05-22 11:39:53 +0200897 else /* same & no change */
898 ripng_timeout_update (rinfo);
899
paul718e3742002-12-13 20:15:29 +0000900 /* Unlock tempolary lock of the route. */
901 route_unlock_node (rp);
902 }
903}
904
905/* Add redistributed route to RIPng table. */
906void
907ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
Christian Franke5bb328e2016-10-01 22:35:32 +0200908 ifindex_t ifindex, struct in6_addr *nexthop,
909 route_tag_t tag)
paul718e3742002-12-13 20:15:29 +0000910{
911 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200912 struct ripng_info *rinfo = NULL, newinfo;
913 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +0000914
915 /* Redistribute route */
916 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
917 return;
918 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
919 return;
920
921 rp = route_node_get (ripng->table, (struct prefix *) p);
paul718e3742002-12-13 20:15:29 +0000922
Feng Lue97c31a2015-05-22 11:39:53 +0200923 memset (&newinfo, 0, sizeof (struct ripng_info));
924 newinfo.type = type;
925 newinfo.sub_type = sub_type;
926 newinfo.ifindex = ifindex;
927 newinfo.metric = 1;
Christian Franke5bb328e2016-10-01 22:35:32 +0200928 if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
929 newinfo.tag = tag;
Feng Lue97c31a2015-05-22 11:39:53 +0200930 newinfo.rp = rp;
931 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
932 newinfo.nexthop = *nexthop;
933
934 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +0000935 {
Feng Lue97c31a2015-05-22 11:39:53 +0200936 rinfo = listgetdata (listhead (list));
937
hassoa94434b2003-05-25 17:10:12 +0000938 if (rinfo->type == ZEBRA_ROUTE_CONNECT
939 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
940 && rinfo->metric != RIPNG_METRIC_INFINITY) {
941 route_unlock_node (rp);
942 return;
943 }
944
945 /* Manually configured RIPng route check.
946 * They have the precedence on all the other entries.
947 **/
948 if (rinfo->type == ZEBRA_ROUTE_RIPNG
949 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
950 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
951 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
952 (sub_type != RIPNG_ROUTE_DEFAULT))) {
953 route_unlock_node (rp);
954 return;
955 }
956 }
hassoa94434b2003-05-25 17:10:12 +0000957
Feng Lue97c31a2015-05-22 11:39:53 +0200958 rinfo = ripng_ecmp_replace (&newinfo);
paul718e3742002-12-13 20:15:29 +0000959 route_unlock_node (rp);
960 }
Feng Lue97c31a2015-05-22 11:39:53 +0200961 else
962 rinfo = ripng_ecmp_add (&newinfo);
hassoa94434b2003-05-25 17:10:12 +0000963
964 if (IS_RIPNG_DEBUG_EVENT) {
965 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +0000966 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000967 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +0000968 ifindex2ifname(ifindex));
969 else
ajsc6106812004-12-08 19:51:16 +0000970 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000971 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +0000972 ifindex2ifname(ifindex));
973 }
974
975 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000976}
977
978/* Delete redistributed route to RIPng table. */
979void
980ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +0000981 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +0000982{
983 struct route_node *rp;
984 struct ripng_info *rinfo;
985
986 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
987 return;
988 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
989 return;
990
991 rp = route_node_lookup (ripng->table, (struct prefix *) p);
992
993 if (rp)
994 {
Feng Lue97c31a2015-05-22 11:39:53 +0200995 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +0000996
Feng Lue97c31a2015-05-22 11:39:53 +0200997 if (list != NULL && listcount (list) != 0)
998 {
999 rinfo = listgetdata (listhead (list));
1000 if (rinfo != NULL
1001 && rinfo->type == type
1002 && rinfo->sub_type == sub_type
1003 && rinfo->ifindex == ifindex)
1004 {
1005 /* Perform poisoned reverse. */
1006 rinfo->metric = RIPNG_METRIC_INFINITY;
1007 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1008 ripng_garbage_collect, ripng->garbage_time);
1009 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001010
Feng Lue97c31a2015-05-22 11:39:53 +02001011 /* Aggregate count decrement. */
1012 ripng_aggregate_decrement (rp, rinfo);
hassoa94434b2003-05-25 17:10:12 +00001013
Feng Lue97c31a2015-05-22 11:39:53 +02001014 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001015
Feng Lue97c31a2015-05-22 11:39:53 +02001016 if (IS_RIPNG_DEBUG_EVENT)
1017 zlog_debug ("Poisone %s/%d on the interface %s with an "
1018 "infinity metric [delete]",
1019 inet6_ntoa (p->prefix), p->prefixlen,
1020 ifindex2ifname (ifindex));
1021
1022 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1023 }
1024 }
1025 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001026 }
1027}
1028
1029/* Withdraw redistributed route. */
1030void
1031ripng_redistribute_withdraw (int type)
1032{
1033 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001034 struct ripng_info *rinfo = NULL;
1035 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001036
hassoa94434b2003-05-25 17:10:12 +00001037 if (!ripng)
1038 return;
1039
paul718e3742002-12-13 20:15:29 +00001040 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001041 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00001042 {
Feng Lue97c31a2015-05-22 11:39:53 +02001043 rinfo = listgetdata (listhead (list));
hassoa94434b2003-05-25 17:10:12 +00001044 if ((rinfo->type == type)
1045 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001046 {
hassoa94434b2003-05-25 17:10:12 +00001047 /* Perform poisoned reverse. */
1048 rinfo->metric = RIPNG_METRIC_INFINITY;
1049 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1050 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001051 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001052
hassoa94434b2003-05-25 17:10:12 +00001053 /* Aggregate count decrement. */
1054 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001055
hassoa94434b2003-05-25 17:10:12 +00001056 rinfo->flags |= RIPNG_RTF_CHANGED;
1057
1058 if (IS_RIPNG_DEBUG_EVENT) {
1059 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1060
ajsc6106812004-12-08 19:51:16 +00001061 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001062 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001063 ifindex2ifname(rinfo->ifindex));
1064 }
1065
1066 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001067 }
1068 }
1069}
1070
1071/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001072static void
paul718e3742002-12-13 20:15:29 +00001073ripng_response_process (struct ripng_packet *packet, int size,
1074 struct sockaddr_in6 *from, struct interface *ifp,
1075 int hoplimit)
1076{
1077 caddr_t lim;
1078 struct rte *rte;
1079 struct ripng_nexthop nexthop;
1080
1081 /* RFC2080 2.4.2 Response Messages:
1082 The Response must be ignored if it is not from the RIPng port. */
1083 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1084 {
1085 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001086 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001087 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001088 return;
1089 }
1090
1091 /* The datagram's IPv6 source address should be checked to see
1092 whether the datagram is from a valid neighbor; the source of the
1093 datagram must be a link-local address. */
1094 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1095 {
1096 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001097 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001098 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001099 return;
1100 }
1101
1102 /* It is also worth checking to see whether the response is from one
1103 of the router's own addresses. Interfaces on broadcast networks
1104 may receive copies of their own multicasts immediately. If a
1105 router processes its own output as new input, confusion is likely,
1106 and such datagrams must be ignored. */
1107 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1108 {
1109 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001110 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001111 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001112 return;
1113 }
1114
1115 /* As an additional check, periodic advertisements must have their
1116 hop counts set to 255, and inbound, multicast packets sent from the
1117 RIPng port (i.e. periodic advertisement or triggered update
1118 packets) must be examined to ensure that the hop count is 255. */
1119 if (hoplimit >= 0 && hoplimit != 255)
1120 {
1121 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001122 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001123 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001124 return;
1125 }
1126
hassoa94434b2003-05-25 17:10:12 +00001127 /* Update RIPng peer. */
1128 ripng_peer_update (from, packet->version);
1129
paul718e3742002-12-13 20:15:29 +00001130 /* Reset nexthop. */
1131 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1132 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1133
1134 /* Set RTE pointer. */
1135 rte = packet->rte;
1136
1137 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1138 {
1139 /* First of all, we have to check this RTE is next hop RTE or
1140 not. Next hop RTE is completely different with normal RTE so
1141 we need special treatment. */
1142 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1143 {
1144 ripng_nexthop_rte (rte, from, &nexthop);
1145 continue;
1146 }
1147
1148 /* RTE information validation. */
1149
1150 /* - is the destination prefix valid (e.g., not a multicast
1151 prefix and not a link-local address) A link-local address
1152 should never be present in an RTE. */
1153 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1154 {
1155 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001156 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001157 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001158 continue;
1159 }
1160 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1161 {
1162 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001163 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001164 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001165 continue;
1166 }
1167 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1168 {
1169 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001170 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001171 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001172 continue;
1173 }
1174
1175 /* - is the prefix length valid (i.e., between 0 and 128,
1176 inclusive) */
1177 if (rte->prefixlen > 128)
1178 {
1179 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001180 inet6_ntoa (rte->addr), rte->prefixlen,
1181 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001182 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001183 continue;
1184 }
1185
1186 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1187 if (! (rte->metric >= 1 && rte->metric <= 16))
1188 {
1189 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001190 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001191 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001192 continue;
1193 }
1194
hassoa94434b2003-05-25 17:10:12 +00001195 /* Vincent: XXX Should we compute the direclty reachable nexthop
1196 * for our RIPng network ?
1197 **/
paul718e3742002-12-13 20:15:29 +00001198
1199 /* Routing table updates. */
1200 ripng_route_process (rte, from, &nexthop, ifp);
1201 }
1202}
1203
1204/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001205static void
paul718e3742002-12-13 20:15:29 +00001206ripng_request_process (struct ripng_packet *packet,int size,
1207 struct sockaddr_in6 *from, struct interface *ifp)
1208{
1209 caddr_t lim;
1210 struct rte *rte;
1211 struct prefix_ipv6 p;
1212 struct route_node *rp;
1213 struct ripng_info *rinfo;
1214 struct ripng_interface *ri;
1215
hassoa94434b2003-05-25 17:10:12 +00001216 /* Does not reponse to the requests on the loopback interfaces */
1217 if (if_is_loopback (ifp))
1218 return;
1219
paul718e3742002-12-13 20:15:29 +00001220 /* Check RIPng process is enabled on this interface. */
1221 ri = ifp->info;
1222 if (! ri->running)
1223 return;
1224
1225 /* When passive interface is specified, suppress responses */
1226 if (ri->passive)
1227 return;
1228
hassoa94434b2003-05-25 17:10:12 +00001229 /* RIPng peer update. */
1230 ripng_peer_update (from, packet->version);
1231
paul718e3742002-12-13 20:15:29 +00001232 lim = ((caddr_t) packet) + size;
1233 rte = packet->rte;
1234
1235 /* The Request is processed entry by entry. If there are no
1236 entries, no response is given. */
1237 if (lim == (caddr_t) rte)
1238 return;
1239
1240 /* There is one special case. If there is exactly one entry in the
1241 request, and it has a destination prefix of zero, a prefix length
1242 of zero, and a metric of infinity (i.e., 16), then this is a
1243 request to send the entire routing table. In that case, a call
1244 is made to the output process to send the routing table to the
1245 requesting address/port. */
1246 if (lim == ((caddr_t) (rte + 1)) &&
1247 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1248 rte->prefixlen == 0 &&
1249 rte->metric == RIPNG_METRIC_INFINITY)
1250 {
1251 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001252 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001253 }
1254 else
1255 {
1256 /* Except for this special case, processing is quite simple.
1257 Examine the list of RTEs in the Request one by one. For each
1258 entry, look up the destination in the router's routing
1259 database and, if there is a route, put that route's metric in
1260 the metric field of the RTE. If there is no explicit route
1261 to the specified destination, put infinity in the metric
1262 field. Once all the entries have been filled in, change the
1263 command from Request to Response and send the datagram back
1264 to the requestor. */
1265 memset (&p, 0, sizeof (struct prefix_ipv6));
1266 p.family = AF_INET6;
1267
1268 for (; ((caddr_t) rte) < lim; rte++)
1269 {
1270 p.prefix = rte->addr;
1271 p.prefixlen = rte->prefixlen;
1272 apply_mask_ipv6 (&p);
1273
1274 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1275
1276 if (rp)
1277 {
Feng Lue97c31a2015-05-22 11:39:53 +02001278 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001279 rte->metric = rinfo->metric;
1280 route_unlock_node (rp);
1281 }
1282 else
1283 rte->metric = RIPNG_METRIC_INFINITY;
1284 }
1285 packet->command = RIPNG_RESPONSE;
1286
1287 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1288 }
1289}
1290
1291/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001292static int
paul718e3742002-12-13 20:15:29 +00001293ripng_read (struct thread *thread)
1294{
1295 int len;
1296 int sock;
1297 struct sockaddr_in6 from;
1298 struct ripng_packet *packet;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001299 ifindex_t ifindex = 0;
paul718e3742002-12-13 20:15:29 +00001300 struct interface *ifp;
1301 int hoplimit = -1;
1302
1303 /* Check ripng is active and alive. */
1304 assert (ripng != NULL);
1305 assert (ripng->sock >= 0);
1306
1307 /* Fetch thread data and set read pointer to empty for event
1308 managing. `sock' sould be same as ripng->sock. */
1309 sock = THREAD_FD (thread);
1310 ripng->t_read = NULL;
1311
1312 /* Add myself to the next event. */
1313 ripng_event (RIPNG_READ, sock);
1314
1315 /* Read RIPng packet. */
1316 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1317 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1318 &hoplimit);
1319 if (len < 0)
1320 {
ajs6099b3b2004-11-20 02:06:59 +00001321 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001322 return len;
1323 }
1324
1325 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1326 (4)) must be multiple size of one RTE size (20). */
1327 if (((len - 4) % 20) != 0)
1328 {
1329 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001330 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001331 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001332 return 0;
1333 }
1334
1335 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1336 ifp = if_lookup_by_index (ifindex);
1337
1338 /* RIPng packet received. */
1339 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001340 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001341 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001342 ifp ? ifp->name : "unknown");
1343
1344 /* Logging before packet checking. */
1345 if (IS_RIPNG_DEBUG_RECV)
1346 ripng_packet_dump (packet, len, "RECV");
1347
1348 /* Packet comes from unknown interface. */
1349 if (ifp == NULL)
1350 {
1351 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1352 return 0;
1353 }
1354
1355 /* Packet version mismatch checking. */
1356 if (packet->version != ripng->version)
1357 {
1358 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1359 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001360 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001361 return 0;
1362 }
1363
1364 /* Process RIPng packet. */
1365 switch (packet->command)
1366 {
1367 case RIPNG_REQUEST:
1368 ripng_request_process (packet, len, &from, ifp);
1369 break;
1370 case RIPNG_RESPONSE:
1371 ripng_response_process (packet, len, &from, ifp, hoplimit);
1372 break;
1373 default:
1374 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001375 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001376 break;
1377 }
1378 return 0;
1379}
1380
1381/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001382static void
1383ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001384{
1385 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001386 struct ripng_info *rinfo = NULL;
1387 struct list *list = NULL;
1388 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001389
1390 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001391 if ((list = rp->info) != NULL)
1392 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1393 {
1394 UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1395 /* This flag can be set only on the first entry. */
1396 break;
1397 }
paul718e3742002-12-13 20:15:29 +00001398}
1399
1400/* Regular update of RIPng route. Send all routing formation to RIPng
1401 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001402static int
paul718e3742002-12-13 20:15:29 +00001403ripng_update (struct thread *t)
1404{
hasso52dc7ee2004-09-23 19:18:23 +00001405 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001406 struct interface *ifp;
1407 struct ripng_interface *ri;
1408
1409 /* Clear update timer thread. */
1410 ripng->t_update = NULL;
1411
1412 /* Logging update event. */
1413 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001414 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001415
1416 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001417 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001418 {
paul718e3742002-12-13 20:15:29 +00001419 ri = ifp->info;
1420
1421 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1422 continue;
1423
1424 if (! ri->running)
1425 continue;
1426
1427 /* When passive interface is specified, suppress announce to the
1428 interface. */
1429 if (ri->passive)
1430 continue;
1431
1432#if RIPNG_ADVANCED
1433 if (ri->ri_send == RIPNG_SEND_OFF)
1434 {
1435 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001436 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001437 "[Event] RIPng send to if %d is suppressed by config",
1438 ifp->ifindex);
1439 continue;
1440 }
1441#endif /* RIPNG_ADVANCED */
1442
hassoa94434b2003-05-25 17:10:12 +00001443 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001444 }
1445
1446 /* Triggered updates may be suppressed if a regular update is due by
1447 the time the triggered update would be sent. */
1448 if (ripng->t_triggered_interval)
1449 {
1450 thread_cancel (ripng->t_triggered_interval);
1451 ripng->t_triggered_interval = NULL;
1452 }
1453 ripng->trigger = 0;
1454
1455 /* Reset flush event. */
1456 ripng_event (RIPNG_UPDATE_EVENT, 0);
1457
1458 return 0;
1459}
1460
1461/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001462static int
paul718e3742002-12-13 20:15:29 +00001463ripng_triggered_interval (struct thread *t)
1464{
1465 ripng->t_triggered_interval = NULL;
1466
1467 if (ripng->trigger)
1468 {
1469 ripng->trigger = 0;
1470 ripng_triggered_update (t);
1471 }
1472 return 0;
1473}
1474
1475/* Execute triggered update. */
1476int
1477ripng_triggered_update (struct thread *t)
1478{
hasso52dc7ee2004-09-23 19:18:23 +00001479 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001480 struct interface *ifp;
1481 struct ripng_interface *ri;
1482 int interval;
1483
1484 ripng->t_triggered_update = NULL;
1485
1486 /* Cancel interval timer. */
1487 if (ripng->t_triggered_interval)
1488 {
1489 thread_cancel (ripng->t_triggered_interval);
1490 ripng->t_triggered_interval = NULL;
1491 }
1492 ripng->trigger = 0;
1493
1494 /* Logging triggered update. */
1495 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001496 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001497
1498 /* Split Horizon processing is done when generating triggered
1499 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001500 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001501 {
paul718e3742002-12-13 20:15:29 +00001502 ri = ifp->info;
1503
1504 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1505 continue;
1506
1507 if (! ri->running)
1508 continue;
1509
1510 /* When passive interface is specified, suppress announce to the
1511 interface. */
1512 if (ri->passive)
1513 continue;
1514
hassoa94434b2003-05-25 17:10:12 +00001515 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001516 }
1517
1518 /* Once all of the triggered updates have been generated, the route
1519 change flags should be cleared. */
1520 ripng_clear_changed_flag ();
1521
1522 /* After a triggered update is sent, a timer should be set for a
1523 random interval between 1 and 5 seconds. If other changes that
1524 would trigger updates occur before the timer expires, a single
1525 update is triggered when the timer expires. */
1526 interval = (random () % 5) + 1;
1527
1528 ripng->t_triggered_interval =
1529 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1530
1531 return 0;
1532}
1533
1534/* Write routing table entry to the stream and return next index of
1535 the routing table entry in the stream. */
1536int
1537ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001538 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001539{
1540 /* RIPng packet header. */
1541 if (num == 0)
1542 {
1543 stream_putc (s, RIPNG_RESPONSE);
1544 stream_putc (s, RIPNG_V1);
1545 stream_putw (s, 0);
1546 }
1547
1548 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001549 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001550 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001551 else
hassoc9e52be2004-09-26 16:09:34 +00001552 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001553 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001554 if (p)
1555 stream_putc (s, p->prefixlen);
1556 else
1557 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001558 stream_putc (s, metric);
1559
1560 return ++num;
1561}
1562
1563/* Send RESPONSE message to specified destination. */
1564void
1565ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001566 int route_type)
paul718e3742002-12-13 20:15:29 +00001567{
1568 int ret;
paul718e3742002-12-13 20:15:29 +00001569 struct route_node *rp;
1570 struct ripng_info *rinfo;
1571 struct ripng_interface *ri;
1572 struct ripng_aggregate *aggregate;
1573 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001574 struct list * ripng_rte_list;
Feng Lue97c31a2015-05-22 11:39:53 +02001575 struct list *list = NULL;
1576 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001577
hassoa94434b2003-05-25 17:10:12 +00001578 if (IS_RIPNG_DEBUG_EVENT) {
1579 if (to)
ajsc6106812004-12-08 19:51:16 +00001580 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001581 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001582 else
ajsc6106812004-12-08 19:51:16 +00001583 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001584 }
paul718e3742002-12-13 20:15:29 +00001585
paul718e3742002-12-13 20:15:29 +00001586 /* Get RIPng interface. */
1587 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001588
1589 ripng_rte_list = ripng_rte_new();
1590
paul718e3742002-12-13 20:15:29 +00001591 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1592 {
Feng Lue97c31a2015-05-22 11:39:53 +02001593 if ((list = rp->info) != NULL &&
1594 (rinfo = listgetdata (listhead (list))) != NULL &&
1595 rinfo->suppress == 0)
paul718e3742002-12-13 20:15:29 +00001596 {
hassoa94434b2003-05-25 17:10:12 +00001597 /* If no route-map are applied, the RTE will be these following
1598 * informations.
1599 */
paul718e3742002-12-13 20:15:29 +00001600 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001601 rinfo->metric_out = rinfo->metric;
1602 rinfo->tag_out = rinfo->tag;
1603 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1604 /* In order to avoid some local loops,
1605 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1606 * otherwise set it to 0. The nexthop should not be propagated
1607 * beyond the local broadcast/multicast area in order
1608 * to avoid an IGP multi-level recursive look-up.
1609 */
1610 if (rinfo->ifindex == ifp->ifindex)
1611 rinfo->nexthop_out = rinfo->nexthop;
1612
1613 /* Apply output filters. */
Matthieu Boutier543e7912014-09-10 16:50:44 +02001614 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
hassoa94434b2003-05-25 17:10:12 +00001615 if (ret < 0)
1616 continue;
paul718e3742002-12-13 20:15:29 +00001617
1618 /* Changed route only output. */
1619 if (route_type == ripng_changed_route &&
1620 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1621 continue;
1622
1623 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001624 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1625 {
1626 /* We perform split horizon for RIPng routes. */
Feng Lue97c31a2015-05-22 11:39:53 +02001627 int suppress = 0;
1628 struct ripng_info *tmp_rinfo = NULL;
1629
1630 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1631 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1632 tmp_rinfo->ifindex == ifp->ifindex)
1633 {
1634 suppress = 1;
1635 break;
1636 }
1637 if (suppress)
hassoa94434b2003-05-25 17:10:12 +00001638 continue;
1639 }
paul718e3742002-12-13 20:15:29 +00001640
1641 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001642 rinfo->metric_set = 0;
1643 /* nexthop_out,
1644 * metric_out
1645 * and tag_out are already initialized.
1646 */
paul718e3742002-12-13 20:15:29 +00001647
hassoa94434b2003-05-25 17:10:12 +00001648 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001649 if (ri->routemap[RIPNG_FILTER_OUT])
1650 {
1651 int ret;
paul718e3742002-12-13 20:15:29 +00001652
1653 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1654 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001655 rinfo);
paul718e3742002-12-13 20:15:29 +00001656
1657 if (ret == RMAP_DENYMATCH)
1658 {
1659 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001660 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001661 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001662 continue;
paul718e3742002-12-13 20:15:29 +00001663 }
1664
paul718e3742002-12-13 20:15:29 +00001665 }
1666
hassoa94434b2003-05-25 17:10:12 +00001667 /* Redistribute route-map. */
1668 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001669 {
hassoa94434b2003-05-25 17:10:12 +00001670 int ret;
1671
1672 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1673 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001674 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001675
1676 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001677 {
hassoa94434b2003-05-25 17:10:12 +00001678 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001679 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001680 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001681 continue;
paul718e3742002-12-13 20:15:29 +00001682 }
hassoa94434b2003-05-25 17:10:12 +00001683 }
paul718e3742002-12-13 20:15:29 +00001684
hassoa94434b2003-05-25 17:10:12 +00001685 /* When the route-map does not set metric. */
1686 if (! rinfo->metric_set)
1687 {
1688 /* If the redistribute metric is set. */
1689 if (ripng->route_map[rinfo->type].metric_config
1690 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001691 {
hassoa94434b2003-05-25 17:10:12 +00001692 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1693 }
1694 else
1695 {
1696 /* If the route is not connected or localy generated
1697 one, use default-metric value */
1698 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1699 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001700 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001701 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001702 }
1703 }
1704
hassoa94434b2003-05-25 17:10:12 +00001705 /* Apply offset-list */
1706 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1707 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001708
hassoa94434b2003-05-25 17:10:12 +00001709 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1710 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1711
1712 /* Perform split-horizon with poisoned reverse
1713 * for RIPng routes.
1714 **/
1715 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
Feng Lue97c31a2015-05-22 11:39:53 +02001716 struct ripng_info *tmp_rinfo = NULL;
1717
1718 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1719 if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1720 tmp_rinfo->ifindex == ifp->ifindex)
1721 rinfo->metric_out = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +00001722 }
1723
1724 /* Add RTE to the list */
1725 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001726 }
hassoa94434b2003-05-25 17:10:12 +00001727
1728 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001729 if ((aggregate = rp->aggregate) != NULL &&
1730 aggregate->count > 0 &&
1731 aggregate->suppress == 0)
1732 {
hassoa94434b2003-05-25 17:10:12 +00001733 /* If no route-map are applied, the RTE will be these following
1734 * informations.
1735 */
paul718e3742002-12-13 20:15:29 +00001736 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001737 aggregate->metric_set = 0;
1738 aggregate->metric_out = aggregate->metric;
1739 aggregate->tag_out = aggregate->tag;
1740 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001741
1742 /* Apply output filters.*/
Matthieu Boutier543e7912014-09-10 16:50:44 +02001743 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
hassoa94434b2003-05-25 17:10:12 +00001744 if (ret < 0)
1745 continue;
paul718e3742002-12-13 20:15:29 +00001746
hassoa94434b2003-05-25 17:10:12 +00001747 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001748 if (ri->routemap[RIPNG_FILTER_OUT])
1749 {
1750 int ret;
1751 struct ripng_info newinfo;
1752
hassoa94434b2003-05-25 17:10:12 +00001753 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001754 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001755 /* the nexthop is :: */
1756 newinfo.metric = aggregate->metric;
1757 newinfo.metric_out = aggregate->metric_out;
1758 newinfo.tag = aggregate->tag;
1759 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001760
1761 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1762 (struct prefix *) p, RMAP_RIPNG,
1763 &newinfo);
1764
1765 if (ret == RMAP_DENYMATCH)
1766 {
1767 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001768 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001769 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001770 continue;
paul718e3742002-12-13 20:15:29 +00001771 }
1772
hassoa94434b2003-05-25 17:10:12 +00001773 aggregate->metric_out = newinfo.metric_out;
1774 aggregate->tag_out = newinfo.tag_out;
1775 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1776 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001777 }
1778
hassoa94434b2003-05-25 17:10:12 +00001779 /* There is no redistribute routemap for the aggregated RTE */
1780
paul718e3742002-12-13 20:15:29 +00001781 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001782 /* XXX, vincent, in order to increase time convergence,
1783 * it should be announced if a child has changed.
1784 */
paul718e3742002-12-13 20:15:29 +00001785 if (route_type == ripng_changed_route)
1786 continue;
1787
hassoa94434b2003-05-25 17:10:12 +00001788 /* Apply offset-list */
1789 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1790 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001791
hassoa94434b2003-05-25 17:10:12 +00001792 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1793 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1794
1795 /* Add RTE to the list */
1796 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001797 }
1798
1799 }
paul718e3742002-12-13 20:15:29 +00001800
hassoa94434b2003-05-25 17:10:12 +00001801 /* Flush the list */
1802 ripng_rte_send(ripng_rte_list, ifp, to);
1803 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001804}
1805
1806/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001807static int
1808ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001809{
1810 /* ripng should be NULL. */
1811 assert (ripng == NULL);
1812
1813 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001814 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001815
1816 /* Default version and timer values. */
1817 ripng->version = RIPNG_V1;
1818 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1819 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1820 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1821 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1822
1823 /* Make buffer. */
1824 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1825 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1826
1827 /* Initialize RIPng routig table. */
1828 ripng->table = route_table_init ();
1829 ripng->route = route_table_init ();
1830 ripng->aggregate = route_table_init ();
1831
1832 /* Make socket. */
1833 ripng->sock = ripng_make_socket ();
1834 if (ripng->sock < 0)
1835 return ripng->sock;
1836
1837 /* Threads. */
1838 ripng_event (RIPNG_READ, ripng->sock);
1839 ripng_event (RIPNG_UPDATE_EVENT, 1);
1840
1841 return 0;
1842}
1843
hassoa94434b2003-05-25 17:10:12 +00001844/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001845int
1846ripng_request (struct interface *ifp)
1847{
1848 struct rte *rte;
1849 struct ripng_packet ripng_packet;
1850
hassoa94434b2003-05-25 17:10:12 +00001851 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1852 if (if_is_loopback(ifp))
1853 return 0;
1854
1855 /* If interface is down, don't send RIP packet. */
1856 if (! if_is_up (ifp))
1857 return 0;
1858
paul718e3742002-12-13 20:15:29 +00001859 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001860 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001861
1862 memset (&ripng_packet, 0, sizeof (ripng_packet));
1863 ripng_packet.command = RIPNG_REQUEST;
1864 ripng_packet.version = RIPNG_V1;
1865 rte = ripng_packet.rte;
1866 rte->metric = RIPNG_METRIC_INFINITY;
1867
1868 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1869 NULL, ifp);
1870}
1871
David Lamparter6b0655a2014-06-04 06:53:35 +02001872
Paul Jakma6ac29a52008-08-15 13:45:30 +01001873static int
paul718e3742002-12-13 20:15:29 +00001874ripng_update_jitter (int time)
1875{
Donald Sharpf31bab42015-06-19 19:26:19 -04001876 return ((random () % (time + 1)) - (time / 2));
paul718e3742002-12-13 20:15:29 +00001877}
1878
1879void
1880ripng_event (enum ripng_event event, int sock)
1881{
paul718e3742002-12-13 20:15:29 +00001882 int jitter = 0;
1883
1884 switch (event)
1885 {
1886 case RIPNG_READ:
1887 if (!ripng->t_read)
1888 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1889 break;
1890 case RIPNG_UPDATE_EVENT:
1891 if (ripng->t_update)
1892 {
1893 thread_cancel (ripng->t_update);
1894 ripng->t_update = NULL;
1895 }
1896 /* Update timer jitter. */
1897 jitter = ripng_update_jitter (ripng->update_time);
1898
1899 ripng->t_update =
1900 thread_add_timer (master, ripng_update, NULL,
1901 sock ? 2 : ripng->update_time + jitter);
1902 break;
1903 case RIPNG_TRIGGERED_UPDATE:
1904 if (ripng->t_triggered_interval)
1905 ripng->trigger = 1;
1906 else if (! ripng->t_triggered_update)
1907 ripng->t_triggered_update =
1908 thread_add_event (master, ripng_triggered_update, NULL, 0);
1909 break;
1910 default:
1911 break;
1912 }
1913}
David Lamparter6b0655a2014-06-04 06:53:35 +02001914
paul718e3742002-12-13 20:15:29 +00001915
paul718e3742002-12-13 20:15:29 +00001916/* Print out routes update time. */
1917static void
1918ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1919{
paul718e3742002-12-13 20:15:29 +00001920 time_t clock;
1921 struct tm *tm;
1922#define TIME_BUF 25
1923 char timebuf [TIME_BUF];
1924 struct thread *thread;
1925
paul718e3742002-12-13 20:15:29 +00001926 if ((thread = rinfo->t_timeout) != NULL)
1927 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001928 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001929 tm = gmtime (&clock);
1930 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1931 vty_out (vty, "%5s", timebuf);
1932 }
1933 else if ((thread = rinfo->t_garbage_collect) != NULL)
1934 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001935 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001936 tm = gmtime (&clock);
1937 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1938 vty_out (vty, "%5s", timebuf);
1939 }
1940}
1941
Paul Jakma6ac29a52008-08-15 13:45:30 +01001942static char *
hassoa94434b2003-05-25 17:10:12 +00001943ripng_route_subtype_print (struct ripng_info *rinfo)
1944{
1945 static char str[3];
1946 memset(str, 0, 3);
1947
1948 if (rinfo->suppress)
1949 strcat(str, "S");
1950
1951 switch (rinfo->sub_type)
1952 {
1953 case RIPNG_ROUTE_RTE:
1954 strcat(str, "n");
1955 break;
1956 case RIPNG_ROUTE_STATIC:
1957 strcat(str, "s");
1958 break;
1959 case RIPNG_ROUTE_DEFAULT:
1960 strcat(str, "d");
1961 break;
1962 case RIPNG_ROUTE_REDISTRIBUTE:
1963 strcat(str, "r");
1964 break;
1965 case RIPNG_ROUTE_INTERFACE:
1966 strcat(str, "i");
1967 break;
1968 default:
1969 strcat(str, "?");
1970 break;
1971 }
1972
1973 return str;
1974}
1975
paul718e3742002-12-13 20:15:29 +00001976DEFUN (show_ipv6_ripng,
1977 show_ipv6_ripng_cmd,
1978 "show ipv6 ripng",
1979 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001980 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001981 "Show RIPng routes\n")
1982{
1983 struct route_node *rp;
1984 struct ripng_info *rinfo;
1985 struct ripng_aggregate *aggregate;
1986 struct prefix_ipv6 *p;
Feng Lue97c31a2015-05-22 11:39:53 +02001987 struct list *list = NULL;
1988 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001989 int len;
1990
hassoa94434b2003-05-25 17:10:12 +00001991 if (! ripng)
1992 return CMD_SUCCESS;
1993
paul718e3742002-12-13 20:15:29 +00001994 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00001995 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
1996 "Sub-codes:%s"
1997 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
1998 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
1999 " Network Next Hop Via Metric Tag Time%s",
2000 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002001 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2002
2003 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2004 {
2005 if ((aggregate = rp->aggregate) != NULL)
2006 {
2007 p = (struct prefix_ipv6 *) &rp->p;
2008
2009#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002010 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002011 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002012 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002013#else
hassoa94434b2003-05-25 17:10:12 +00002014 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002015 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002016#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002017 vty_out (vty, "%s", VTY_NEWLINE);
2018 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002019
hassoa94434b2003-05-25 17:10:12 +00002020 vty_out (vty, "%*s", 28, " ");
2021 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002022 aggregate->tag,
2023 VTY_NEWLINE);
2024 }
2025
Feng Lue97c31a2015-05-22 11:39:53 +02002026 if ((list = rp->info) != NULL)
2027 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00002028 {
2029 p = (struct prefix_ipv6 *) &rp->p;
2030
2031#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002032 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2033 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002034 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002035 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002036 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002037#else
ajsf52d13c2005-10-01 17:38:06 +00002038 len = vty_out (vty, "%c(%s) %s/%d ",
2039 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002040 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002041 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002042#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002043 vty_out (vty, "%s", VTY_NEWLINE);
2044 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002045 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002046
hassoa94434b2003-05-25 17:10:12 +00002047 len = 28 - len;
2048 if (len > 0)
2049 len = vty_out (vty, "%*s", len, " ");
2050
2051 /* from */
2052 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2053 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2054 {
2055 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2056 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2057 {
2058 len = vty_out (vty, "kill");
2059 } else
2060 len = vty_out (vty, "self");
2061
2062 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002063 if (len > 0)
2064 vty_out (vty, "%*s", len, " ");
2065
hassoa94434b2003-05-25 17:10:12 +00002066 vty_out (vty, " %2d %3d ",
2067 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002068
hassoa94434b2003-05-25 17:10:12 +00002069 /* time */
2070 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2071 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2072 {
2073 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002074 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002075 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2076 {
2077 /* poisonous reversed routes (gc) */
2078 ripng_vty_out_uptime (vty, rinfo);
2079 }
paul718e3742002-12-13 20:15:29 +00002080
2081 vty_out (vty, "%s", VTY_NEWLINE);
2082 }
2083 }
2084
2085 return CMD_SUCCESS;
2086}
2087
hassoa94434b2003-05-25 17:10:12 +00002088DEFUN (show_ipv6_ripng_status,
2089 show_ipv6_ripng_status_cmd,
2090 "show ipv6 ripng status",
2091 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002092 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002093 "Show RIPng routes\n"
2094 "IPv6 routing protocol process parameters and statistics\n")
2095{
hasso52dc7ee2004-09-23 19:18:23 +00002096 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002097 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002098
2099 if (! ripng)
2100 return CMD_SUCCESS;
2101
2102 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2103 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2104 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002105 vty_out (vty, " next due in %lu seconds%s",
2106 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002107 VTY_NEWLINE);
2108 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2109 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2110 VTY_NEWLINE);
2111
2112 /* Filtering status show. */
2113 config_show_distribute (vty);
2114
2115 /* Default metric information. */
2116 vty_out (vty, " Default redistribution metric is %d%s",
2117 ripng->default_metric, VTY_NEWLINE);
2118
2119 /* Redistribute information. */
2120 vty_out (vty, " Redistributing:");
2121 ripng_redistribute_write (vty, 0);
2122 vty_out (vty, "%s", VTY_NEWLINE);
2123
2124 vty_out (vty, " Default version control: send version %d,", ripng->version);
2125 vty_out (vty, " receive version %d %s", ripng->version,
2126 VTY_NEWLINE);
2127
2128 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2129
paul1eb8ef22005-04-07 07:30:20 +00002130 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002131 {
2132 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002133
hassoa94434b2003-05-25 17:10:12 +00002134 ri = ifp->info;
2135
2136 if (ri->enable_network || ri->enable_interface)
2137 {
2138
2139 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2140 ripng->version,
2141 ripng->version,
2142 VTY_NEWLINE);
2143 }
2144 }
2145
2146 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2147 ripng_network_write (vty, 0);
2148
2149 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2150 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2151 ripng_peer_display (vty);
2152
2153 return CMD_SUCCESS;
2154}
2155
paul718e3742002-12-13 20:15:29 +00002156DEFUN (router_ripng,
2157 router_ripng_cmd,
2158 "router ripng",
2159 "Enable a routing process\n"
2160 "Make RIPng instance command\n")
2161{
2162 int ret;
2163
2164 vty->node = RIPNG_NODE;
2165
2166 if (!ripng)
2167 {
2168 ret = ripng_create ();
2169
2170 /* Notice to user we couldn't create RIPng. */
2171 if (ret < 0)
2172 {
2173 zlog_warn ("can't create RIPng");
2174 return CMD_WARNING;
2175 }
2176 }
2177
2178 return CMD_SUCCESS;
2179}
2180
hassoa94434b2003-05-25 17:10:12 +00002181DEFUN (no_router_ripng,
2182 no_router_ripng_cmd,
2183 "no router ripng",
2184 NO_STR
2185 "Enable a routing process\n"
2186 "Make RIPng instance command\n")
2187{
2188 if(ripng)
2189 ripng_clean();
2190 return CMD_SUCCESS;
2191}
2192
paul718e3742002-12-13 20:15:29 +00002193DEFUN (ripng_route,
2194 ripng_route_cmd,
2195 "route IPV6ADDR",
2196 "Static route setup\n"
2197 "Set static RIPng route announcement\n")
2198{
2199 int ret;
2200 struct prefix_ipv6 p;
2201 struct route_node *rp;
2202
2203 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2204 if (ret <= 0)
2205 {
2206 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2207 return CMD_WARNING;
2208 }
2209 apply_mask_ipv6 (&p);
2210
2211 rp = route_node_get (ripng->route, (struct prefix *) &p);
2212 if (rp->info)
2213 {
2214 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2215 route_unlock_node (rp);
2216 return CMD_WARNING;
2217 }
2218 rp->info = (void *)1;
2219
Christian Franke5bb328e2016-10-01 22:35:32 +02002220 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL, 0);
paul718e3742002-12-13 20:15:29 +00002221
2222 return CMD_SUCCESS;
2223}
2224
2225DEFUN (no_ripng_route,
2226 no_ripng_route_cmd,
2227 "no route IPV6ADDR",
2228 NO_STR
2229 "Static route setup\n"
2230 "Delete static RIPng route announcement\n")
2231{
2232 int ret;
2233 struct prefix_ipv6 p;
2234 struct route_node *rp;
2235
2236 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2237 if (ret <= 0)
2238 {
2239 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2240 return CMD_WARNING;
2241 }
2242 apply_mask_ipv6 (&p);
2243
2244 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2245 if (! rp)
2246 {
2247 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2248 return CMD_WARNING;
2249 }
2250
2251 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2252 route_unlock_node (rp);
2253
2254 rp->info = NULL;
2255 route_unlock_node (rp);
2256
2257 return CMD_SUCCESS;
2258}
2259
2260DEFUN (ripng_aggregate_address,
2261 ripng_aggregate_address_cmd,
2262 "aggregate-address X:X::X:X/M",
2263 "Set aggregate RIPng route announcement\n"
2264 "Aggregate network\n")
2265{
2266 int ret;
2267 struct prefix p;
2268 struct route_node *node;
2269
2270 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2271 if (ret <= 0)
2272 {
2273 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2274 return CMD_WARNING;
2275 }
2276
2277 /* Check aggregate alredy exist or not. */
2278 node = route_node_get (ripng->aggregate, &p);
2279 if (node->info)
2280 {
2281 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2282 route_unlock_node (node);
2283 return CMD_WARNING;
2284 }
2285 node->info = (void *)1;
2286
2287 ripng_aggregate_add (&p);
2288
2289 return CMD_SUCCESS;
2290}
2291
2292DEFUN (no_ripng_aggregate_address,
2293 no_ripng_aggregate_address_cmd,
2294 "no aggregate-address X:X::X:X/M",
2295 NO_STR
2296 "Delete aggregate RIPng route announcement\n"
2297 "Aggregate network")
2298{
2299 int ret;
2300 struct prefix p;
2301 struct route_node *rn;
2302
2303 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2304 if (ret <= 0)
2305 {
2306 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2307 return CMD_WARNING;
2308 }
2309
2310 rn = route_node_lookup (ripng->aggregate, &p);
2311 if (! rn)
2312 {
2313 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2314 return CMD_WARNING;
2315 }
2316 route_unlock_node (rn);
2317 rn->info = NULL;
2318 route_unlock_node (rn);
2319
2320 ripng_aggregate_delete (&p);
2321
2322 return CMD_SUCCESS;
2323}
2324
2325DEFUN (ripng_default_metric,
2326 ripng_default_metric_cmd,
2327 "default-metric <1-16>",
2328 "Set a metric of redistribute routes\n"
2329 "Default metric\n")
2330{
2331 if (ripng)
2332 {
2333 ripng->default_metric = atoi (argv[0]);
2334 }
2335 return CMD_SUCCESS;
2336}
2337
2338DEFUN (no_ripng_default_metric,
2339 no_ripng_default_metric_cmd,
2340 "no default-metric",
2341 NO_STR
2342 "Set a metric of redistribute routes\n"
2343 "Default metric\n")
2344{
2345 if (ripng)
2346 {
2347 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2348 }
2349 return CMD_SUCCESS;
2350}
2351
2352ALIAS (no_ripng_default_metric,
2353 no_ripng_default_metric_val_cmd,
2354 "no default-metric <1-16>",
2355 NO_STR
2356 "Set a metric of redistribute routes\n"
2357 "Default metric\n")
2358
2359#if 0
2360/* RIPng update timer setup. */
2361DEFUN (ripng_update_timer,
2362 ripng_update_timer_cmd,
2363 "update-timer SECOND",
2364 "Set RIPng update timer in seconds\n"
2365 "Seconds\n")
2366{
2367 unsigned long update;
2368 char *endptr = NULL;
2369
2370 update = strtoul (argv[0], &endptr, 10);
2371 if (update == ULONG_MAX || *endptr != '\0')
2372 {
2373 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2374 return CMD_WARNING;
2375 }
2376
2377 ripng->update_time = update;
2378
2379 ripng_event (RIPNG_UPDATE_EVENT, 0);
2380 return CMD_SUCCESS;
2381}
2382
2383DEFUN (no_ripng_update_timer,
2384 no_ripng_update_timer_cmd,
2385 "no update-timer SECOND",
2386 NO_STR
2387 "Unset RIPng update timer in seconds\n"
2388 "Seconds\n")
2389{
2390 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2391 ripng_event (RIPNG_UPDATE_EVENT, 0);
2392 return CMD_SUCCESS;
2393}
2394
2395/* RIPng timeout timer setup. */
2396DEFUN (ripng_timeout_timer,
2397 ripng_timeout_timer_cmd,
2398 "timeout-timer SECOND",
2399 "Set RIPng timeout timer in seconds\n"
2400 "Seconds\n")
2401{
2402 unsigned long timeout;
2403 char *endptr = NULL;
2404
2405 timeout = strtoul (argv[0], &endptr, 10);
2406 if (timeout == ULONG_MAX || *endptr != '\0')
2407 {
2408 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2409 return CMD_WARNING;
2410 }
2411
2412 ripng->timeout_time = timeout;
2413
2414 return CMD_SUCCESS;
2415}
2416
2417DEFUN (no_ripng_timeout_timer,
2418 no_ripng_timeout_timer_cmd,
2419 "no timeout-timer SECOND",
2420 NO_STR
2421 "Unset RIPng timeout timer in seconds\n"
2422 "Seconds\n")
2423{
2424 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2425 return CMD_SUCCESS;
2426}
2427
2428/* RIPng garbage timer setup. */
2429DEFUN (ripng_garbage_timer,
2430 ripng_garbage_timer_cmd,
2431 "garbage-timer SECOND",
2432 "Set RIPng garbage timer in seconds\n"
2433 "Seconds\n")
2434{
2435 unsigned long garbage;
2436 char *endptr = NULL;
2437
2438 garbage = strtoul (argv[0], &endptr, 10);
2439 if (garbage == ULONG_MAX || *endptr != '\0')
2440 {
2441 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2442 return CMD_WARNING;
2443 }
2444
2445 ripng->garbage_time = garbage;
2446
2447 return CMD_SUCCESS;
2448}
2449
2450DEFUN (no_ripng_garbage_timer,
2451 no_ripng_garbage_timer_cmd,
2452 "no garbage-timer SECOND",
2453 NO_STR
2454 "Unset RIPng garbage timer in seconds\n"
2455 "Seconds\n")
2456{
2457 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2458 return CMD_SUCCESS;
2459}
2460#endif /* 0 */
2461
2462DEFUN (ripng_timers,
2463 ripng_timers_cmd,
2464 "timers basic <0-65535> <0-65535> <0-65535>",
2465 "RIPng timers setup\n"
2466 "Basic timer\n"
2467 "Routing table update timer value in second. Default is 30.\n"
2468 "Routing information timeout timer. Default is 180.\n"
2469 "Garbage collection timer. Default is 120.\n")
2470{
2471 unsigned long update;
2472 unsigned long timeout;
2473 unsigned long garbage;
paul718e3742002-12-13 20:15:29 +00002474
Ulrich Weber69898802011-11-17 21:35:08 +04002475 VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2476 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2477 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
paul718e3742002-12-13 20:15:29 +00002478
2479 /* Set each timer value. */
2480 ripng->update_time = update;
2481 ripng->timeout_time = timeout;
2482 ripng->garbage_time = garbage;
2483
2484 /* Reset update timer thread. */
2485 ripng_event (RIPNG_UPDATE_EVENT, 0);
2486
2487 return CMD_SUCCESS;
2488}
2489
2490DEFUN (no_ripng_timers,
2491 no_ripng_timers_cmd,
2492 "no timers basic",
2493 NO_STR
2494 "RIPng timers setup\n"
2495 "Basic timer\n")
2496{
2497 /* Set each timer value to the default. */
2498 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2499 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2500 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2501
2502 /* Reset update timer thread. */
2503 ripng_event (RIPNG_UPDATE_EVENT, 0);
2504
2505 return CMD_SUCCESS;
2506}
2507
hassoa94434b2003-05-25 17:10:12 +00002508ALIAS (no_ripng_timers,
2509 no_ripng_timers_val_cmd,
2510 "no timers basic <0-65535> <0-65535> <0-65535>",
2511 NO_STR
2512 "RIPng timers setup\n"
2513 "Basic timer\n"
2514 "Routing table update timer value in second. Default is 30.\n"
2515 "Routing information timeout timer. Default is 180.\n"
2516 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002517
2518DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2519 "show ipv6 protocols",
2520 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002521 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002522 "Routing protocol information")
2523{
2524 if (! ripng)
2525 return CMD_SUCCESS;
2526
2527 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2528
2529 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2530 ripng->update_time, 0,
2531 VTY_NEWLINE);
2532
2533 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2534 ripng->timeout_time,
2535 ripng->garbage_time,
2536 VTY_NEWLINE);
2537
2538 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2539 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2540
2541 return CMD_SUCCESS;
2542}
2543
2544/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002545DEFUN (ripng_default_information_originate,
2546 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002547 "default-information originate",
2548 "Default route information\n"
2549 "Distribute default route\n")
2550{
2551 struct prefix_ipv6 p;
2552
hassoa94434b2003-05-25 17:10:12 +00002553 if (! ripng ->default_information) {
2554 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002555
hassoa94434b2003-05-25 17:10:12 +00002556 str2prefix_ipv6 ("::/0", &p);
Christian Franke5bb328e2016-10-01 22:35:32 +02002557 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
hassoa94434b2003-05-25 17:10:12 +00002558 }
paul718e3742002-12-13 20:15:29 +00002559
2560 return CMD_SUCCESS;
2561}
2562
paula2c62832003-04-23 17:01:31 +00002563DEFUN (no_ripng_default_information_originate,
2564 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002565 "no default-information originate",
2566 NO_STR
2567 "Default route information\n"
2568 "Distribute default route\n")
2569{
2570 struct prefix_ipv6 p;
2571
hassoa94434b2003-05-25 17:10:12 +00002572 if (ripng->default_information) {
2573 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002574
hassoa94434b2003-05-25 17:10:12 +00002575 str2prefix_ipv6 ("::/0", &p);
2576 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2577 }
paul718e3742002-12-13 20:15:29 +00002578
2579 return CMD_SUCCESS;
2580}
2581
Feng Lu72855b12015-05-22 11:39:54 +02002582/* Update ECMP routes to zebra when ECMP is disabled. */
2583static void
2584ripng_ecmp_disable (void)
2585{
2586 struct route_node *rp;
2587 struct ripng_info *rinfo, *tmp_rinfo;
2588 struct list *list;
2589 struct listnode *node, *nextnode;
2590
2591 if (!ripng)
2592 return;
2593
2594 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2595 if ((list = rp->info) != NULL && listcount (list) > 1)
2596 {
2597 rinfo = listgetdata (listhead (list));
2598 if (!ripng_route_rte (rinfo))
2599 continue;
2600
2601 /* Drop all other entries, except the first one. */
2602 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
2603 if (tmp_rinfo != rinfo)
2604 {
2605 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
2606 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
2607 list_delete_node (list, node);
2608 ripng_info_free (tmp_rinfo);
2609 }
2610
2611 /* Update zebra. */
2612 ripng_zebra_ipv6_add (rp);
2613
2614 /* Set the route change flag. */
2615 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
2616
2617 /* Signal the output process to trigger an update. */
2618 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
2619 }
2620}
2621
2622DEFUN (ripng_allow_ecmp,
2623 ripng_allow_ecmp_cmd,
2624 "allow-ecmp",
2625 "Allow Equal Cost MultiPath\n")
2626{
2627 if (ripng->ecmp)
2628 {
2629 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2630 return CMD_WARNING;
2631 }
2632
2633 ripng->ecmp = 1;
2634 zlog_info ("ECMP is enabled.");
2635 return CMD_SUCCESS;
2636}
2637
2638DEFUN (no_ripng_allow_ecmp,
2639 no_ripng_allow_ecmp_cmd,
2640 "no allow-ecmp",
2641 NO_STR
2642 "Allow Equal Cost MultiPath\n")
2643{
2644 if (!ripng->ecmp)
2645 {
2646 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2647 return CMD_WARNING;
2648 }
2649
2650 ripng->ecmp = 0;
2651 zlog_info ("ECMP is disabled.");
2652 ripng_ecmp_disable ();
2653 return CMD_SUCCESS;
2654}
2655
paul718e3742002-12-13 20:15:29 +00002656/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002657static int
paul718e3742002-12-13 20:15:29 +00002658ripng_config_write (struct vty *vty)
2659{
hassoa94434b2003-05-25 17:10:12 +00002660 int ripng_network_write (struct vty *, int);
2661 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002662 int write = 0;
2663 struct route_node *rp;
2664
2665 if (ripng)
2666 {
2667
2668 /* RIPng router. */
2669 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2670
2671 if (ripng->default_information)
2672 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2673
hassoa94434b2003-05-25 17:10:12 +00002674 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002675
2676 /* RIPng default metric configuration */
2677 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2678 vty_out (vty, " default-metric %d%s",
2679 ripng->default_metric, VTY_NEWLINE);
2680
hassoa94434b2003-05-25 17:10:12 +00002681 ripng_redistribute_write (vty, 1);
2682
2683 /* RIP offset-list configuration. */
2684 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002685
2686 /* RIPng aggregate routes. */
2687 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2688 if (rp->info != NULL)
2689 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002690 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002691 rp->p.prefixlen,
2692
2693 VTY_NEWLINE);
2694
Feng Lu72855b12015-05-22 11:39:54 +02002695 /* ECMP configuration. */
2696 if (ripng->ecmp)
2697 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
2698
paul718e3742002-12-13 20:15:29 +00002699 /* RIPng static routes. */
2700 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2701 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002702 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002703 rp->p.prefixlen,
2704 VTY_NEWLINE);
2705
2706 /* RIPng timers configuration. */
2707 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2708 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2709 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2710 {
2711 vty_out (vty, " timers basic %ld %ld %ld%s",
2712 ripng->update_time,
2713 ripng->timeout_time,
2714 ripng->garbage_time,
2715 VTY_NEWLINE);
2716 }
2717#if 0
2718 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2719 vty_out (vty, " update-timer %d%s", ripng->update_time,
2720 VTY_NEWLINE);
2721 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2722 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2723 VTY_NEWLINE);
2724 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2725 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2726 VTY_NEWLINE);
2727#endif /* 0 */
2728
2729 write += config_write_distribute (vty);
2730
2731 write += config_write_if_rmap (vty);
2732
2733 write++;
2734 }
2735 return write;
2736}
2737
2738/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002739static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002740{
2741 RIPNG_NODE,
2742 "%s(config-router)# ",
2743 1,
2744};
2745
Paul Jakma6ac29a52008-08-15 13:45:30 +01002746static void
paul718e3742002-12-13 20:15:29 +00002747ripng_distribute_update (struct distribute *dist)
2748{
2749 struct interface *ifp;
2750 struct ripng_interface *ri;
2751 struct access_list *alist;
2752 struct prefix_list *plist;
2753
2754 if (! dist->ifname)
2755 return;
2756
2757 ifp = if_lookup_by_name (dist->ifname);
2758 if (ifp == NULL)
2759 return;
2760
2761 ri = ifp->info;
2762
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002763 if (dist->list[DISTRIBUTE_V6_IN])
paul718e3742002-12-13 20:15:29 +00002764 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002765 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_IN]);
paul718e3742002-12-13 20:15:29 +00002766 if (alist)
2767 ri->list[RIPNG_FILTER_IN] = alist;
2768 else
2769 ri->list[RIPNG_FILTER_IN] = NULL;
2770 }
2771 else
2772 ri->list[RIPNG_FILTER_IN] = NULL;
2773
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002774 if (dist->list[DISTRIBUTE_V6_OUT])
paul718e3742002-12-13 20:15:29 +00002775 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002776 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_OUT]);
paul718e3742002-12-13 20:15:29 +00002777 if (alist)
2778 ri->list[RIPNG_FILTER_OUT] = alist;
2779 else
2780 ri->list[RIPNG_FILTER_OUT] = NULL;
2781 }
2782 else
2783 ri->list[RIPNG_FILTER_OUT] = NULL;
2784
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002785 if (dist->prefix[DISTRIBUTE_V6_IN])
paul718e3742002-12-13 20:15:29 +00002786 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002787 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_IN]);
paul718e3742002-12-13 20:15:29 +00002788 if (plist)
2789 ri->prefix[RIPNG_FILTER_IN] = plist;
2790 else
2791 ri->prefix[RIPNG_FILTER_IN] = NULL;
2792 }
2793 else
2794 ri->prefix[RIPNG_FILTER_IN] = NULL;
2795
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002796 if (dist->prefix[DISTRIBUTE_V6_OUT])
paul718e3742002-12-13 20:15:29 +00002797 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02002798 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_OUT]);
paul718e3742002-12-13 20:15:29 +00002799 if (plist)
2800 ri->prefix[RIPNG_FILTER_OUT] = plist;
2801 else
2802 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2803 }
2804 else
2805 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2806}
hassoa94434b2003-05-25 17:10:12 +00002807
paul718e3742002-12-13 20:15:29 +00002808void
2809ripng_distribute_update_interface (struct interface *ifp)
2810{
2811 struct distribute *dist;
2812
2813 dist = distribute_lookup (ifp->name);
2814 if (dist)
2815 ripng_distribute_update (dist);
2816}
2817
2818/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002819static void
hassoc9e52be2004-09-26 16:09:34 +00002820ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002821{
2822 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002823 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002824
paul1eb8ef22005-04-07 07:30:20 +00002825 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2826 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002827}
hassoc9e52be2004-09-26 16:09:34 +00002828
Paul Jakma6ac29a52008-08-15 13:45:30 +01002829static void
hassoc9e52be2004-09-26 16:09:34 +00002830ripng_distribute_update_all_wrapper (struct access_list *notused)
2831{
2832 ripng_distribute_update_all(NULL);
2833}
David Lamparter6b0655a2014-06-04 06:53:35 +02002834
hassoa94434b2003-05-25 17:10:12 +00002835/* delete all the added ripng routes. */
2836void
2837ripng_clean()
2838{
2839 int i;
2840 struct route_node *rp;
2841 struct ripng_info *rinfo;
Feng Lue97c31a2015-05-22 11:39:53 +02002842 struct ripng_aggregate *aggregate;
2843 struct list *list = NULL;
2844 struct listnode *listnode = NULL;
hassoa94434b2003-05-25 17:10:12 +00002845
2846 if (ripng) {
2847 /* Clear RIPng routes */
Feng Lue97c31a2015-05-22 11:39:53 +02002848 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2849 {
2850 if ((list = rp->info) != NULL)
2851 {
2852 rinfo = listgetdata (listhead (list));
2853 if (ripng_route_rte (rinfo))
2854 ripng_zebra_ipv6_delete (rp);
hassoa94434b2003-05-25 17:10:12 +00002855
Feng Lue97c31a2015-05-22 11:39:53 +02002856 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2857 {
2858 RIPNG_TIMER_OFF (rinfo->t_timeout);
2859 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2860 ripng_info_free (rinfo);
2861 }
2862 list_delete (list);
2863 rp->info = NULL;
2864 route_unlock_node (rp);
2865 }
hassoa94434b2003-05-25 17:10:12 +00002866
Feng Lue97c31a2015-05-22 11:39:53 +02002867 if ((aggregate = rp->aggregate) != NULL)
2868 {
2869 ripng_aggregate_free (aggregate);
2870 rp->aggregate = NULL;
2871 route_unlock_node (rp);
2872 }
hassoa94434b2003-05-25 17:10:12 +00002873 }
2874
2875 /* Cancel the RIPng timers */
2876 RIPNG_TIMER_OFF (ripng->t_update);
2877 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2878 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2879
2880 /* Cancel the read thread */
2881 if (ripng->t_read) {
2882 thread_cancel (ripng->t_read);
2883 ripng->t_read = NULL;
2884 }
2885
2886 /* Close the RIPng socket */
2887 if (ripng->sock >= 0) {
2888 close(ripng->sock);
2889 ripng->sock = -1;
2890 }
2891
2892 /* Static RIPng route configuration. */
2893 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2894 if (rp->info) {
2895 rp->info = NULL;
2896 route_unlock_node (rp);
2897 }
2898
2899 /* RIPng aggregated prefixes */
2900 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2901 if (rp->info) {
2902 rp->info = NULL;
2903 route_unlock_node (rp);
2904 }
2905
2906 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2907 if (ripng->route_map[i].name)
2908 free (ripng->route_map[i].name);
2909
2910 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2911 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2912 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2913
2914 XFREE (MTYPE_RIPNG, ripng);
2915 ripng = NULL;
2916 } /* if (ripng) */
2917
2918 ripng_clean_network();
2919 ripng_passive_interface_clean ();
2920 ripng_offset_clean ();
2921 ripng_interface_clean ();
2922 ripng_redistribute_clean ();
2923}
2924
2925/* Reset all values to the default settings. */
2926void
2927ripng_reset ()
2928{
2929 /* Call ripd related reset functions. */
2930 ripng_debug_reset ();
2931 ripng_route_map_reset ();
2932
2933 /* Call library reset functions. */
2934 vty_reset ();
2935 access_list_reset ();
2936 prefix_list_reset ();
2937
2938 distribute_list_reset ();
2939
2940 ripng_interface_reset ();
2941
2942 ripng_zclient_reset ();
2943}
paul718e3742002-12-13 20:15:29 +00002944
Paul Jakma6ac29a52008-08-15 13:45:30 +01002945static void
paul718e3742002-12-13 20:15:29 +00002946ripng_if_rmap_update (struct if_rmap *if_rmap)
2947{
2948 struct interface *ifp;
2949 struct ripng_interface *ri;
2950 struct route_map *rmap;
2951
2952 ifp = if_lookup_by_name (if_rmap->ifname);
2953 if (ifp == NULL)
2954 return;
2955
2956 ri = ifp->info;
2957
2958 if (if_rmap->routemap[IF_RMAP_IN])
2959 {
2960 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2961 if (rmap)
2962 ri->routemap[IF_RMAP_IN] = rmap;
2963 else
2964 ri->routemap[IF_RMAP_IN] = NULL;
2965 }
2966 else
2967 ri->routemap[RIPNG_FILTER_IN] = NULL;
2968
2969 if (if_rmap->routemap[IF_RMAP_OUT])
2970 {
2971 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2972 if (rmap)
2973 ri->routemap[IF_RMAP_OUT] = rmap;
2974 else
2975 ri->routemap[IF_RMAP_OUT] = NULL;
2976 }
2977 else
2978 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2979}
2980
2981void
2982ripng_if_rmap_update_interface (struct interface *ifp)
2983{
2984 struct if_rmap *if_rmap;
2985
2986 if_rmap = if_rmap_lookup (ifp->name);
2987 if (if_rmap)
2988 ripng_if_rmap_update (if_rmap);
2989}
2990
Paul Jakma6ac29a52008-08-15 13:45:30 +01002991static void
paul718e3742002-12-13 20:15:29 +00002992ripng_routemap_update_redistribute (void)
2993{
2994 int i;
2995
2996 if (ripng)
2997 {
2998 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2999 {
3000 if (ripng->route_map[i].name)
3001 ripng->route_map[i].map =
3002 route_map_lookup_by_name (ripng->route_map[i].name);
3003 }
3004 }
3005}
3006
Paul Jakma6ac29a52008-08-15 13:45:30 +01003007static void
hasso98b718a2004-10-11 12:57:57 +00003008ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00003009{
3010 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00003011 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003012
paul1eb8ef22005-04-07 07:30:20 +00003013 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
3014 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003015
3016 ripng_routemap_update_redistribute ();
3017}
3018
3019/* Initialize ripng structure and set commands. */
3020void
3021ripng_init ()
3022{
3023 /* Randomize. */
Donald Sharpf31bab42015-06-19 19:26:19 -04003024 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00003025
3026 /* Install RIPNG_NODE. */
3027 install_node (&cmd_ripng_node, ripng_config_write);
3028
3029 /* Install ripng commands. */
3030 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003031 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003032
paul718e3742002-12-13 20:15:29 +00003033 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003034 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00003035
3036 install_default (RIPNG_NODE);
3037 install_element (RIPNG_NODE, &ripng_route_cmd);
3038 install_element (RIPNG_NODE, &no_ripng_route_cmd);
3039 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3040 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3041
3042 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3043 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
3044 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
3045
3046 install_element (RIPNG_NODE, &ripng_timers_cmd);
3047 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00003048 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00003049#if 0
3050 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3051 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3052 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3053 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3054 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3055 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3056#endif /* 0 */
3057
paula2c62832003-04-23 17:01:31 +00003058 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3059 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00003060
Feng Lu72855b12015-05-22 11:39:54 +02003061 install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
3062 install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
3063
paul718e3742002-12-13 20:15:29 +00003064 ripng_if_init ();
3065 ripng_debug_init ();
3066
3067 /* Access list install. */
3068 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003069 access_list_add_hook (ripng_distribute_update_all_wrapper);
3070 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003071
3072 /* Prefix list initialize.*/
3073 prefix_list_init ();
3074 prefix_list_add_hook (ripng_distribute_update_all);
3075 prefix_list_delete_hook (ripng_distribute_update_all);
3076
3077 /* Distribute list install. */
3078 distribute_list_init (RIPNG_NODE);
3079 distribute_list_add_hook (ripng_distribute_update);
3080 distribute_list_delete_hook (ripng_distribute_update);
3081
3082 /* Route-map for interface. */
3083 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003084 ripng_offset_init ();
3085
paul718e3742002-12-13 20:15:29 +00003086 route_map_add_hook (ripng_routemap_update);
3087 route_map_delete_hook (ripng_routemap_update);
3088
hasso0750d212003-05-24 21:41:49 +00003089 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003090 if_rmap_hook_add (ripng_if_rmap_update);
3091 if_rmap_hook_delete (ripng_if_rmap_update);
3092}