]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripngd.c
Merge pull request #8647 from sworleys/DVNI-Config-Changes
[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 default:
1937 break;
1938 }
1939 }
1940
1941
1942 /* Print out routes update time. */
1943 static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
1944 {
1945 time_t clock;
1946 struct tm tm;
1947 #define TIME_BUF 25
1948 char timebuf[TIME_BUF];
1949 struct thread *thread;
1950
1951 if ((thread = rinfo->t_timeout) != NULL) {
1952 clock = thread_timer_remain_second(thread);
1953 gmtime_r(&clock, &tm);
1954 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
1955 vty_out(vty, "%5s", timebuf);
1956 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
1957 clock = thread_timer_remain_second(thread);
1958 gmtime_r(&clock, &tm);
1959 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
1960 vty_out(vty, "%5s", timebuf);
1961 }
1962 }
1963
1964 static char *ripng_route_subtype_print(struct ripng_info *rinfo)
1965 {
1966 static char str[3];
1967 memset(str, 0, 3);
1968
1969 if (rinfo->suppress)
1970 strlcat(str, "S", sizeof(str));
1971
1972 switch (rinfo->sub_type) {
1973 case RIPNG_ROUTE_RTE:
1974 strlcat(str, "n", sizeof(str));
1975 break;
1976 case RIPNG_ROUTE_STATIC:
1977 strlcat(str, "s", sizeof(str));
1978 break;
1979 case RIPNG_ROUTE_DEFAULT:
1980 strlcat(str, "d", sizeof(str));
1981 break;
1982 case RIPNG_ROUTE_REDISTRIBUTE:
1983 strlcat(str, "r", sizeof(str));
1984 break;
1985 case RIPNG_ROUTE_INTERFACE:
1986 strlcat(str, "i", sizeof(str));
1987 break;
1988 default:
1989 strlcat(str, "?", sizeof(str));
1990 break;
1991 }
1992
1993 return str;
1994 }
1995
1996 DEFUN (show_ipv6_ripng,
1997 show_ipv6_ripng_cmd,
1998 "show ipv6 ripng [vrf NAME]",
1999 SHOW_STR
2000 IPV6_STR
2001 "Show RIPng routes\n"
2002 VRF_CMD_HELP_STR)
2003 {
2004 struct ripng *ripng;
2005 struct agg_node *rp;
2006 struct ripng_info *rinfo;
2007 struct ripng_aggregate *aggregate;
2008 struct list *list = NULL;
2009 struct listnode *listnode = NULL;
2010 int len;
2011 const char *vrf_name;
2012 int idx = 0;
2013
2014 if (argv_find(argv, argc, "vrf", &idx))
2015 vrf_name = argv[idx + 1]->arg;
2016 else
2017 vrf_name = VRF_DEFAULT_NAME;
2018
2019 ripng = ripng_lookup_by_vrf_name(vrf_name);
2020 if (!ripng) {
2021 vty_out(vty, "%% RIPng instance not found\n");
2022 return CMD_SUCCESS;
2023 }
2024 if (!ripng->enabled) {
2025 vty_out(vty, "%% RIPng instance is disabled\n");
2026 return CMD_SUCCESS;
2027 }
2028
2029 /* Header of display. */
2030 vty_out(vty,
2031 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2032 "Sub-codes:\n"
2033 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2034 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2035 " Network Next Hop Via Metric Tag Time\n");
2036
2037 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2038 if ((aggregate = rp->aggregate) != NULL) {
2039 #ifdef DEBUG
2040 vty_out(vty, "R(a) %d/%d %pRN ", aggregate->count,
2041 aggregate->suppress, rp);
2042 #else
2043 vty_out(vty, "R(a) %pRN ", rp);
2044 #endif /* DEBUG */
2045 vty_out(vty, "\n");
2046 vty_out(vty, "%*s", 18, " ");
2047
2048 vty_out(vty, "%*s", 28, " ");
2049 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "\n",
2050 aggregate->metric, (route_tag_t)aggregate->tag);
2051 }
2052
2053 if ((list = rp->info) != NULL)
2054 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2055 #ifdef DEBUG
2056 vty_out(vty, "%c(%s) 0/%d %pRN ",
2057 zebra_route_char(rinfo->type),
2058 ripng_route_subtype_print(rinfo),
2059 rinfo->suppress, rp);
2060 #else
2061 vty_out(vty, "%c(%s) %pRN ",
2062 zebra_route_char(rinfo->type),
2063 ripng_route_subtype_print(rinfo), rp);
2064 #endif /* DEBUG */
2065 vty_out(vty, "\n");
2066 vty_out(vty, "%*s", 18, " ");
2067 len = vty_out(vty, "%pI6",
2068 &rinfo->nexthop);
2069
2070 len = 28 - len;
2071 if (len > 0)
2072 vty_out(vty, "%*s", len, " ");
2073
2074 /* from */
2075 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2076 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2077 len = vty_out(
2078 vty, "%s",
2079 ifindex2ifname(
2080 rinfo->ifindex,
2081 ripng->vrf->vrf_id));
2082 } else if (rinfo->metric
2083 == RIPNG_METRIC_INFINITY) {
2084 len = vty_out(vty, "kill");
2085 } else
2086 len = vty_out(vty, "self");
2087
2088 len = 9 - len;
2089 if (len > 0)
2090 vty_out(vty, "%*s", len, " ");
2091
2092 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2093 rinfo->metric, (route_tag_t)rinfo->tag);
2094
2095 /* time */
2096 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2097 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2098 /* RTE from remote RIP routers */
2099 ripng_vty_out_uptime(vty, rinfo);
2100 } else if (rinfo->metric
2101 == RIPNG_METRIC_INFINITY) {
2102 /* poisonous reversed routes (gc) */
2103 ripng_vty_out_uptime(vty, rinfo);
2104 }
2105
2106 vty_out(vty, "\n");
2107 }
2108 }
2109
2110 return CMD_SUCCESS;
2111 }
2112
2113 DEFUN (show_ipv6_ripng_status,
2114 show_ipv6_ripng_status_cmd,
2115 "show ipv6 ripng [vrf NAME] status",
2116 SHOW_STR
2117 IPV6_STR
2118 "Show RIPng routes\n"
2119 VRF_CMD_HELP_STR
2120 "IPv6 routing protocol process parameters and statistics\n")
2121 {
2122 struct ripng *ripng;
2123 struct interface *ifp;
2124 const char *vrf_name;
2125 int idx = 0;
2126
2127 if (argv_find(argv, argc, "vrf", &idx))
2128 vrf_name = argv[idx + 1]->arg;
2129 else
2130 vrf_name = VRF_DEFAULT_NAME;
2131
2132 ripng = ripng_lookup_by_vrf_name(vrf_name);
2133 if (!ripng) {
2134 vty_out(vty, "%% RIPng instance not found\n");
2135 return CMD_SUCCESS;
2136 }
2137 if (!ripng->enabled) {
2138 vty_out(vty, "%% RIPng instance is disabled\n");
2139 return CMD_SUCCESS;
2140 }
2141
2142 vty_out(vty, "Routing Protocol is \"RIPng\"\n");
2143 vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
2144 ripng->update_time);
2145 vty_out(vty, " next due in %lu seconds\n",
2146 thread_timer_remain_second(ripng->t_update));
2147 vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time);
2148 vty_out(vty, " garbage collect after %u seconds\n",
2149 ripng->garbage_time);
2150
2151 /* Filtering status show. */
2152 config_show_distribute(vty, ripng->distribute_ctx);
2153
2154 /* Default metric information. */
2155 vty_out(vty, " Default redistribution metric is %d\n",
2156 ripng->default_metric);
2157
2158 /* Redistribute information. */
2159 vty_out(vty, " Redistributing:");
2160 ripng_redistribute_write(vty, ripng);
2161 vty_out(vty, "\n");
2162
2163 vty_out(vty, " Default version control: send version %d,",
2164 ripng->version);
2165 vty_out(vty, " receive version %d \n", ripng->version);
2166
2167 vty_out(vty, " Interface Send Recv\n");
2168
2169 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
2170 struct ripng_interface *ri;
2171
2172 ri = ifp->info;
2173
2174 if (ri->enable_network || ri->enable_interface) {
2175
2176 vty_out(vty, " %-17s%-3d %-3d\n", ifp->name,
2177 ripng->version, ripng->version);
2178 }
2179 }
2180
2181 vty_out(vty, " Routing for Networks:\n");
2182 ripng_network_write(vty, ripng);
2183
2184 vty_out(vty, " Routing Information Sources:\n");
2185 vty_out(vty,
2186 " Gateway BadPackets BadRoutes Distance Last Update\n");
2187 ripng_peer_display(vty, ripng);
2188
2189 return CMD_SUCCESS;
2190 }
2191
2192 /* Update ECMP routes to zebra when ECMP is disabled. */
2193 void ripng_ecmp_disable(struct ripng *ripng)
2194 {
2195 struct agg_node *rp;
2196 struct ripng_info *rinfo, *tmp_rinfo;
2197 struct list *list;
2198 struct listnode *node, *nextnode;
2199
2200 if (!ripng)
2201 return;
2202
2203 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
2204 if ((list = rp->info) != NULL && listcount(list) > 1) {
2205 rinfo = listgetdata(listhead(list));
2206 if (!ripng_route_rte(rinfo))
2207 continue;
2208
2209 /* Drop all other entries, except the first one. */
2210 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2211 if (tmp_rinfo != rinfo) {
2212 THREAD_OFF(tmp_rinfo->t_timeout);
2213 THREAD_OFF(
2214 tmp_rinfo->t_garbage_collect);
2215 list_delete_node(list, node);
2216 ripng_info_free(tmp_rinfo);
2217 }
2218
2219 /* Update zebra. */
2220 ripng_zebra_ipv6_add(ripng, rp);
2221
2222 /* Set the route change flag. */
2223 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2224
2225 /* Signal the output process to trigger an update. */
2226 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
2227 }
2228 }
2229
2230 /* RIPng configuration write function. */
2231 static int ripng_config_write(struct vty *vty)
2232 {
2233 struct ripng *ripng;
2234 int write = 0;
2235
2236 RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
2237 char xpath[XPATH_MAXLEN];
2238 struct lyd_node *dnode;
2239
2240 snprintf(xpath, sizeof(xpath),
2241 "/frr-ripngd:ripngd/instance[vrf='%s']",
2242 ripng->vrf_name);
2243
2244 dnode = yang_dnode_get(running_config->dnode, xpath);
2245 assert(dnode);
2246
2247 nb_cli_show_dnode_cmds(vty, dnode, false);
2248
2249 config_write_distribute(vty, ripng->distribute_ctx);
2250 config_write_if_rmap(vty, ripng->if_rmap_ctx);
2251
2252 vty_out(vty, "exit\n");
2253
2254 write = 1;
2255 }
2256
2257 return write;
2258 }
2259
2260 static int ripng_config_write(struct vty *vty);
2261 /* RIPng node structure. */
2262 static struct cmd_node cmd_ripng_node = {
2263 .name = "ripng",
2264 .node = RIPNG_NODE,
2265 .parent_node = CONFIG_NODE,
2266 .prompt = "%s(config-router)# ",
2267 .config_write = ripng_config_write,
2268 };
2269
2270 static void ripng_distribute_update(struct distribute_ctx *ctx,
2271 struct distribute *dist)
2272 {
2273 struct interface *ifp;
2274 struct ripng_interface *ri;
2275 struct access_list *alist;
2276 struct prefix_list *plist;
2277
2278 if (!ctx->vrf || !dist->ifname)
2279 return;
2280
2281 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
2282 if (ifp == NULL)
2283 return;
2284
2285 ri = ifp->info;
2286
2287 if (dist->list[DISTRIBUTE_V6_IN]) {
2288 alist = access_list_lookup(AFI_IP6,
2289 dist->list[DISTRIBUTE_V6_IN]);
2290 if (alist)
2291 ri->list[RIPNG_FILTER_IN] = alist;
2292 else
2293 ri->list[RIPNG_FILTER_IN] = NULL;
2294 } else
2295 ri->list[RIPNG_FILTER_IN] = NULL;
2296
2297 if (dist->list[DISTRIBUTE_V6_OUT]) {
2298 alist = access_list_lookup(AFI_IP6,
2299 dist->list[DISTRIBUTE_V6_OUT]);
2300 if (alist)
2301 ri->list[RIPNG_FILTER_OUT] = alist;
2302 else
2303 ri->list[RIPNG_FILTER_OUT] = NULL;
2304 } else
2305 ri->list[RIPNG_FILTER_OUT] = NULL;
2306
2307 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2308 plist = prefix_list_lookup(AFI_IP6,
2309 dist->prefix[DISTRIBUTE_V6_IN]);
2310 if (plist)
2311 ri->prefix[RIPNG_FILTER_IN] = plist;
2312 else
2313 ri->prefix[RIPNG_FILTER_IN] = NULL;
2314 } else
2315 ri->prefix[RIPNG_FILTER_IN] = NULL;
2316
2317 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2318 plist = prefix_list_lookup(AFI_IP6,
2319 dist->prefix[DISTRIBUTE_V6_OUT]);
2320 if (plist)
2321 ri->prefix[RIPNG_FILTER_OUT] = plist;
2322 else
2323 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2324 } else
2325 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2326 }
2327
2328 void ripng_distribute_update_interface(struct interface *ifp)
2329 {
2330 struct ripng_interface *ri = ifp->info;
2331 struct ripng *ripng = ri->ripng;
2332 struct distribute *dist;
2333
2334 if (!ripng)
2335 return;
2336 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
2337 if (dist)
2338 ripng_distribute_update(ripng->distribute_ctx, dist);
2339 }
2340
2341 /* Update all interface's distribute list. */
2342 static void ripng_distribute_update_all(struct prefix_list *notused)
2343 {
2344 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2345 struct interface *ifp;
2346
2347 FOR_ALL_INTERFACES (vrf, ifp)
2348 ripng_distribute_update_interface(ifp);
2349 }
2350
2351 static void ripng_distribute_update_all_wrapper(struct access_list *notused)
2352 {
2353 ripng_distribute_update_all(NULL);
2354 }
2355
2356 /* delete all the added ripng routes. */
2357 void ripng_clean(struct ripng *ripng)
2358 {
2359 ripng_interface_clean(ripng);
2360
2361 if (ripng->enabled)
2362 ripng_instance_disable(ripng);
2363
2364 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
2365 if (ripng->redist[i].route_map.name)
2366 free(ripng->redist[i].route_map.name);
2367
2368 agg_table_finish(ripng->table);
2369 list_delete(&ripng->peer_list);
2370 distribute_list_delete(&ripng->distribute_ctx);
2371 if_rmap_ctx_delete(ripng->if_rmap_ctx);
2372
2373 stream_free(ripng->ibuf);
2374 stream_free(ripng->obuf);
2375
2376 ripng_clean_network(ripng);
2377 ripng_passive_interface_clean(ripng);
2378 vector_free(ripng->enable_if);
2379 agg_table_finish(ripng->enable_network);
2380 vector_free(ripng->passive_interface);
2381 list_delete(&ripng->offset_list_master);
2382
2383 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2384 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
2385 XFREE(MTYPE_RIPNG, ripng);
2386 }
2387
2388 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2389 struct if_rmap *if_rmap)
2390 {
2391 struct interface *ifp = NULL;
2392 struct ripng_interface *ri;
2393 struct route_map *rmap;
2394 struct vrf *vrf = NULL;
2395
2396 if (ctx->name)
2397 vrf = vrf_lookup_by_name(ctx->name);
2398 if (vrf)
2399 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
2400 if (ifp == NULL)
2401 return;
2402
2403 ri = ifp->info;
2404
2405 if (if_rmap->routemap[IF_RMAP_IN]) {
2406 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2407 if (rmap)
2408 ri->routemap[IF_RMAP_IN] = rmap;
2409 else
2410 ri->routemap[IF_RMAP_IN] = NULL;
2411 } else
2412 ri->routemap[RIPNG_FILTER_IN] = NULL;
2413
2414 if (if_rmap->routemap[IF_RMAP_OUT]) {
2415 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2416 if (rmap)
2417 ri->routemap[IF_RMAP_OUT] = rmap;
2418 else
2419 ri->routemap[IF_RMAP_OUT] = NULL;
2420 } else
2421 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2422 }
2423
2424 void ripng_if_rmap_update_interface(struct interface *ifp)
2425 {
2426 struct ripng_interface *ri = ifp->info;
2427 struct ripng *ripng = ri->ripng;
2428 struct if_rmap *if_rmap;
2429 struct if_rmap_ctx *ctx;
2430
2431 if (!ripng)
2432 return;
2433 ctx = ripng->if_rmap_ctx;
2434 if (!ctx)
2435 return;
2436 if_rmap = if_rmap_lookup(ctx, ifp->name);
2437 if (if_rmap)
2438 ripng_if_rmap_update(ctx, if_rmap);
2439 }
2440
2441 static void ripng_routemap_update_redistribute(struct ripng *ripng)
2442 {
2443 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2444 if (ripng->redist[i].route_map.name) {
2445 ripng->redist[i].route_map.map =
2446 route_map_lookup_by_name(
2447 ripng->redist[i].route_map.name);
2448 route_map_counter_increment(
2449 ripng->redist[i].route_map.map);
2450 }
2451 }
2452 }
2453
2454 static void ripng_routemap_update(const char *unused)
2455 {
2456 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2457 struct ripng *ripng;
2458 struct interface *ifp;
2459
2460 FOR_ALL_INTERFACES (vrf, ifp)
2461 ripng_if_rmap_update_interface(ifp);
2462
2463 ripng = vrf->info;
2464 if (ripng)
2465 ripng_routemap_update_redistribute(ripng);
2466 }
2467
2468 /* Link RIPng instance to VRF. */
2469 static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2470 {
2471 struct interface *ifp;
2472
2473 ripng->vrf = vrf;
2474 ripng->distribute_ctx->vrf = vrf;
2475 vrf->info = ripng;
2476
2477 FOR_ALL_INTERFACES (vrf, ifp)
2478 ripng_interface_sync(ifp);
2479 }
2480
2481 /* Unlink RIPng instance from VRF. */
2482 static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2483 {
2484 struct interface *ifp;
2485
2486 ripng->vrf = NULL;
2487 ripng->distribute_ctx->vrf = NULL;
2488 vrf->info = NULL;
2489
2490 FOR_ALL_INTERFACES (vrf, ifp)
2491 ripng_interface_sync(ifp);
2492 }
2493
2494 static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2495 int sock)
2496 {
2497 ripng->sock = sock;
2498
2499 ripng_vrf_link(ripng, vrf);
2500 ripng->enabled = true;
2501
2502 /* Resend all redistribute requests. */
2503 ripng_redistribute_enable(ripng);
2504
2505 /* Create read and timer thread. */
2506 ripng_event(ripng, RIPNG_READ, ripng->sock);
2507 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2508
2509 ripng_zebra_vrf_register(vrf);
2510 }
2511
2512 static void ripng_instance_disable(struct ripng *ripng)
2513 {
2514 struct vrf *vrf = ripng->vrf;
2515 struct agg_node *rp;
2516
2517 /* Clear RIPng routes */
2518 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2519 struct ripng_aggregate *aggregate;
2520 struct list *list;
2521
2522 if ((list = rp->info) != NULL) {
2523 struct ripng_info *rinfo;
2524 struct listnode *listnode;
2525
2526 rinfo = listgetdata(listhead(list));
2527 if (ripng_route_rte(rinfo))
2528 ripng_zebra_ipv6_delete(ripng, rp);
2529
2530 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2531 THREAD_OFF(rinfo->t_timeout);
2532 THREAD_OFF(rinfo->t_garbage_collect);
2533 ripng_info_free(rinfo);
2534 }
2535 list_delete(&list);
2536 rp->info = NULL;
2537 agg_unlock_node(rp);
2538 }
2539
2540 if ((aggregate = rp->aggregate) != NULL) {
2541 ripng_aggregate_free(aggregate);
2542 rp->aggregate = NULL;
2543 agg_unlock_node(rp);
2544 }
2545 }
2546
2547 /* Flush all redistribute requests. */
2548 ripng_redistribute_disable(ripng);
2549
2550 /* Cancel the RIPng timers */
2551 THREAD_OFF(ripng->t_update);
2552 THREAD_OFF(ripng->t_triggered_update);
2553 THREAD_OFF(ripng->t_triggered_interval);
2554
2555 /* Cancel the read thread */
2556 THREAD_OFF(ripng->t_read);
2557
2558 /* Close the RIPng socket */
2559 if (ripng->sock >= 0) {
2560 close(ripng->sock);
2561 ripng->sock = -1;
2562 }
2563
2564 /* Clear existing peers. */
2565 list_delete_all_node(ripng->peer_list);
2566
2567 ripng_zebra_vrf_deregister(vrf);
2568
2569 ripng_vrf_unlink(ripng, vrf);
2570 ripng->enabled = false;
2571 }
2572
2573 static int ripng_vrf_new(struct vrf *vrf)
2574 {
2575 if (IS_RIPNG_DEBUG_EVENT)
2576 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2577 vrf->vrf_id);
2578
2579 return 0;
2580 }
2581
2582 static int ripng_vrf_delete(struct vrf *vrf)
2583 {
2584 struct ripng *ripng;
2585
2586 if (IS_RIPNG_DEBUG_EVENT)
2587 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2588 vrf->vrf_id);
2589
2590 ripng = ripng_lookup_by_vrf_name(vrf->name);
2591 if (!ripng)
2592 return 0;
2593
2594 ripng_clean(ripng);
2595 return 0;
2596 }
2597
2598 static int ripng_vrf_enable(struct vrf *vrf)
2599 {
2600 struct ripng *ripng;
2601 int socket;
2602
2603 ripng = ripng_lookup_by_vrf_name(vrf->name);
2604 if (!ripng || ripng->enabled)
2605 return 0;
2606
2607 if (IS_RIPNG_DEBUG_EVENT)
2608 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2609 vrf->vrf_id);
2610
2611 /* Activate the VRF RIPng instance. */
2612 socket = ripng_make_socket(vrf);
2613 if (socket < 0)
2614 return -1;
2615
2616 ripng_instance_enable(ripng, vrf, socket);
2617
2618 return 0;
2619 }
2620
2621 static int ripng_vrf_disable(struct vrf *vrf)
2622 {
2623 struct ripng *ripng;
2624
2625 ripng = ripng_lookup_by_vrf_name(vrf->name);
2626 if (!ripng || !ripng->enabled)
2627 return 0;
2628
2629 if (IS_RIPNG_DEBUG_EVENT)
2630 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2631 vrf->vrf_id);
2632
2633 /* Deactivate the VRF RIPng instance. */
2634 if (ripng->enabled)
2635 ripng_instance_disable(ripng);
2636
2637 return 0;
2638 }
2639
2640 void ripng_vrf_init(void)
2641 {
2642 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
2643 ripng_vrf_delete);
2644
2645 vrf_cmd_init(NULL);
2646 }
2647
2648 void ripng_vrf_terminate(void)
2649 {
2650 vrf_terminate();
2651 }
2652
2653 /* Initialize ripng structure and set commands. */
2654 void ripng_init(void)
2655 {
2656 /* Install RIPNG_NODE. */
2657 install_node(&cmd_ripng_node);
2658
2659 /* Install ripng commands. */
2660 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2661 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
2662
2663 install_default(RIPNG_NODE);
2664
2665 ripng_if_init();
2666 ripng_debug_init();
2667
2668 /* Access list install. */
2669 access_list_init();
2670 access_list_add_hook(ripng_distribute_update_all_wrapper);
2671 access_list_delete_hook(ripng_distribute_update_all_wrapper);
2672
2673 /* Prefix list initialize.*/
2674 prefix_list_init();
2675 prefix_list_add_hook(ripng_distribute_update_all);
2676 prefix_list_delete_hook(ripng_distribute_update_all);
2677
2678 /* Route-map for interface. */
2679 ripng_route_map_init();
2680
2681 route_map_add_hook(ripng_routemap_update);
2682 route_map_delete_hook(ripng_routemap_update);
2683
2684 if_rmap_init(RIPNG_NODE);
2685 }