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