]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripngd.c
Merge pull request #8850 from opensourcerouting/ospf6-checksum-json
[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 > 128) {
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 write = 1;
2274 }
2275
2276 return write;
2277 }
2278
2279 static int ripng_config_write(struct vty *vty);
2280 /* RIPng node structure. */
2281 static struct cmd_node cmd_ripng_node = {
2282 .name = "ripng",
2283 .node = RIPNG_NODE,
2284 .parent_node = CONFIG_NODE,
2285 .prompt = "%s(config-router)# ",
2286 .config_write = ripng_config_write,
2287 };
2288
2289 static void ripng_distribute_update(struct distribute_ctx *ctx,
2290 struct distribute *dist)
2291 {
2292 struct interface *ifp;
2293 struct ripng_interface *ri;
2294 struct access_list *alist;
2295 struct prefix_list *plist;
2296
2297 if (!ctx->vrf || !dist->ifname)
2298 return;
2299
2300 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
2301 if (ifp == NULL)
2302 return;
2303
2304 ri = ifp->info;
2305
2306 if (dist->list[DISTRIBUTE_V6_IN]) {
2307 alist = access_list_lookup(AFI_IP6,
2308 dist->list[DISTRIBUTE_V6_IN]);
2309 if (alist)
2310 ri->list[RIPNG_FILTER_IN] = alist;
2311 else
2312 ri->list[RIPNG_FILTER_IN] = NULL;
2313 } else
2314 ri->list[RIPNG_FILTER_IN] = NULL;
2315
2316 if (dist->list[DISTRIBUTE_V6_OUT]) {
2317 alist = access_list_lookup(AFI_IP6,
2318 dist->list[DISTRIBUTE_V6_OUT]);
2319 if (alist)
2320 ri->list[RIPNG_FILTER_OUT] = alist;
2321 else
2322 ri->list[RIPNG_FILTER_OUT] = NULL;
2323 } else
2324 ri->list[RIPNG_FILTER_OUT] = NULL;
2325
2326 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2327 plist = prefix_list_lookup(AFI_IP6,
2328 dist->prefix[DISTRIBUTE_V6_IN]);
2329 if (plist)
2330 ri->prefix[RIPNG_FILTER_IN] = plist;
2331 else
2332 ri->prefix[RIPNG_FILTER_IN] = NULL;
2333 } else
2334 ri->prefix[RIPNG_FILTER_IN] = NULL;
2335
2336 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2337 plist = prefix_list_lookup(AFI_IP6,
2338 dist->prefix[DISTRIBUTE_V6_OUT]);
2339 if (plist)
2340 ri->prefix[RIPNG_FILTER_OUT] = plist;
2341 else
2342 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2343 } else
2344 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2345 }
2346
2347 void ripng_distribute_update_interface(struct interface *ifp)
2348 {
2349 struct ripng_interface *ri = ifp->info;
2350 struct ripng *ripng = ri->ripng;
2351 struct distribute *dist;
2352
2353 if (!ripng)
2354 return;
2355 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
2356 if (dist)
2357 ripng_distribute_update(ripng->distribute_ctx, dist);
2358 }
2359
2360 /* Update all interface's distribute list. */
2361 static void ripng_distribute_update_all(struct prefix_list *notused)
2362 {
2363 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2364 struct interface *ifp;
2365
2366 FOR_ALL_INTERFACES (vrf, ifp)
2367 ripng_distribute_update_interface(ifp);
2368 }
2369
2370 static void ripng_distribute_update_all_wrapper(struct access_list *notused)
2371 {
2372 ripng_distribute_update_all(NULL);
2373 }
2374
2375 /* delete all the added ripng routes. */
2376 void ripng_clean(struct ripng *ripng)
2377 {
2378 ripng_interface_clean(ripng);
2379
2380 if (ripng->enabled)
2381 ripng_instance_disable(ripng);
2382
2383 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
2384 if (ripng->redist[i].route_map.name)
2385 free(ripng->redist[i].route_map.name);
2386
2387 agg_table_finish(ripng->table);
2388 list_delete(&ripng->peer_list);
2389 distribute_list_delete(&ripng->distribute_ctx);
2390 if_rmap_ctx_delete(ripng->if_rmap_ctx);
2391
2392 stream_free(ripng->ibuf);
2393 stream_free(ripng->obuf);
2394
2395 ripng_clean_network(ripng);
2396 ripng_passive_interface_clean(ripng);
2397 vector_free(ripng->enable_if);
2398 agg_table_finish(ripng->enable_network);
2399 vector_free(ripng->passive_interface);
2400 list_delete(&ripng->offset_list_master);
2401
2402 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2403 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
2404 XFREE(MTYPE_RIPNG, ripng);
2405 }
2406
2407 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2408 struct if_rmap *if_rmap)
2409 {
2410 struct interface *ifp = NULL;
2411 struct ripng_interface *ri;
2412 struct route_map *rmap;
2413 struct vrf *vrf = NULL;
2414
2415 if (ctx->name)
2416 vrf = vrf_lookup_by_name(ctx->name);
2417 if (vrf)
2418 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
2419 if (ifp == NULL)
2420 return;
2421
2422 ri = ifp->info;
2423
2424 if (if_rmap->routemap[IF_RMAP_IN]) {
2425 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2426 if (rmap)
2427 ri->routemap[IF_RMAP_IN] = rmap;
2428 else
2429 ri->routemap[IF_RMAP_IN] = NULL;
2430 } else
2431 ri->routemap[RIPNG_FILTER_IN] = NULL;
2432
2433 if (if_rmap->routemap[IF_RMAP_OUT]) {
2434 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2435 if (rmap)
2436 ri->routemap[IF_RMAP_OUT] = rmap;
2437 else
2438 ri->routemap[IF_RMAP_OUT] = NULL;
2439 } else
2440 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2441 }
2442
2443 void ripng_if_rmap_update_interface(struct interface *ifp)
2444 {
2445 struct ripng_interface *ri = ifp->info;
2446 struct ripng *ripng = ri->ripng;
2447 struct if_rmap *if_rmap;
2448 struct if_rmap_ctx *ctx;
2449
2450 if (!ripng)
2451 return;
2452 ctx = ripng->if_rmap_ctx;
2453 if (!ctx)
2454 return;
2455 if_rmap = if_rmap_lookup(ctx, ifp->name);
2456 if (if_rmap)
2457 ripng_if_rmap_update(ctx, if_rmap);
2458 }
2459
2460 static void ripng_routemap_update_redistribute(struct ripng *ripng)
2461 {
2462 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2463 if (ripng->redist[i].route_map.name) {
2464 ripng->redist[i].route_map.map =
2465 route_map_lookup_by_name(
2466 ripng->redist[i].route_map.name);
2467 route_map_counter_increment(
2468 ripng->redist[i].route_map.map);
2469 }
2470 }
2471 }
2472
2473 static void ripng_routemap_update(const char *unused)
2474 {
2475 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2476 struct ripng *ripng;
2477 struct interface *ifp;
2478
2479 FOR_ALL_INTERFACES (vrf, ifp)
2480 ripng_if_rmap_update_interface(ifp);
2481
2482 ripng = vrf->info;
2483 if (ripng)
2484 ripng_routemap_update_redistribute(ripng);
2485 }
2486
2487 /* Link RIPng instance to VRF. */
2488 static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2489 {
2490 struct interface *ifp;
2491
2492 ripng->vrf = vrf;
2493 ripng->distribute_ctx->vrf = vrf;
2494 vrf->info = ripng;
2495
2496 FOR_ALL_INTERFACES (vrf, ifp)
2497 ripng_interface_sync(ifp);
2498 }
2499
2500 /* Unlink RIPng instance from VRF. */
2501 static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2502 {
2503 struct interface *ifp;
2504
2505 ripng->vrf = NULL;
2506 ripng->distribute_ctx->vrf = NULL;
2507 vrf->info = NULL;
2508
2509 FOR_ALL_INTERFACES (vrf, ifp)
2510 ripng_interface_sync(ifp);
2511 }
2512
2513 static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2514 int sock)
2515 {
2516 ripng->sock = sock;
2517
2518 ripng_vrf_link(ripng, vrf);
2519 ripng->enabled = true;
2520
2521 /* Resend all redistribute requests. */
2522 ripng_redistribute_enable(ripng);
2523
2524 /* Create read and timer thread. */
2525 ripng_event(ripng, RIPNG_READ, ripng->sock);
2526 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2527
2528 ripng_zebra_vrf_register(vrf);
2529 }
2530
2531 static void ripng_instance_disable(struct ripng *ripng)
2532 {
2533 struct vrf *vrf = ripng->vrf;
2534 struct agg_node *rp;
2535
2536 /* Clear RIPng routes */
2537 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2538 struct ripng_aggregate *aggregate;
2539 struct list *list;
2540
2541 if ((list = rp->info) != NULL) {
2542 struct ripng_info *rinfo;
2543 struct listnode *listnode;
2544
2545 rinfo = listgetdata(listhead(list));
2546 if (ripng_route_rte(rinfo))
2547 ripng_zebra_ipv6_delete(ripng, rp);
2548
2549 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2550 RIPNG_TIMER_OFF(rinfo->t_timeout);
2551 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
2552 ripng_info_free(rinfo);
2553 }
2554 list_delete(&list);
2555 rp->info = NULL;
2556 agg_unlock_node(rp);
2557 }
2558
2559 if ((aggregate = rp->aggregate) != NULL) {
2560 ripng_aggregate_free(aggregate);
2561 rp->aggregate = NULL;
2562 agg_unlock_node(rp);
2563 }
2564 }
2565
2566 /* Flush all redistribute requests. */
2567 ripng_redistribute_disable(ripng);
2568
2569 /* Cancel the RIPng timers */
2570 RIPNG_TIMER_OFF(ripng->t_update);
2571 RIPNG_TIMER_OFF(ripng->t_triggered_update);
2572 RIPNG_TIMER_OFF(ripng->t_triggered_interval);
2573
2574 /* Cancel the read thread */
2575 thread_cancel(&ripng->t_read);
2576
2577 /* Close the RIPng socket */
2578 if (ripng->sock >= 0) {
2579 close(ripng->sock);
2580 ripng->sock = -1;
2581 }
2582
2583 /* Clear existing peers. */
2584 list_delete_all_node(ripng->peer_list);
2585
2586 ripng_zebra_vrf_deregister(vrf);
2587
2588 ripng_vrf_unlink(ripng, vrf);
2589 ripng->enabled = false;
2590 }
2591
2592 static int ripng_vrf_new(struct vrf *vrf)
2593 {
2594 if (IS_RIPNG_DEBUG_EVENT)
2595 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2596 vrf->vrf_id);
2597
2598 return 0;
2599 }
2600
2601 static int ripng_vrf_delete(struct vrf *vrf)
2602 {
2603 if (IS_RIPNG_DEBUG_EVENT)
2604 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2605 vrf->vrf_id);
2606
2607 return 0;
2608 }
2609
2610 static int ripng_vrf_enable(struct vrf *vrf)
2611 {
2612 struct ripng *ripng;
2613 int socket;
2614
2615 ripng = ripng_lookup_by_vrf_name(vrf->name);
2616 if (!ripng) {
2617 char *old_vrf_name = NULL;
2618
2619 ripng = (struct ripng *)vrf->info;
2620 if (!ripng)
2621 return 0;
2622 /* update vrf name */
2623 if (ripng->vrf_name)
2624 old_vrf_name = ripng->vrf_name;
2625 ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name);
2626 /*
2627 * HACK: Change the RIPng VRF in the running configuration directly,
2628 * bypassing the northbound layer. This is necessary to avoid deleting
2629 * the RIPng and readding it in the new VRF, which would have
2630 * several implications.
2631 */
2632 if (yang_module_find("frr-ripngd") && old_vrf_name) {
2633 struct lyd_node *ripng_dnode;
2634 char oldpath[XPATH_MAXLEN];
2635 char newpath[XPATH_MAXLEN];
2636
2637 ripng_dnode = yang_dnode_getf(
2638 running_config->dnode,
2639 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2640 old_vrf_name);
2641 if (ripng_dnode) {
2642 yang_dnode_get_path(lyd_parent(ripng_dnode),
2643 oldpath, sizeof(oldpath));
2644 yang_dnode_change_leaf(ripng_dnode, vrf->name);
2645 yang_dnode_get_path(lyd_parent(ripng_dnode),
2646 newpath, sizeof(newpath));
2647 nb_running_move_tree(oldpath, newpath);
2648 running_config->version++;
2649 }
2650 }
2651 XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
2652 }
2653
2654 if (ripng->enabled)
2655 return 0;
2656
2657 if (IS_RIPNG_DEBUG_EVENT)
2658 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2659 vrf->vrf_id);
2660
2661 /* Activate the VRF RIPng instance. */
2662 socket = ripng_make_socket(vrf);
2663 if (socket < 0)
2664 return -1;
2665
2666 ripng_instance_enable(ripng, vrf, socket);
2667
2668 return 0;
2669 }
2670
2671 static int ripng_vrf_disable(struct vrf *vrf)
2672 {
2673 struct ripng *ripng;
2674
2675 ripng = ripng_lookup_by_vrf_name(vrf->name);
2676 if (!ripng || !ripng->enabled)
2677 return 0;
2678
2679 if (IS_RIPNG_DEBUG_EVENT)
2680 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2681 vrf->vrf_id);
2682
2683 /* Deactivate the VRF RIPng instance. */
2684 if (ripng->enabled)
2685 ripng_instance_disable(ripng);
2686
2687 return 0;
2688 }
2689
2690 void ripng_vrf_init(void)
2691 {
2692 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
2693 ripng_vrf_delete, ripng_vrf_enable);
2694
2695 vrf_cmd_init(NULL, &ripngd_privs);
2696 }
2697
2698 void ripng_vrf_terminate(void)
2699 {
2700 vrf_terminate();
2701 }
2702
2703 /* Initialize ripng structure and set commands. */
2704 void ripng_init(void)
2705 {
2706 /* Install RIPNG_NODE. */
2707 install_node(&cmd_ripng_node);
2708
2709 /* Install ripng commands. */
2710 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2711 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
2712
2713 install_default(RIPNG_NODE);
2714
2715 ripng_if_init();
2716 ripng_debug_init();
2717
2718 /* Access list install. */
2719 access_list_init();
2720 access_list_add_hook(ripng_distribute_update_all_wrapper);
2721 access_list_delete_hook(ripng_distribute_update_all_wrapper);
2722
2723 /* Prefix list initialize.*/
2724 prefix_list_init();
2725 prefix_list_add_hook(ripng_distribute_update_all);
2726 prefix_list_delete_hook(ripng_distribute_update_all);
2727
2728 /* Route-map for interface. */
2729 ripng_route_map_init();
2730
2731 route_map_add_hook(ripng_routemap_update);
2732 route_map_delete_hook(ripng_routemap_update);
2733
2734 if_rmap_init(RIPNG_NODE);
2735 }