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