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