blob: 21e45b6ea20e1a8d43d45f1c88bf1ecc8d964fc8 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
paul718e3742002-12-13 20:15:29 +000024#include "prefix.h"
25#include "filter.h"
26#include "log.h"
27#include "thread.h"
28#include "memory.h"
29#include "if.h"
30#include "stream.h"
31#include "table.h"
32#include "command.h"
33#include "sockopt.h"
34#include "distribute.h"
35#include "plist.h"
36#include "routemap.h"
hasso0750d212003-05-24 21:41:49 +000037#include "if_rmap.h"
paul27d47aa2003-11-17 09:04:53 +000038#include "privs.h"
paul718e3742002-12-13 20:15:29 +000039
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
hassoa94434b2003-05-25 17:10:12 +000043#include "ripngd/ripng_nexthop.h"
paul718e3742002-12-13 20:15:29 +000044
45/* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48struct ripng *ripng = NULL;
49
50enum
51{
52 ripng_all_route,
53 ripng_changed_route,
paul718e3742002-12-13 20:15:29 +000054};
55
paul27d47aa2003-11-17 09:04:53 +000056extern struct zebra_privs_t ripngd_privs;
57
paul718e3742002-12-13 20:15:29 +000058/* Prototypes. */
59void
hassoa94434b2003-05-25 17:10:12 +000060ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
paul718e3742002-12-13 20:15:29 +000061
62int
63ripng_triggered_update (struct thread *);
64
65/* RIPng next hop specification. */
66struct ripng_nexthop
67{
68 enum ripng_nexthop_type
69 {
70 RIPNG_NEXTHOP_UNSPEC,
71 RIPNG_NEXTHOP_ADDRESS
72 } flag;
73 struct in6_addr address;
74};
paul718e3742002-12-13 20:15:29 +000075
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static int
hassoa94434b2003-05-25 17:10:12 +000077ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
paul718e3742002-12-13 20:15:29 +000082/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
David Lamparter6b0655a2014-06-04 06:53:35 +020098
paul718e3742002-12-13 20:15:29 +000099/* Create ripng socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100100static int
paul718e3742002-12-13 20:15:29 +0000101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't make ripng socket");
111 return sock;
112 }
113
114 ret = setsockopt_so_recvbuf (sock, 8096);
115 if (ret < 0)
116 return ret;
117 ret = setsockopt_ipv6_pktinfo (sock, 1);
118 if (ret < 0)
119 return ret;
Stephen Hemminger6d0732c2011-09-28 14:23:35 +0400120#ifdef IPTOS_PREC_INTERNETCONTROL
121 ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
122 if (ret < 0)
123 return ret;
124#endif
paul718e3742002-12-13 20:15:29 +0000125 ret = setsockopt_ipv6_multicast_hops (sock, 255);
126 if (ret < 0)
127 return ret;
128 ret = setsockopt_ipv6_multicast_loop (sock, 0);
129 if (ret < 0)
130 return ret;
131 ret = setsockopt_ipv6_hoplimit (sock, 1);
132 if (ret < 0)
133 return ret;
134
135 memset (&ripaddr, 0, sizeof (ripaddr));
136 ripaddr.sin6_family = AF_INET6;
137#ifdef SIN6_LEN
138 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
139#endif /* SIN6_LEN */
140 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
141
paul27d47aa2003-11-17 09:04:53 +0000142 if (ripngd_privs.change (ZPRIVS_RAISE))
143 zlog_err ("ripng_make_socket: could not raise privs");
144
paul718e3742002-12-13 20:15:29 +0000145 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
146 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000147 {
ajs6099b3b2004-11-20 02:06:59 +0000148 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000149 if (ripngd_privs.change (ZPRIVS_LOWER))
150 zlog_err ("ripng_make_socket: could not lower privs");
151 return ret;
152 }
153 if (ripngd_privs.change (ZPRIVS_LOWER))
154 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000155 return sock;
156}
157
158/* Send RIPng packet. */
159int
160ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
161 struct interface *ifp)
162{
163 int ret;
164 struct msghdr msg;
165 struct iovec iov;
166 struct cmsghdr *cmsgptr;
167 char adata [256];
168 struct in6_pktinfo *pkt;
169 struct sockaddr_in6 addr;
170
hassoa94434b2003-05-25 17:10:12 +0000171 if (IS_RIPNG_DEBUG_SEND) {
172 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000173 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000174 zlog_debug (" send interface %s", ifp->name);
175 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000176 }
paul718e3742002-12-13 20:15:29 +0000177
178 memset (&addr, 0, sizeof (struct sockaddr_in6));
179 addr.sin6_family = AF_INET6;
180#ifdef SIN6_LEN
181 addr.sin6_len = sizeof (struct sockaddr_in6);
182#endif /* SIN6_LEN */
183 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
184
185 /* When destination is specified. */
186 if (to != NULL)
187 {
188 addr.sin6_addr = to->sin6_addr;
189 addr.sin6_port = to->sin6_port;
190 }
191 else
192 {
193 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
194 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
195 }
196
197 msg.msg_name = (void *) &addr;
198 msg.msg_namelen = sizeof (struct sockaddr_in6);
199 msg.msg_iov = &iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = (void *) adata;
202 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
203
204 iov.iov_base = buf;
205 iov.iov_len = bufsize;
206
207 cmsgptr = (struct cmsghdr *)adata;
208 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
209 cmsgptr->cmsg_level = IPPROTO_IPV6;
210 cmsgptr->cmsg_type = IPV6_PKTINFO;
211
212 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
213 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
214 pkt->ipi6_ifindex = ifp->ifindex;
215
216 ret = sendmsg (ripng->sock, &msg, 0);
217
hassoa94434b2003-05-25 17:10:12 +0000218 if (ret < 0) {
219 if (to)
220 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000221 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000222 else
ajs6099b3b2004-11-20 02:06:59 +0000223 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000224 }
paul718e3742002-12-13 20:15:29 +0000225
226 return ret;
227}
228
229/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100230static int
paul718e3742002-12-13 20:15:29 +0000231ripng_recv_packet (int sock, u_char *buf, int bufsize,
232 struct sockaddr_in6 *from, unsigned int *ifindex,
233 int *hoplimit)
234{
235 int ret;
236 struct msghdr msg;
237 struct iovec iov;
238 struct cmsghdr *cmsgptr;
David Lamparterab90fc02015-03-03 09:07:25 +0100239 struct in6_addr dst = { .s6_addr = { 0 } };
paul718e3742002-12-13 20:15:29 +0000240
241 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
242 point I can't determine size of cmsghdr */
243 char adata[1024];
244
245 /* Fill in message and iovec. */
246 msg.msg_name = (void *) from;
247 msg.msg_namelen = sizeof (struct sockaddr_in6);
248 msg.msg_iov = &iov;
249 msg.msg_iovlen = 1;
250 msg.msg_control = (void *) adata;
251 msg.msg_controllen = sizeof adata;
252 iov.iov_base = buf;
253 iov.iov_len = bufsize;
254
255 /* If recvmsg fail return minus value. */
256 ret = recvmsg (sock, &msg, 0);
257 if (ret < 0)
258 return ret;
259
ajsb99760a2005-01-04 16:24:43 +0000260 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000261 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
262 {
263 /* I want interface index which this packet comes from. */
264 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265 cmsgptr->cmsg_type == IPV6_PKTINFO)
266 {
267 struct in6_pktinfo *ptr;
268
269 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270 *ifindex = ptr->ipi6_ifindex;
271 dst = ptr->ipi6_addr;
272
273 if (*ifindex == 0)
274 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275 }
276
277 /* Incoming packet's multicast hop limit. */
278 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemminger5eb9d112009-12-10 15:52:33 +0300280 {
281 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282 *hoplimit = *phoplimit;
283 }
paul718e3742002-12-13 20:15:29 +0000284 }
285
286 /* Hoplimit check shold be done when destination address is
287 multicast address. */
288 if (! IN6_IS_ADDR_MULTICAST (&dst))
289 *hoplimit = -1;
290
291 return ret;
292}
293
294/* Dump rip packet */
295void
hasso7a1d5832004-10-08 06:32:23 +0000296ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000297{
298 caddr_t lim;
299 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000300 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000301
302 /* Set command string. */
303 if (packet->command == RIPNG_REQUEST)
304 command_str = "request";
305 else if (packet->command == RIPNG_RESPONSE)
306 command_str = "response";
307 else
308 command_str = "unknown";
309
310 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000311 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000312 sndrcv, command_str, packet->version, size);
313
314 /* Dump each routing table entry. */
315 rte = packet->rte;
316
317 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318 {
319 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000320 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000321 else
ajsc6106812004-12-08 19:51:16 +0000322 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000323 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000324 rte->metric, ntohs (rte->tag));
325 }
326}
327
328/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100329static void
paul718e3742002-12-13 20:15:29 +0000330ripng_nexthop_rte (struct rte *rte,
331 struct sockaddr_in6 *from,
332 struct ripng_nexthop *nexthop)
333{
334 char buf[INET6_BUFSIZ];
335
336 /* Logging before checking RTE. */
337 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000338 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000339 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000340
341 /* RFC2080 2.1.1 Next Hop:
342 The route tag and prefix length in the next hop RTE must be
343 set to zero on sending and ignored on receiption. */
344 if (ntohs (rte->tag) != 0)
345 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000346 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000347
348 if (rte->prefixlen != 0)
349 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000350 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000351
352 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353 next hop RTE indicates that the next hop address should be the
354 originator of the RIPng advertisement. An address specified as a
355 next hop must be a link-local address. */
356 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357 {
358 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359 memset (&nexthop->address, 0, sizeof (struct in6_addr));
360 return;
361 }
362
363 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364 {
365 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367 return;
368 }
369
370 /* The purpose of the next hop RTE is to eliminate packets being
371 routed through extra hops in the system. It is particularly useful
372 when RIPng is not being run on all of the routers on a network.
373 Note that next hop RTE is "advisory". That is, if the provided
374 information is ignored, a possibly sub-optimal, but absolutely
375 valid, route may be taken. If the received next hop address is not
376 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
377 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000378 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000379 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382 memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384 return;
385}
386
387/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100388static int
paul718e3742002-12-13 20:15:29 +0000389ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390{
paul1eb8ef22005-04-07 07:30:20 +0000391 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000392 struct connected *connected;
393 struct prefix *p;
394
paul1eb8ef22005-04-07 07:30:20 +0000395 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396 {
397 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000398
paul1eb8ef22005-04-07 07:30:20 +0000399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
paul718e3742002-12-13 20:15:29 +0000404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100408static int
paul718e3742002-12-13 20:15:29 +0000409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
paul718e3742002-12-13 20:15:29 +0000423 /* Unlock route_node. */
Feng Lue97c31a2015-05-22 11:39:53 +0200424 listnode_delete (rp->info, rinfo);
425 if (list_isempty ((struct list *)rp->info))
426 {
427 list_free (rp->info);
428 rp->info = NULL;
429 route_unlock_node (rp);
430 }
paul718e3742002-12-13 20:15:29 +0000431
432 /* Free RIPng routing information. */
433 ripng_info_free (rinfo);
434
435 return 0;
436}
437
Feng Lue97c31a2015-05-22 11:39:53 +0200438static void ripng_timeout_update (struct ripng_info *rinfo);
439
440/* Add new route to the ECMP list.
441 * RETURN: the new entry added in the list
442 */
443struct ripng_info *
444ripng_ecmp_add (struct ripng_info *rinfo_new)
445{
446 struct route_node *rp = rinfo_new->rp;
447 struct ripng_info *rinfo = NULL;
448 struct list *list = NULL;
449
450 if (rp->info == NULL)
451 rp->info = list_new ();
452 list = (struct list *)rp->info;
453
454 rinfo = ripng_info_new ();
455 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
456 listnode_add (list, rinfo);
457
458 if (ripng_route_rte (rinfo))
459 {
460 ripng_timeout_update (rinfo);
461 ripng_zebra_ipv6_add (rp);
462 }
463
464 ripng_aggregate_increment (rp, rinfo);
465
466 /* Set the route change flag on the first entry. */
467 rinfo = listgetdata (listhead (list));
468 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
469
470 /* Signal the output process to trigger an update. */
471 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
472
473 return rinfo;
474}
475
476/* Replace the ECMP list with the new route.
477 * RETURN: the new entry added in the list
478 */
479struct ripng_info *
480ripng_ecmp_replace (struct ripng_info *rinfo_new)
481{
482 struct route_node *rp = rinfo_new->rp;
483 struct list *list = (struct list *)rp->info;
484 struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
485 struct listnode *node = NULL, *nextnode = NULL;
486
487 if (list == NULL || listcount (list) == 0)
488 return ripng_ecmp_add (rinfo_new);
489
490 /* Get the first entry */
491 rinfo = listgetdata (listhead (list));
492
493 /* Learnt route replaced by a local one. Delete it from zebra. */
494 if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
495 if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
496 ripng_zebra_ipv6_delete (rp);
497
498 if (rinfo->metric != RIPNG_METRIC_INFINITY)
499 ripng_aggregate_decrement_list (rp, list);
500
501 /* Re-use the first entry, and delete the others. */
502 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
503 if (tmp_rinfo != rinfo)
504 {
505 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
506 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
507 list_delete_node (list, node);
508 ripng_info_free (tmp_rinfo);
509 }
510
511 RIPNG_TIMER_OFF (rinfo->t_timeout);
512 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
513 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
514
515 if (ripng_route_rte (rinfo))
516 {
517 ripng_timeout_update (rinfo);
518 /* The ADD message implies an update. */
519 ripng_zebra_ipv6_add (rp);
520 }
521
522 ripng_aggregate_increment (rp, rinfo);
523
524 /* Set the route change flag. */
525 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
526
527 /* Signal the output process to trigger an update. */
528 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
529
530 return rinfo;
531}
532
533/* Delete one route from the ECMP list.
534 * RETURN:
535 * null - the entry is freed, and other entries exist in the list
536 * the entry - the entry is the last one in the list; its metric is set
537 * to INFINITY, and the garbage collector is started for it
538 */
539struct ripng_info *
540ripng_ecmp_delete (struct ripng_info *rinfo)
541{
542 struct route_node *rp = rinfo->rp;
543 struct list *list = (struct list *)rp->info;
544
545 RIPNG_TIMER_OFF (rinfo->t_timeout);
546
547 if (rinfo->metric != RIPNG_METRIC_INFINITY)
548 ripng_aggregate_decrement (rp, rinfo);
549
550 if (listcount (list) > 1)
551 {
552 /* Some other ECMP entries still exist. Just delete this entry. */
553 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
554 listnode_delete (list, rinfo);
555 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
556 /* The ADD message implies the update. */
557 ripng_zebra_ipv6_add (rp);
558 ripng_info_free (rinfo);
559 rinfo = NULL;
560 }
561 else
562 {
563 assert (rinfo == listgetdata (listhead (list)));
564
565 /* This is the only entry left in the list. We must keep it in
566 * the list for garbage collection time, with INFINITY metric. */
567
568 rinfo->metric = RIPNG_METRIC_INFINITY;
569 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
570 ripng_garbage_collect, ripng->garbage_time);
571
572 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
573 ripng_zebra_ipv6_delete (rp);
574 }
575
576 /* Set the route change flag on the first entry. */
577 rinfo = listgetdata (listhead (list));
578 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
579
580 /* Signal the output process to trigger an update. */
581 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
582
583 return rinfo;
584}
585
paul718e3742002-12-13 20:15:29 +0000586/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100587static int
paul718e3742002-12-13 20:15:29 +0000588ripng_timeout (struct thread *t)
589{
Feng Lue97c31a2015-05-22 11:39:53 +0200590 ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
paul718e3742002-12-13 20:15:29 +0000591 return 0;
592}
593
Paul Jakma6ac29a52008-08-15 13:45:30 +0100594static void
paul718e3742002-12-13 20:15:29 +0000595ripng_timeout_update (struct ripng_info *rinfo)
596{
597 if (rinfo->metric != RIPNG_METRIC_INFINITY)
598 {
599 RIPNG_TIMER_OFF (rinfo->t_timeout);
600 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
601 }
602}
603
Paul Jakma6ac29a52008-08-15 13:45:30 +0100604static int
hassoa94434b2003-05-25 17:10:12 +0000605ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
606{
607 struct distribute *dist;
608 struct access_list *alist;
609 struct prefix_list *plist;
610
611 /* Input distribute-list filtering. */
612 if (ri->list[RIPNG_FILTER_IN])
613 {
614 if (access_list_apply (ri->list[RIPNG_FILTER_IN],
615 (struct prefix *) p) == FILTER_DENY)
616 {
617 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000618 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000619 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000620 return -1;
621 }
622 }
623 if (ri->prefix[RIPNG_FILTER_IN])
624 {
625 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
626 (struct prefix *) p) == PREFIX_DENY)
627 {
628 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000629 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000630 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000631 return -1;
632 }
633 }
634
635 /* All interface filter check. */
636 dist = distribute_lookup (NULL);
637 if (dist)
638 {
639 if (dist->list[DISTRIBUTE_IN])
640 {
641 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
642
643 if (alist)
644 {
645 if (access_list_apply (alist,
646 (struct prefix *) p) == FILTER_DENY)
647 {
648 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000649 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000650 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000651 return -1;
652 }
653 }
654 }
655 if (dist->prefix[DISTRIBUTE_IN])
656 {
657 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
658
659 if (plist)
660 {
661 if (prefix_list_apply (plist,
662 (struct prefix *) p) == PREFIX_DENY)
663 {
664 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000665 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000666 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000667 return -1;
668 }
669 }
670 }
671 }
672 return 0;
673}
674
Paul Jakma6ac29a52008-08-15 13:45:30 +0100675static int
hassoa94434b2003-05-25 17:10:12 +0000676ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
677{
678 struct distribute *dist;
679 struct access_list *alist;
680 struct prefix_list *plist;
681
682 if (ri->list[RIPNG_FILTER_OUT])
683 {
684 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
685 (struct prefix *) p) == FILTER_DENY)
686 {
687 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000688 zlog_debug ("%s/%d is filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000689 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000690 return -1;
691 }
692 }
693 if (ri->prefix[RIPNG_FILTER_OUT])
694 {
695 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
696 (struct prefix *) p) == PREFIX_DENY)
697 {
698 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000699 zlog_debug ("%s/%d is filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000700 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000701 return -1;
702 }
703 }
704
705 /* All interface filter check. */
706 dist = distribute_lookup (NULL);
707 if (dist)
708 {
709 if (dist->list[DISTRIBUTE_OUT])
710 {
711 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
712
713 if (alist)
714 {
715 if (access_list_apply (alist,
716 (struct prefix *) p) == FILTER_DENY)
717 {
718 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000719 zlog_debug ("%s/%d filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000720 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000721 return -1;
722 }
723 }
724 }
725 if (dist->prefix[DISTRIBUTE_OUT])
726 {
727 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
728
729 if (plist)
730 {
731 if (prefix_list_apply (plist,
732 (struct prefix *) p) == PREFIX_DENY)
733 {
734 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000735 zlog_debug ("%s/%d filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000736 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000737 return -1;
738 }
739 }
740 }
741 }
742 return 0;
743}
744
paul718e3742002-12-13 20:15:29 +0000745/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100746static void
paul718e3742002-12-13 20:15:29 +0000747ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
748 struct ripng_nexthop *ripng_nexthop,
749 struct interface *ifp)
750{
hassoa94434b2003-05-25 17:10:12 +0000751 int ret;
paul718e3742002-12-13 20:15:29 +0000752 struct prefix_ipv6 p;
753 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200754 struct ripng_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000755 struct ripng_interface *ri;
756 struct in6_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000757 int same = 0;
Feng Lue97c31a2015-05-22 11:39:53 +0200758 struct list *list = NULL;
759 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000760
761 /* Make prefix structure. */
762 memset (&p, 0, sizeof (struct prefix_ipv6));
763 p.family = AF_INET6;
764 /* p.prefix = rte->addr; */
765 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
766 p.prefixlen = rte->prefixlen;
767
768 /* Make sure mask is applied. */
769 /* XXX We have to check the prefix is valid or not before call
770 apply_mask_ipv6. */
771 apply_mask_ipv6 (&p);
772
773 /* Apply input filters. */
774 ri = ifp->info;
775
hassoa94434b2003-05-25 17:10:12 +0000776 ret = ripng_incoming_filter (&p, ri);
777 if (ret < 0)
778 return;
paul718e3742002-12-13 20:15:29 +0000779
Feng Lue97c31a2015-05-22 11:39:53 +0200780 memset (&newinfo, 0, sizeof (newinfo));
781 newinfo.type = ZEBRA_ROUTE_RIPNG;
782 newinfo.sub_type = RIPNG_ROUTE_RTE;
783 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
784 newinfo.nexthop = ripng_nexthop->address;
785 else
786 newinfo.nexthop = from->sin6_addr;
787 newinfo.from = from->sin6_addr;
788 newinfo.ifindex = ifp->ifindex;
789 newinfo.metric = rte->metric;
790 newinfo.metric_out = rte->metric; /* XXX */
791 newinfo.tag = ntohs (rte->tag); /* XXX */
792
paul718e3742002-12-13 20:15:29 +0000793 /* Modify entry. */
794 if (ri->routemap[RIPNG_FILTER_IN])
795 {
796 int ret;
paul718e3742002-12-13 20:15:29 +0000797
798 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
799 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
800
801 if (ret == RMAP_DENYMATCH)
802 {
803 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000804 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000805 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000806 return;
807 }
808
hassoa94434b2003-05-25 17:10:12 +0000809 /* Get back the object */
810 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
811 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
812 /* the nexthop get changed by the routemap */
813 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
814 ripng_nexthop->address = newinfo.nexthop;
815 else
816 ripng_nexthop->address = in6addr_any;
817 }
818 } else {
819 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
820 /* the nexthop get changed by the routemap */
821 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
822 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
823 ripng_nexthop->address = newinfo.nexthop;
824 }
825 }
826 }
827 rte->tag = htons(newinfo.tag_out); /* XXX */
828 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000829 }
830
hassoa94434b2003-05-25 17:10:12 +0000831 /* Once the entry has been validated, update the metric by
832 * adding the cost of the network on wich the message
833 * arrived. If the result is greater than infinity, use infinity
834 * (RFC2453 Sec. 3.9.2)
835 **/
836
837 /* Zebra ripngd can handle offset-list in. */
838 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
839
840 /* If offset-list does not modify the metric use interface's
841 * one. */
842 if (! ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000843 rte->metric += ifp->metric ? ifp->metric : 1;
hassoa94434b2003-05-25 17:10:12 +0000844
845 if (rte->metric > RIPNG_METRIC_INFINITY)
846 rte->metric = RIPNG_METRIC_INFINITY;
847
paul718e3742002-12-13 20:15:29 +0000848 /* Set nexthop pointer. */
849 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
850 nexthop = &ripng_nexthop->address;
851 else
852 nexthop = &from->sin6_addr;
853
854 /* Lookup RIPng routing table. */
855 rp = route_node_get (ripng->table, (struct prefix *) &p);
856
Feng Lue97c31a2015-05-22 11:39:53 +0200857 newinfo.rp = rp;
858 newinfo.nexthop = *nexthop;
859 newinfo.metric = rte->metric;
860 newinfo.tag = ntohs (rte->tag);
861
862 /* Check to see whether there is already RIPng route on the table. */
863 if ((list = rp->info) != NULL)
864 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
865 {
866 /* Need to compare with redistributed entry or local entry */
867 if (!ripng_route_rte (rinfo))
868 break;
869
870 if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
871 IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
872 break;
873
874 if (!listnextnode (node))
875 {
876 /* Not found in the list */
877
878 if (rte->metric > rinfo->metric)
879 {
880 /* New route has a greater metric. Discard it. */
881 route_unlock_node (rp);
882 return;
883 }
884
885 if (rte->metric < rinfo->metric)
886 /* New route has a smaller metric. Replace the ECMP list
887 * with the new one in below. */
888 break;
889
890 /* Metrics are same. Keep "rinfo" null and the new route
891 * is added in the ECMP list in below. */
892 }
893 }
894
hassoa94434b2003-05-25 17:10:12 +0000895 if (rinfo)
896 {
897 /* Redistributed route check. */
898 if (rinfo->type != ZEBRA_ROUTE_RIPNG
899 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200900 {
901 route_unlock_node (rp);
902 return;
903 }
hassoa94434b2003-05-25 17:10:12 +0000904
905 /* Local static route. */
906 if (rinfo->type == ZEBRA_ROUTE_RIPNG
907 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
908 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
909 && rinfo->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200910 {
911 route_unlock_node (rp);
912 return;
913 }
hassoa94434b2003-05-25 17:10:12 +0000914 }
915
Feng Lue97c31a2015-05-22 11:39:53 +0200916 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000917 {
918 /* Now, check to see whether there is already an explicit route
919 for the destination prefix. If there is no such route, add
920 this route to the routing table, unless the metric is
921 infinity (there is no point in adding a route which
922 unusable). */
923 if (rte->metric != RIPNG_METRIC_INFINITY)
Feng Lue97c31a2015-05-22 11:39:53 +0200924 ripng_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000925 }
926 else
927 {
paul718e3742002-12-13 20:15:29 +0000928 /* If there is an existing route, compare the next hop address
929 to the address of the router from which the datagram came.
930 If this datagram is from the same router as the existing
931 route, reinitialize the timeout. */
932 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
933 && (rinfo->ifindex == ifp->ifindex));
934
paul718e3742002-12-13 20:15:29 +0000935 /* Next, compare the metrics. If the datagram is from the same
936 router as the existing route, and the new metric is different
937 than the old one; or, if the new metric is lower than the old
938 one; do the following actions: */
939 if ((same && rinfo->metric != rte->metric) ||
940 rte->metric < rinfo->metric)
941 {
Feng Lue97c31a2015-05-22 11:39:53 +0200942 if (listcount (list) == 1)
943 {
944 if (newinfo.metric != RIPNG_METRIC_INFINITY)
945 ripng_ecmp_replace (&newinfo);
946 else
947 ripng_ecmp_delete (rinfo);
948 }
949 else
950 {
951 if (newinfo.metric < rinfo->metric)
952 ripng_ecmp_replace (&newinfo);
953 else /* newinfo.metric > rinfo->metric */
954 ripng_ecmp_delete (rinfo);
955 }
paul718e3742002-12-13 20:15:29 +0000956 }
Feng Lue97c31a2015-05-22 11:39:53 +0200957 else /* same & no change */
958 ripng_timeout_update (rinfo);
959
paul718e3742002-12-13 20:15:29 +0000960 /* Unlock tempolary lock of the route. */
961 route_unlock_node (rp);
962 }
963}
964
965/* Add redistributed route to RIPng table. */
966void
967ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +0000968 unsigned int ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000969{
970 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +0200971 struct ripng_info *rinfo = NULL, newinfo;
972 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +0000973
974 /* Redistribute route */
975 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
976 return;
977 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
978 return;
979
980 rp = route_node_get (ripng->table, (struct prefix *) p);
paul718e3742002-12-13 20:15:29 +0000981
Feng Lue97c31a2015-05-22 11:39:53 +0200982 memset (&newinfo, 0, sizeof (struct ripng_info));
983 newinfo.type = type;
984 newinfo.sub_type = sub_type;
985 newinfo.ifindex = ifindex;
986 newinfo.metric = 1;
987 newinfo.rp = rp;
988 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
989 newinfo.nexthop = *nexthop;
990
991 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +0000992 {
Feng Lue97c31a2015-05-22 11:39:53 +0200993 rinfo = listgetdata (listhead (list));
994
hassoa94434b2003-05-25 17:10:12 +0000995 if (rinfo->type == ZEBRA_ROUTE_CONNECT
996 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
997 && rinfo->metric != RIPNG_METRIC_INFINITY) {
998 route_unlock_node (rp);
999 return;
1000 }
1001
1002 /* Manually configured RIPng route check.
1003 * They have the precedence on all the other entries.
1004 **/
1005 if (rinfo->type == ZEBRA_ROUTE_RIPNG
1006 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
1007 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
1008 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
1009 (sub_type != RIPNG_ROUTE_DEFAULT))) {
1010 route_unlock_node (rp);
1011 return;
1012 }
1013 }
hassoa94434b2003-05-25 17:10:12 +00001014
Feng Lue97c31a2015-05-22 11:39:53 +02001015 rinfo = ripng_ecmp_replace (&newinfo);
paul718e3742002-12-13 20:15:29 +00001016 route_unlock_node (rp);
1017 }
Feng Lue97c31a2015-05-22 11:39:53 +02001018 else
1019 rinfo = ripng_ecmp_add (&newinfo);
hassoa94434b2003-05-25 17:10:12 +00001020
1021 if (IS_RIPNG_DEBUG_EVENT) {
1022 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +00001023 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001024 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001025 ifindex2ifname(ifindex));
1026 else
ajsc6106812004-12-08 19:51:16 +00001027 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001028 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001029 ifindex2ifname(ifindex));
1030 }
1031
1032 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001033}
1034
1035/* Delete redistributed route to RIPng table. */
1036void
1037ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1038 unsigned int ifindex)
1039{
1040 struct route_node *rp;
1041 struct ripng_info *rinfo;
1042
1043 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1044 return;
1045 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1046 return;
1047
1048 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1049
1050 if (rp)
1051 {
Feng Lue97c31a2015-05-22 11:39:53 +02001052 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001053
Feng Lue97c31a2015-05-22 11:39:53 +02001054 if (list != NULL && listcount (list) != 0)
1055 {
1056 rinfo = listgetdata (listhead (list));
1057 if (rinfo != NULL
1058 && rinfo->type == type
1059 && rinfo->sub_type == sub_type
1060 && rinfo->ifindex == ifindex)
1061 {
1062 /* Perform poisoned reverse. */
1063 rinfo->metric = RIPNG_METRIC_INFINITY;
1064 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1065 ripng_garbage_collect, ripng->garbage_time);
1066 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001067
Feng Lue97c31a2015-05-22 11:39:53 +02001068 /* Aggregate count decrement. */
1069 ripng_aggregate_decrement (rp, rinfo);
hassoa94434b2003-05-25 17:10:12 +00001070
Feng Lue97c31a2015-05-22 11:39:53 +02001071 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001072
Feng Lue97c31a2015-05-22 11:39:53 +02001073 if (IS_RIPNG_DEBUG_EVENT)
1074 zlog_debug ("Poisone %s/%d on the interface %s with an "
1075 "infinity metric [delete]",
1076 inet6_ntoa (p->prefix), p->prefixlen,
1077 ifindex2ifname (ifindex));
1078
1079 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1080 }
1081 }
1082 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001083 }
1084}
1085
1086/* Withdraw redistributed route. */
1087void
1088ripng_redistribute_withdraw (int type)
1089{
1090 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001091 struct ripng_info *rinfo = NULL;
1092 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001093
hassoa94434b2003-05-25 17:10:12 +00001094 if (!ripng)
1095 return;
1096
paul718e3742002-12-13 20:15:29 +00001097 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001098 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00001099 {
Feng Lue97c31a2015-05-22 11:39:53 +02001100 rinfo = listgetdata (listhead (list));
hassoa94434b2003-05-25 17:10:12 +00001101 if ((rinfo->type == type)
1102 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001103 {
hassoa94434b2003-05-25 17:10:12 +00001104 /* Perform poisoned reverse. */
1105 rinfo->metric = RIPNG_METRIC_INFINITY;
1106 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1107 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001108 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001109
hassoa94434b2003-05-25 17:10:12 +00001110 /* Aggregate count decrement. */
1111 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001112
hassoa94434b2003-05-25 17:10:12 +00001113 rinfo->flags |= RIPNG_RTF_CHANGED;
1114
1115 if (IS_RIPNG_DEBUG_EVENT) {
1116 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1117
ajsc6106812004-12-08 19:51:16 +00001118 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001119 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001120 ifindex2ifname(rinfo->ifindex));
1121 }
1122
1123 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001124 }
1125 }
1126}
1127
1128/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001129static void
paul718e3742002-12-13 20:15:29 +00001130ripng_response_process (struct ripng_packet *packet, int size,
1131 struct sockaddr_in6 *from, struct interface *ifp,
1132 int hoplimit)
1133{
1134 caddr_t lim;
1135 struct rte *rte;
1136 struct ripng_nexthop nexthop;
1137
1138 /* RFC2080 2.4.2 Response Messages:
1139 The Response must be ignored if it is not from the RIPng port. */
1140 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1141 {
1142 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001143 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001144 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001145 return;
1146 }
1147
1148 /* The datagram's IPv6 source address should be checked to see
1149 whether the datagram is from a valid neighbor; the source of the
1150 datagram must be a link-local address. */
1151 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1152 {
1153 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001154 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001155 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001156 return;
1157 }
1158
1159 /* It is also worth checking to see whether the response is from one
1160 of the router's own addresses. Interfaces on broadcast networks
1161 may receive copies of their own multicasts immediately. If a
1162 router processes its own output as new input, confusion is likely,
1163 and such datagrams must be ignored. */
1164 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1165 {
1166 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001167 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001168 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001169 return;
1170 }
1171
1172 /* As an additional check, periodic advertisements must have their
1173 hop counts set to 255, and inbound, multicast packets sent from the
1174 RIPng port (i.e. periodic advertisement or triggered update
1175 packets) must be examined to ensure that the hop count is 255. */
1176 if (hoplimit >= 0 && hoplimit != 255)
1177 {
1178 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001179 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001180 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001181 return;
1182 }
1183
hassoa94434b2003-05-25 17:10:12 +00001184 /* Update RIPng peer. */
1185 ripng_peer_update (from, packet->version);
1186
paul718e3742002-12-13 20:15:29 +00001187 /* Reset nexthop. */
1188 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1189 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1190
1191 /* Set RTE pointer. */
1192 rte = packet->rte;
1193
1194 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1195 {
1196 /* First of all, we have to check this RTE is next hop RTE or
1197 not. Next hop RTE is completely different with normal RTE so
1198 we need special treatment. */
1199 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1200 {
1201 ripng_nexthop_rte (rte, from, &nexthop);
1202 continue;
1203 }
1204
1205 /* RTE information validation. */
1206
1207 /* - is the destination prefix valid (e.g., not a multicast
1208 prefix and not a link-local address) A link-local address
1209 should never be present in an RTE. */
1210 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1211 {
1212 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001213 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001214 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001215 continue;
1216 }
1217 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1218 {
1219 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001220 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001221 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001222 continue;
1223 }
1224 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1225 {
1226 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001227 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001228 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001229 continue;
1230 }
1231
1232 /* - is the prefix length valid (i.e., between 0 and 128,
1233 inclusive) */
1234 if (rte->prefixlen > 128)
1235 {
1236 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001237 inet6_ntoa (rte->addr), rte->prefixlen,
1238 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001239 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001240 continue;
1241 }
1242
1243 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1244 if (! (rte->metric >= 1 && rte->metric <= 16))
1245 {
1246 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001247 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001248 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001249 continue;
1250 }
1251
hassoa94434b2003-05-25 17:10:12 +00001252 /* Vincent: XXX Should we compute the direclty reachable nexthop
1253 * for our RIPng network ?
1254 **/
paul718e3742002-12-13 20:15:29 +00001255
1256 /* Routing table updates. */
1257 ripng_route_process (rte, from, &nexthop, ifp);
1258 }
1259}
1260
1261/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001262static void
paul718e3742002-12-13 20:15:29 +00001263ripng_request_process (struct ripng_packet *packet,int size,
1264 struct sockaddr_in6 *from, struct interface *ifp)
1265{
1266 caddr_t lim;
1267 struct rte *rte;
1268 struct prefix_ipv6 p;
1269 struct route_node *rp;
1270 struct ripng_info *rinfo;
1271 struct ripng_interface *ri;
1272
hassoa94434b2003-05-25 17:10:12 +00001273 /* Does not reponse to the requests on the loopback interfaces */
1274 if (if_is_loopback (ifp))
1275 return;
1276
paul718e3742002-12-13 20:15:29 +00001277 /* Check RIPng process is enabled on this interface. */
1278 ri = ifp->info;
1279 if (! ri->running)
1280 return;
1281
1282 /* When passive interface is specified, suppress responses */
1283 if (ri->passive)
1284 return;
1285
hassoa94434b2003-05-25 17:10:12 +00001286 /* RIPng peer update. */
1287 ripng_peer_update (from, packet->version);
1288
paul718e3742002-12-13 20:15:29 +00001289 lim = ((caddr_t) packet) + size;
1290 rte = packet->rte;
1291
1292 /* The Request is processed entry by entry. If there are no
1293 entries, no response is given. */
1294 if (lim == (caddr_t) rte)
1295 return;
1296
1297 /* There is one special case. If there is exactly one entry in the
1298 request, and it has a destination prefix of zero, a prefix length
1299 of zero, and a metric of infinity (i.e., 16), then this is a
1300 request to send the entire routing table. In that case, a call
1301 is made to the output process to send the routing table to the
1302 requesting address/port. */
1303 if (lim == ((caddr_t) (rte + 1)) &&
1304 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1305 rte->prefixlen == 0 &&
1306 rte->metric == RIPNG_METRIC_INFINITY)
1307 {
1308 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001309 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001310 }
1311 else
1312 {
1313 /* Except for this special case, processing is quite simple.
1314 Examine the list of RTEs in the Request one by one. For each
1315 entry, look up the destination in the router's routing
1316 database and, if there is a route, put that route's metric in
1317 the metric field of the RTE. If there is no explicit route
1318 to the specified destination, put infinity in the metric
1319 field. Once all the entries have been filled in, change the
1320 command from Request to Response and send the datagram back
1321 to the requestor. */
1322 memset (&p, 0, sizeof (struct prefix_ipv6));
1323 p.family = AF_INET6;
1324
1325 for (; ((caddr_t) rte) < lim; rte++)
1326 {
1327 p.prefix = rte->addr;
1328 p.prefixlen = rte->prefixlen;
1329 apply_mask_ipv6 (&p);
1330
1331 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1332
1333 if (rp)
1334 {
Feng Lue97c31a2015-05-22 11:39:53 +02001335 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001336 rte->metric = rinfo->metric;
1337 route_unlock_node (rp);
1338 }
1339 else
1340 rte->metric = RIPNG_METRIC_INFINITY;
1341 }
1342 packet->command = RIPNG_RESPONSE;
1343
1344 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1345 }
1346}
1347
1348/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001349static int
paul718e3742002-12-13 20:15:29 +00001350ripng_read (struct thread *thread)
1351{
1352 int len;
1353 int sock;
1354 struct sockaddr_in6 from;
1355 struct ripng_packet *packet;
David Lamparter6ed810d2015-04-21 10:13:07 +02001356 unsigned int ifindex = 0;
paul718e3742002-12-13 20:15:29 +00001357 struct interface *ifp;
1358 int hoplimit = -1;
1359
1360 /* Check ripng is active and alive. */
1361 assert (ripng != NULL);
1362 assert (ripng->sock >= 0);
1363
1364 /* Fetch thread data and set read pointer to empty for event
1365 managing. `sock' sould be same as ripng->sock. */
1366 sock = THREAD_FD (thread);
1367 ripng->t_read = NULL;
1368
1369 /* Add myself to the next event. */
1370 ripng_event (RIPNG_READ, sock);
1371
1372 /* Read RIPng packet. */
1373 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1374 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1375 &hoplimit);
1376 if (len < 0)
1377 {
ajs6099b3b2004-11-20 02:06:59 +00001378 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001379 return len;
1380 }
1381
1382 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1383 (4)) must be multiple size of one RTE size (20). */
1384 if (((len - 4) % 20) != 0)
1385 {
1386 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001387 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001388 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001389 return 0;
1390 }
1391
1392 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1393 ifp = if_lookup_by_index (ifindex);
1394
1395 /* RIPng packet received. */
1396 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001397 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001398 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001399 ifp ? ifp->name : "unknown");
1400
1401 /* Logging before packet checking. */
1402 if (IS_RIPNG_DEBUG_RECV)
1403 ripng_packet_dump (packet, len, "RECV");
1404
1405 /* Packet comes from unknown interface. */
1406 if (ifp == NULL)
1407 {
1408 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1409 return 0;
1410 }
1411
1412 /* Packet version mismatch checking. */
1413 if (packet->version != ripng->version)
1414 {
1415 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1416 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001417 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001418 return 0;
1419 }
1420
1421 /* Process RIPng packet. */
1422 switch (packet->command)
1423 {
1424 case RIPNG_REQUEST:
1425 ripng_request_process (packet, len, &from, ifp);
1426 break;
1427 case RIPNG_RESPONSE:
1428 ripng_response_process (packet, len, &from, ifp, hoplimit);
1429 break;
1430 default:
1431 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001432 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001433 break;
1434 }
1435 return 0;
1436}
1437
1438/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001439static void
1440ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001441{
1442 struct route_node *rp;
Feng Lue97c31a2015-05-22 11:39:53 +02001443 struct ripng_info *rinfo = NULL;
1444 struct list *list = NULL;
1445 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001446
1447 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
Feng Lue97c31a2015-05-22 11:39:53 +02001448 if ((list = rp->info) != NULL)
1449 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1450 {
1451 UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1452 /* This flag can be set only on the first entry. */
1453 break;
1454 }
paul718e3742002-12-13 20:15:29 +00001455}
1456
1457/* Regular update of RIPng route. Send all routing formation to RIPng
1458 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001459static int
paul718e3742002-12-13 20:15:29 +00001460ripng_update (struct thread *t)
1461{
hasso52dc7ee2004-09-23 19:18:23 +00001462 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001463 struct interface *ifp;
1464 struct ripng_interface *ri;
1465
1466 /* Clear update timer thread. */
1467 ripng->t_update = NULL;
1468
1469 /* Logging update event. */
1470 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001471 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001472
1473 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001474 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001475 {
paul718e3742002-12-13 20:15:29 +00001476 ri = ifp->info;
1477
1478 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1479 continue;
1480
1481 if (! ri->running)
1482 continue;
1483
1484 /* When passive interface is specified, suppress announce to the
1485 interface. */
1486 if (ri->passive)
1487 continue;
1488
1489#if RIPNG_ADVANCED
1490 if (ri->ri_send == RIPNG_SEND_OFF)
1491 {
1492 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001493 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001494 "[Event] RIPng send to if %d is suppressed by config",
1495 ifp->ifindex);
1496 continue;
1497 }
1498#endif /* RIPNG_ADVANCED */
1499
hassoa94434b2003-05-25 17:10:12 +00001500 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001501 }
1502
1503 /* Triggered updates may be suppressed if a regular update is due by
1504 the time the triggered update would be sent. */
1505 if (ripng->t_triggered_interval)
1506 {
1507 thread_cancel (ripng->t_triggered_interval);
1508 ripng->t_triggered_interval = NULL;
1509 }
1510 ripng->trigger = 0;
1511
1512 /* Reset flush event. */
1513 ripng_event (RIPNG_UPDATE_EVENT, 0);
1514
1515 return 0;
1516}
1517
1518/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001519static int
paul718e3742002-12-13 20:15:29 +00001520ripng_triggered_interval (struct thread *t)
1521{
1522 ripng->t_triggered_interval = NULL;
1523
1524 if (ripng->trigger)
1525 {
1526 ripng->trigger = 0;
1527 ripng_triggered_update (t);
1528 }
1529 return 0;
1530}
1531
1532/* Execute triggered update. */
1533int
1534ripng_triggered_update (struct thread *t)
1535{
hasso52dc7ee2004-09-23 19:18:23 +00001536 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001537 struct interface *ifp;
1538 struct ripng_interface *ri;
1539 int interval;
1540
1541 ripng->t_triggered_update = NULL;
1542
1543 /* Cancel interval timer. */
1544 if (ripng->t_triggered_interval)
1545 {
1546 thread_cancel (ripng->t_triggered_interval);
1547 ripng->t_triggered_interval = NULL;
1548 }
1549 ripng->trigger = 0;
1550
1551 /* Logging triggered update. */
1552 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001553 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001554
1555 /* Split Horizon processing is done when generating triggered
1556 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001557 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001558 {
paul718e3742002-12-13 20:15:29 +00001559 ri = ifp->info;
1560
1561 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1562 continue;
1563
1564 if (! ri->running)
1565 continue;
1566
1567 /* When passive interface is specified, suppress announce to the
1568 interface. */
1569 if (ri->passive)
1570 continue;
1571
hassoa94434b2003-05-25 17:10:12 +00001572 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001573 }
1574
1575 /* Once all of the triggered updates have been generated, the route
1576 change flags should be cleared. */
1577 ripng_clear_changed_flag ();
1578
1579 /* After a triggered update is sent, a timer should be set for a
1580 random interval between 1 and 5 seconds. If other changes that
1581 would trigger updates occur before the timer expires, a single
1582 update is triggered when the timer expires. */
1583 interval = (random () % 5) + 1;
1584
1585 ripng->t_triggered_interval =
1586 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1587
1588 return 0;
1589}
1590
1591/* Write routing table entry to the stream and return next index of
1592 the routing table entry in the stream. */
1593int
1594ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001595 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001596{
1597 /* RIPng packet header. */
1598 if (num == 0)
1599 {
1600 stream_putc (s, RIPNG_RESPONSE);
1601 stream_putc (s, RIPNG_V1);
1602 stream_putw (s, 0);
1603 }
1604
1605 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001606 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001607 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001608 else
hassoc9e52be2004-09-26 16:09:34 +00001609 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001610 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001611 if (p)
1612 stream_putc (s, p->prefixlen);
1613 else
1614 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001615 stream_putc (s, metric);
1616
1617 return ++num;
1618}
1619
1620/* Send RESPONSE message to specified destination. */
1621void
1622ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001623 int route_type)
paul718e3742002-12-13 20:15:29 +00001624{
1625 int ret;
paul718e3742002-12-13 20:15:29 +00001626 struct route_node *rp;
1627 struct ripng_info *rinfo;
1628 struct ripng_interface *ri;
1629 struct ripng_aggregate *aggregate;
1630 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001631 struct list * ripng_rte_list;
Feng Lue97c31a2015-05-22 11:39:53 +02001632 struct list *list = NULL;
1633 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00001634
hassoa94434b2003-05-25 17:10:12 +00001635 if (IS_RIPNG_DEBUG_EVENT) {
1636 if (to)
ajsc6106812004-12-08 19:51:16 +00001637 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001638 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001639 else
ajsc6106812004-12-08 19:51:16 +00001640 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001641 }
paul718e3742002-12-13 20:15:29 +00001642
paul718e3742002-12-13 20:15:29 +00001643 /* Get RIPng interface. */
1644 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001645
1646 ripng_rte_list = ripng_rte_new();
1647
paul718e3742002-12-13 20:15:29 +00001648 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1649 {
Feng Lue97c31a2015-05-22 11:39:53 +02001650 if ((list = rp->info) != NULL &&
1651 (rinfo = listgetdata (listhead (list))) != NULL &&
1652 rinfo->suppress == 0)
paul718e3742002-12-13 20:15:29 +00001653 {
hassoa94434b2003-05-25 17:10:12 +00001654 /* If no route-map are applied, the RTE will be these following
1655 * informations.
1656 */
paul718e3742002-12-13 20:15:29 +00001657 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001658 rinfo->metric_out = rinfo->metric;
1659 rinfo->tag_out = rinfo->tag;
1660 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1661 /* In order to avoid some local loops,
1662 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1663 * otherwise set it to 0. The nexthop should not be propagated
1664 * beyond the local broadcast/multicast area in order
1665 * to avoid an IGP multi-level recursive look-up.
1666 */
1667 if (rinfo->ifindex == ifp->ifindex)
1668 rinfo->nexthop_out = rinfo->nexthop;
1669
1670 /* Apply output filters. */
1671 ret = ripng_outgoing_filter (p, ri);
1672 if (ret < 0)
1673 continue;
paul718e3742002-12-13 20:15:29 +00001674
1675 /* Changed route only output. */
1676 if (route_type == ripng_changed_route &&
1677 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1678 continue;
1679
1680 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001681 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1682 {
1683 /* We perform split horizon for RIPng routes. */
Feng Lue97c31a2015-05-22 11:39:53 +02001684 int suppress = 0;
1685 struct ripng_info *tmp_rinfo = NULL;
1686
1687 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1688 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1689 tmp_rinfo->ifindex == ifp->ifindex)
1690 {
1691 suppress = 1;
1692 break;
1693 }
1694 if (suppress)
hassoa94434b2003-05-25 17:10:12 +00001695 continue;
1696 }
paul718e3742002-12-13 20:15:29 +00001697
1698 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001699 rinfo->metric_set = 0;
1700 /* nexthop_out,
1701 * metric_out
1702 * and tag_out are already initialized.
1703 */
paul718e3742002-12-13 20:15:29 +00001704
hassoa94434b2003-05-25 17:10:12 +00001705 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001706 if (ri->routemap[RIPNG_FILTER_OUT])
1707 {
1708 int ret;
paul718e3742002-12-13 20:15:29 +00001709
1710 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1711 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001712 rinfo);
paul718e3742002-12-13 20:15:29 +00001713
1714 if (ret == RMAP_DENYMATCH)
1715 {
1716 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001717 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001718 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001719 continue;
paul718e3742002-12-13 20:15:29 +00001720 }
1721
paul718e3742002-12-13 20:15:29 +00001722 }
1723
hassoa94434b2003-05-25 17:10:12 +00001724 /* Redistribute route-map. */
1725 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001726 {
hassoa94434b2003-05-25 17:10:12 +00001727 int ret;
1728
1729 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1730 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001731 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001732
1733 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001734 {
hassoa94434b2003-05-25 17:10:12 +00001735 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001736 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001737 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001738 continue;
paul718e3742002-12-13 20:15:29 +00001739 }
hassoa94434b2003-05-25 17:10:12 +00001740 }
paul718e3742002-12-13 20:15:29 +00001741
hassoa94434b2003-05-25 17:10:12 +00001742 /* When the route-map does not set metric. */
1743 if (! rinfo->metric_set)
1744 {
1745 /* If the redistribute metric is set. */
1746 if (ripng->route_map[rinfo->type].metric_config
1747 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001748 {
hassoa94434b2003-05-25 17:10:12 +00001749 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1750 }
1751 else
1752 {
1753 /* If the route is not connected or localy generated
1754 one, use default-metric value */
1755 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1756 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001757 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001758 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001759 }
1760 }
1761
hassoa94434b2003-05-25 17:10:12 +00001762 /* Apply offset-list */
1763 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1764 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001765
hassoa94434b2003-05-25 17:10:12 +00001766 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1767 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1768
1769 /* Perform split-horizon with poisoned reverse
1770 * for RIPng routes.
1771 **/
1772 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
Feng Lue97c31a2015-05-22 11:39:53 +02001773 struct ripng_info *tmp_rinfo = NULL;
1774
1775 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1776 if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1777 tmp_rinfo->ifindex == ifp->ifindex)
1778 rinfo->metric_out = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +00001779 }
1780
1781 /* Add RTE to the list */
1782 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001783 }
hassoa94434b2003-05-25 17:10:12 +00001784
1785 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001786 if ((aggregate = rp->aggregate) != NULL &&
1787 aggregate->count > 0 &&
1788 aggregate->suppress == 0)
1789 {
hassoa94434b2003-05-25 17:10:12 +00001790 /* If no route-map are applied, the RTE will be these following
1791 * informations.
1792 */
paul718e3742002-12-13 20:15:29 +00001793 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001794 aggregate->metric_set = 0;
1795 aggregate->metric_out = aggregate->metric;
1796 aggregate->tag_out = aggregate->tag;
1797 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001798
1799 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001800 ret = ripng_outgoing_filter (p, ri);
1801 if (ret < 0)
1802 continue;
paul718e3742002-12-13 20:15:29 +00001803
hassoa94434b2003-05-25 17:10:12 +00001804 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001805 if (ri->routemap[RIPNG_FILTER_OUT])
1806 {
1807 int ret;
1808 struct ripng_info newinfo;
1809
hassoa94434b2003-05-25 17:10:12 +00001810 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001811 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001812 /* the nexthop is :: */
1813 newinfo.metric = aggregate->metric;
1814 newinfo.metric_out = aggregate->metric_out;
1815 newinfo.tag = aggregate->tag;
1816 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001817
1818 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1819 (struct prefix *) p, RMAP_RIPNG,
1820 &newinfo);
1821
1822 if (ret == RMAP_DENYMATCH)
1823 {
1824 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001825 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001826 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001827 continue;
paul718e3742002-12-13 20:15:29 +00001828 }
1829
hassoa94434b2003-05-25 17:10:12 +00001830 aggregate->metric_out = newinfo.metric_out;
1831 aggregate->tag_out = newinfo.tag_out;
1832 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1833 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001834 }
1835
hassoa94434b2003-05-25 17:10:12 +00001836 /* There is no redistribute routemap for the aggregated RTE */
1837
paul718e3742002-12-13 20:15:29 +00001838 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001839 /* XXX, vincent, in order to increase time convergence,
1840 * it should be announced if a child has changed.
1841 */
paul718e3742002-12-13 20:15:29 +00001842 if (route_type == ripng_changed_route)
1843 continue;
1844
hassoa94434b2003-05-25 17:10:12 +00001845 /* Apply offset-list */
1846 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1847 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001848
hassoa94434b2003-05-25 17:10:12 +00001849 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1850 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1851
1852 /* Add RTE to the list */
1853 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001854 }
1855
1856 }
paul718e3742002-12-13 20:15:29 +00001857
hassoa94434b2003-05-25 17:10:12 +00001858 /* Flush the list */
1859 ripng_rte_send(ripng_rte_list, ifp, to);
1860 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001861}
1862
1863/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001864static int
1865ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001866{
1867 /* ripng should be NULL. */
1868 assert (ripng == NULL);
1869
1870 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001871 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001872
1873 /* Default version and timer values. */
1874 ripng->version = RIPNG_V1;
1875 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1876 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1877 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1878 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1879
1880 /* Make buffer. */
1881 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1882 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1883
1884 /* Initialize RIPng routig table. */
1885 ripng->table = route_table_init ();
1886 ripng->route = route_table_init ();
1887 ripng->aggregate = route_table_init ();
1888
1889 /* Make socket. */
1890 ripng->sock = ripng_make_socket ();
1891 if (ripng->sock < 0)
1892 return ripng->sock;
1893
1894 /* Threads. */
1895 ripng_event (RIPNG_READ, ripng->sock);
1896 ripng_event (RIPNG_UPDATE_EVENT, 1);
1897
1898 return 0;
1899}
1900
hassoa94434b2003-05-25 17:10:12 +00001901/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001902int
1903ripng_request (struct interface *ifp)
1904{
1905 struct rte *rte;
1906 struct ripng_packet ripng_packet;
1907
hassoa94434b2003-05-25 17:10:12 +00001908 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1909 if (if_is_loopback(ifp))
1910 return 0;
1911
1912 /* If interface is down, don't send RIP packet. */
1913 if (! if_is_up (ifp))
1914 return 0;
1915
paul718e3742002-12-13 20:15:29 +00001916 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001917 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001918
1919 memset (&ripng_packet, 0, sizeof (ripng_packet));
1920 ripng_packet.command = RIPNG_REQUEST;
1921 ripng_packet.version = RIPNG_V1;
1922 rte = ripng_packet.rte;
1923 rte->metric = RIPNG_METRIC_INFINITY;
1924
1925 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1926 NULL, ifp);
1927}
1928
David Lamparter6b0655a2014-06-04 06:53:35 +02001929
Paul Jakma6ac29a52008-08-15 13:45:30 +01001930static int
paul718e3742002-12-13 20:15:29 +00001931ripng_update_jitter (int time)
1932{
1933 return ((rand () % (time + 1)) - (time / 2));
1934}
1935
1936void
1937ripng_event (enum ripng_event event, int sock)
1938{
paul718e3742002-12-13 20:15:29 +00001939 int jitter = 0;
1940
1941 switch (event)
1942 {
1943 case RIPNG_READ:
1944 if (!ripng->t_read)
1945 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1946 break;
1947 case RIPNG_UPDATE_EVENT:
1948 if (ripng->t_update)
1949 {
1950 thread_cancel (ripng->t_update);
1951 ripng->t_update = NULL;
1952 }
1953 /* Update timer jitter. */
1954 jitter = ripng_update_jitter (ripng->update_time);
1955
1956 ripng->t_update =
1957 thread_add_timer (master, ripng_update, NULL,
1958 sock ? 2 : ripng->update_time + jitter);
1959 break;
1960 case RIPNG_TRIGGERED_UPDATE:
1961 if (ripng->t_triggered_interval)
1962 ripng->trigger = 1;
1963 else if (! ripng->t_triggered_update)
1964 ripng->t_triggered_update =
1965 thread_add_event (master, ripng_triggered_update, NULL, 0);
1966 break;
1967 default:
1968 break;
1969 }
1970}
David Lamparter6b0655a2014-06-04 06:53:35 +02001971
paul718e3742002-12-13 20:15:29 +00001972
paul718e3742002-12-13 20:15:29 +00001973/* Print out routes update time. */
1974static void
1975ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1976{
paul718e3742002-12-13 20:15:29 +00001977 time_t clock;
1978 struct tm *tm;
1979#define TIME_BUF 25
1980 char timebuf [TIME_BUF];
1981 struct thread *thread;
1982
paul718e3742002-12-13 20:15:29 +00001983 if ((thread = rinfo->t_timeout) != NULL)
1984 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001985 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001986 tm = gmtime (&clock);
1987 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1988 vty_out (vty, "%5s", timebuf);
1989 }
1990 else if ((thread = rinfo->t_garbage_collect) != NULL)
1991 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001992 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001993 tm = gmtime (&clock);
1994 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1995 vty_out (vty, "%5s", timebuf);
1996 }
1997}
1998
Paul Jakma6ac29a52008-08-15 13:45:30 +01001999static char *
hassoa94434b2003-05-25 17:10:12 +00002000ripng_route_subtype_print (struct ripng_info *rinfo)
2001{
2002 static char str[3];
2003 memset(str, 0, 3);
2004
2005 if (rinfo->suppress)
2006 strcat(str, "S");
2007
2008 switch (rinfo->sub_type)
2009 {
2010 case RIPNG_ROUTE_RTE:
2011 strcat(str, "n");
2012 break;
2013 case RIPNG_ROUTE_STATIC:
2014 strcat(str, "s");
2015 break;
2016 case RIPNG_ROUTE_DEFAULT:
2017 strcat(str, "d");
2018 break;
2019 case RIPNG_ROUTE_REDISTRIBUTE:
2020 strcat(str, "r");
2021 break;
2022 case RIPNG_ROUTE_INTERFACE:
2023 strcat(str, "i");
2024 break;
2025 default:
2026 strcat(str, "?");
2027 break;
2028 }
2029
2030 return str;
2031}
2032
paul718e3742002-12-13 20:15:29 +00002033DEFUN (show_ipv6_ripng,
2034 show_ipv6_ripng_cmd,
2035 "show ipv6 ripng",
2036 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002037 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002038 "Show RIPng routes\n")
2039{
2040 struct route_node *rp;
2041 struct ripng_info *rinfo;
2042 struct ripng_aggregate *aggregate;
2043 struct prefix_ipv6 *p;
Feng Lue97c31a2015-05-22 11:39:53 +02002044 struct list *list = NULL;
2045 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002046 int len;
2047
hassoa94434b2003-05-25 17:10:12 +00002048 if (! ripng)
2049 return CMD_SUCCESS;
2050
paul718e3742002-12-13 20:15:29 +00002051 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00002052 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2053 "Sub-codes:%s"
2054 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2055 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2056 " Network Next Hop Via Metric Tag Time%s",
2057 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002058 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2059
2060 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2061 {
2062 if ((aggregate = rp->aggregate) != NULL)
2063 {
2064 p = (struct prefix_ipv6 *) &rp->p;
2065
2066#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002067 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002068 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002069 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002070#else
hassoa94434b2003-05-25 17:10:12 +00002071 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002072 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002073#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002074 vty_out (vty, "%s", VTY_NEWLINE);
2075 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002076
hassoa94434b2003-05-25 17:10:12 +00002077 vty_out (vty, "%*s", 28, " ");
2078 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002079 aggregate->tag,
2080 VTY_NEWLINE);
2081 }
2082
Feng Lue97c31a2015-05-22 11:39:53 +02002083 if ((list = rp->info) != NULL)
2084 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00002085 {
2086 p = (struct prefix_ipv6 *) &rp->p;
2087
2088#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002089 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2090 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002091 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002092 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002093 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002094#else
ajsf52d13c2005-10-01 17:38:06 +00002095 len = vty_out (vty, "%c(%s) %s/%d ",
2096 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002097 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002098 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002099#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002100 vty_out (vty, "%s", VTY_NEWLINE);
2101 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002102 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002103
hassoa94434b2003-05-25 17:10:12 +00002104 len = 28 - len;
2105 if (len > 0)
2106 len = vty_out (vty, "%*s", len, " ");
2107
2108 /* from */
2109 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2110 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2111 {
2112 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2113 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2114 {
2115 len = vty_out (vty, "kill");
2116 } else
2117 len = vty_out (vty, "self");
2118
2119 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002120 if (len > 0)
2121 vty_out (vty, "%*s", len, " ");
2122
hassoa94434b2003-05-25 17:10:12 +00002123 vty_out (vty, " %2d %3d ",
2124 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002125
hassoa94434b2003-05-25 17:10:12 +00002126 /* time */
2127 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2128 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2129 {
2130 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002131 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002132 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2133 {
2134 /* poisonous reversed routes (gc) */
2135 ripng_vty_out_uptime (vty, rinfo);
2136 }
paul718e3742002-12-13 20:15:29 +00002137
2138 vty_out (vty, "%s", VTY_NEWLINE);
2139 }
2140 }
2141
2142 return CMD_SUCCESS;
2143}
2144
hassoa94434b2003-05-25 17:10:12 +00002145DEFUN (show_ipv6_ripng_status,
2146 show_ipv6_ripng_status_cmd,
2147 "show ipv6 ripng status",
2148 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002149 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002150 "Show RIPng routes\n"
2151 "IPv6 routing protocol process parameters and statistics\n")
2152{
hasso52dc7ee2004-09-23 19:18:23 +00002153 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002154 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002155
2156 if (! ripng)
2157 return CMD_SUCCESS;
2158
2159 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2160 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2161 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002162 vty_out (vty, " next due in %lu seconds%s",
2163 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002164 VTY_NEWLINE);
2165 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2166 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2167 VTY_NEWLINE);
2168
2169 /* Filtering status show. */
2170 config_show_distribute (vty);
2171
2172 /* Default metric information. */
2173 vty_out (vty, " Default redistribution metric is %d%s",
2174 ripng->default_metric, VTY_NEWLINE);
2175
2176 /* Redistribute information. */
2177 vty_out (vty, " Redistributing:");
2178 ripng_redistribute_write (vty, 0);
2179 vty_out (vty, "%s", VTY_NEWLINE);
2180
2181 vty_out (vty, " Default version control: send version %d,", ripng->version);
2182 vty_out (vty, " receive version %d %s", ripng->version,
2183 VTY_NEWLINE);
2184
2185 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2186
paul1eb8ef22005-04-07 07:30:20 +00002187 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002188 {
2189 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002190
hassoa94434b2003-05-25 17:10:12 +00002191 ri = ifp->info;
2192
2193 if (ri->enable_network || ri->enable_interface)
2194 {
2195
2196 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2197 ripng->version,
2198 ripng->version,
2199 VTY_NEWLINE);
2200 }
2201 }
2202
2203 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2204 ripng_network_write (vty, 0);
2205
2206 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2207 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2208 ripng_peer_display (vty);
2209
2210 return CMD_SUCCESS;
2211}
2212
paul718e3742002-12-13 20:15:29 +00002213DEFUN (router_ripng,
2214 router_ripng_cmd,
2215 "router ripng",
2216 "Enable a routing process\n"
2217 "Make RIPng instance command\n")
2218{
2219 int ret;
2220
2221 vty->node = RIPNG_NODE;
2222
2223 if (!ripng)
2224 {
2225 ret = ripng_create ();
2226
2227 /* Notice to user we couldn't create RIPng. */
2228 if (ret < 0)
2229 {
2230 zlog_warn ("can't create RIPng");
2231 return CMD_WARNING;
2232 }
2233 }
2234
2235 return CMD_SUCCESS;
2236}
2237
hassoa94434b2003-05-25 17:10:12 +00002238DEFUN (no_router_ripng,
2239 no_router_ripng_cmd,
2240 "no router ripng",
2241 NO_STR
2242 "Enable a routing process\n"
2243 "Make RIPng instance command\n")
2244{
2245 if(ripng)
2246 ripng_clean();
2247 return CMD_SUCCESS;
2248}
2249
paul718e3742002-12-13 20:15:29 +00002250DEFUN (ripng_route,
2251 ripng_route_cmd,
2252 "route IPV6ADDR",
2253 "Static route setup\n"
2254 "Set static RIPng route announcement\n")
2255{
2256 int ret;
2257 struct prefix_ipv6 p;
2258 struct route_node *rp;
2259
2260 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2261 if (ret <= 0)
2262 {
2263 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2264 return CMD_WARNING;
2265 }
2266 apply_mask_ipv6 (&p);
2267
2268 rp = route_node_get (ripng->route, (struct prefix *) &p);
2269 if (rp->info)
2270 {
2271 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2272 route_unlock_node (rp);
2273 return CMD_WARNING;
2274 }
2275 rp->info = (void *)1;
2276
hassoa94434b2003-05-25 17:10:12 +00002277 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002278
2279 return CMD_SUCCESS;
2280}
2281
2282DEFUN (no_ripng_route,
2283 no_ripng_route_cmd,
2284 "no route IPV6ADDR",
2285 NO_STR
2286 "Static route setup\n"
2287 "Delete static RIPng route announcement\n")
2288{
2289 int ret;
2290 struct prefix_ipv6 p;
2291 struct route_node *rp;
2292
2293 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2294 if (ret <= 0)
2295 {
2296 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2297 return CMD_WARNING;
2298 }
2299 apply_mask_ipv6 (&p);
2300
2301 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2302 if (! rp)
2303 {
2304 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2305 return CMD_WARNING;
2306 }
2307
2308 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2309 route_unlock_node (rp);
2310
2311 rp->info = NULL;
2312 route_unlock_node (rp);
2313
2314 return CMD_SUCCESS;
2315}
2316
2317DEFUN (ripng_aggregate_address,
2318 ripng_aggregate_address_cmd,
2319 "aggregate-address X:X::X:X/M",
2320 "Set aggregate RIPng route announcement\n"
2321 "Aggregate network\n")
2322{
2323 int ret;
2324 struct prefix p;
2325 struct route_node *node;
2326
2327 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2328 if (ret <= 0)
2329 {
2330 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2331 return CMD_WARNING;
2332 }
2333
2334 /* Check aggregate alredy exist or not. */
2335 node = route_node_get (ripng->aggregate, &p);
2336 if (node->info)
2337 {
2338 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2339 route_unlock_node (node);
2340 return CMD_WARNING;
2341 }
2342 node->info = (void *)1;
2343
2344 ripng_aggregate_add (&p);
2345
2346 return CMD_SUCCESS;
2347}
2348
2349DEFUN (no_ripng_aggregate_address,
2350 no_ripng_aggregate_address_cmd,
2351 "no aggregate-address X:X::X:X/M",
2352 NO_STR
2353 "Delete aggregate RIPng route announcement\n"
2354 "Aggregate network")
2355{
2356 int ret;
2357 struct prefix p;
2358 struct route_node *rn;
2359
2360 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2361 if (ret <= 0)
2362 {
2363 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2364 return CMD_WARNING;
2365 }
2366
2367 rn = route_node_lookup (ripng->aggregate, &p);
2368 if (! rn)
2369 {
2370 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2371 return CMD_WARNING;
2372 }
2373 route_unlock_node (rn);
2374 rn->info = NULL;
2375 route_unlock_node (rn);
2376
2377 ripng_aggregate_delete (&p);
2378
2379 return CMD_SUCCESS;
2380}
2381
2382DEFUN (ripng_default_metric,
2383 ripng_default_metric_cmd,
2384 "default-metric <1-16>",
2385 "Set a metric of redistribute routes\n"
2386 "Default metric\n")
2387{
2388 if (ripng)
2389 {
2390 ripng->default_metric = atoi (argv[0]);
2391 }
2392 return CMD_SUCCESS;
2393}
2394
2395DEFUN (no_ripng_default_metric,
2396 no_ripng_default_metric_cmd,
2397 "no default-metric",
2398 NO_STR
2399 "Set a metric of redistribute routes\n"
2400 "Default metric\n")
2401{
2402 if (ripng)
2403 {
2404 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2405 }
2406 return CMD_SUCCESS;
2407}
2408
2409ALIAS (no_ripng_default_metric,
2410 no_ripng_default_metric_val_cmd,
2411 "no default-metric <1-16>",
2412 NO_STR
2413 "Set a metric of redistribute routes\n"
2414 "Default metric\n")
2415
2416#if 0
2417/* RIPng update timer setup. */
2418DEFUN (ripng_update_timer,
2419 ripng_update_timer_cmd,
2420 "update-timer SECOND",
2421 "Set RIPng update timer in seconds\n"
2422 "Seconds\n")
2423{
2424 unsigned long update;
2425 char *endptr = NULL;
2426
2427 update = strtoul (argv[0], &endptr, 10);
2428 if (update == ULONG_MAX || *endptr != '\0')
2429 {
2430 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2431 return CMD_WARNING;
2432 }
2433
2434 ripng->update_time = update;
2435
2436 ripng_event (RIPNG_UPDATE_EVENT, 0);
2437 return CMD_SUCCESS;
2438}
2439
2440DEFUN (no_ripng_update_timer,
2441 no_ripng_update_timer_cmd,
2442 "no update-timer SECOND",
2443 NO_STR
2444 "Unset RIPng update timer in seconds\n"
2445 "Seconds\n")
2446{
2447 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2448 ripng_event (RIPNG_UPDATE_EVENT, 0);
2449 return CMD_SUCCESS;
2450}
2451
2452/* RIPng timeout timer setup. */
2453DEFUN (ripng_timeout_timer,
2454 ripng_timeout_timer_cmd,
2455 "timeout-timer SECOND",
2456 "Set RIPng timeout timer in seconds\n"
2457 "Seconds\n")
2458{
2459 unsigned long timeout;
2460 char *endptr = NULL;
2461
2462 timeout = strtoul (argv[0], &endptr, 10);
2463 if (timeout == ULONG_MAX || *endptr != '\0')
2464 {
2465 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2466 return CMD_WARNING;
2467 }
2468
2469 ripng->timeout_time = timeout;
2470
2471 return CMD_SUCCESS;
2472}
2473
2474DEFUN (no_ripng_timeout_timer,
2475 no_ripng_timeout_timer_cmd,
2476 "no timeout-timer SECOND",
2477 NO_STR
2478 "Unset RIPng timeout timer in seconds\n"
2479 "Seconds\n")
2480{
2481 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2482 return CMD_SUCCESS;
2483}
2484
2485/* RIPng garbage timer setup. */
2486DEFUN (ripng_garbage_timer,
2487 ripng_garbage_timer_cmd,
2488 "garbage-timer SECOND",
2489 "Set RIPng garbage timer in seconds\n"
2490 "Seconds\n")
2491{
2492 unsigned long garbage;
2493 char *endptr = NULL;
2494
2495 garbage = strtoul (argv[0], &endptr, 10);
2496 if (garbage == ULONG_MAX || *endptr != '\0')
2497 {
2498 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2499 return CMD_WARNING;
2500 }
2501
2502 ripng->garbage_time = garbage;
2503
2504 return CMD_SUCCESS;
2505}
2506
2507DEFUN (no_ripng_garbage_timer,
2508 no_ripng_garbage_timer_cmd,
2509 "no garbage-timer SECOND",
2510 NO_STR
2511 "Unset RIPng garbage timer in seconds\n"
2512 "Seconds\n")
2513{
2514 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2515 return CMD_SUCCESS;
2516}
2517#endif /* 0 */
2518
2519DEFUN (ripng_timers,
2520 ripng_timers_cmd,
2521 "timers basic <0-65535> <0-65535> <0-65535>",
2522 "RIPng timers setup\n"
2523 "Basic timer\n"
2524 "Routing table update timer value in second. Default is 30.\n"
2525 "Routing information timeout timer. Default is 180.\n"
2526 "Garbage collection timer. Default is 120.\n")
2527{
2528 unsigned long update;
2529 unsigned long timeout;
2530 unsigned long garbage;
paul718e3742002-12-13 20:15:29 +00002531
Ulrich Weber69898802011-11-17 21:35:08 +04002532 VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2533 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2534 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
paul718e3742002-12-13 20:15:29 +00002535
2536 /* Set each timer value. */
2537 ripng->update_time = update;
2538 ripng->timeout_time = timeout;
2539 ripng->garbage_time = garbage;
2540
2541 /* Reset update timer thread. */
2542 ripng_event (RIPNG_UPDATE_EVENT, 0);
2543
2544 return CMD_SUCCESS;
2545}
2546
2547DEFUN (no_ripng_timers,
2548 no_ripng_timers_cmd,
2549 "no timers basic",
2550 NO_STR
2551 "RIPng timers setup\n"
2552 "Basic timer\n")
2553{
2554 /* Set each timer value to the default. */
2555 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2556 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2557 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2558
2559 /* Reset update timer thread. */
2560 ripng_event (RIPNG_UPDATE_EVENT, 0);
2561
2562 return CMD_SUCCESS;
2563}
2564
hassoa94434b2003-05-25 17:10:12 +00002565ALIAS (no_ripng_timers,
2566 no_ripng_timers_val_cmd,
2567 "no timers basic <0-65535> <0-65535> <0-65535>",
2568 NO_STR
2569 "RIPng timers setup\n"
2570 "Basic timer\n"
2571 "Routing table update timer value in second. Default is 30.\n"
2572 "Routing information timeout timer. Default is 180.\n"
2573 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002574
2575DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2576 "show ipv6 protocols",
2577 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002578 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002579 "Routing protocol information")
2580{
2581 if (! ripng)
2582 return CMD_SUCCESS;
2583
2584 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2585
2586 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2587 ripng->update_time, 0,
2588 VTY_NEWLINE);
2589
2590 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2591 ripng->timeout_time,
2592 ripng->garbage_time,
2593 VTY_NEWLINE);
2594
2595 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2596 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2597
2598 return CMD_SUCCESS;
2599}
2600
2601/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002602DEFUN (ripng_default_information_originate,
2603 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002604 "default-information originate",
2605 "Default route information\n"
2606 "Distribute default route\n")
2607{
2608 struct prefix_ipv6 p;
2609
hassoa94434b2003-05-25 17:10:12 +00002610 if (! ripng ->default_information) {
2611 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002612
hassoa94434b2003-05-25 17:10:12 +00002613 str2prefix_ipv6 ("::/0", &p);
2614 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2615 }
paul718e3742002-12-13 20:15:29 +00002616
2617 return CMD_SUCCESS;
2618}
2619
paula2c62832003-04-23 17:01:31 +00002620DEFUN (no_ripng_default_information_originate,
2621 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002622 "no default-information originate",
2623 NO_STR
2624 "Default route information\n"
2625 "Distribute default route\n")
2626{
2627 struct prefix_ipv6 p;
2628
hassoa94434b2003-05-25 17:10:12 +00002629 if (ripng->default_information) {
2630 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002631
hassoa94434b2003-05-25 17:10:12 +00002632 str2prefix_ipv6 ("::/0", &p);
2633 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2634 }
paul718e3742002-12-13 20:15:29 +00002635
2636 return CMD_SUCCESS;
2637}
2638
2639/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002640static int
paul718e3742002-12-13 20:15:29 +00002641ripng_config_write (struct vty *vty)
2642{
hassoa94434b2003-05-25 17:10:12 +00002643 int ripng_network_write (struct vty *, int);
2644 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002645 int write = 0;
2646 struct route_node *rp;
2647
2648 if (ripng)
2649 {
2650
2651 /* RIPng router. */
2652 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2653
2654 if (ripng->default_information)
2655 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2656
hassoa94434b2003-05-25 17:10:12 +00002657 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002658
2659 /* RIPng default metric configuration */
2660 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2661 vty_out (vty, " default-metric %d%s",
2662 ripng->default_metric, VTY_NEWLINE);
2663
hassoa94434b2003-05-25 17:10:12 +00002664 ripng_redistribute_write (vty, 1);
2665
2666 /* RIP offset-list configuration. */
2667 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002668
2669 /* RIPng aggregate routes. */
2670 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2671 if (rp->info != NULL)
2672 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002673 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002674 rp->p.prefixlen,
2675
2676 VTY_NEWLINE);
2677
2678 /* RIPng static routes. */
2679 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2680 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002681 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002682 rp->p.prefixlen,
2683 VTY_NEWLINE);
2684
2685 /* RIPng timers configuration. */
2686 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2687 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2688 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2689 {
2690 vty_out (vty, " timers basic %ld %ld %ld%s",
2691 ripng->update_time,
2692 ripng->timeout_time,
2693 ripng->garbage_time,
2694 VTY_NEWLINE);
2695 }
2696#if 0
2697 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2698 vty_out (vty, " update-timer %d%s", ripng->update_time,
2699 VTY_NEWLINE);
2700 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2701 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2702 VTY_NEWLINE);
2703 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2704 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2705 VTY_NEWLINE);
2706#endif /* 0 */
2707
2708 write += config_write_distribute (vty);
2709
2710 write += config_write_if_rmap (vty);
2711
2712 write++;
2713 }
2714 return write;
2715}
2716
2717/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002718static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002719{
2720 RIPNG_NODE,
2721 "%s(config-router)# ",
2722 1,
2723};
2724
Paul Jakma6ac29a52008-08-15 13:45:30 +01002725static void
paul718e3742002-12-13 20:15:29 +00002726ripng_distribute_update (struct distribute *dist)
2727{
2728 struct interface *ifp;
2729 struct ripng_interface *ri;
2730 struct access_list *alist;
2731 struct prefix_list *plist;
2732
2733 if (! dist->ifname)
2734 return;
2735
2736 ifp = if_lookup_by_name (dist->ifname);
2737 if (ifp == NULL)
2738 return;
2739
2740 ri = ifp->info;
2741
2742 if (dist->list[DISTRIBUTE_IN])
2743 {
2744 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2745 if (alist)
2746 ri->list[RIPNG_FILTER_IN] = alist;
2747 else
2748 ri->list[RIPNG_FILTER_IN] = NULL;
2749 }
2750 else
2751 ri->list[RIPNG_FILTER_IN] = NULL;
2752
2753 if (dist->list[DISTRIBUTE_OUT])
2754 {
2755 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2756 if (alist)
2757 ri->list[RIPNG_FILTER_OUT] = alist;
2758 else
2759 ri->list[RIPNG_FILTER_OUT] = NULL;
2760 }
2761 else
2762 ri->list[RIPNG_FILTER_OUT] = NULL;
2763
2764 if (dist->prefix[DISTRIBUTE_IN])
2765 {
2766 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2767 if (plist)
2768 ri->prefix[RIPNG_FILTER_IN] = plist;
2769 else
2770 ri->prefix[RIPNG_FILTER_IN] = NULL;
2771 }
2772 else
2773 ri->prefix[RIPNG_FILTER_IN] = NULL;
2774
2775 if (dist->prefix[DISTRIBUTE_OUT])
2776 {
2777 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2778 if (plist)
2779 ri->prefix[RIPNG_FILTER_OUT] = plist;
2780 else
2781 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2782 }
2783 else
2784 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2785}
hassoa94434b2003-05-25 17:10:12 +00002786
paul718e3742002-12-13 20:15:29 +00002787void
2788ripng_distribute_update_interface (struct interface *ifp)
2789{
2790 struct distribute *dist;
2791
2792 dist = distribute_lookup (ifp->name);
2793 if (dist)
2794 ripng_distribute_update (dist);
2795}
2796
2797/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002798static void
hassoc9e52be2004-09-26 16:09:34 +00002799ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002800{
2801 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002802 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002803
paul1eb8ef22005-04-07 07:30:20 +00002804 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2805 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002806}
hassoc9e52be2004-09-26 16:09:34 +00002807
Paul Jakma6ac29a52008-08-15 13:45:30 +01002808static void
hassoc9e52be2004-09-26 16:09:34 +00002809ripng_distribute_update_all_wrapper (struct access_list *notused)
2810{
2811 ripng_distribute_update_all(NULL);
2812}
David Lamparter6b0655a2014-06-04 06:53:35 +02002813
hassoa94434b2003-05-25 17:10:12 +00002814/* delete all the added ripng routes. */
2815void
2816ripng_clean()
2817{
2818 int i;
2819 struct route_node *rp;
2820 struct ripng_info *rinfo;
Feng Lue97c31a2015-05-22 11:39:53 +02002821 struct ripng_aggregate *aggregate;
2822 struct list *list = NULL;
2823 struct listnode *listnode = NULL;
hassoa94434b2003-05-25 17:10:12 +00002824
2825 if (ripng) {
2826 /* Clear RIPng routes */
Feng Lue97c31a2015-05-22 11:39:53 +02002827 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2828 {
2829 if ((list = rp->info) != NULL)
2830 {
2831 rinfo = listgetdata (listhead (list));
2832 if (ripng_route_rte (rinfo))
2833 ripng_zebra_ipv6_delete (rp);
hassoa94434b2003-05-25 17:10:12 +00002834
Feng Lue97c31a2015-05-22 11:39:53 +02002835 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2836 {
2837 RIPNG_TIMER_OFF (rinfo->t_timeout);
2838 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2839 ripng_info_free (rinfo);
2840 }
2841 list_delete (list);
2842 rp->info = NULL;
2843 route_unlock_node (rp);
2844 }
hassoa94434b2003-05-25 17:10:12 +00002845
Feng Lue97c31a2015-05-22 11:39:53 +02002846 if ((aggregate = rp->aggregate) != NULL)
2847 {
2848 ripng_aggregate_free (aggregate);
2849 rp->aggregate = NULL;
2850 route_unlock_node (rp);
2851 }
hassoa94434b2003-05-25 17:10:12 +00002852 }
2853
2854 /* Cancel the RIPng timers */
2855 RIPNG_TIMER_OFF (ripng->t_update);
2856 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2857 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2858
2859 /* Cancel the read thread */
2860 if (ripng->t_read) {
2861 thread_cancel (ripng->t_read);
2862 ripng->t_read = NULL;
2863 }
2864
2865 /* Close the RIPng socket */
2866 if (ripng->sock >= 0) {
2867 close(ripng->sock);
2868 ripng->sock = -1;
2869 }
2870
2871 /* Static RIPng route configuration. */
2872 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2873 if (rp->info) {
2874 rp->info = NULL;
2875 route_unlock_node (rp);
2876 }
2877
2878 /* RIPng aggregated prefixes */
2879 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2880 if (rp->info) {
2881 rp->info = NULL;
2882 route_unlock_node (rp);
2883 }
2884
2885 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2886 if (ripng->route_map[i].name)
2887 free (ripng->route_map[i].name);
2888
2889 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2890 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2891 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2892
2893 XFREE (MTYPE_RIPNG, ripng);
2894 ripng = NULL;
2895 } /* if (ripng) */
2896
2897 ripng_clean_network();
2898 ripng_passive_interface_clean ();
2899 ripng_offset_clean ();
2900 ripng_interface_clean ();
2901 ripng_redistribute_clean ();
2902}
2903
2904/* Reset all values to the default settings. */
2905void
2906ripng_reset ()
2907{
2908 /* Call ripd related reset functions. */
2909 ripng_debug_reset ();
2910 ripng_route_map_reset ();
2911
2912 /* Call library reset functions. */
2913 vty_reset ();
2914 access_list_reset ();
2915 prefix_list_reset ();
2916
2917 distribute_list_reset ();
2918
2919 ripng_interface_reset ();
2920
2921 ripng_zclient_reset ();
2922}
paul718e3742002-12-13 20:15:29 +00002923
Paul Jakma6ac29a52008-08-15 13:45:30 +01002924static void
paul718e3742002-12-13 20:15:29 +00002925ripng_if_rmap_update (struct if_rmap *if_rmap)
2926{
2927 struct interface *ifp;
2928 struct ripng_interface *ri;
2929 struct route_map *rmap;
2930
2931 ifp = if_lookup_by_name (if_rmap->ifname);
2932 if (ifp == NULL)
2933 return;
2934
2935 ri = ifp->info;
2936
2937 if (if_rmap->routemap[IF_RMAP_IN])
2938 {
2939 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2940 if (rmap)
2941 ri->routemap[IF_RMAP_IN] = rmap;
2942 else
2943 ri->routemap[IF_RMAP_IN] = NULL;
2944 }
2945 else
2946 ri->routemap[RIPNG_FILTER_IN] = NULL;
2947
2948 if (if_rmap->routemap[IF_RMAP_OUT])
2949 {
2950 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2951 if (rmap)
2952 ri->routemap[IF_RMAP_OUT] = rmap;
2953 else
2954 ri->routemap[IF_RMAP_OUT] = NULL;
2955 }
2956 else
2957 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2958}
2959
2960void
2961ripng_if_rmap_update_interface (struct interface *ifp)
2962{
2963 struct if_rmap *if_rmap;
2964
2965 if_rmap = if_rmap_lookup (ifp->name);
2966 if (if_rmap)
2967 ripng_if_rmap_update (if_rmap);
2968}
2969
Paul Jakma6ac29a52008-08-15 13:45:30 +01002970static void
paul718e3742002-12-13 20:15:29 +00002971ripng_routemap_update_redistribute (void)
2972{
2973 int i;
2974
2975 if (ripng)
2976 {
2977 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2978 {
2979 if (ripng->route_map[i].name)
2980 ripng->route_map[i].map =
2981 route_map_lookup_by_name (ripng->route_map[i].name);
2982 }
2983 }
2984}
2985
Paul Jakma6ac29a52008-08-15 13:45:30 +01002986static void
hasso98b718a2004-10-11 12:57:57 +00002987ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00002988{
2989 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002990 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002991
paul1eb8ef22005-04-07 07:30:20 +00002992 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2993 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002994
2995 ripng_routemap_update_redistribute ();
2996}
2997
2998/* Initialize ripng structure and set commands. */
2999void
3000ripng_init ()
3001{
3002 /* Randomize. */
3003 srand (time (NULL));
3004
3005 /* Install RIPNG_NODE. */
3006 install_node (&cmd_ripng_node, ripng_config_write);
3007
3008 /* Install ripng commands. */
3009 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003010 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003011
3012 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003013 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00003014
3015 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00003016 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00003017
3018 install_default (RIPNG_NODE);
3019 install_element (RIPNG_NODE, &ripng_route_cmd);
3020 install_element (RIPNG_NODE, &no_ripng_route_cmd);
3021 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3022 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3023
3024 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3025 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
3026 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
3027
3028 install_element (RIPNG_NODE, &ripng_timers_cmd);
3029 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00003030 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00003031#if 0
3032 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3033 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3034 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3035 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3036 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3037 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3038#endif /* 0 */
3039
paula2c62832003-04-23 17:01:31 +00003040 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3041 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00003042
3043 ripng_if_init ();
3044 ripng_debug_init ();
3045
3046 /* Access list install. */
3047 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003048 access_list_add_hook (ripng_distribute_update_all_wrapper);
3049 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003050
3051 /* Prefix list initialize.*/
3052 prefix_list_init ();
3053 prefix_list_add_hook (ripng_distribute_update_all);
3054 prefix_list_delete_hook (ripng_distribute_update_all);
3055
3056 /* Distribute list install. */
3057 distribute_list_init (RIPNG_NODE);
3058 distribute_list_add_hook (ripng_distribute_update);
3059 distribute_list_delete_hook (ripng_distribute_update);
3060
3061 /* Route-map for interface. */
3062 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003063 ripng_offset_init ();
3064
paul718e3742002-12-13 20:15:29 +00003065 route_map_add_hook (ripng_routemap_update);
3066 route_map_delete_hook (ripng_routemap_update);
3067
hasso0750d212003-05-24 21:41:49 +00003068 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003069 if_rmap_hook_add (ripng_if_rmap_update);
3070 if_rmap_hook_delete (ripng_if_rmap_update);
3071}