]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripngd.c
Merge pull request #12933 from Orange-OpenSource/link_state
[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 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
2235 vty_out(vty, "exit\n");
2236
2237 write = 1;
2238 }
2239
2240 return write;
2241 }
2242
2243 static int ripng_config_write(struct vty *vty);
2244 /* RIPng node structure. */
2245 static struct cmd_node cmd_ripng_node = {
2246 .name = "ripng",
2247 .node = RIPNG_NODE,
2248 .parent_node = CONFIG_NODE,
2249 .prompt = "%s(config-router)# ",
2250 .config_write = ripng_config_write,
2251 };
2252
2253 static void ripng_distribute_update(struct distribute_ctx *ctx,
2254 struct distribute *dist)
2255 {
2256 struct interface *ifp;
2257 struct ripng_interface *ri;
2258 struct access_list *alist;
2259 struct prefix_list *plist;
2260
2261 if (!ctx->vrf || !dist->ifname)
2262 return;
2263
2264 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
2265 if (ifp == NULL)
2266 return;
2267
2268 ri = ifp->info;
2269
2270 if (dist->list[DISTRIBUTE_V6_IN]) {
2271 alist = access_list_lookup(AFI_IP6,
2272 dist->list[DISTRIBUTE_V6_IN]);
2273 if (alist)
2274 ri->list[RIPNG_FILTER_IN] = alist;
2275 else
2276 ri->list[RIPNG_FILTER_IN] = NULL;
2277 } else
2278 ri->list[RIPNG_FILTER_IN] = NULL;
2279
2280 if (dist->list[DISTRIBUTE_V6_OUT]) {
2281 alist = access_list_lookup(AFI_IP6,
2282 dist->list[DISTRIBUTE_V6_OUT]);
2283 if (alist)
2284 ri->list[RIPNG_FILTER_OUT] = alist;
2285 else
2286 ri->list[RIPNG_FILTER_OUT] = NULL;
2287 } else
2288 ri->list[RIPNG_FILTER_OUT] = NULL;
2289
2290 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2291 plist = prefix_list_lookup(AFI_IP6,
2292 dist->prefix[DISTRIBUTE_V6_IN]);
2293 if (plist)
2294 ri->prefix[RIPNG_FILTER_IN] = plist;
2295 else
2296 ri->prefix[RIPNG_FILTER_IN] = NULL;
2297 } else
2298 ri->prefix[RIPNG_FILTER_IN] = NULL;
2299
2300 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2301 plist = prefix_list_lookup(AFI_IP6,
2302 dist->prefix[DISTRIBUTE_V6_OUT]);
2303 if (plist)
2304 ri->prefix[RIPNG_FILTER_OUT] = plist;
2305 else
2306 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2307 } else
2308 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2309 }
2310
2311 void ripng_distribute_update_interface(struct interface *ifp)
2312 {
2313 struct ripng_interface *ri = ifp->info;
2314 struct ripng *ripng = ri->ripng;
2315 struct distribute *dist;
2316
2317 if (!ripng)
2318 return;
2319 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
2320 if (dist)
2321 ripng_distribute_update(ripng->distribute_ctx, dist);
2322 }
2323
2324 /* Update all interface's distribute list. */
2325 static void ripng_distribute_update_all(struct prefix_list *notused)
2326 {
2327 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2328 struct interface *ifp;
2329
2330 FOR_ALL_INTERFACES (vrf, ifp)
2331 ripng_distribute_update_interface(ifp);
2332 }
2333
2334 static void ripng_distribute_update_all_wrapper(struct access_list *notused)
2335 {
2336 ripng_distribute_update_all(NULL);
2337 }
2338
2339 /* delete all the added ripng routes. */
2340 void ripng_clean(struct ripng *ripng)
2341 {
2342 ripng_interface_clean(ripng);
2343
2344 if (ripng->enabled)
2345 ripng_instance_disable(ripng);
2346
2347 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
2348 if (ripng->redist[i].route_map.name)
2349 free(ripng->redist[i].route_map.name);
2350
2351 agg_table_finish(ripng->table);
2352 list_delete(&ripng->peer_list);
2353 distribute_list_delete(&ripng->distribute_ctx);
2354 if_rmap_ctx_delete(ripng->if_rmap_ctx);
2355
2356 stream_free(ripng->ibuf);
2357 stream_free(ripng->obuf);
2358
2359 ripng_clean_network(ripng);
2360 ripng_passive_interface_clean(ripng);
2361 vector_free(ripng->enable_if);
2362 agg_table_finish(ripng->enable_network);
2363 vector_free(ripng->passive_interface);
2364 list_delete(&ripng->offset_list_master);
2365
2366 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2367 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
2368 XFREE(MTYPE_RIPNG, ripng);
2369 }
2370
2371 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2372 struct if_rmap *if_rmap)
2373 {
2374 struct interface *ifp = NULL;
2375 struct ripng_interface *ri;
2376 struct route_map *rmap;
2377 struct vrf *vrf = NULL;
2378
2379 if (ctx->name)
2380 vrf = vrf_lookup_by_name(ctx->name);
2381 if (vrf)
2382 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
2383 if (ifp == NULL)
2384 return;
2385
2386 ri = ifp->info;
2387
2388 if (if_rmap->routemap[IF_RMAP_IN]) {
2389 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2390 if (rmap)
2391 ri->routemap[IF_RMAP_IN] = rmap;
2392 else
2393 ri->routemap[IF_RMAP_IN] = NULL;
2394 } else
2395 ri->routemap[RIPNG_FILTER_IN] = NULL;
2396
2397 if (if_rmap->routemap[IF_RMAP_OUT]) {
2398 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2399 if (rmap)
2400 ri->routemap[IF_RMAP_OUT] = rmap;
2401 else
2402 ri->routemap[IF_RMAP_OUT] = NULL;
2403 } else
2404 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2405 }
2406
2407 void ripng_if_rmap_update_interface(struct interface *ifp)
2408 {
2409 struct ripng_interface *ri = ifp->info;
2410 struct ripng *ripng = ri->ripng;
2411 struct if_rmap *if_rmap;
2412 struct if_rmap_ctx *ctx;
2413
2414 if (!ripng)
2415 return;
2416 ctx = ripng->if_rmap_ctx;
2417 if (!ctx)
2418 return;
2419 if_rmap = if_rmap_lookup(ctx, ifp->name);
2420 if (if_rmap)
2421 ripng_if_rmap_update(ctx, if_rmap);
2422 }
2423
2424 static void ripng_routemap_update_redistribute(struct ripng *ripng)
2425 {
2426 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2427 if (ripng->redist[i].route_map.name) {
2428 ripng->redist[i].route_map.map =
2429 route_map_lookup_by_name(
2430 ripng->redist[i].route_map.name);
2431 route_map_counter_increment(
2432 ripng->redist[i].route_map.map);
2433 }
2434 }
2435 }
2436
2437 static void ripng_routemap_update(const char *unused)
2438 {
2439 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2440 struct ripng *ripng;
2441 struct interface *ifp;
2442
2443 FOR_ALL_INTERFACES (vrf, ifp)
2444 ripng_if_rmap_update_interface(ifp);
2445
2446 ripng = vrf->info;
2447 if (ripng)
2448 ripng_routemap_update_redistribute(ripng);
2449 }
2450
2451 /* Link RIPng instance to VRF. */
2452 static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2453 {
2454 struct interface *ifp;
2455
2456 ripng->vrf = vrf;
2457 ripng->distribute_ctx->vrf = vrf;
2458 vrf->info = ripng;
2459
2460 FOR_ALL_INTERFACES (vrf, ifp)
2461 ripng_interface_sync(ifp);
2462 }
2463
2464 /* Unlink RIPng instance from VRF. */
2465 static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2466 {
2467 struct interface *ifp;
2468
2469 ripng->vrf = NULL;
2470 ripng->distribute_ctx->vrf = NULL;
2471 vrf->info = NULL;
2472
2473 FOR_ALL_INTERFACES (vrf, ifp)
2474 ripng_interface_sync(ifp);
2475 }
2476
2477 static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2478 int sock)
2479 {
2480 ripng->sock = sock;
2481
2482 ripng_vrf_link(ripng, vrf);
2483 ripng->enabled = true;
2484
2485 /* Resend all redistribute requests. */
2486 ripng_redistribute_enable(ripng);
2487
2488 /* Create read and timer thread. */
2489 ripng_event(ripng, RIPNG_READ, ripng->sock);
2490 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2491
2492 ripng_zebra_vrf_register(vrf);
2493 }
2494
2495 static void ripng_instance_disable(struct ripng *ripng)
2496 {
2497 struct vrf *vrf = ripng->vrf;
2498 struct agg_node *rp;
2499
2500 /* Clear RIPng routes */
2501 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2502 struct ripng_aggregate *aggregate;
2503 struct list *list;
2504
2505 if ((list = rp->info) != NULL) {
2506 struct ripng_info *rinfo;
2507 struct listnode *listnode;
2508
2509 rinfo = listgetdata(listhead(list));
2510 if (ripng_route_rte(rinfo))
2511 ripng_zebra_ipv6_delete(ripng, rp);
2512
2513 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2514 EVENT_OFF(rinfo->t_timeout);
2515 EVENT_OFF(rinfo->t_garbage_collect);
2516 ripng_info_free(rinfo);
2517 }
2518 list_delete(&list);
2519 rp->info = NULL;
2520 agg_unlock_node(rp);
2521 }
2522
2523 if ((aggregate = rp->aggregate) != NULL) {
2524 ripng_aggregate_free(aggregate);
2525 rp->aggregate = NULL;
2526 agg_unlock_node(rp);
2527 }
2528 }
2529
2530 /* Flush all redistribute requests. */
2531 ripng_redistribute_disable(ripng);
2532
2533 /* Cancel the RIPng timers */
2534 EVENT_OFF(ripng->t_update);
2535 EVENT_OFF(ripng->t_triggered_update);
2536 EVENT_OFF(ripng->t_triggered_interval);
2537
2538 /* Cancel the read thread */
2539 EVENT_OFF(ripng->t_read);
2540
2541 /* Close the RIPng socket */
2542 if (ripng->sock >= 0) {
2543 close(ripng->sock);
2544 ripng->sock = -1;
2545 }
2546
2547 /* Clear existing peers. */
2548 list_delete_all_node(ripng->peer_list);
2549
2550 ripng_zebra_vrf_deregister(vrf);
2551
2552 ripng_vrf_unlink(ripng, vrf);
2553 ripng->enabled = false;
2554 }
2555
2556 static int ripng_vrf_new(struct vrf *vrf)
2557 {
2558 if (IS_RIPNG_DEBUG_EVENT)
2559 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2560 vrf->vrf_id);
2561
2562 return 0;
2563 }
2564
2565 static int ripng_vrf_delete(struct vrf *vrf)
2566 {
2567 struct ripng *ripng;
2568
2569 if (IS_RIPNG_DEBUG_EVENT)
2570 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2571 vrf->vrf_id);
2572
2573 ripng = ripng_lookup_by_vrf_name(vrf->name);
2574 if (!ripng)
2575 return 0;
2576
2577 ripng_clean(ripng);
2578 return 0;
2579 }
2580
2581 static int ripng_vrf_enable(struct vrf *vrf)
2582 {
2583 struct ripng *ripng;
2584 int socket;
2585
2586 ripng = ripng_lookup_by_vrf_name(vrf->name);
2587 if (!ripng || ripng->enabled)
2588 return 0;
2589
2590 if (IS_RIPNG_DEBUG_EVENT)
2591 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2592 vrf->vrf_id);
2593
2594 /* Activate the VRF RIPng instance. */
2595 socket = ripng_make_socket(vrf);
2596 if (socket < 0)
2597 return -1;
2598
2599 ripng_instance_enable(ripng, vrf, socket);
2600
2601 return 0;
2602 }
2603
2604 static int ripng_vrf_disable(struct vrf *vrf)
2605 {
2606 struct ripng *ripng;
2607
2608 ripng = ripng_lookup_by_vrf_name(vrf->name);
2609 if (!ripng || !ripng->enabled)
2610 return 0;
2611
2612 if (IS_RIPNG_DEBUG_EVENT)
2613 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2614 vrf->vrf_id);
2615
2616 /* Deactivate the VRF RIPng instance. */
2617 if (ripng->enabled)
2618 ripng_instance_disable(ripng);
2619
2620 return 0;
2621 }
2622
2623 void ripng_vrf_init(void)
2624 {
2625 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
2626 ripng_vrf_delete);
2627
2628 vrf_cmd_init(NULL);
2629 }
2630
2631 void ripng_vrf_terminate(void)
2632 {
2633 vrf_terminate();
2634 }
2635
2636 /* Initialize ripng structure and set commands. */
2637 void ripng_init(void)
2638 {
2639 /* Install RIPNG_NODE. */
2640 install_node(&cmd_ripng_node);
2641
2642 /* Install ripng commands. */
2643 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2644 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
2645
2646 install_default(RIPNG_NODE);
2647
2648 ripng_if_init();
2649 ripng_debug_init();
2650
2651 /* Access list install. */
2652 access_list_init();
2653 access_list_add_hook(ripng_distribute_update_all_wrapper);
2654 access_list_delete_hook(ripng_distribute_update_all_wrapper);
2655
2656 /* Prefix list initialize.*/
2657 prefix_list_init();
2658 prefix_list_add_hook(ripng_distribute_update_all);
2659 prefix_list_delete_hook(ripng_distribute_update_all);
2660
2661 /* Route-map for interface. */
2662 ripng_route_map_init();
2663
2664 route_map_add_hook(ripng_routemap_update);
2665 route_map_delete_hook(ripng_routemap_update);
2666
2667 if_rmap_init(RIPNG_NODE);
2668 }