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