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