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