]> git.proxmox.com Git - mirror_frr.git/blame_incremental - ripngd/ripngd.c
zebra: Allow ns delete to happen after under/over flow checks
[mirror_frr.git] / ripngd / ripngd.c
... / ...
CommitLineData
1/* 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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <zebra.h>
22
23#include "prefix.h"
24#include "filter.h"
25#include "log.h"
26#include "thread.h"
27#include "memory.h"
28#include "if.h"
29#include "stream.h"
30#include "agg_table.h"
31#include "command.h"
32#include "sockopt.h"
33#include "distribute.h"
34#include "plist.h"
35#include "routemap.h"
36#include "if_rmap.h"
37#include "privs.h"
38#include "lib_errors.h"
39#include "northbound_cli.h"
40
41#include "ripngd/ripngd.h"
42#include "ripngd/ripng_route.h"
43#include "ripngd/ripng_debug.h"
44#include "ripngd/ripng_nexthop.h"
45
46/* RIPng structure which includes many parameters related to RIPng
47 protocol. If ripng couldn't active or ripng doesn't configured,
48 ripng->fd must be negative value. */
49struct ripng *ripng = NULL;
50
51enum { ripng_all_route,
52 ripng_changed_route,
53};
54
55/* Prototypes. */
56void ripng_output_process(struct interface *, struct sockaddr_in6 *, int);
57
58int ripng_triggered_update(struct thread *);
59
60/* RIPng next hop specification. */
61struct ripng_nexthop {
62 enum ripng_nexthop_type {
63 RIPNG_NEXTHOP_UNSPEC,
64 RIPNG_NEXTHOP_ADDRESS
65 } flag;
66 struct in6_addr address;
67};
68
69int ripng_route_rte(struct ripng_info *rinfo)
70{
71 return (rinfo->type == ZEBRA_ROUTE_RIPNG
72 && rinfo->sub_type == RIPNG_ROUTE_RTE);
73}
74
75/* Allocate new ripng information. */
76struct ripng_info *ripng_info_new()
77{
78 struct ripng_info *new;
79
80 new = XCALLOC(MTYPE_RIPNG_ROUTE, sizeof(struct ripng_info));
81 return new;
82}
83
84/* Free ripng information. */
85void ripng_info_free(struct ripng_info *rinfo)
86{
87 XFREE(MTYPE_RIPNG_ROUTE, rinfo);
88}
89
90/* Create ripng socket. */
91int ripng_make_socket(void)
92{
93 int ret;
94 int sock;
95 struct sockaddr_in6 ripaddr;
96
97 sock = socket(AF_INET6, SOCK_DGRAM, 0);
98 if (sock < 0) {
99 flog_err_sys(EC_LIB_SOCKET, "Can't make ripng socket");
100 return sock;
101 }
102
103 setsockopt_so_recvbuf(sock, 8096);
104 ret = setsockopt_ipv6_pktinfo(sock, 1);
105 if (ret < 0)
106 goto error;
107#ifdef IPTOS_PREC_INTERNETCONTROL
108 ret = setsockopt_ipv6_tclass(sock, IPTOS_PREC_INTERNETCONTROL);
109 if (ret < 0)
110 goto error;
111#endif
112 ret = setsockopt_ipv6_multicast_hops(sock, 255);
113 if (ret < 0)
114 goto error;
115 ret = setsockopt_ipv6_multicast_loop(sock, 0);
116 if (ret < 0)
117 goto error;
118 ret = setsockopt_ipv6_hoplimit(sock, 1);
119 if (ret < 0)
120 goto error;
121
122 memset(&ripaddr, 0, sizeof(ripaddr));
123 ripaddr.sin6_family = AF_INET6;
124#ifdef SIN6_LEN
125 ripaddr.sin6_len = sizeof(struct sockaddr_in6);
126#endif /* SIN6_LEN */
127 ripaddr.sin6_port = htons(RIPNG_PORT_DEFAULT);
128
129 frr_elevate_privs(&ripngd_privs) {
130 ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
131 if (ret < 0) {
132 zlog_err("Can't bind ripng socket: %s.",
133 safe_strerror(errno));
134 goto error;
135 }
136 }
137 return sock;
138
139error:
140 close(sock);
141 return ret;
142}
143
144/* Send RIPng packet. */
145int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to,
146 struct interface *ifp)
147{
148 int ret;
149 struct msghdr msg;
150 struct iovec iov;
151 struct cmsghdr *cmsgptr;
152 char adata[256];
153 struct in6_pktinfo *pkt;
154 struct sockaddr_in6 addr;
155
156 if (IS_RIPNG_DEBUG_SEND) {
157 if (to)
158 zlog_debug("send to %s", inet6_ntoa(to->sin6_addr));
159 zlog_debug(" send interface %s", ifp->name);
160 zlog_debug(" send packet size %d", bufsize);
161 }
162
163 memset(&addr, 0, sizeof(struct sockaddr_in6));
164 addr.sin6_family = AF_INET6;
165#ifdef SIN6_LEN
166 addr.sin6_len = sizeof(struct sockaddr_in6);
167#endif /* SIN6_LEN */
168 addr.sin6_flowinfo = htonl(RIPNG_PRIORITY_DEFAULT);
169
170 /* When destination is specified. */
171 if (to != NULL) {
172 addr.sin6_addr = to->sin6_addr;
173 addr.sin6_port = to->sin6_port;
174 } else {
175 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
176 addr.sin6_port = htons(RIPNG_PORT_DEFAULT);
177 }
178
179 memset(&msg, 0, sizeof(msg));
180 msg.msg_name = (void *)&addr;
181 msg.msg_namelen = sizeof(struct sockaddr_in6);
182 msg.msg_iov = &iov;
183 msg.msg_iovlen = 1;
184 msg.msg_control = (void *)adata;
185 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
186
187 iov.iov_base = buf;
188 iov.iov_len = bufsize;
189
190 cmsgptr = (struct cmsghdr *)adata;
191 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
192 cmsgptr->cmsg_level = IPPROTO_IPV6;
193 cmsgptr->cmsg_type = IPV6_PKTINFO;
194
195 pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
196 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
197 pkt->ipi6_ifindex = ifp->ifindex;
198
199 ret = sendmsg(ripng->sock, &msg, 0);
200
201 if (ret < 0) {
202 if (to)
203 flog_err_sys(EC_LIB_SOCKET,
204 "RIPng send fail on %s to %s: %s",
205 ifp->name, inet6_ntoa(to->sin6_addr),
206 safe_strerror(errno));
207 else
208 flog_err_sys(EC_LIB_SOCKET, "RIPng send fail on %s: %s",
209 ifp->name, safe_strerror(errno));
210 }
211
212 return ret;
213}
214
215/* Receive UDP RIPng packet from socket. */
216static int ripng_recv_packet(int sock, uint8_t *buf, int bufsize,
217 struct sockaddr_in6 *from, ifindex_t *ifindex,
218 int *hoplimit)
219{
220 int ret;
221 struct msghdr msg;
222 struct iovec iov;
223 struct cmsghdr *cmsgptr;
224 struct in6_addr dst = {.s6_addr = {0}};
225
226 memset(&dst, 0, sizeof(struct in6_addr));
227
228 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
229 point I can't determine size of cmsghdr */
230 char adata[1024];
231
232 /* Fill in message and iovec. */
233 memset(&msg, 0, sizeof(msg));
234 msg.msg_name = (void *)from;
235 msg.msg_namelen = sizeof(struct sockaddr_in6);
236 msg.msg_iov = &iov;
237 msg.msg_iovlen = 1;
238 msg.msg_control = (void *)adata;
239 msg.msg_controllen = sizeof adata;
240 iov.iov_base = buf;
241 iov.iov_len = bufsize;
242
243 /* If recvmsg fail return minus value. */
244 ret = recvmsg(sock, &msg, 0);
245 if (ret < 0)
246 return ret;
247
248 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
249 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
250 /* I want interface index which this packet comes from. */
251 if (cmsgptr->cmsg_level == IPPROTO_IPV6
252 && cmsgptr->cmsg_type == IPV6_PKTINFO) {
253 struct in6_pktinfo *ptr;
254
255 ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
256 *ifindex = ptr->ipi6_ifindex;
257 dst = ptr->ipi6_addr;
258
259 if (*ifindex == 0)
260 zlog_warn(
261 "Interface index returned by IPV6_PKTINFO is zero");
262 }
263
264 /* Incoming packet's multicast hop limit. */
265 if (cmsgptr->cmsg_level == IPPROTO_IPV6
266 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
267 int *phoplimit = (int *)CMSG_DATA(cmsgptr);
268 *hoplimit = *phoplimit;
269 }
270 }
271
272 /* Hoplimit check shold be done when destination address is
273 multicast address. */
274 if (!IN6_IS_ADDR_MULTICAST(&dst))
275 *hoplimit = -1;
276
277 return ret;
278}
279
280/* Dump rip packet */
281void ripng_packet_dump(struct ripng_packet *packet, int size,
282 const char *sndrcv)
283{
284 caddr_t lim;
285 struct rte *rte;
286 const char *command_str;
287
288 /* Set command string. */
289 if (packet->command == RIPNG_REQUEST)
290 command_str = "request";
291 else if (packet->command == RIPNG_RESPONSE)
292 command_str = "response";
293 else
294 command_str = "unknown";
295
296 /* Dump packet header. */
297 zlog_debug("%s %s version %d packet size %d", sndrcv, command_str,
298 packet->version, size);
299
300 /* Dump each routing table entry. */
301 rte = packet->rte;
302
303 for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) {
304 if (rte->metric == RIPNG_METRIC_NEXTHOP)
305 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte->addr),
306 rte->prefixlen);
307 else
308 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI,
309 inet6_ntoa(rte->addr), rte->prefixlen,
310 rte->metric, (route_tag_t)ntohs(rte->tag));
311 }
312}
313
314/* RIPng next hop address RTE (Route Table Entry). */
315static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from,
316 struct ripng_nexthop *nexthop)
317{
318 char buf[INET6_BUFSIZ];
319
320 /* Logging before checking RTE. */
321 if (IS_RIPNG_DEBUG_RECV)
322 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
323 " prefixlen %d",
324 inet6_ntoa(rte->addr), (route_tag_t)ntohs(rte->tag),
325 rte->prefixlen);
326
327 /* RFC2080 2.1.1 Next Hop:
328 The route tag and prefix length in the next hop RTE must be
329 set to zero on sending and ignored on receiption. */
330 if (ntohs(rte->tag) != 0)
331 zlog_warn(
332 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
333 " from %s",
334 (route_tag_t)ntohs(rte->tag),
335 inet6_ntoa(from->sin6_addr));
336
337 if (rte->prefixlen != 0)
338 zlog_warn(
339 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
340 rte->prefixlen, inet6_ntoa(from->sin6_addr));
341
342 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
343 next hop RTE indicates that the next hop address should be the
344 originator of the RIPng advertisement. An address specified as a
345 next hop must be a link-local address. */
346 if (IN6_IS_ADDR_UNSPECIFIED(&rte->addr)) {
347 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
348 memset(&nexthop->address, 0, sizeof(struct in6_addr));
349 return;
350 }
351
352 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
353 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
354 IPV6_ADDR_COPY(&nexthop->address, &rte->addr);
355 return;
356 }
357
358 /* The purpose of the next hop RTE is to eliminate packets being
359 routed through extra hops in the system. It is particularly useful
360 when RIPng is not being run on all of the routers on a network.
361 Note that next hop RTE is "advisory". That is, if the provided
362 information is ignored, a possibly sub-optimal, but absolutely
363 valid, route may be taken. If the received next hop address is not
364 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
365 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
366 inet6_ntoa(rte->addr),
367 inet_ntop(AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
368
369 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
370 memset(&nexthop->address, 0, sizeof(struct in6_addr));
371
372 return;
373}
374
375/* If ifp has same link-local address then return 1. */
376static int ripng_lladdr_check(struct interface *ifp, struct in6_addr *addr)
377{
378 struct listnode *node;
379 struct connected *connected;
380 struct prefix *p;
381
382 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
383 p = connected->address;
384
385 if (p->family == AF_INET6
386 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)
387 && IN6_ARE_ADDR_EQUAL(&p->u.prefix6, addr))
388 return 1;
389 }
390 return 0;
391}
392
393/* RIPng route garbage collect timer. */
394static int ripng_garbage_collect(struct thread *t)
395{
396 struct ripng_info *rinfo;
397 struct agg_node *rp;
398
399 rinfo = THREAD_ARG(t);
400 rinfo->t_garbage_collect = NULL;
401
402 /* Off timeout timer. */
403 RIPNG_TIMER_OFF(rinfo->t_timeout);
404
405 /* Get route_node pointer. */
406 rp = rinfo->rp;
407
408 /* Unlock route_node. */
409 listnode_delete(rp->info, rinfo);
410 if (list_isempty((struct list *)rp->info)) {
411 list_delete((struct list **)&rp->info);
412 agg_unlock_node(rp);
413 }
414
415 /* Free RIPng routing information. */
416 ripng_info_free(rinfo);
417
418 return 0;
419}
420
421static void ripng_timeout_update(struct ripng_info *rinfo);
422
423/* Add new route to the ECMP list.
424 * RETURN: the new entry added in the list, or NULL if it is not the first
425 * entry and ECMP is not allowed.
426 */
427struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new)
428{
429 struct agg_node *rp = rinfo_new->rp;
430 struct ripng_info *rinfo = NULL;
431 struct list *list = NULL;
432
433 if (rp->info == NULL)
434 rp->info = list_new();
435 list = (struct list *)rp->info;
436
437 /* If ECMP is not allowed and some entry already exists in the list,
438 * do nothing. */
439 if (listcount(list) && !ripng->ecmp)
440 return NULL;
441
442 rinfo = ripng_info_new();
443 memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
444 listnode_add(list, rinfo);
445
446 if (ripng_route_rte(rinfo)) {
447 ripng_timeout_update(rinfo);
448 ripng_zebra_ipv6_add(rp);
449 }
450
451 ripng_aggregate_increment(rp, rinfo);
452
453 /* Set the route change flag on the first entry. */
454 rinfo = listgetdata(listhead(list));
455 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
456
457 /* Signal the output process to trigger an update. */
458 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
459
460 return rinfo;
461}
462
463/* Replace the ECMP list with the new route.
464 * RETURN: the new entry added in the list
465 */
466struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
467{
468 struct agg_node *rp = rinfo_new->rp;
469 struct list *list = (struct list *)rp->info;
470 struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
471 struct listnode *node = NULL, *nextnode = NULL;
472
473 if (list == NULL || listcount(list) == 0)
474 return ripng_ecmp_add(rinfo_new);
475
476 /* Get the first entry */
477 rinfo = listgetdata(listhead(list));
478
479 /* Learnt route replaced by a local one. Delete it from zebra. */
480 if (ripng_route_rte(rinfo) && !ripng_route_rte(rinfo_new))
481 if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
482 ripng_zebra_ipv6_delete(rp);
483
484 if (rinfo->metric != RIPNG_METRIC_INFINITY)
485 ripng_aggregate_decrement_list(rp, list);
486
487 /* Re-use the first entry, and delete the others. */
488 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
489 if (tmp_rinfo != rinfo) {
490 RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
491 RIPNG_TIMER_OFF(tmp_rinfo->t_garbage_collect);
492 list_delete_node(list, node);
493 ripng_info_free(tmp_rinfo);
494 }
495
496 RIPNG_TIMER_OFF(rinfo->t_timeout);
497 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
498 memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
499
500 if (ripng_route_rte(rinfo)) {
501 ripng_timeout_update(rinfo);
502 /* The ADD message implies an update. */
503 ripng_zebra_ipv6_add(rp);
504 }
505
506 ripng_aggregate_increment(rp, rinfo);
507
508 /* Set the route change flag. */
509 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
510
511 /* Signal the output process to trigger an update. */
512 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
513
514 return rinfo;
515}
516
517/* Delete one route from the ECMP list.
518 * RETURN:
519 * null - the entry is freed, and other entries exist in the list
520 * the entry - the entry is the last one in the list; its metric is set
521 * to INFINITY, and the garbage collector is started for it
522 */
523struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
524{
525 struct agg_node *rp = rinfo->rp;
526 struct list *list = (struct list *)rp->info;
527
528 RIPNG_TIMER_OFF(rinfo->t_timeout);
529
530 if (rinfo->metric != RIPNG_METRIC_INFINITY)
531 ripng_aggregate_decrement(rp, rinfo);
532
533 if (listcount(list) > 1) {
534 /* Some other ECMP entries still exist. Just delete this entry.
535 */
536 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
537 listnode_delete(list, rinfo);
538 if (ripng_route_rte(rinfo)
539 && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
540 /* The ADD message implies the update. */
541 ripng_zebra_ipv6_add(rp);
542 ripng_info_free(rinfo);
543 rinfo = NULL;
544 } else {
545 assert(rinfo == listgetdata(listhead(list)));
546
547 /* This is the only entry left in the list. We must keep it in
548 * the list for garbage collection time, with INFINITY metric.
549 */
550
551 rinfo->metric = RIPNG_METRIC_INFINITY;
552 RIPNG_TIMER_ON(rinfo->t_garbage_collect, ripng_garbage_collect,
553 ripng->garbage_time);
554
555 if (ripng_route_rte(rinfo)
556 && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
557 ripng_zebra_ipv6_delete(rp);
558 }
559
560 /* Set the route change flag on the first entry. */
561 rinfo = listgetdata(listhead(list));
562 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
563
564 /* Signal the output process to trigger an update. */
565 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
566
567 return rinfo;
568}
569
570/* Timeout RIPng routes. */
571static int ripng_timeout(struct thread *t)
572{
573 ripng_ecmp_delete((struct ripng_info *)THREAD_ARG(t));
574 return 0;
575}
576
577static void ripng_timeout_update(struct ripng_info *rinfo)
578{
579 if (rinfo->metric != RIPNG_METRIC_INFINITY) {
580 RIPNG_TIMER_OFF(rinfo->t_timeout);
581 RIPNG_TIMER_ON(rinfo->t_timeout, ripng_timeout,
582 ripng->timeout_time);
583 }
584}
585
586static int ripng_filter(int ripng_distribute, struct prefix_ipv6 *p,
587 struct ripng_interface *ri)
588{
589 struct distribute *dist;
590 struct access_list *alist;
591 struct prefix_list *plist;
592 int distribute = ripng_distribute == RIPNG_FILTER_OUT
593 ? DISTRIBUTE_V6_OUT
594 : DISTRIBUTE_V6_IN;
595 const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
596
597 /* Input distribute-list filtering. */
598 if (ri->list[ripng_distribute]) {
599 if (access_list_apply(ri->list[ripng_distribute],
600 (struct prefix *)p)
601 == FILTER_DENY) {
602 if (IS_RIPNG_DEBUG_PACKET)
603 zlog_debug("%s/%d filtered by distribute %s",
604 inet6_ntoa(p->prefix), p->prefixlen,
605 inout);
606 return -1;
607 }
608 }
609 if (ri->prefix[ripng_distribute]) {
610 if (prefix_list_apply(ri->prefix[ripng_distribute],
611 (struct prefix *)p)
612 == PREFIX_DENY) {
613 if (IS_RIPNG_DEBUG_PACKET)
614 zlog_debug("%s/%d filtered by prefix-list %s",
615 inet6_ntoa(p->prefix), p->prefixlen,
616 inout);
617 return -1;
618 }
619 }
620
621 /* All interface filter check. */
622 dist = distribute_lookup(NULL);
623 if (dist) {
624 if (dist->list[distribute]) {
625 alist = access_list_lookup(AFI_IP6,
626 dist->list[distribute]);
627
628 if (alist) {
629 if (access_list_apply(alist, (struct prefix *)p)
630 == FILTER_DENY) {
631 if (IS_RIPNG_DEBUG_PACKET)
632 zlog_debug(
633 "%s/%d filtered by distribute %s",
634 inet6_ntoa(p->prefix),
635 p->prefixlen, inout);
636 return -1;
637 }
638 }
639 }
640 if (dist->prefix[distribute]) {
641 plist = prefix_list_lookup(AFI_IP6,
642 dist->prefix[distribute]);
643
644 if (plist) {
645 if (prefix_list_apply(plist, (struct prefix *)p)
646 == PREFIX_DENY) {
647 if (IS_RIPNG_DEBUG_PACKET)
648 zlog_debug(
649 "%s/%d filtered by prefix-list %s",
650 inet6_ntoa(p->prefix),
651 p->prefixlen, inout);
652 return -1;
653 }
654 }
655 }
656 }
657 return 0;
658}
659
660/* Process RIPng route according to RFC2080. */
661static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
662 struct ripng_nexthop *ripng_nexthop,
663 struct interface *ifp)
664{
665 int ret;
666 struct prefix_ipv6 p;
667 struct agg_node *rp;
668 struct ripng_info *rinfo = NULL, newinfo;
669 struct ripng_interface *ri;
670 struct in6_addr *nexthop;
671 int same = 0;
672 struct list *list = NULL;
673 struct listnode *node = NULL;
674
675 /* Make prefix structure. */
676 memset(&p, 0, sizeof(struct prefix_ipv6));
677 p.family = AF_INET6;
678 /* p.prefix = rte->addr; */
679 IPV6_ADDR_COPY(&p.prefix, &rte->addr);
680 p.prefixlen = rte->prefixlen;
681
682 /* Make sure mask is applied. */
683 /* XXX We have to check the prefix is valid or not before call
684 apply_mask_ipv6. */
685 apply_mask_ipv6(&p);
686
687 /* Apply input filters. */
688 ri = ifp->info;
689
690 ret = ripng_filter(RIPNG_FILTER_IN, &p, ri);
691 if (ret < 0)
692 return;
693
694 memset(&newinfo, 0, sizeof(newinfo));
695 newinfo.type = ZEBRA_ROUTE_RIPNG;
696 newinfo.sub_type = RIPNG_ROUTE_RTE;
697 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
698 newinfo.nexthop = ripng_nexthop->address;
699 else
700 newinfo.nexthop = from->sin6_addr;
701 newinfo.from = from->sin6_addr;
702 newinfo.ifindex = ifp->ifindex;
703 newinfo.metric = rte->metric;
704 newinfo.metric_out = rte->metric; /* XXX */
705 newinfo.tag = ntohs(rte->tag); /* XXX */
706
707 /* Modify entry. */
708 if (ri->routemap[RIPNG_FILTER_IN]) {
709 ret = route_map_apply(ri->routemap[RIPNG_FILTER_IN],
710 (struct prefix *)&p, RMAP_RIPNG,
711 &newinfo);
712
713 if (ret == RMAP_DENYMATCH) {
714 if (IS_RIPNG_DEBUG_PACKET)
715 zlog_debug(
716 "RIPng %s/%d is filtered by route-map in",
717 inet6_ntoa(p.prefix), p.prefixlen);
718 return;
719 }
720
721 /* Get back the object */
722 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
723 if (!IPV6_ADDR_SAME(&newinfo.nexthop,
724 &ripng_nexthop->address)) {
725 /* the nexthop get changed by the routemap */
726 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
727 ripng_nexthop->address =
728 newinfo.nexthop;
729 else
730 ripng_nexthop->address = in6addr_any;
731 }
732 } else {
733 if (!IPV6_ADDR_SAME(&newinfo.nexthop,
734 &from->sin6_addr)) {
735 /* the nexthop get changed by the routemap */
736 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
737 ripng_nexthop->flag =
738 RIPNG_NEXTHOP_ADDRESS;
739 ripng_nexthop->address =
740 newinfo.nexthop;
741 }
742 }
743 }
744 rte->tag = htons(newinfo.tag_out); /* XXX */
745 rte->metric =
746 newinfo.metric_out; /* XXX: the routemap uses the
747 metric_out field */
748 }
749
750 /* Once the entry has been validated, update the metric by
751 * adding the cost of the network on wich the message
752 * arrived. If the result is greater than infinity, use infinity
753 * (RFC2453 Sec. 3.9.2)
754 **/
755
756 /* Zebra ripngd can handle offset-list in. */
757 ret = ripng_offset_list_apply_in(&p, ifp, &rte->metric);
758
759 /* If offset-list does not modify the metric use interface's
760 * one. */
761 if (!ret)
762 rte->metric += ifp->metric ? ifp->metric : 1;
763
764 if (rte->metric > RIPNG_METRIC_INFINITY)
765 rte->metric = RIPNG_METRIC_INFINITY;
766
767 /* Set nexthop pointer. */
768 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
769 nexthop = &ripng_nexthop->address;
770 else
771 nexthop = &from->sin6_addr;
772
773 /* Lookup RIPng routing table. */
774 rp = agg_node_get(ripng->table, (struct prefix *)&p);
775
776 newinfo.rp = rp;
777 newinfo.nexthop = *nexthop;
778 newinfo.metric = rte->metric;
779 newinfo.tag = ntohs(rte->tag);
780
781 /* Check to see whether there is already RIPng route on the table. */
782 if ((list = rp->info) != NULL)
783 for (ALL_LIST_ELEMENTS_RO(list, node, rinfo)) {
784 /* Need to compare with redistributed entry or local
785 * entry */
786 if (!ripng_route_rte(rinfo))
787 break;
788
789 if (IPV6_ADDR_SAME(&rinfo->from, &from->sin6_addr)
790 && IPV6_ADDR_SAME(&rinfo->nexthop, nexthop))
791 break;
792
793 if (!listnextnode(node)) {
794 /* Not found in the list */
795
796 if (rte->metric > rinfo->metric) {
797 /* New route has a greater metric.
798 * Discard it. */
799 agg_unlock_node(rp);
800 return;
801 }
802
803 if (rte->metric < rinfo->metric)
804 /* New route has a smaller metric.
805 * Replace the ECMP list
806 * with the new one in below. */
807 break;
808
809 /* Metrics are same. Unless ECMP is disabled,
810 * keep "rinfo" null and
811 * the new route is added in the ECMP list in
812 * below. */
813 if (!ripng->ecmp)
814 break;
815 }
816 }
817
818 if (rinfo) {
819 /* Redistributed route check. */
820 if (rinfo->type != ZEBRA_ROUTE_RIPNG
821 && rinfo->metric != RIPNG_METRIC_INFINITY) {
822 agg_unlock_node(rp);
823 return;
824 }
825
826 /* Local static route. */
827 if (rinfo->type == ZEBRA_ROUTE_RIPNG
828 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
829 || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
830 && rinfo->metric != RIPNG_METRIC_INFINITY) {
831 agg_unlock_node(rp);
832 return;
833 }
834 }
835
836 if (!rinfo) {
837 /* Now, check to see whether there is already an explicit route
838 for the destination prefix. If there is no such route, add
839 this route to the routing table, unless the metric is
840 infinity (there is no point in adding a route which
841 unusable). */
842 if (rte->metric != RIPNG_METRIC_INFINITY)
843 ripng_ecmp_add(&newinfo);
844 else
845 agg_unlock_node(rp);
846 } else {
847 /* If there is an existing route, compare the next hop address
848 to the address of the router from which the datagram came.
849 If this datagram is from the same router as the existing
850 route, reinitialize the timeout. */
851 same = (IN6_ARE_ADDR_EQUAL(&rinfo->from, &from->sin6_addr)
852 && (rinfo->ifindex == ifp->ifindex));
853
854 /*
855 * RFC 2080 - Section 2.4.2:
856 * "If the new metric is the same as the old one, examine the
857 * timeout
858 * for the existing route. If it is at least halfway to the
859 * expiration
860 * point, switch to the new route. This heuristic is optional,
861 * but
862 * highly recommended".
863 */
864 if (!ripng->ecmp && !same && rinfo->metric == rte->metric
865 && rinfo->t_timeout
866 && (thread_timer_remain_second(rinfo->t_timeout)
867 < (ripng->timeout_time / 2))) {
868 ripng_ecmp_replace(&newinfo);
869 }
870 /* Next, compare the metrics. If the datagram is from the same
871 router as the existing route, and the new metric is different
872 than the old one; or, if the new metric is lower than the old
873 one; do the following actions: */
874 else if ((same && rinfo->metric != rte->metric)
875 || rte->metric < rinfo->metric) {
876 if (listcount(list) == 1) {
877 if (newinfo.metric != RIPNG_METRIC_INFINITY)
878 ripng_ecmp_replace(&newinfo);
879 else
880 ripng_ecmp_delete(rinfo);
881 } else {
882 if (newinfo.metric < rinfo->metric)
883 ripng_ecmp_replace(&newinfo);
884 else /* newinfo.metric > rinfo->metric */
885 ripng_ecmp_delete(rinfo);
886 }
887 } else /* same & no change */
888 ripng_timeout_update(rinfo);
889
890 /* Unlock tempolary lock of the route. */
891 agg_unlock_node(rp);
892 }
893}
894
895/* Add redistributed route to RIPng table. */
896void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p,
897 ifindex_t ifindex, struct in6_addr *nexthop,
898 route_tag_t tag)
899{
900 struct agg_node *rp;
901 struct ripng_info *rinfo = NULL, newinfo;
902 struct list *list = NULL;
903
904 /* Redistribute route */
905 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
906 return;
907 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
908 return;
909
910 rp = agg_node_get(ripng->table, (struct prefix *)p);
911
912 memset(&newinfo, 0, sizeof(struct ripng_info));
913 newinfo.type = type;
914 newinfo.sub_type = sub_type;
915 newinfo.ifindex = ifindex;
916 newinfo.metric = 1;
917 if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
918 newinfo.tag = tag;
919 newinfo.rp = rp;
920 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
921 newinfo.nexthop = *nexthop;
922
923 if ((list = rp->info) != NULL && listcount(list) != 0) {
924 rinfo = listgetdata(listhead(list));
925
926 if (rinfo->type == ZEBRA_ROUTE_CONNECT
927 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
928 && rinfo->metric != RIPNG_METRIC_INFINITY) {
929 agg_unlock_node(rp);
930 return;
931 }
932
933 /* Manually configured RIPng route check.
934 * They have the precedence on all the other entries.
935 **/
936 if (rinfo->type == ZEBRA_ROUTE_RIPNG
937 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
938 || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))) {
939 if (type != ZEBRA_ROUTE_RIPNG
940 || ((sub_type != RIPNG_ROUTE_STATIC)
941 && (sub_type != RIPNG_ROUTE_DEFAULT))) {
942 agg_unlock_node(rp);
943 return;
944 }
945 }
946
947 ripng_ecmp_replace(&newinfo);
948 agg_unlock_node(rp);
949 } else
950 ripng_ecmp_add(&newinfo);
951
952 if (IS_RIPNG_DEBUG_EVENT) {
953 if (!nexthop)
954 zlog_debug(
955 "Redistribute new prefix %s/%d on the interface %s",
956 inet6_ntoa(p->prefix), p->prefixlen,
957 ifindex2ifname(ifindex, VRF_DEFAULT));
958 else
959 zlog_debug(
960 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
961 inet6_ntoa(p->prefix), p->prefixlen,
962 inet6_ntoa(*nexthop),
963 ifindex2ifname(ifindex, VRF_DEFAULT));
964 }
965
966 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
967}
968
969/* Delete redistributed route to RIPng table. */
970void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p,
971 ifindex_t ifindex)
972{
973 struct agg_node *rp;
974 struct ripng_info *rinfo;
975
976 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
977 return;
978 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
979 return;
980
981 rp = agg_node_lookup(ripng->table, (struct prefix *)p);
982
983 if (rp) {
984 struct list *list = rp->info;
985
986 if (list != NULL && listcount(list) != 0) {
987 rinfo = listgetdata(listhead(list));
988 if (rinfo != NULL && rinfo->type == type
989 && rinfo->sub_type == sub_type
990 && rinfo->ifindex == ifindex) {
991 /* Perform poisoned reverse. */
992 rinfo->metric = RIPNG_METRIC_INFINITY;
993 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
994 ripng_garbage_collect,
995 ripng->garbage_time);
996 RIPNG_TIMER_OFF(rinfo->t_timeout);
997
998 /* Aggregate count decrement. */
999 ripng_aggregate_decrement(rp, rinfo);
1000
1001 rinfo->flags |= RIPNG_RTF_CHANGED;
1002
1003 if (IS_RIPNG_DEBUG_EVENT)
1004 zlog_debug(
1005 "Poisone %s/%d on the interface %s with an "
1006 "infinity metric [delete]",
1007 inet6_ntoa(p->prefix),
1008 p->prefixlen,
1009 ifindex2ifname(ifindex,
1010 VRF_DEFAULT));
1011
1012 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
1013 }
1014 }
1015 agg_unlock_node(rp);
1016 }
1017}
1018
1019/* Withdraw redistributed route. */
1020void ripng_redistribute_withdraw(int type)
1021{
1022 struct agg_node *rp;
1023 struct ripng_info *rinfo = NULL;
1024 struct list *list = NULL;
1025
1026 if (!ripng)
1027 return;
1028
1029 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
1030 if ((list = rp->info) != NULL) {
1031 rinfo = listgetdata(listhead(list));
1032 if ((rinfo->type == type)
1033 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) {
1034 /* Perform poisoned reverse. */
1035 rinfo->metric = RIPNG_METRIC_INFINITY;
1036 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
1037 ripng_garbage_collect,
1038 ripng->garbage_time);
1039 RIPNG_TIMER_OFF(rinfo->t_timeout);
1040
1041 /* Aggregate count decrement. */
1042 ripng_aggregate_decrement(rp, rinfo);
1043
1044 rinfo->flags |= RIPNG_RTF_CHANGED;
1045
1046 if (IS_RIPNG_DEBUG_EVENT) {
1047 struct prefix_ipv6 *p =
1048 (struct prefix_ipv6 *)&rp->p;
1049
1050 zlog_debug(
1051 "Poisone %s/%d on the interface %s [withdraw]",
1052 inet6_ntoa(p->prefix),
1053 p->prefixlen,
1054 ifindex2ifname(rinfo->ifindex,
1055 VRF_DEFAULT));
1056 }
1057
1058 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
1059 }
1060 }
1061}
1062
1063/* RIP routing information. */
1064static void ripng_response_process(struct ripng_packet *packet, int size,
1065 struct sockaddr_in6 *from,
1066 struct interface *ifp, int hoplimit)
1067{
1068 caddr_t lim;
1069 struct rte *rte;
1070 struct ripng_nexthop nexthop;
1071
1072 /* RFC2080 2.4.2 Response Messages:
1073 The Response must be ignored if it is not from the RIPng port. */
1074 if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
1075 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1076 ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr));
1077 ripng_peer_bad_packet(from);
1078 return;
1079 }
1080
1081 /* The datagram's IPv6 source address should be checked to see
1082 whether the datagram is from a valid neighbor; the source of the
1083 datagram must be a link-local address. */
1084 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
1085 zlog_warn("RIPng packet comes from non link local address %s",
1086 inet6_ntoa(from->sin6_addr));
1087 ripng_peer_bad_packet(from);
1088 return;
1089 }
1090
1091 /* It is also worth checking to see whether the response is from one
1092 of the router's own addresses. Interfaces on broadcast networks
1093 may receive copies of their own multicasts immediately. If a
1094 router processes its own output as new input, confusion is likely,
1095 and such datagrams must be ignored. */
1096 if (ripng_lladdr_check(ifp, &from->sin6_addr)) {
1097 zlog_warn(
1098 "RIPng packet comes from my own link local address %s",
1099 inet6_ntoa(from->sin6_addr));
1100 ripng_peer_bad_packet(from);
1101 return;
1102 }
1103
1104 /* As an additional check, periodic advertisements must have their
1105 hop counts set to 255, and inbound, multicast packets sent from the
1106 RIPng port (i.e. periodic advertisement or triggered update
1107 packets) must be examined to ensure that the hop count is 255. */
1108 if (hoplimit >= 0 && hoplimit != 255) {
1109 zlog_warn(
1110 "RIPng packet comes with non 255 hop count %d from %s",
1111 hoplimit, inet6_ntoa(from->sin6_addr));
1112 ripng_peer_bad_packet(from);
1113 return;
1114 }
1115
1116 /* Update RIPng peer. */
1117 ripng_peer_update(from, packet->version);
1118
1119 /* Reset nexthop. */
1120 memset(&nexthop, 0, sizeof(struct ripng_nexthop));
1121 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1122
1123 /* Set RTE pointer. */
1124 rte = packet->rte;
1125
1126 for (lim = ((caddr_t)packet) + size; (caddr_t)rte < lim; rte++) {
1127 /* First of all, we have to check this RTE is next hop RTE or
1128 not. Next hop RTE is completely different with normal RTE so
1129 we need special treatment. */
1130 if (rte->metric == RIPNG_METRIC_NEXTHOP) {
1131 ripng_nexthop_rte(rte, from, &nexthop);
1132 continue;
1133 }
1134
1135 /* RTE information validation. */
1136
1137 /* - is the destination prefix valid (e.g., not a multicast
1138 prefix and not a link-local address) A link-local address
1139 should never be present in an RTE. */
1140 if (IN6_IS_ADDR_MULTICAST(&rte->addr)) {
1141 zlog_warn(
1142 "Destination prefix is a multicast address %s/%d [%d]",
1143 inet6_ntoa(rte->addr), rte->prefixlen,
1144 rte->metric);
1145 ripng_peer_bad_route(from);
1146 continue;
1147 }
1148 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
1149 zlog_warn(
1150 "Destination prefix is a link-local address %s/%d [%d]",
1151 inet6_ntoa(rte->addr), rte->prefixlen,
1152 rte->metric);
1153 ripng_peer_bad_route(from);
1154 continue;
1155 }
1156 if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
1157 zlog_warn(
1158 "Destination prefix is a loopback address %s/%d [%d]",
1159 inet6_ntoa(rte->addr), rte->prefixlen,
1160 rte->metric);
1161 ripng_peer_bad_route(from);
1162 continue;
1163 }
1164
1165 /* - is the prefix length valid (i.e., between 0 and 128,
1166 inclusive) */
1167 if (rte->prefixlen > 128) {
1168 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1169 inet6_ntoa(rte->addr), rte->prefixlen,
1170 inet6_ntoa(from->sin6_addr), ifp->name);
1171 ripng_peer_bad_route(from);
1172 continue;
1173 }
1174
1175 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1176 if (!(rte->metric >= 1 && rte->metric <= 16)) {
1177 zlog_warn("Invalid metric %d from %s%%%s", rte->metric,
1178 inet6_ntoa(from->sin6_addr), ifp->name);
1179 ripng_peer_bad_route(from);
1180 continue;
1181 }
1182
1183 /* Vincent: XXX Should we compute the direclty reachable nexthop
1184 * for our RIPng network ?
1185 **/
1186
1187 /* Routing table updates. */
1188 ripng_route_process(rte, from, &nexthop, ifp);
1189 }
1190}
1191
1192/* Response to request message. */
1193static void ripng_request_process(struct ripng_packet *packet, int size,
1194 struct sockaddr_in6 *from,
1195 struct interface *ifp)
1196{
1197 caddr_t lim;
1198 struct rte *rte;
1199 struct prefix_ipv6 p;
1200 struct agg_node *rp;
1201 struct ripng_info *rinfo;
1202 struct ripng_interface *ri;
1203
1204 /* Does not reponse to the requests on the loopback interfaces */
1205 if (if_is_loopback(ifp))
1206 return;
1207
1208 /* Check RIPng process is enabled on this interface. */
1209 ri = ifp->info;
1210 if (!ri->running)
1211 return;
1212
1213 /* When passive interface is specified, suppress responses */
1214 if (ri->passive)
1215 return;
1216
1217 /* RIPng peer update. */
1218 ripng_peer_update(from, packet->version);
1219
1220 lim = ((caddr_t)packet) + size;
1221 rte = packet->rte;
1222
1223 /* The Request is processed entry by entry. If there are no
1224 entries, no response is given. */
1225 if (lim == (caddr_t)rte)
1226 return;
1227
1228 /* There is one special case. If there is exactly one entry in the
1229 request, and it has a destination prefix of zero, a prefix length
1230 of zero, and a metric of infinity (i.e., 16), then this is a
1231 request to send the entire routing table. In that case, a call
1232 is made to the output process to send the routing table to the
1233 requesting address/port. */
1234 if (lim == ((caddr_t)(rte + 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte->addr)
1235 && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) {
1236 /* All route with split horizon */
1237 ripng_output_process(ifp, from, ripng_all_route);
1238 } else {
1239 /* Except for this special case, processing is quite simple.
1240 Examine the list of RTEs in the Request one by one. For each
1241 entry, look up the destination in the router's routing
1242 database and, if there is a route, put that route's metric in
1243 the metric field of the RTE. If there is no explicit route
1244 to the specified destination, put infinity in the metric
1245 field. Once all the entries have been filled in, change the
1246 command from Request to Response and send the datagram back
1247 to the requestor. */
1248 memset(&p, 0, sizeof(struct prefix_ipv6));
1249 p.family = AF_INET6;
1250
1251 for (; ((caddr_t)rte) < lim; rte++) {
1252 p.prefix = rte->addr;
1253 p.prefixlen = rte->prefixlen;
1254 apply_mask_ipv6(&p);
1255
1256 rp = agg_node_lookup(ripng->table, (struct prefix *)&p);
1257
1258 if (rp) {
1259 rinfo = listgetdata(
1260 listhead((struct list *)rp->info));
1261 rte->metric = rinfo->metric;
1262 agg_unlock_node(rp);
1263 } else
1264 rte->metric = RIPNG_METRIC_INFINITY;
1265 }
1266 packet->command = RIPNG_RESPONSE;
1267
1268 ripng_send_packet((caddr_t)packet, size, from, ifp);
1269 }
1270}
1271
1272/* First entry point of reading RIPng packet. */
1273static int ripng_read(struct thread *thread)
1274{
1275 int len;
1276 int sock;
1277 struct sockaddr_in6 from;
1278 struct ripng_packet *packet;
1279 ifindex_t ifindex = 0;
1280 struct interface *ifp;
1281 int hoplimit = -1;
1282
1283 /* Check ripng is active and alive. */
1284 assert(ripng != NULL);
1285 assert(ripng->sock >= 0);
1286
1287 /* Fetch thread data and set read pointer to empty for event
1288 managing. `sock' sould be same as ripng->sock. */
1289 sock = THREAD_FD(thread);
1290 ripng->t_read = NULL;
1291
1292 /* Add myself to the next event. */
1293 ripng_event(RIPNG_READ, sock);
1294
1295 /* Read RIPng packet. */
1296 len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
1297 STREAM_SIZE(ripng->ibuf), &from, &ifindex,
1298 &hoplimit);
1299 if (len < 0) {
1300 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno));
1301 return len;
1302 }
1303
1304 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1305 (4)) must be multiple size of one RTE size (20). */
1306 if (((len - 4) % 20) != 0) {
1307 zlog_warn("RIPng invalid packet size %d from %s", len,
1308 inet6_ntoa(from.sin6_addr));
1309 ripng_peer_bad_packet(&from);
1310 return 0;
1311 }
1312
1313 packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
1314 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
1315
1316 /* RIPng packet received. */
1317 if (IS_RIPNG_DEBUG_EVENT)
1318 zlog_debug("RIPng packet received from %s port %d on %s",
1319 inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
1320 ifp ? ifp->name : "unknown");
1321
1322 /* Logging before packet checking. */
1323 if (IS_RIPNG_DEBUG_RECV)
1324 ripng_packet_dump(packet, len, "RECV");
1325
1326 /* Packet comes from unknown interface. */
1327 if (ifp == NULL) {
1328 zlog_warn("RIPng packet comes from unknown interface %d",
1329 ifindex);
1330 return 0;
1331 }
1332
1333 /* Packet version mismatch checking. */
1334 if (packet->version != ripng->version) {
1335 zlog_warn(
1336 "RIPng packet version %d doesn't fit to my version %d",
1337 packet->version, ripng->version);
1338 ripng_peer_bad_packet(&from);
1339 return 0;
1340 }
1341
1342 /* Process RIPng packet. */
1343 switch (packet->command) {
1344 case RIPNG_REQUEST:
1345 ripng_request_process(packet, len, &from, ifp);
1346 break;
1347 case RIPNG_RESPONSE:
1348 ripng_response_process(packet, len, &from, ifp, hoplimit);
1349 break;
1350 default:
1351 zlog_warn("Invalid RIPng command %d", packet->command);
1352 ripng_peer_bad_packet(&from);
1353 break;
1354 }
1355 return 0;
1356}
1357
1358/* Walk down the RIPng routing table then clear changed flag. */
1359static void ripng_clear_changed_flag(void)
1360{
1361 struct agg_node *rp;
1362 struct ripng_info *rinfo = NULL;
1363 struct list *list = NULL;
1364 struct listnode *listnode = NULL;
1365
1366 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
1367 if ((list = rp->info) != NULL)
1368 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1369 UNSET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
1370 /* This flag can be set only on the first entry.
1371 */
1372 break;
1373 }
1374}
1375
1376/* Regular update of RIPng route. Send all routing formation to RIPng
1377 enabled interface. */
1378static int ripng_update(struct thread *t)
1379{
1380 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
1381 struct interface *ifp;
1382 struct ripng_interface *ri;
1383
1384 /* Clear update timer thread. */
1385 ripng->t_update = NULL;
1386
1387 /* Logging update event. */
1388 if (IS_RIPNG_DEBUG_EVENT)
1389 zlog_debug("RIPng update timer expired!");
1390
1391 /* Supply routes to each interface. */
1392 FOR_ALL_INTERFACES (vrf, ifp) {
1393 ri = ifp->info;
1394
1395 if (if_is_loopback(ifp) || !if_is_up(ifp))
1396 continue;
1397
1398 if (!ri->running)
1399 continue;
1400
1401 /* When passive interface is specified, suppress announce to the
1402 interface. */
1403 if (ri->passive)
1404 continue;
1405
1406#if RIPNG_ADVANCED
1407 if (ri->ri_send == RIPNG_SEND_OFF) {
1408 if (IS_RIPNG_DEBUG_EVENT)
1409 zlog_debug(
1410 "[Event] RIPng send to if %d is suppressed by config",
1411 ifp->ifindex);
1412 continue;
1413 }
1414#endif /* RIPNG_ADVANCED */
1415
1416 ripng_output_process(ifp, NULL, ripng_all_route);
1417 }
1418
1419 /* Triggered updates may be suppressed if a regular update is due by
1420 the time the triggered update would be sent. */
1421 if (ripng->t_triggered_interval) {
1422 thread_cancel(ripng->t_triggered_interval);
1423 ripng->t_triggered_interval = NULL;
1424 }
1425 ripng->trigger = 0;
1426
1427 /* Reset flush event. */
1428 ripng_event(RIPNG_UPDATE_EVENT, 0);
1429
1430 return 0;
1431}
1432
1433/* Triggered update interval timer. */
1434static int ripng_triggered_interval(struct thread *t)
1435{
1436 ripng->t_triggered_interval = NULL;
1437
1438 if (ripng->trigger) {
1439 ripng->trigger = 0;
1440 ripng_triggered_update(t);
1441 }
1442 return 0;
1443}
1444
1445/* Execute triggered update. */
1446int ripng_triggered_update(struct thread *t)
1447{
1448 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
1449 struct interface *ifp;
1450 struct ripng_interface *ri;
1451 int interval;
1452
1453 ripng->t_triggered_update = NULL;
1454
1455 /* Cancel interval timer. */
1456 if (ripng->t_triggered_interval) {
1457 thread_cancel(ripng->t_triggered_interval);
1458 ripng->t_triggered_interval = NULL;
1459 }
1460 ripng->trigger = 0;
1461
1462 /* Logging triggered update. */
1463 if (IS_RIPNG_DEBUG_EVENT)
1464 zlog_debug("RIPng triggered update!");
1465
1466 /* Split Horizon processing is done when generating triggered
1467 updates as well as normal updates (see section 2.6). */
1468 FOR_ALL_INTERFACES (vrf, ifp) {
1469 ri = ifp->info;
1470
1471 if (if_is_loopback(ifp) || !if_is_up(ifp))
1472 continue;
1473
1474 if (!ri->running)
1475 continue;
1476
1477 /* When passive interface is specified, suppress announce to the
1478 interface. */
1479 if (ri->passive)
1480 continue;
1481
1482 ripng_output_process(ifp, NULL, ripng_changed_route);
1483 }
1484
1485 /* Once all of the triggered updates have been generated, the route
1486 change flags should be cleared. */
1487 ripng_clear_changed_flag();
1488
1489 /* After a triggered update is sent, a timer should be set for a
1490 random interval between 1 and 5 seconds. If other changes that
1491 would trigger updates occur before the timer expires, a single
1492 update is triggered when the timer expires. */
1493 interval = (random() % 5) + 1;
1494
1495 ripng->t_triggered_interval = NULL;
1496 thread_add_timer(master, ripng_triggered_interval, NULL, interval,
1497 &ripng->t_triggered_interval);
1498
1499 return 0;
1500}
1501
1502/* Write routing table entry to the stream and return next index of
1503 the routing table entry in the stream. */
1504int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
1505 struct in6_addr *nexthop, uint16_t tag, uint8_t metric)
1506{
1507 /* RIPng packet header. */
1508 if (num == 0) {
1509 stream_putc(s, RIPNG_RESPONSE);
1510 stream_putc(s, RIPNG_V1);
1511 stream_putw(s, 0);
1512 }
1513
1514 /* Write routing table entry. */
1515 if (!nexthop) {
1516 assert(p);
1517 stream_write(s, (uint8_t *)&p->prefix, sizeof(struct in6_addr));
1518 } else
1519 stream_write(s, (uint8_t *)nexthop, sizeof(struct in6_addr));
1520 stream_putw(s, tag);
1521 if (p)
1522 stream_putc(s, p->prefixlen);
1523 else
1524 stream_putc(s, 0);
1525 stream_putc(s, metric);
1526
1527 return ++num;
1528}
1529
1530/* Send RESPONSE message to specified destination. */
1531void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
1532 int route_type)
1533{
1534 int ret;
1535 struct agg_node *rp;
1536 struct ripng_info *rinfo;
1537 struct ripng_interface *ri;
1538 struct ripng_aggregate *aggregate;
1539 struct prefix_ipv6 *p;
1540 struct list *ripng_rte_list;
1541 struct list *list = NULL;
1542 struct listnode *listnode = NULL;
1543
1544 if (IS_RIPNG_DEBUG_EVENT) {
1545 if (to)
1546 zlog_debug("RIPng update routes to neighbor %s",
1547 inet6_ntoa(to->sin6_addr));
1548 else
1549 zlog_debug("RIPng update routes on interface %s",
1550 ifp->name);
1551 }
1552
1553 /* Get RIPng interface. */
1554 ri = ifp->info;
1555
1556 ripng_rte_list = ripng_rte_new();
1557
1558 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
1559 if ((list = rp->info) != NULL
1560 && (rinfo = listgetdata(listhead(list))) != NULL
1561 && rinfo->suppress == 0) {
1562 /* If no route-map are applied, the RTE will be these
1563 * following
1564 * information.
1565 */
1566 p = (struct prefix_ipv6 *)&rp->p;
1567 rinfo->metric_out = rinfo->metric;
1568 rinfo->tag_out = rinfo->tag;
1569 memset(&rinfo->nexthop_out, 0,
1570 sizeof(rinfo->nexthop_out));
1571 /* In order to avoid some local loops,
1572 * if the RIPng route has a nexthop via this interface,
1573 * keep the nexthop,
1574 * otherwise set it to 0. The nexthop should not be
1575 * propagated
1576 * beyond the local broadcast/multicast area in order
1577 * to avoid an IGP multi-level recursive look-up.
1578 */
1579 if (rinfo->ifindex == ifp->ifindex)
1580 rinfo->nexthop_out = rinfo->nexthop;
1581
1582 /* Apply output filters. */
1583 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1584 if (ret < 0)
1585 continue;
1586
1587 /* Changed route only output. */
1588 if (route_type == ripng_changed_route
1589 && (!(rinfo->flags & RIPNG_RTF_CHANGED)))
1590 continue;
1591
1592 /* Split horizon. */
1593 if (ri->split_horizon == RIPNG_SPLIT_HORIZON) {
1594 /* We perform split horizon for RIPng routes. */
1595 int suppress = 0;
1596 struct ripng_info *tmp_rinfo = NULL;
1597
1598 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1599 tmp_rinfo))
1600 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG
1601 && tmp_rinfo->ifindex
1602 == ifp->ifindex) {
1603 suppress = 1;
1604 break;
1605 }
1606 if (suppress)
1607 continue;
1608 }
1609
1610 /* Preparation for route-map. */
1611 rinfo->metric_set = 0;
1612 /* nexthop_out,
1613 * metric_out
1614 * and tag_out are already initialized.
1615 */
1616
1617 /* Interface route-map */
1618 if (ri->routemap[RIPNG_FILTER_OUT]) {
1619 ret = route_map_apply(
1620 ri->routemap[RIPNG_FILTER_OUT],
1621 (struct prefix *)p, RMAP_RIPNG, rinfo);
1622
1623 if (ret == RMAP_DENYMATCH) {
1624 if (IS_RIPNG_DEBUG_PACKET)
1625 zlog_debug(
1626 "RIPng %s/%d is filtered by route-map out",
1627 inet6_ntoa(p->prefix),
1628 p->prefixlen);
1629 continue;
1630 }
1631 }
1632
1633 /* Redistribute route-map. */
1634 if (ripng->route_map[rinfo->type].name) {
1635 ret = route_map_apply(
1636 ripng->route_map[rinfo->type].map,
1637 (struct prefix *)p, RMAP_RIPNG, rinfo);
1638
1639 if (ret == RMAP_DENYMATCH) {
1640 if (IS_RIPNG_DEBUG_PACKET)
1641 zlog_debug(
1642 "RIPng %s/%d is filtered by route-map",
1643 inet6_ntoa(p->prefix),
1644 p->prefixlen);
1645 continue;
1646 }
1647 }
1648
1649 /* When the route-map does not set metric. */
1650 if (!rinfo->metric_set) {
1651 /* If the redistribute metric is set. */
1652 if (ripng->route_map[rinfo->type].metric_config
1653 && rinfo->metric != RIPNG_METRIC_INFINITY) {
1654 rinfo->metric_out =
1655 ripng->route_map[rinfo->type]
1656 .metric;
1657 } else {
1658 /* If the route is not connected or
1659 localy generated
1660 one, use default-metric value */
1661 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1662 && rinfo->type
1663 != ZEBRA_ROUTE_CONNECT
1664 && rinfo->metric
1665 != RIPNG_METRIC_INFINITY)
1666 rinfo->metric_out =
1667 ripng->default_metric;
1668 }
1669 }
1670
1671 /* Apply offset-list */
1672 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1673 ripng_offset_list_apply_out(p, ifp,
1674 &rinfo->metric_out);
1675
1676 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1677 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1678
1679 /* Perform split-horizon with poisoned reverse
1680 * for RIPng routes.
1681 **/
1682 if (ri->split_horizon
1683 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1684 struct ripng_info *tmp_rinfo = NULL;
1685
1686 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1687 tmp_rinfo))
1688 if ((tmp_rinfo->type
1689 == ZEBRA_ROUTE_RIPNG)
1690 && tmp_rinfo->ifindex
1691 == ifp->ifindex)
1692 rinfo->metric_out =
1693 RIPNG_METRIC_INFINITY;
1694 }
1695
1696 /* Add RTE to the list */
1697 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
1698 }
1699
1700 /* Process the aggregated RTE entry */
1701 if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0
1702 && aggregate->suppress == 0) {
1703 /* If no route-map are applied, the RTE will be these
1704 * following
1705 * information.
1706 */
1707 p = (struct prefix_ipv6 *)&rp->p;
1708 aggregate->metric_set = 0;
1709 aggregate->metric_out = aggregate->metric;
1710 aggregate->tag_out = aggregate->tag;
1711 memset(&aggregate->nexthop_out, 0,
1712 sizeof(aggregate->nexthop_out));
1713
1714 /* Apply output filters.*/
1715 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1716 if (ret < 0)
1717 continue;
1718
1719 /* Interface route-map */
1720 if (ri->routemap[RIPNG_FILTER_OUT]) {
1721 struct ripng_info newinfo;
1722
1723 /* let's cast the aggregate structure to
1724 * ripng_info */
1725 memset(&newinfo, 0, sizeof(struct ripng_info));
1726 /* the nexthop is :: */
1727 newinfo.metric = aggregate->metric;
1728 newinfo.metric_out = aggregate->metric_out;
1729 newinfo.tag = aggregate->tag;
1730 newinfo.tag_out = aggregate->tag_out;
1731
1732 ret = route_map_apply(
1733 ri->routemap[RIPNG_FILTER_OUT],
1734 (struct prefix *)p, RMAP_RIPNG,
1735 &newinfo);
1736
1737 if (ret == RMAP_DENYMATCH) {
1738 if (IS_RIPNG_DEBUG_PACKET)
1739 zlog_debug(
1740 "RIPng %s/%d is filtered by route-map out",
1741 inet6_ntoa(p->prefix),
1742 p->prefixlen);
1743 continue;
1744 }
1745
1746 aggregate->metric_out = newinfo.metric_out;
1747 aggregate->tag_out = newinfo.tag_out;
1748 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1749 aggregate->nexthop_out =
1750 newinfo.nexthop_out;
1751 }
1752
1753 /* There is no redistribute routemap for the aggregated
1754 * RTE */
1755
1756 /* Changed route only output. */
1757 /* XXX, vincent, in order to increase time convergence,
1758 * it should be announced if a child has changed.
1759 */
1760 if (route_type == ripng_changed_route)
1761 continue;
1762
1763 /* Apply offset-list */
1764 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1765 ripng_offset_list_apply_out(
1766 p, ifp, &aggregate->metric_out);
1767
1768 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1769 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1770
1771 /* Add RTE to the list */
1772 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
1773 }
1774 }
1775
1776 /* Flush the list */
1777 ripng_rte_send(ripng_rte_list, ifp, to);
1778 ripng_rte_free(ripng_rte_list);
1779}
1780
1781/* Create new RIPng instance and set it to global variable. */
1782int ripng_create(int socket)
1783{
1784 /* ripng should be NULL. */
1785 assert(ripng == NULL);
1786
1787 /* Allocaste RIPng instance. */
1788 ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
1789
1790 /* Default version and timer values. */
1791 ripng->version = RIPNG_V1;
1792 ripng->update_time = yang_get_default_uint32(
1793 "%s/timers/update-interval", RIPNG_INSTANCE);
1794 ripng->timeout_time = yang_get_default_uint32(
1795 "%s/timers/holddown-interval", RIPNG_INSTANCE);
1796 ripng->garbage_time = yang_get_default_uint32(
1797 "%s/timers/flush-interval", RIPNG_INSTANCE);
1798 ripng->default_metric =
1799 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE);
1800 ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE);
1801
1802 /* Make buffer. */
1803 ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
1804 ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
1805
1806 /* Initialize RIPng routig table. */
1807 ripng->table = agg_table_init();
1808
1809 /* Make socket. */
1810 ripng->sock = socket;
1811
1812 /* Threads. */
1813 ripng_event(RIPNG_READ, ripng->sock);
1814 ripng_event(RIPNG_UPDATE_EVENT, 1);
1815
1816 return 0;
1817}
1818
1819/* Send RIPng request to the interface. */
1820int ripng_request(struct interface *ifp)
1821{
1822 struct rte *rte;
1823 struct ripng_packet ripng_packet;
1824
1825 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1826 */
1827 if (if_is_loopback(ifp))
1828 return 0;
1829
1830 /* If interface is down, don't send RIP packet. */
1831 if (!if_is_up(ifp))
1832 return 0;
1833
1834 if (IS_RIPNG_DEBUG_EVENT)
1835 zlog_debug("RIPng send request to %s", ifp->name);
1836
1837 memset(&ripng_packet, 0, sizeof(ripng_packet));
1838 ripng_packet.command = RIPNG_REQUEST;
1839 ripng_packet.version = RIPNG_V1;
1840 rte = ripng_packet.rte;
1841 rte->metric = RIPNG_METRIC_INFINITY;
1842
1843 return ripng_send_packet((caddr_t)&ripng_packet, sizeof(ripng_packet),
1844 NULL, ifp);
1845}
1846
1847
1848static int ripng_update_jitter(int time)
1849{
1850 return ((random() % (time + 1)) - (time / 2));
1851}
1852
1853void ripng_event(enum ripng_event event, int sock)
1854{
1855 int jitter = 0;
1856
1857 switch (event) {
1858 case RIPNG_READ:
1859 thread_add_read(master, ripng_read, NULL, sock, &ripng->t_read);
1860 break;
1861 case RIPNG_UPDATE_EVENT:
1862 if (ripng->t_update) {
1863 thread_cancel(ripng->t_update);
1864 ripng->t_update = NULL;
1865 }
1866 /* Update timer jitter. */
1867 jitter = ripng_update_jitter(ripng->update_time);
1868
1869 ripng->t_update = NULL;
1870 thread_add_timer(master, ripng_update, NULL,
1871 sock ? 2 : ripng->update_time + jitter,
1872 &ripng->t_update);
1873 break;
1874 case RIPNG_TRIGGERED_UPDATE:
1875 if (ripng->t_triggered_interval)
1876 ripng->trigger = 1;
1877 else
1878 thread_add_event(master, ripng_triggered_update, NULL,
1879 0, &ripng->t_triggered_update);
1880 break;
1881 default:
1882 break;
1883 }
1884}
1885
1886
1887/* Print out routes update time. */
1888static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
1889{
1890 time_t clock;
1891 struct tm *tm;
1892#define TIME_BUF 25
1893 char timebuf[TIME_BUF];
1894 struct thread *thread;
1895
1896 if ((thread = rinfo->t_timeout) != NULL) {
1897 clock = thread_timer_remain_second(thread);
1898 tm = gmtime(&clock);
1899 strftime(timebuf, TIME_BUF, "%M:%S", tm);
1900 vty_out(vty, "%5s", timebuf);
1901 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
1902 clock = thread_timer_remain_second(thread);
1903 tm = gmtime(&clock);
1904 strftime(timebuf, TIME_BUF, "%M:%S", tm);
1905 vty_out(vty, "%5s", timebuf);
1906 }
1907}
1908
1909static char *ripng_route_subtype_print(struct ripng_info *rinfo)
1910{
1911 static char str[3];
1912 memset(str, 0, 3);
1913
1914 if (rinfo->suppress)
1915 strcat(str, "S");
1916
1917 switch (rinfo->sub_type) {
1918 case RIPNG_ROUTE_RTE:
1919 strcat(str, "n");
1920 break;
1921 case RIPNG_ROUTE_STATIC:
1922 strcat(str, "s");
1923 break;
1924 case RIPNG_ROUTE_DEFAULT:
1925 strcat(str, "d");
1926 break;
1927 case RIPNG_ROUTE_REDISTRIBUTE:
1928 strcat(str, "r");
1929 break;
1930 case RIPNG_ROUTE_INTERFACE:
1931 strcat(str, "i");
1932 break;
1933 default:
1934 strcat(str, "?");
1935 break;
1936 }
1937
1938 return str;
1939}
1940
1941DEFUN (show_ipv6_ripng,
1942 show_ipv6_ripng_cmd,
1943 "show ipv6 ripng",
1944 SHOW_STR
1945 IPV6_STR
1946 "Show RIPng routes\n")
1947{
1948 struct agg_node *rp;
1949 struct ripng_info *rinfo;
1950 struct ripng_aggregate *aggregate;
1951 struct prefix_ipv6 *p;
1952 struct list *list = NULL;
1953 struct listnode *listnode = NULL;
1954 int len;
1955
1956 if (!ripng)
1957 return CMD_SUCCESS;
1958
1959 /* Header of display. */
1960 vty_out(vty,
1961 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1962 "Sub-codes:\n"
1963 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1964 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1965 " Network Next Hop Via Metric Tag Time\n");
1966
1967 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
1968 if ((aggregate = rp->aggregate) != NULL) {
1969 p = (struct prefix_ipv6 *)&rp->p;
1970
1971#ifdef DEBUG
1972 vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count,
1973 aggregate->suppress, inet6_ntoa(p->prefix),
1974 p->prefixlen);
1975#else
1976 vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix),
1977 p->prefixlen);
1978#endif /* DEBUG */
1979 vty_out(vty, "\n");
1980 vty_out(vty, "%*s", 18, " ");
1981
1982 vty_out(vty, "%*s", 28, " ");
1983 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "\n",
1984 aggregate->metric, (route_tag_t)aggregate->tag);
1985 }
1986
1987 if ((list = rp->info) != NULL)
1988 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1989 p = (struct prefix_ipv6 *)&rp->p;
1990
1991#ifdef DEBUG
1992 vty_out(vty, "%c(%s) 0/%d %s/%d ",
1993 zebra_route_char(rinfo->type),
1994 ripng_route_subtype_print(rinfo),
1995 rinfo->suppress, inet6_ntoa(p->prefix),
1996 p->prefixlen);
1997#else
1998 vty_out(vty, "%c(%s) %s/%d ",
1999 zebra_route_char(rinfo->type),
2000 ripng_route_subtype_print(rinfo),
2001 inet6_ntoa(p->prefix), p->prefixlen);
2002#endif /* DEBUG */
2003 vty_out(vty, "\n");
2004 vty_out(vty, "%*s", 18, " ");
2005 len = vty_out(vty, "%s",
2006 inet6_ntoa(rinfo->nexthop));
2007
2008 len = 28 - len;
2009 if (len > 0)
2010 vty_out(vty, "%*s", len, " ");
2011
2012 /* from */
2013 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2014 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2015 len = vty_out(
2016 vty, "%s",
2017 ifindex2ifname(rinfo->ifindex,
2018 VRF_DEFAULT));
2019 } else if (rinfo->metric
2020 == RIPNG_METRIC_INFINITY) {
2021 len = vty_out(vty, "kill");
2022 } else
2023 len = vty_out(vty, "self");
2024
2025 len = 9 - len;
2026 if (len > 0)
2027 vty_out(vty, "%*s", len, " ");
2028
2029 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2030 rinfo->metric, (route_tag_t)rinfo->tag);
2031
2032 /* time */
2033 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2034 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2035 /* RTE from remote RIP routers */
2036 ripng_vty_out_uptime(vty, rinfo);
2037 } else if (rinfo->metric
2038 == RIPNG_METRIC_INFINITY) {
2039 /* poisonous reversed routes (gc) */
2040 ripng_vty_out_uptime(vty, rinfo);
2041 }
2042
2043 vty_out(vty, "\n");
2044 }
2045 }
2046
2047 return CMD_SUCCESS;
2048}
2049
2050DEFUN (show_ipv6_ripng_status,
2051 show_ipv6_ripng_status_cmd,
2052 "show ipv6 ripng status",
2053 SHOW_STR
2054 IPV6_STR
2055 "Show RIPng routes\n"
2056 "IPv6 routing protocol process parameters and statistics\n")
2057{
2058 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2059 struct interface *ifp;
2060
2061 if (!ripng)
2062 return CMD_SUCCESS;
2063
2064 vty_out(vty, "Routing Protocol is \"RIPng\"\n");
2065 vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
2066 ripng->update_time);
2067 vty_out(vty, " next due in %lu seconds\n",
2068 thread_timer_remain_second(ripng->t_update));
2069 vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time);
2070 vty_out(vty, " garbage collect after %u seconds\n",
2071 ripng->garbage_time);
2072
2073 /* Filtering status show. */
2074 config_show_distribute(vty);
2075
2076 /* Default metric information. */
2077 vty_out(vty, " Default redistribution metric is %d\n",
2078 ripng->default_metric);
2079
2080 /* Redistribute information. */
2081 vty_out(vty, " Redistributing:");
2082 ripng_redistribute_write(vty);
2083 vty_out(vty, "\n");
2084
2085 vty_out(vty, " Default version control: send version %d,",
2086 ripng->version);
2087 vty_out(vty, " receive version %d \n", ripng->version);
2088
2089 vty_out(vty, " Interface Send Recv\n");
2090
2091 FOR_ALL_INTERFACES (vrf, ifp) {
2092 struct ripng_interface *ri;
2093
2094 ri = ifp->info;
2095
2096 if (ri->enable_network || ri->enable_interface) {
2097
2098 vty_out(vty, " %-17s%-3d %-3d\n", ifp->name,
2099 ripng->version, ripng->version);
2100 }
2101 }
2102
2103 vty_out(vty, " Routing for Networks:\n");
2104 ripng_network_write(vty);
2105
2106 vty_out(vty, " Routing Information Sources:\n");
2107 vty_out(vty,
2108 " Gateway BadPackets BadRoutes Distance Last Update\n");
2109 ripng_peer_display(vty);
2110
2111 return CMD_SUCCESS;
2112}
2113
2114#if 0
2115/* RIPng update timer setup. */
2116DEFUN (ripng_update_timer,
2117 ripng_update_timer_cmd,
2118 "update-timer SECOND",
2119 "Set RIPng update timer in seconds\n"
2120 "Seconds\n")
2121{
2122 unsigned long update;
2123 char *endptr = NULL;
2124
2125 update = strtoul (argv[0], &endptr, 10);
2126 if (update == ULONG_MAX || *endptr != '\0')
2127 {
2128 vty_out (vty, "update timer value error\n");
2129 return CMD_WARNING_CONFIG_FAILED;
2130 }
2131
2132 ripng->update_time = update;
2133
2134 ripng_event (RIPNG_UPDATE_EVENT, 0);
2135 return CMD_SUCCESS;
2136}
2137
2138DEFUN (no_ripng_update_timer,
2139 no_ripng_update_timer_cmd,
2140 "no update-timer SECOND",
2141 NO_STR
2142 "Unset RIPng update timer in seconds\n"
2143 "Seconds\n")
2144{
2145 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2146 ripng_event (RIPNG_UPDATE_EVENT, 0);
2147 return CMD_SUCCESS;
2148}
2149
2150/* RIPng timeout timer setup. */
2151DEFUN (ripng_timeout_timer,
2152 ripng_timeout_timer_cmd,
2153 "timeout-timer SECOND",
2154 "Set RIPng timeout timer in seconds\n"
2155 "Seconds\n")
2156{
2157 unsigned long timeout;
2158 char *endptr = NULL;
2159
2160 timeout = strtoul (argv[0], &endptr, 10);
2161 if (timeout == ULONG_MAX || *endptr != '\0')
2162 {
2163 vty_out (vty, "timeout timer value error\n");
2164 return CMD_WARNING_CONFIG_FAILED;
2165 }
2166
2167 ripng->timeout_time = timeout;
2168
2169 return CMD_SUCCESS;
2170}
2171
2172DEFUN (no_ripng_timeout_timer,
2173 no_ripng_timeout_timer_cmd,
2174 "no timeout-timer SECOND",
2175 NO_STR
2176 "Unset RIPng timeout timer in seconds\n"
2177 "Seconds\n")
2178{
2179 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2180 return CMD_SUCCESS;
2181}
2182
2183/* RIPng garbage timer setup. */
2184DEFUN (ripng_garbage_timer,
2185 ripng_garbage_timer_cmd,
2186 "garbage-timer SECOND",
2187 "Set RIPng garbage timer in seconds\n"
2188 "Seconds\n")
2189{
2190 unsigned long garbage;
2191 char *endptr = NULL;
2192
2193 garbage = strtoul (argv[0], &endptr, 10);
2194 if (garbage == ULONG_MAX || *endptr != '\0')
2195 {
2196 vty_out (vty, "garbage timer value error\n");
2197 return CMD_WARNING_CONFIG_FAILED;
2198 }
2199
2200 ripng->garbage_time = garbage;
2201
2202 return CMD_SUCCESS;
2203}
2204
2205DEFUN (no_ripng_garbage_timer,
2206 no_ripng_garbage_timer_cmd,
2207 "no garbage-timer SECOND",
2208 NO_STR
2209 "Unset RIPng garbage timer in seconds\n"
2210 "Seconds\n")
2211{
2212 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2213 return CMD_SUCCESS;
2214}
2215#endif /* 0 */
2216
2217#if 0
2218DEFUN (show_ipv6_protocols,
2219 show_ipv6_protocols_cmd,
2220 "show ipv6 protocols",
2221 SHOW_STR
2222 IPV6_STR
2223 "Routing protocol information\n")
2224{
2225 if (! ripng)
2226 return CMD_SUCCESS;
2227
2228 vty_out (vty, "Routing Protocol is \"ripng\"\n");
2229
2230 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds\n",
2231 ripng->update_time, 0);
2232
2233 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld\n",
2234 ripng->timeout_time,
2235 ripng->garbage_time);
2236
2237 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2238 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2239
2240 return CMD_SUCCESS;
2241}
2242#endif
2243
2244/* Update ECMP routes to zebra when ECMP is disabled. */
2245void ripng_ecmp_disable(void)
2246{
2247 struct agg_node *rp;
2248 struct ripng_info *rinfo, *tmp_rinfo;
2249 struct list *list;
2250 struct listnode *node, *nextnode;
2251
2252 if (!ripng)
2253 return;
2254
2255 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
2256 if ((list = rp->info) != NULL && listcount(list) > 1) {
2257 rinfo = listgetdata(listhead(list));
2258 if (!ripng_route_rte(rinfo))
2259 continue;
2260
2261 /* Drop all other entries, except the first one. */
2262 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2263 if (tmp_rinfo != rinfo) {
2264 RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
2265 RIPNG_TIMER_OFF(
2266 tmp_rinfo->t_garbage_collect);
2267 list_delete_node(list, node);
2268 ripng_info_free(tmp_rinfo);
2269 }
2270
2271 /* Update zebra. */
2272 ripng_zebra_ipv6_add(rp);
2273
2274 /* Set the route change flag. */
2275 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2276
2277 /* Signal the output process to trigger an update. */
2278 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
2279 }
2280}
2281
2282/* RIPng configuration write function. */
2283static int ripng_config_write(struct vty *vty)
2284{
2285 struct lyd_node *dnode;
2286 int write = 0;
2287
2288 dnode = yang_dnode_get(running_config->dnode,
2289 "/frr-ripngd:ripngd/instance");
2290 if (dnode) {
2291 nb_cli_show_dnode_cmds(vty, dnode, false);
2292
2293 config_write_distribute(vty);
2294
2295 config_write_if_rmap(vty);
2296
2297 write = 1;
2298 }
2299
2300 return write;
2301}
2302
2303/* RIPng node structure. */
2304static struct cmd_node cmd_ripng_node = {
2305 RIPNG_NODE, "%s(config-router)# ", 1,
2306};
2307
2308static void ripng_distribute_update(struct distribute *dist)
2309{
2310 struct interface *ifp;
2311 struct ripng_interface *ri;
2312 struct access_list *alist;
2313 struct prefix_list *plist;
2314
2315 if (!dist->ifname)
2316 return;
2317
2318 ifp = if_lookup_by_name(dist->ifname, VRF_DEFAULT);
2319 if (ifp == NULL)
2320 return;
2321
2322 ri = ifp->info;
2323
2324 if (dist->list[DISTRIBUTE_V6_IN]) {
2325 alist = access_list_lookup(AFI_IP6,
2326 dist->list[DISTRIBUTE_V6_IN]);
2327 if (alist)
2328 ri->list[RIPNG_FILTER_IN] = alist;
2329 else
2330 ri->list[RIPNG_FILTER_IN] = NULL;
2331 } else
2332 ri->list[RIPNG_FILTER_IN] = NULL;
2333
2334 if (dist->list[DISTRIBUTE_V6_OUT]) {
2335 alist = access_list_lookup(AFI_IP6,
2336 dist->list[DISTRIBUTE_V6_OUT]);
2337 if (alist)
2338 ri->list[RIPNG_FILTER_OUT] = alist;
2339 else
2340 ri->list[RIPNG_FILTER_OUT] = NULL;
2341 } else
2342 ri->list[RIPNG_FILTER_OUT] = NULL;
2343
2344 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2345 plist = prefix_list_lookup(AFI_IP6,
2346 dist->prefix[DISTRIBUTE_V6_IN]);
2347 if (plist)
2348 ri->prefix[RIPNG_FILTER_IN] = plist;
2349 else
2350 ri->prefix[RIPNG_FILTER_IN] = NULL;
2351 } else
2352 ri->prefix[RIPNG_FILTER_IN] = NULL;
2353
2354 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2355 plist = prefix_list_lookup(AFI_IP6,
2356 dist->prefix[DISTRIBUTE_V6_OUT]);
2357 if (plist)
2358 ri->prefix[RIPNG_FILTER_OUT] = plist;
2359 else
2360 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2361 } else
2362 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2363}
2364
2365void ripng_distribute_update_interface(struct interface *ifp)
2366{
2367 struct distribute *dist;
2368
2369 dist = distribute_lookup(ifp->name);
2370 if (dist)
2371 ripng_distribute_update(dist);
2372}
2373
2374/* Update all interface's distribute list. */
2375static void ripng_distribute_update_all(struct prefix_list *notused)
2376{
2377 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2378 struct interface *ifp;
2379
2380 FOR_ALL_INTERFACES (vrf, ifp)
2381 ripng_distribute_update_interface(ifp);
2382}
2383
2384static void ripng_distribute_update_all_wrapper(struct access_list *notused)
2385{
2386 ripng_distribute_update_all(NULL);
2387}
2388
2389/* delete all the added ripng routes. */
2390void ripng_clean()
2391{
2392 int i;
2393 struct agg_node *rp;
2394 struct ripng_info *rinfo;
2395 struct ripng_aggregate *aggregate;
2396 struct list *list = NULL;
2397 struct listnode *listnode = NULL;
2398
2399 if (ripng) {
2400 /* Clear RIPng routes */
2401 for (rp = agg_route_top(ripng->table); rp;
2402 rp = agg_route_next(rp)) {
2403 if ((list = rp->info) != NULL) {
2404 rinfo = listgetdata(listhead(list));
2405 if (ripng_route_rte(rinfo))
2406 ripng_zebra_ipv6_delete(rp);
2407
2408 for (ALL_LIST_ELEMENTS_RO(list, listnode,
2409 rinfo)) {
2410 RIPNG_TIMER_OFF(rinfo->t_timeout);
2411 RIPNG_TIMER_OFF(
2412 rinfo->t_garbage_collect);
2413 ripng_info_free(rinfo);
2414 }
2415 list_delete(&list);
2416 rp->info = NULL;
2417 agg_unlock_node(rp);
2418 }
2419
2420 if ((aggregate = rp->aggregate) != NULL) {
2421 ripng_aggregate_free(aggregate);
2422 rp->aggregate = NULL;
2423 agg_unlock_node(rp);
2424 }
2425 }
2426
2427 /* Cancel the RIPng timers */
2428 RIPNG_TIMER_OFF(ripng->t_update);
2429 RIPNG_TIMER_OFF(ripng->t_triggered_update);
2430 RIPNG_TIMER_OFF(ripng->t_triggered_interval);
2431
2432 /* Cancel the read thread */
2433 if (ripng->t_read) {
2434 thread_cancel(ripng->t_read);
2435 ripng->t_read = NULL;
2436 }
2437
2438 /* Close the RIPng socket */
2439 if (ripng->sock >= 0) {
2440 close(ripng->sock);
2441 ripng->sock = -1;
2442 }
2443
2444 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2445 if (ripng->route_map[i].name)
2446 free(ripng->route_map[i].name);
2447
2448 agg_table_finish(ripng->table);
2449
2450 stream_free(ripng->ibuf);
2451 stream_free(ripng->obuf);
2452
2453 XFREE(MTYPE_RIPNG, ripng);
2454 ripng = NULL;
2455 } /* if (ripng) */
2456
2457 ripng_clean_network();
2458 ripng_passive_interface_clean();
2459 ripng_offset_clean();
2460 ripng_interface_clean();
2461 ripng_redistribute_clean();
2462}
2463
2464static void ripng_if_rmap_update(struct if_rmap *if_rmap)
2465{
2466 struct interface *ifp;
2467 struct ripng_interface *ri;
2468 struct route_map *rmap;
2469
2470 ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT);
2471 if (ifp == NULL)
2472 return;
2473
2474 ri = ifp->info;
2475
2476 if (if_rmap->routemap[IF_RMAP_IN]) {
2477 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2478 if (rmap)
2479 ri->routemap[IF_RMAP_IN] = rmap;
2480 else
2481 ri->routemap[IF_RMAP_IN] = NULL;
2482 } else
2483 ri->routemap[RIPNG_FILTER_IN] = NULL;
2484
2485 if (if_rmap->routemap[IF_RMAP_OUT]) {
2486 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2487 if (rmap)
2488 ri->routemap[IF_RMAP_OUT] = rmap;
2489 else
2490 ri->routemap[IF_RMAP_OUT] = NULL;
2491 } else
2492 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2493}
2494
2495void ripng_if_rmap_update_interface(struct interface *ifp)
2496{
2497 struct if_rmap *if_rmap;
2498
2499 if_rmap = if_rmap_lookup(ifp->name);
2500 if (if_rmap)
2501 ripng_if_rmap_update(if_rmap);
2502}
2503
2504static void ripng_routemap_update_redistribute(void)
2505{
2506 int i;
2507
2508 if (ripng) {
2509 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2510 if (ripng->route_map[i].name)
2511 ripng->route_map[i].map =
2512 route_map_lookup_by_name(
2513 ripng->route_map[i].name);
2514 }
2515 }
2516}
2517
2518static void ripng_routemap_update(const char *unused)
2519{
2520 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2521 struct interface *ifp;
2522
2523 FOR_ALL_INTERFACES (vrf, ifp)
2524 ripng_if_rmap_update_interface(ifp);
2525
2526 ripng_routemap_update_redistribute();
2527}
2528
2529/* Initialize ripng structure and set commands. */
2530void ripng_init()
2531{
2532 /* Install RIPNG_NODE. */
2533 install_node(&cmd_ripng_node, ripng_config_write);
2534
2535 /* Install ripng commands. */
2536 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2537 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
2538
2539 install_default(RIPNG_NODE);
2540
2541#if 0
2542 install_element (VIEW_NODE, &show_ipv6_protocols_cmd);
2543 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2544 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2545 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2546 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2547 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2548 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2549#endif /* 0 */
2550
2551 ripng_if_init();
2552 ripng_debug_init();
2553
2554 /* Access list install. */
2555 access_list_init();
2556 access_list_add_hook(ripng_distribute_update_all_wrapper);
2557 access_list_delete_hook(ripng_distribute_update_all_wrapper);
2558
2559 /* Prefix list initialize.*/
2560 prefix_list_init();
2561 prefix_list_add_hook(ripng_distribute_update_all);
2562 prefix_list_delete_hook(ripng_distribute_update_all);
2563
2564 /* Distribute list install. */
2565 distribute_list_init(RIPNG_NODE);
2566 distribute_list_add_hook(ripng_distribute_update);
2567 distribute_list_delete_hook(ripng_distribute_update);
2568
2569 /* Route-map for interface. */
2570 ripng_route_map_init();
2571 ripng_offset_init();
2572
2573 route_map_add_hook(ripng_routemap_update);
2574 route_map_delete_hook(ripng_routemap_update);
2575
2576 if_rmap_init(RIPNG_NODE);
2577 if_rmap_hook_add(ripng_if_rmap_update);
2578 if_rmap_hook_delete(ripng_if_rmap_update);
2579}