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