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