]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripngd.c
bfdd: Modify bfdd to quietly accept access-lists
[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
41 #include "ripngd/ripngd.h"
42 #include "ripngd/ripng_route.h"
43 #include "ripngd/ripng_debug.h"
44 #include "ripngd/ripng_nexthop.h"
45
46 enum { ripng_all_route,
47 ripng_changed_route,
48 };
49
50 static void ripng_distribute_update(struct distribute_ctx *ctx,
51 struct distribute *dist);
52
53 /* Prototypes. */
54 void ripng_output_process(struct interface *, struct sockaddr_in6 *, int);
55 static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
56 int sock);
57 static void ripng_instance_disable(struct ripng *ripng);
58 int ripng_triggered_update(struct thread *);
59 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
60 struct if_rmap *if_rmap);
61
62 /* Generate rb-tree of RIPng instances. */
63 static inline int ripng_instance_compare(const struct ripng *a,
64 const struct ripng *b)
65 {
66 return strcmp(a->vrf_name, b->vrf_name);
67 }
68 RB_GENERATE(ripng_instance_head, ripng, entry, ripng_instance_compare)
69
70 struct ripng_instance_head ripng_instances = RB_INITIALIZER(&ripng_instances);
71
72 /* RIPng next hop specification. */
73 struct ripng_nexthop {
74 enum ripng_nexthop_type {
75 RIPNG_NEXTHOP_UNSPEC,
76 RIPNG_NEXTHOP_ADDRESS
77 } flag;
78 struct in6_addr address;
79 };
80
81 int ripng_route_rte(struct ripng_info *rinfo)
82 {
83 return (rinfo->type == ZEBRA_ROUTE_RIPNG
84 && rinfo->sub_type == RIPNG_ROUTE_RTE);
85 }
86
87 /* Allocate new ripng information. */
88 struct ripng_info *ripng_info_new(void)
89 {
90 struct ripng_info *new;
91
92 new = XCALLOC(MTYPE_RIPNG_ROUTE, sizeof(struct ripng_info));
93 return new;
94 }
95
96 /* Free ripng information. */
97 void ripng_info_free(struct ripng_info *rinfo)
98 {
99 XFREE(MTYPE_RIPNG_ROUTE, rinfo);
100 }
101
102 struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo)
103 {
104 return agg_get_table_info(agg_get_table(rinfo->rp));
105 }
106
107 /* Create ripng socket. */
108 int ripng_make_socket(struct vrf *vrf)
109 {
110 int ret;
111 int sock;
112 struct sockaddr_in6 ripaddr;
113 const char *vrf_dev = NULL;
114
115 /* Make datagram socket. */
116 if (vrf->vrf_id != VRF_DEFAULT)
117 vrf_dev = vrf->name;
118 frr_elevate_privs(&ripngd_privs)
119 {
120 sock = vrf_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
121 vrf->vrf_id, vrf_dev);
122 if (sock < 0) {
123 flog_err_sys(EC_LIB_SOCKET,
124 "Cannot create UDP socket: %s",
125 safe_strerror(errno));
126 return -1;
127 }
128 }
129
130 sockopt_reuseaddr(sock);
131 sockopt_reuseport(sock);
132 setsockopt_so_recvbuf(sock, 8096);
133 ret = setsockopt_ipv6_pktinfo(sock, 1);
134 if (ret < 0)
135 goto error;
136 #ifdef IPTOS_PREC_INTERNETCONTROL
137 ret = setsockopt_ipv6_tclass(sock, IPTOS_PREC_INTERNETCONTROL);
138 if (ret < 0)
139 goto error;
140 #endif
141 ret = setsockopt_ipv6_multicast_hops(sock, 255);
142 if (ret < 0)
143 goto error;
144 ret = setsockopt_ipv6_multicast_loop(sock, 0);
145 if (ret < 0)
146 goto error;
147 ret = setsockopt_ipv6_hoplimit(sock, 1);
148 if (ret < 0)
149 goto error;
150
151 memset(&ripaddr, 0, sizeof(ripaddr));
152 ripaddr.sin6_family = AF_INET6;
153 #ifdef SIN6_LEN
154 ripaddr.sin6_len = sizeof(struct sockaddr_in6);
155 #endif /* SIN6_LEN */
156 ripaddr.sin6_port = htons(RIPNG_PORT_DEFAULT);
157
158 frr_elevate_privs(&ripngd_privs) {
159 ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
160 if (ret < 0) {
161 zlog_err("Can't bind ripng socket: %s.",
162 safe_strerror(errno));
163 goto error;
164 }
165 }
166 return sock;
167
168 error:
169 close(sock);
170 return ret;
171 }
172
173 /* Send RIPng packet. */
174 int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to,
175 struct interface *ifp)
176 {
177 struct ripng_interface *ri = ifp->info;
178 struct ripng *ripng = ri->ripng;
179 int ret;
180 struct msghdr msg;
181 struct iovec iov;
182 struct cmsghdr *cmsgptr;
183 char adata[256] = {};
184 struct in6_pktinfo *pkt;
185 struct sockaddr_in6 addr;
186
187 if (IS_RIPNG_DEBUG_SEND) {
188 if (to)
189 zlog_debug("send to %s", inet6_ntoa(to->sin6_addr));
190 zlog_debug(" send interface %s", ifp->name);
191 zlog_debug(" send packet size %d", bufsize);
192 }
193
194 memset(&addr, 0, sizeof(struct sockaddr_in6));
195 addr.sin6_family = AF_INET6;
196 #ifdef SIN6_LEN
197 addr.sin6_len = sizeof(struct sockaddr_in6);
198 #endif /* SIN6_LEN */
199 addr.sin6_flowinfo = htonl(RIPNG_PRIORITY_DEFAULT);
200
201 /* When destination is specified. */
202 if (to != NULL) {
203 addr.sin6_addr = to->sin6_addr;
204 addr.sin6_port = to->sin6_port;
205 } else {
206 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
207 addr.sin6_port = htons(RIPNG_PORT_DEFAULT);
208 }
209
210 memset(&msg, 0, sizeof(msg));
211 msg.msg_name = (void *)&addr;
212 msg.msg_namelen = sizeof(struct sockaddr_in6);
213 msg.msg_iov = &iov;
214 msg.msg_iovlen = 1;
215 msg.msg_control = (void *)adata;
216 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
217
218 iov.iov_base = buf;
219 iov.iov_len = bufsize;
220
221 cmsgptr = (struct cmsghdr *)adata;
222 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
223 cmsgptr->cmsg_level = IPPROTO_IPV6;
224 cmsgptr->cmsg_type = IPV6_PKTINFO;
225
226 pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
227 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
228 pkt->ipi6_ifindex = ifp->ifindex;
229
230 ret = sendmsg(ripng->sock, &msg, 0);
231
232 if (ret < 0) {
233 if (to)
234 flog_err_sys(EC_LIB_SOCKET,
235 "RIPng send fail on %s to %s: %s",
236 ifp->name, inet6_ntoa(to->sin6_addr),
237 safe_strerror(errno));
238 else
239 flog_err_sys(EC_LIB_SOCKET, "RIPng send fail on %s: %s",
240 ifp->name, safe_strerror(errno));
241 }
242
243 return ret;
244 }
245
246 /* Receive UDP RIPng packet from socket. */
247 static int ripng_recv_packet(int sock, uint8_t *buf, int bufsize,
248 struct sockaddr_in6 *from, ifindex_t *ifindex,
249 int *hoplimit)
250 {
251 int ret;
252 struct msghdr msg;
253 struct iovec iov;
254 struct cmsghdr *cmsgptr;
255 struct in6_addr dst = {.s6_addr = {0}};
256
257 memset(&dst, 0, sizeof(struct in6_addr));
258
259 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
260 point I can't determine size of cmsghdr */
261 char adata[1024];
262
263 /* Fill in message and iovec. */
264 memset(&msg, 0, sizeof(msg));
265 msg.msg_name = (void *)from;
266 msg.msg_namelen = sizeof(struct sockaddr_in6);
267 msg.msg_iov = &iov;
268 msg.msg_iovlen = 1;
269 msg.msg_control = (void *)adata;
270 msg.msg_controllen = sizeof adata;
271 iov.iov_base = buf;
272 iov.iov_len = bufsize;
273
274 /* If recvmsg fail return minus value. */
275 ret = recvmsg(sock, &msg, 0);
276 if (ret < 0)
277 return ret;
278
279 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
280 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
281 /* I want interface index which this packet comes from. */
282 if (cmsgptr->cmsg_level == IPPROTO_IPV6
283 && cmsgptr->cmsg_type == IPV6_PKTINFO) {
284 struct in6_pktinfo *ptr;
285
286 ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
287 *ifindex = ptr->ipi6_ifindex;
288 dst = ptr->ipi6_addr;
289
290 if (*ifindex == 0)
291 zlog_warn(
292 "Interface index returned by IPV6_PKTINFO is zero");
293 }
294
295 /* Incoming packet's multicast hop limit. */
296 if (cmsgptr->cmsg_level == IPPROTO_IPV6
297 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
298 int *phoplimit = (int *)CMSG_DATA(cmsgptr);
299 *hoplimit = *phoplimit;
300 }
301 }
302
303 /* Hoplimit check shold be done when destination address is
304 multicast address. */
305 if (!IN6_IS_ADDR_MULTICAST(&dst))
306 *hoplimit = -1;
307
308 return ret;
309 }
310
311 /* Dump rip packet */
312 void ripng_packet_dump(struct ripng_packet *packet, int size,
313 const char *sndrcv)
314 {
315 caddr_t lim;
316 struct rte *rte;
317 const char *command_str;
318
319 /* Set command string. */
320 if (packet->command == RIPNG_REQUEST)
321 command_str = "request";
322 else if (packet->command == RIPNG_RESPONSE)
323 command_str = "response";
324 else
325 command_str = "unknown";
326
327 /* Dump packet header. */
328 zlog_debug("%s %s version %d packet size %d", sndrcv, command_str,
329 packet->version, size);
330
331 /* Dump each routing table entry. */
332 rte = packet->rte;
333
334 for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) {
335 if (rte->metric == RIPNG_METRIC_NEXTHOP)
336 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte->addr),
337 rte->prefixlen);
338 else
339 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI,
340 inet6_ntoa(rte->addr), rte->prefixlen,
341 rte->metric, (route_tag_t)ntohs(rte->tag));
342 }
343 }
344
345 /* RIPng next hop address RTE (Route Table Entry). */
346 static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from,
347 struct ripng_nexthop *nexthop)
348 {
349 char buf[INET6_BUFSIZ];
350
351 /* Logging before checking RTE. */
352 if (IS_RIPNG_DEBUG_RECV)
353 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
354 " prefixlen %d",
355 inet6_ntoa(rte->addr), (route_tag_t)ntohs(rte->tag),
356 rte->prefixlen);
357
358 /* RFC2080 2.1.1 Next Hop:
359 The route tag and prefix length in the next hop RTE must be
360 set to zero on sending and ignored on receiption. */
361 if (ntohs(rte->tag) != 0)
362 zlog_warn(
363 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
364 " from %s",
365 (route_tag_t)ntohs(rte->tag),
366 inet6_ntoa(from->sin6_addr));
367
368 if (rte->prefixlen != 0)
369 zlog_warn(
370 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
371 rte->prefixlen, inet6_ntoa(from->sin6_addr));
372
373 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
374 next hop RTE indicates that the next hop address should be the
375 originator of the RIPng advertisement. An address specified as a
376 next hop must be a link-local address. */
377 if (IN6_IS_ADDR_UNSPECIFIED(&rte->addr)) {
378 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
379 memset(&nexthop->address, 0, sizeof(struct in6_addr));
380 return;
381 }
382
383 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
384 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
385 IPV6_ADDR_COPY(&nexthop->address, &rte->addr);
386 return;
387 }
388
389 /* The purpose of the next hop RTE is to eliminate packets being
390 routed through extra hops in the system. It is particularly useful
391 when RIPng is not being run on all of the routers on a network.
392 Note that next hop RTE is "advisory". That is, if the provided
393 information is ignored, a possibly sub-optimal, but absolutely
394 valid, route may be taken. If the received next hop address is not
395 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
396 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
397 inet6_ntoa(rte->addr),
398 inet_ntop(AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
399
400 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
401 memset(&nexthop->address, 0, sizeof(struct in6_addr));
402
403 return;
404 }
405
406 /* If ifp has same link-local address then return 1. */
407 static int ripng_lladdr_check(struct interface *ifp, struct in6_addr *addr)
408 {
409 struct listnode *node;
410 struct connected *connected;
411 struct prefix *p;
412
413 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
414 p = connected->address;
415
416 if (p->family == AF_INET6
417 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)
418 && IN6_ARE_ADDR_EQUAL(&p->u.prefix6, addr))
419 return 1;
420 }
421 return 0;
422 }
423
424 /* RIPng route garbage collect timer. */
425 static int ripng_garbage_collect(struct thread *t)
426 {
427 struct ripng_info *rinfo;
428 struct agg_node *rp;
429
430 rinfo = THREAD_ARG(t);
431 rinfo->t_garbage_collect = NULL;
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("%s/%d filtered by distribute %s",
642 inet6_ntoa(p->prefix), p->prefixlen,
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("%s/%d filtered by prefix-list %s",
653 inet6_ntoa(p->prefix), p->prefixlen,
654 inout);
655 return -1;
656 }
657 }
658
659 /* All interface filter check. */
660 dist = distribute_lookup(ri->ripng->distribute_ctx, NULL);
661 if (dist) {
662 if (dist->list[distribute]) {
663 alist = access_list_lookup(AFI_IP6,
664 dist->list[distribute]);
665
666 if (alist) {
667 if (access_list_apply(alist, (struct prefix *)p)
668 == FILTER_DENY) {
669 if (IS_RIPNG_DEBUG_PACKET)
670 zlog_debug(
671 "%s/%d filtered by distribute %s",
672 inet6_ntoa(p->prefix),
673 p->prefixlen, inout);
674 return -1;
675 }
676 }
677 }
678 if (dist->prefix[distribute]) {
679 plist = prefix_list_lookup(AFI_IP6,
680 dist->prefix[distribute]);
681
682 if (plist) {
683 if (prefix_list_apply(plist, (struct prefix *)p)
684 == PREFIX_DENY) {
685 if (IS_RIPNG_DEBUG_PACKET)
686 zlog_debug(
687 "%s/%d filtered by prefix-list %s",
688 inet6_ntoa(p->prefix),
689 p->prefixlen, inout);
690 return -1;
691 }
692 }
693 }
694 }
695 return 0;
696 }
697
698 /* Process RIPng route according to RFC2080. */
699 static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
700 struct ripng_nexthop *ripng_nexthop,
701 struct interface *ifp)
702 {
703 int ret;
704 struct prefix_ipv6 p;
705 struct agg_node *rp;
706 struct ripng_info *rinfo = NULL, newinfo;
707 struct ripng_interface *ri;
708 struct ripng *ripng;
709 struct in6_addr *nexthop;
710 int same = 0;
711 struct list *list = NULL;
712 struct listnode *node = NULL;
713
714 /* Make prefix structure. */
715 memset(&p, 0, sizeof(struct prefix_ipv6));
716 p.family = AF_INET6;
717 /* p.prefix = rte->addr; */
718 IPV6_ADDR_COPY(&p.prefix, &rte->addr);
719 p.prefixlen = rte->prefixlen;
720
721 /* Make sure mask is applied. */
722 /* XXX We have to check the prefix is valid or not before call
723 apply_mask_ipv6. */
724 apply_mask_ipv6(&p);
725
726 ri = ifp->info;
727 ripng = ri->ripng;
728
729 /* Apply input filters. */
730 ret = ripng_filter(RIPNG_FILTER_IN, &p, ri);
731 if (ret < 0)
732 return;
733
734 memset(&newinfo, 0, sizeof(newinfo));
735 newinfo.type = ZEBRA_ROUTE_RIPNG;
736 newinfo.sub_type = RIPNG_ROUTE_RTE;
737 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
738 newinfo.nexthop = ripng_nexthop->address;
739 else
740 newinfo.nexthop = from->sin6_addr;
741 newinfo.from = from->sin6_addr;
742 newinfo.ifindex = ifp->ifindex;
743 newinfo.metric = rte->metric;
744 newinfo.metric_out = rte->metric; /* XXX */
745 newinfo.tag = ntohs(rte->tag); /* XXX */
746
747 /* Modify entry. */
748 if (ri->routemap[RIPNG_FILTER_IN]) {
749 ret = route_map_apply(ri->routemap[RIPNG_FILTER_IN],
750 (struct prefix *)&p, RMAP_RIPNG,
751 &newinfo);
752
753 if (ret == RMAP_DENYMATCH) {
754 if (IS_RIPNG_DEBUG_PACKET)
755 zlog_debug(
756 "RIPng %s/%d is filtered by route-map in",
757 inet6_ntoa(p.prefix), p.prefixlen);
758 return;
759 }
760
761 /* Get back the object */
762 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
763 if (!IPV6_ADDR_SAME(&newinfo.nexthop,
764 &ripng_nexthop->address)) {
765 /* the nexthop get changed by the routemap */
766 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
767 ripng_nexthop->address =
768 newinfo.nexthop;
769 else
770 ripng_nexthop->address = in6addr_any;
771 }
772 } else {
773 if (!IPV6_ADDR_SAME(&newinfo.nexthop,
774 &from->sin6_addr)) {
775 /* the nexthop get changed by the routemap */
776 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
777 ripng_nexthop->flag =
778 RIPNG_NEXTHOP_ADDRESS;
779 ripng_nexthop->address =
780 newinfo.nexthop;
781 }
782 }
783 }
784 rte->tag = htons(newinfo.tag_out); /* XXX */
785 rte->metric =
786 newinfo.metric_out; /* XXX: the routemap uses the
787 metric_out field */
788 }
789
790 /* Once the entry has been validated, update the metric by
791 * adding the cost of the network on wich the message
792 * arrived. If the result is greater than infinity, use infinity
793 * (RFC2453 Sec. 3.9.2)
794 **/
795
796 /* Zebra ripngd can handle offset-list in. */
797 ret = ripng_offset_list_apply_in(ripng, &p, ifp, &rte->metric);
798
799 /* If offset-list does not modify the metric use interface's
800 * one. */
801 if (!ret)
802 rte->metric += ifp->metric ? ifp->metric : 1;
803
804 if (rte->metric > RIPNG_METRIC_INFINITY)
805 rte->metric = RIPNG_METRIC_INFINITY;
806
807 /* Set nexthop pointer. */
808 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
809 nexthop = &ripng_nexthop->address;
810 else
811 nexthop = &from->sin6_addr;
812
813 /* Lookup RIPng routing table. */
814 rp = agg_node_get(ripng->table, (struct prefix *)&p);
815
816 newinfo.rp = rp;
817 newinfo.nexthop = *nexthop;
818 newinfo.metric = rte->metric;
819 newinfo.tag = ntohs(rte->tag);
820
821 /* Check to see whether there is already RIPng route on the table. */
822 if ((list = rp->info) != NULL)
823 for (ALL_LIST_ELEMENTS_RO(list, node, rinfo)) {
824 /* Need to compare with redistributed entry or local
825 * entry */
826 if (!ripng_route_rte(rinfo))
827 break;
828
829 if (IPV6_ADDR_SAME(&rinfo->from, &from->sin6_addr)
830 && IPV6_ADDR_SAME(&rinfo->nexthop, nexthop))
831 break;
832
833 if (!listnextnode(node)) {
834 /* Not found in the list */
835
836 if (rte->metric > rinfo->metric) {
837 /* New route has a greater metric.
838 * Discard it. */
839 agg_unlock_node(rp);
840 return;
841 }
842
843 if (rte->metric < rinfo->metric)
844 /* New route has a smaller metric.
845 * Replace the ECMP list
846 * with the new one in below. */
847 break;
848
849 /* Metrics are same. Unless ECMP is disabled,
850 * keep "rinfo" null and
851 * the new route is added in the ECMP list in
852 * below. */
853 if (!ripng->ecmp)
854 break;
855 }
856 }
857
858 if (rinfo) {
859 /* Redistributed route check. */
860 if (rinfo->type != ZEBRA_ROUTE_RIPNG
861 && rinfo->metric != RIPNG_METRIC_INFINITY) {
862 agg_unlock_node(rp);
863 return;
864 }
865
866 /* Local static route. */
867 if (rinfo->type == ZEBRA_ROUTE_RIPNG
868 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
869 || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
870 && rinfo->metric != RIPNG_METRIC_INFINITY) {
871 agg_unlock_node(rp);
872 return;
873 }
874 }
875
876 if (!rinfo) {
877 /* Now, check to see whether there is already an explicit route
878 for the destination prefix. If there is no such route, add
879 this route to the routing table, unless the metric is
880 infinity (there is no point in adding a route which
881 unusable). */
882 if (rte->metric != RIPNG_METRIC_INFINITY)
883 ripng_ecmp_add(ripng, &newinfo);
884 else
885 agg_unlock_node(rp);
886 } else {
887 /* If there is an existing route, compare the next hop address
888 to the address of the router from which the datagram came.
889 If this datagram is from the same router as the existing
890 route, reinitialize the timeout. */
891 same = (IN6_ARE_ADDR_EQUAL(&rinfo->from, &from->sin6_addr)
892 && (rinfo->ifindex == ifp->ifindex));
893
894 /*
895 * RFC 2080 - Section 2.4.2:
896 * "If the new metric is the same as the old one, examine the
897 * timeout
898 * for the existing route. If it is at least halfway to the
899 * expiration
900 * point, switch to the new route. This heuristic is optional,
901 * but
902 * highly recommended".
903 */
904 if (!ripng->ecmp && !same && rinfo->metric == rte->metric
905 && rinfo->t_timeout
906 && (thread_timer_remain_second(rinfo->t_timeout)
907 < (ripng->timeout_time / 2))) {
908 ripng_ecmp_replace(ripng, &newinfo);
909 }
910 /* Next, compare the metrics. If the datagram is from the same
911 router as the existing route, and the new metric is different
912 than the old one; or, if the new metric is lower than the old
913 one; do the following actions: */
914 else if ((same && rinfo->metric != rte->metric)
915 || rte->metric < rinfo->metric) {
916 if (listcount(list) == 1) {
917 if (newinfo.metric != RIPNG_METRIC_INFINITY)
918 ripng_ecmp_replace(ripng, &newinfo);
919 else
920 ripng_ecmp_delete(ripng, rinfo);
921 } else {
922 if (newinfo.metric < rinfo->metric)
923 ripng_ecmp_replace(ripng, &newinfo);
924 else /* newinfo.metric > rinfo->metric */
925 ripng_ecmp_delete(ripng, rinfo);
926 }
927 } else /* same & no change */
928 ripng_timeout_update(ripng, rinfo);
929
930 /* Unlock tempolary lock of the route. */
931 agg_unlock_node(rp);
932 }
933 }
934
935 /* Add redistributed route to RIPng table. */
936 void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type,
937 struct prefix_ipv6 *p, ifindex_t ifindex,
938 struct in6_addr *nexthop, route_tag_t tag)
939 {
940 struct agg_node *rp;
941 struct ripng_info *rinfo = NULL, newinfo;
942 struct list *list = NULL;
943
944 /* Redistribute route */
945 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
946 return;
947 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
948 return;
949
950 rp = agg_node_get(ripng->table, (struct prefix *)p);
951
952 memset(&newinfo, 0, sizeof(struct ripng_info));
953 newinfo.type = type;
954 newinfo.sub_type = sub_type;
955 newinfo.ifindex = ifindex;
956 newinfo.metric = 1;
957 if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
958 newinfo.tag = tag;
959 newinfo.rp = rp;
960 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
961 newinfo.nexthop = *nexthop;
962
963 if ((list = rp->info) != NULL && listcount(list) != 0) {
964 rinfo = listgetdata(listhead(list));
965
966 if (rinfo->type == ZEBRA_ROUTE_CONNECT
967 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
968 && rinfo->metric != RIPNG_METRIC_INFINITY) {
969 agg_unlock_node(rp);
970 return;
971 }
972
973 /* Manually configured RIPng route check.
974 * They have the precedence on all the other entries.
975 **/
976 if (rinfo->type == ZEBRA_ROUTE_RIPNG
977 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
978 || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))) {
979 if (type != ZEBRA_ROUTE_RIPNG
980 || ((sub_type != RIPNG_ROUTE_STATIC)
981 && (sub_type != RIPNG_ROUTE_DEFAULT))) {
982 agg_unlock_node(rp);
983 return;
984 }
985 }
986
987 ripng_ecmp_replace(ripng, &newinfo);
988 agg_unlock_node(rp);
989 } else
990 ripng_ecmp_add(ripng, &newinfo);
991
992 if (IS_RIPNG_DEBUG_EVENT) {
993 if (!nexthop)
994 zlog_debug(
995 "Redistribute new prefix %s/%d on the interface %s",
996 inet6_ntoa(p->prefix), p->prefixlen,
997 ifindex2ifname(ifindex, ripng->vrf->vrf_id));
998 else
999 zlog_debug(
1000 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
1001 inet6_ntoa(p->prefix), p->prefixlen,
1002 inet6_ntoa(*nexthop),
1003 ifindex2ifname(ifindex, ripng->vrf->vrf_id));
1004 }
1005
1006 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
1007 }
1008
1009 /* Delete redistributed route to RIPng table. */
1010 void ripng_redistribute_delete(struct ripng *ripng, int type, int sub_type,
1011 struct prefix_ipv6 *p, ifindex_t ifindex)
1012 {
1013 struct agg_node *rp;
1014 struct ripng_info *rinfo;
1015
1016 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
1017 return;
1018 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
1019 return;
1020
1021 rp = agg_node_lookup(ripng->table, (struct prefix *)p);
1022
1023 if (rp) {
1024 struct list *list = rp->info;
1025
1026 if (list != NULL && listcount(list) != 0) {
1027 rinfo = listgetdata(listhead(list));
1028 if (rinfo != NULL && rinfo->type == type
1029 && rinfo->sub_type == sub_type
1030 && rinfo->ifindex == ifindex) {
1031 /* Perform poisoned reverse. */
1032 rinfo->metric = RIPNG_METRIC_INFINITY;
1033 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
1034 ripng_garbage_collect,
1035 ripng->garbage_time);
1036 RIPNG_TIMER_OFF(rinfo->t_timeout);
1037
1038 /* Aggregate count decrement. */
1039 ripng_aggregate_decrement(rp, rinfo);
1040
1041 rinfo->flags |= RIPNG_RTF_CHANGED;
1042
1043 if (IS_RIPNG_DEBUG_EVENT)
1044 zlog_debug(
1045 "Poisone %s/%d on the interface %s with an "
1046 "infinity metric [delete]",
1047 inet6_ntoa(p->prefix),
1048 p->prefixlen,
1049 ifindex2ifname(
1050 ifindex,
1051 ripng->vrf->vrf_id));
1052
1053 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
1054 }
1055 }
1056 agg_unlock_node(rp);
1057 }
1058 }
1059
1060 /* Withdraw redistributed route. */
1061 void ripng_redistribute_withdraw(struct ripng *ripng, int type)
1062 {
1063 struct agg_node *rp;
1064 struct ripng_info *rinfo = NULL;
1065 struct list *list = NULL;
1066
1067 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
1068 if ((list = rp->info) != NULL) {
1069 rinfo = listgetdata(listhead(list));
1070 if ((rinfo->type == type)
1071 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) {
1072 /* Perform poisoned reverse. */
1073 rinfo->metric = RIPNG_METRIC_INFINITY;
1074 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
1075 ripng_garbage_collect,
1076 ripng->garbage_time);
1077 RIPNG_TIMER_OFF(rinfo->t_timeout);
1078
1079 /* Aggregate count decrement. */
1080 ripng_aggregate_decrement(rp, rinfo);
1081
1082 rinfo->flags |= RIPNG_RTF_CHANGED;
1083
1084 if (IS_RIPNG_DEBUG_EVENT) {
1085 struct prefix_ipv6 *p =
1086 (struct prefix_ipv6 *)&rp->p;
1087
1088 zlog_debug(
1089 "Poisone %s/%d on the interface %s [withdraw]",
1090 inet6_ntoa(p->prefix),
1091 p->prefixlen,
1092 ifindex2ifname(
1093 rinfo->ifindex,
1094 ripng->vrf->vrf_id));
1095 }
1096
1097 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
1098 }
1099 }
1100 }
1101
1102 /* RIP routing information. */
1103 static void ripng_response_process(struct ripng_packet *packet, int size,
1104 struct sockaddr_in6 *from,
1105 struct interface *ifp, int hoplimit)
1106 {
1107 struct ripng_interface *ri = ifp->info;
1108 struct ripng *ripng = ri->ripng;
1109 caddr_t lim;
1110 struct rte *rte;
1111 struct ripng_nexthop nexthop;
1112
1113 /* RFC2080 2.4.2 Response Messages:
1114 The Response must be ignored if it is not from the RIPng port. */
1115 if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
1116 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1117 ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr));
1118 ripng_peer_bad_packet(ripng, from);
1119 return;
1120 }
1121
1122 /* The datagram's IPv6 source address should be checked to see
1123 whether the datagram is from a valid neighbor; the source of the
1124 datagram must be a link-local address. */
1125 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
1126 zlog_warn("RIPng packet comes from non link local address %s",
1127 inet6_ntoa(from->sin6_addr));
1128 ripng_peer_bad_packet(ripng, from);
1129 return;
1130 }
1131
1132 /* It is also worth checking to see whether the response is from one
1133 of the router's own addresses. Interfaces on broadcast networks
1134 may receive copies of their own multicasts immediately. If a
1135 router processes its own output as new input, confusion is likely,
1136 and such datagrams must be ignored. */
1137 if (ripng_lladdr_check(ifp, &from->sin6_addr)) {
1138 zlog_warn(
1139 "RIPng packet comes from my own link local address %s",
1140 inet6_ntoa(from->sin6_addr));
1141 ripng_peer_bad_packet(ripng, from);
1142 return;
1143 }
1144
1145 /* As an additional check, periodic advertisements must have their
1146 hop counts set to 255, and inbound, multicast packets sent from the
1147 RIPng port (i.e. periodic advertisement or triggered update
1148 packets) must be examined to ensure that the hop count is 255. */
1149 if (hoplimit >= 0 && hoplimit != 255) {
1150 zlog_warn(
1151 "RIPng packet comes with non 255 hop count %d from %s",
1152 hoplimit, inet6_ntoa(from->sin6_addr));
1153 ripng_peer_bad_packet(ripng, from);
1154 return;
1155 }
1156
1157 /* Update RIPng peer. */
1158 ripng_peer_update(ripng, from, packet->version);
1159
1160 /* Reset nexthop. */
1161 memset(&nexthop, 0, sizeof(struct ripng_nexthop));
1162 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1163
1164 /* Set RTE pointer. */
1165 rte = packet->rte;
1166
1167 for (lim = ((caddr_t)packet) + size; (caddr_t)rte < lim; rte++) {
1168 /* First of all, we have to check this RTE is next hop RTE or
1169 not. Next hop RTE is completely different with normal RTE so
1170 we need special treatment. */
1171 if (rte->metric == RIPNG_METRIC_NEXTHOP) {
1172 ripng_nexthop_rte(rte, from, &nexthop);
1173 continue;
1174 }
1175
1176 /* RTE information validation. */
1177
1178 /* - is the destination prefix valid (e.g., not a multicast
1179 prefix and not a link-local address) A link-local address
1180 should never be present in an RTE. */
1181 if (IN6_IS_ADDR_MULTICAST(&rte->addr)) {
1182 zlog_warn(
1183 "Destination prefix is a multicast address %s/%d [%d]",
1184 inet6_ntoa(rte->addr), rte->prefixlen,
1185 rte->metric);
1186 ripng_peer_bad_route(ripng, from);
1187 continue;
1188 }
1189 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
1190 zlog_warn(
1191 "Destination prefix is a link-local address %s/%d [%d]",
1192 inet6_ntoa(rte->addr), rte->prefixlen,
1193 rte->metric);
1194 ripng_peer_bad_route(ripng, from);
1195 continue;
1196 }
1197 if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
1198 zlog_warn(
1199 "Destination prefix is a loopback address %s/%d [%d]",
1200 inet6_ntoa(rte->addr), rte->prefixlen,
1201 rte->metric);
1202 ripng_peer_bad_route(ripng, from);
1203 continue;
1204 }
1205
1206 /* - is the prefix length valid (i.e., between 0 and 128,
1207 inclusive) */
1208 if (rte->prefixlen > 128) {
1209 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1210 inet6_ntoa(rte->addr), rte->prefixlen,
1211 inet6_ntoa(from->sin6_addr), ifp->name);
1212 ripng_peer_bad_route(ripng, from);
1213 continue;
1214 }
1215
1216 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1217 if (!(rte->metric >= 1 && rte->metric <= 16)) {
1218 zlog_warn("Invalid metric %d from %s%%%s", rte->metric,
1219 inet6_ntoa(from->sin6_addr), ifp->name);
1220 ripng_peer_bad_route(ripng, from);
1221 continue;
1222 }
1223
1224 /* Vincent: XXX Should we compute the direclty reachable nexthop
1225 * for our RIPng network ?
1226 **/
1227
1228 /* Routing table updates. */
1229 ripng_route_process(rte, from, &nexthop, ifp);
1230 }
1231 }
1232
1233 /* Response to request message. */
1234 static void ripng_request_process(struct ripng_packet *packet, int size,
1235 struct sockaddr_in6 *from,
1236 struct interface *ifp)
1237 {
1238 struct ripng *ripng;
1239 caddr_t lim;
1240 struct rte *rte;
1241 struct prefix_ipv6 p;
1242 struct agg_node *rp;
1243 struct ripng_info *rinfo;
1244 struct ripng_interface *ri;
1245
1246 /* Does not reponse to the requests on the loopback interfaces */
1247 if (if_is_loopback(ifp))
1248 return;
1249
1250 /* Check RIPng process is enabled on this interface. */
1251 ri = ifp->info;
1252 if (!ri->running)
1253 return;
1254 ripng = ri->ripng;
1255
1256 /* When passive interface is specified, suppress responses */
1257 if (ri->passive)
1258 return;
1259
1260 /* RIPng peer update. */
1261 ripng_peer_update(ripng, from, packet->version);
1262
1263 lim = ((caddr_t)packet) + size;
1264 rte = packet->rte;
1265
1266 /* The Request is processed entry by entry. If there are no
1267 entries, no response is given. */
1268 if (lim == (caddr_t)rte)
1269 return;
1270
1271 /* There is one special case. If there is exactly one entry in the
1272 request, and it has a destination prefix of zero, a prefix length
1273 of zero, and a metric of infinity (i.e., 16), then this is a
1274 request to send the entire routing table. In that case, a call
1275 is made to the output process to send the routing table to the
1276 requesting address/port. */
1277 if (lim == ((caddr_t)(rte + 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte->addr)
1278 && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) {
1279 /* All route with split horizon */
1280 ripng_output_process(ifp, from, ripng_all_route);
1281 } else {
1282 /* Except for this special case, processing is quite simple.
1283 Examine the list of RTEs in the Request one by one. For each
1284 entry, look up the destination in the router's routing
1285 database and, if there is a route, put that route's metric in
1286 the metric field of the RTE. If there is no explicit route
1287 to the specified destination, put infinity in the metric
1288 field. Once all the entries have been filled in, change the
1289 command from Request to Response and send the datagram back
1290 to the requestor. */
1291 memset(&p, 0, sizeof(struct prefix_ipv6));
1292 p.family = AF_INET6;
1293
1294 for (; ((caddr_t)rte) < lim; rte++) {
1295 p.prefix = rte->addr;
1296 p.prefixlen = rte->prefixlen;
1297 apply_mask_ipv6(&p);
1298
1299 rp = agg_node_lookup(ripng->table, (struct prefix *)&p);
1300
1301 if (rp) {
1302 rinfo = listgetdata(
1303 listhead((struct list *)rp->info));
1304 rte->metric = rinfo->metric;
1305 agg_unlock_node(rp);
1306 } else
1307 rte->metric = RIPNG_METRIC_INFINITY;
1308 }
1309 packet->command = RIPNG_RESPONSE;
1310
1311 ripng_send_packet((caddr_t)packet, size, from, ifp);
1312 }
1313 }
1314
1315 /* First entry point of reading RIPng packet. */
1316 static int ripng_read(struct thread *thread)
1317 {
1318 struct ripng *ripng = THREAD_ARG(thread);
1319 int len;
1320 int sock;
1321 struct sockaddr_in6 from;
1322 struct ripng_packet *packet;
1323 ifindex_t ifindex = 0;
1324 struct interface *ifp;
1325 int hoplimit = -1;
1326
1327 /* Check ripng is active and alive. */
1328 assert(ripng != NULL);
1329 assert(ripng->sock >= 0);
1330
1331 /* Fetch thread data and set read pointer to empty for event
1332 managing. `sock' sould be same as ripng->sock. */
1333 sock = THREAD_FD(thread);
1334 ripng->t_read = NULL;
1335
1336 /* Add myself to the next event. */
1337 ripng_event(ripng, RIPNG_READ, sock);
1338
1339 /* Read RIPng packet. */
1340 len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
1341 STREAM_SIZE(ripng->ibuf), &from, &ifindex,
1342 &hoplimit);
1343 if (len < 0) {
1344 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1345 ripng->vrf_name, safe_strerror(errno));
1346 return len;
1347 }
1348
1349 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1350 (4)) must be multiple size of one RTE size (20). */
1351 if (((len - 4) % 20) != 0) {
1352 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len,
1353 inet6_ntoa(from.sin6_addr), ripng->vrf_name);
1354 ripng_peer_bad_packet(ripng, &from);
1355 return 0;
1356 }
1357
1358 packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
1359 ifp = if_lookup_by_index(ifindex, ripng->vrf->vrf_id);
1360
1361 /* RIPng packet received. */
1362 if (IS_RIPNG_DEBUG_EVENT)
1363 zlog_debug(
1364 "RIPng packet received from %s port %d on %s (VRF %s)",
1365 inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
1366 ifp ? ifp->name : "unknown", ripng->vrf_name);
1367
1368 /* Logging before packet checking. */
1369 if (IS_RIPNG_DEBUG_RECV)
1370 ripng_packet_dump(packet, len, "RECV");
1371
1372 /* Packet comes from unknown interface. */
1373 if (ifp == NULL) {
1374 zlog_warn(
1375 "RIPng packet comes from unknown interface %d (VRF %s)",
1376 ifindex, ripng->vrf_name);
1377 return 0;
1378 }
1379
1380 /* Packet version mismatch checking. */
1381 if (packet->version != ripng->version) {
1382 zlog_warn(
1383 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1384 packet->version, ripng->version, ripng->vrf_name);
1385 ripng_peer_bad_packet(ripng, &from);
1386 return 0;
1387 }
1388
1389 /* Process RIPng packet. */
1390 switch (packet->command) {
1391 case RIPNG_REQUEST:
1392 ripng_request_process(packet, len, &from, ifp);
1393 break;
1394 case RIPNG_RESPONSE:
1395 ripng_response_process(packet, len, &from, ifp, hoplimit);
1396 break;
1397 default:
1398 zlog_warn("Invalid RIPng command %d (VRF %s)", packet->command,
1399 ripng->vrf_name);
1400 ripng_peer_bad_packet(ripng, &from);
1401 break;
1402 }
1403 return 0;
1404 }
1405
1406 /* Walk down the RIPng routing table then clear changed flag. */
1407 static void ripng_clear_changed_flag(struct ripng *ripng)
1408 {
1409 struct agg_node *rp;
1410 struct ripng_info *rinfo = NULL;
1411 struct list *list = NULL;
1412 struct listnode *listnode = NULL;
1413
1414 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
1415 if ((list = rp->info) != NULL)
1416 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1417 UNSET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
1418 /* This flag can be set only on the first entry.
1419 */
1420 break;
1421 }
1422 }
1423
1424 /* Regular update of RIPng route. Send all routing formation to RIPng
1425 enabled interface. */
1426 static int ripng_update(struct thread *t)
1427 {
1428 struct ripng *ripng = THREAD_ARG(t);
1429 struct interface *ifp;
1430 struct ripng_interface *ri;
1431
1432 /* Clear update timer thread. */
1433 ripng->t_update = NULL;
1434
1435 /* Logging update event. */
1436 if (IS_RIPNG_DEBUG_EVENT)
1437 zlog_debug("RIPng update timer expired!");
1438
1439 /* Supply routes to each interface. */
1440 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
1441 ri = ifp->info;
1442
1443 if (if_is_loopback(ifp) || !if_is_up(ifp))
1444 continue;
1445
1446 if (!ri->running)
1447 continue;
1448
1449 /* When passive interface is specified, suppress announce to the
1450 interface. */
1451 if (ri->passive)
1452 continue;
1453
1454 #if RIPNG_ADVANCED
1455 if (ri->ri_send == RIPNG_SEND_OFF) {
1456 if (IS_RIPNG_DEBUG_EVENT)
1457 zlog_debug(
1458 "[Event] RIPng send to if %d is suppressed by config",
1459 ifp->ifindex);
1460 continue;
1461 }
1462 #endif /* RIPNG_ADVANCED */
1463
1464 ripng_output_process(ifp, NULL, ripng_all_route);
1465 }
1466
1467 /* Triggered updates may be suppressed if a regular update is due by
1468 the time the triggered update would be sent. */
1469 if (ripng->t_triggered_interval) {
1470 thread_cancel(ripng->t_triggered_interval);
1471 ripng->t_triggered_interval = NULL;
1472 }
1473 ripng->trigger = 0;
1474
1475 /* Reset flush event. */
1476 ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
1477
1478 return 0;
1479 }
1480
1481 /* Triggered update interval timer. */
1482 static int ripng_triggered_interval(struct thread *t)
1483 {
1484 struct ripng *ripng = THREAD_ARG(t);
1485
1486 ripng->t_triggered_interval = NULL;
1487
1488 if (ripng->trigger) {
1489 ripng->trigger = 0;
1490 ripng_triggered_update(t);
1491 }
1492 return 0;
1493 }
1494
1495 /* Execute triggered update. */
1496 int ripng_triggered_update(struct thread *t)
1497 {
1498 struct ripng *ripng = THREAD_ARG(t);
1499 struct interface *ifp;
1500 struct ripng_interface *ri;
1501 int interval;
1502
1503 ripng->t_triggered_update = NULL;
1504
1505 /* Cancel interval timer. */
1506 if (ripng->t_triggered_interval) {
1507 thread_cancel(ripng->t_triggered_interval);
1508 ripng->t_triggered_interval = NULL;
1509 }
1510 ripng->trigger = 0;
1511
1512 /* Logging triggered update. */
1513 if (IS_RIPNG_DEBUG_EVENT)
1514 zlog_debug("RIPng triggered update!");
1515
1516 /* Split Horizon processing is done when generating triggered
1517 updates as well as normal updates (see section 2.6). */
1518 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
1519 ri = ifp->info;
1520
1521 if (if_is_loopback(ifp) || !if_is_up(ifp))
1522 continue;
1523
1524 if (!ri->running)
1525 continue;
1526
1527 /* When passive interface is specified, suppress announce to the
1528 interface. */
1529 if (ri->passive)
1530 continue;
1531
1532 ripng_output_process(ifp, NULL, ripng_changed_route);
1533 }
1534
1535 /* Once all of the triggered updates have been generated, the route
1536 change flags should be cleared. */
1537 ripng_clear_changed_flag(ripng);
1538
1539 /* After a triggered update is sent, a timer should be set for a
1540 random interval between 1 and 5 seconds. If other changes that
1541 would trigger updates occur before the timer expires, a single
1542 update is triggered when the timer expires. */
1543 interval = (random() % 5) + 1;
1544
1545 ripng->t_triggered_interval = NULL;
1546 thread_add_timer(master, ripng_triggered_interval, ripng, interval,
1547 &ripng->t_triggered_interval);
1548
1549 return 0;
1550 }
1551
1552 /* Write routing table entry to the stream and return next index of
1553 the routing table entry in the stream. */
1554 int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
1555 struct in6_addr *nexthop, uint16_t tag, uint8_t metric)
1556 {
1557 /* RIPng packet header. */
1558 if (num == 0) {
1559 stream_putc(s, RIPNG_RESPONSE);
1560 stream_putc(s, RIPNG_V1);
1561 stream_putw(s, 0);
1562 }
1563
1564 /* Write routing table entry. */
1565 if (!nexthop) {
1566 assert(p);
1567 stream_write(s, (uint8_t *)&p->prefix, sizeof(struct in6_addr));
1568 } else
1569 stream_write(s, (uint8_t *)nexthop, sizeof(struct in6_addr));
1570 stream_putw(s, tag);
1571 if (p)
1572 stream_putc(s, p->prefixlen);
1573 else
1574 stream_putc(s, 0);
1575 stream_putc(s, metric);
1576
1577 return ++num;
1578 }
1579
1580 /* Send RESPONSE message to specified destination. */
1581 void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
1582 int route_type)
1583 {
1584 struct ripng *ripng;
1585 int ret;
1586 struct agg_node *rp;
1587 struct ripng_info *rinfo;
1588 struct ripng_interface *ri;
1589 struct ripng_aggregate *aggregate;
1590 struct prefix_ipv6 *p;
1591 struct list *ripng_rte_list;
1592 struct list *list = NULL;
1593 struct listnode *listnode = NULL;
1594
1595 if (IS_RIPNG_DEBUG_EVENT) {
1596 if (to)
1597 zlog_debug("RIPng update routes to neighbor %s",
1598 inet6_ntoa(to->sin6_addr));
1599 else
1600 zlog_debug("RIPng update routes on interface %s",
1601 ifp->name);
1602 }
1603
1604 /* Get RIPng interface and instance. */
1605 ri = ifp->info;
1606 ripng = ri->ripng;
1607
1608 ripng_rte_list = ripng_rte_new();
1609
1610 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
1611 if ((list = rp->info) != NULL
1612 && (rinfo = listgetdata(listhead(list))) != NULL
1613 && rinfo->suppress == 0) {
1614 /* If no route-map are applied, the RTE will be these
1615 * following
1616 * information.
1617 */
1618 p = (struct prefix_ipv6 *)&rp->p;
1619 rinfo->metric_out = rinfo->metric;
1620 rinfo->tag_out = rinfo->tag;
1621 memset(&rinfo->nexthop_out, 0,
1622 sizeof(rinfo->nexthop_out));
1623 /* In order to avoid some local loops,
1624 * if the RIPng route has a nexthop via this interface,
1625 * keep the nexthop,
1626 * otherwise set it to 0. The nexthop should not be
1627 * propagated
1628 * beyond the local broadcast/multicast area in order
1629 * to avoid an IGP multi-level recursive look-up.
1630 */
1631 if (rinfo->ifindex == ifp->ifindex)
1632 rinfo->nexthop_out = rinfo->nexthop;
1633
1634 /* Apply output filters. */
1635 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1636 if (ret < 0)
1637 continue;
1638
1639 /* Changed route only output. */
1640 if (route_type == ripng_changed_route
1641 && (!(rinfo->flags & RIPNG_RTF_CHANGED)))
1642 continue;
1643
1644 /* Split horizon. */
1645 if (ri->split_horizon == RIPNG_SPLIT_HORIZON) {
1646 /* We perform split horizon for RIPng routes. */
1647 int suppress = 0;
1648 struct ripng_info *tmp_rinfo = NULL;
1649
1650 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1651 tmp_rinfo))
1652 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG
1653 && tmp_rinfo->ifindex
1654 == ifp->ifindex) {
1655 suppress = 1;
1656 break;
1657 }
1658 if (suppress)
1659 continue;
1660 }
1661
1662 /* Preparation for route-map. */
1663 rinfo->metric_set = 0;
1664 /* nexthop_out,
1665 * metric_out
1666 * and tag_out are already initialized.
1667 */
1668
1669 /* Interface route-map */
1670 if (ri->routemap[RIPNG_FILTER_OUT]) {
1671 ret = route_map_apply(
1672 ri->routemap[RIPNG_FILTER_OUT],
1673 (struct prefix *)p, RMAP_RIPNG, rinfo);
1674
1675 if (ret == RMAP_DENYMATCH) {
1676 if (IS_RIPNG_DEBUG_PACKET)
1677 zlog_debug(
1678 "RIPng %s/%d is filtered by route-map out",
1679 inet6_ntoa(p->prefix),
1680 p->prefixlen);
1681 continue;
1682 }
1683 }
1684
1685 /* Redistribute route-map. */
1686 if (ripng->redist[rinfo->type].route_map.name) {
1687 ret = route_map_apply(ripng->redist[rinfo->type]
1688 .route_map.map,
1689 (struct prefix *)p,
1690 RMAP_RIPNG, rinfo);
1691
1692 if (ret == RMAP_DENYMATCH) {
1693 if (IS_RIPNG_DEBUG_PACKET)
1694 zlog_debug(
1695 "RIPng %s/%d is filtered by route-map",
1696 inet6_ntoa(p->prefix),
1697 p->prefixlen);
1698 continue;
1699 }
1700 }
1701
1702 /* When the route-map does not set metric. */
1703 if (!rinfo->metric_set) {
1704 /* If the redistribute metric is set. */
1705 if (ripng->redist[rinfo->type].metric_config
1706 && rinfo->metric != RIPNG_METRIC_INFINITY) {
1707 rinfo->metric_out =
1708 ripng->redist[rinfo->type]
1709 .metric;
1710 } else {
1711 /* If the route is not connected or
1712 localy generated
1713 one, use default-metric value */
1714 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1715 && rinfo->type
1716 != ZEBRA_ROUTE_CONNECT
1717 && rinfo->metric
1718 != RIPNG_METRIC_INFINITY)
1719 rinfo->metric_out =
1720 ripng->default_metric;
1721 }
1722 }
1723
1724 /* Apply offset-list */
1725 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1726 ripng_offset_list_apply_out(ripng, p, ifp,
1727 &rinfo->metric_out);
1728
1729 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1730 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1731
1732 /* Perform split-horizon with poisoned reverse
1733 * for RIPng routes.
1734 **/
1735 if (ri->split_horizon
1736 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1737 struct ripng_info *tmp_rinfo = NULL;
1738
1739 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1740 tmp_rinfo))
1741 if ((tmp_rinfo->type
1742 == ZEBRA_ROUTE_RIPNG)
1743 && tmp_rinfo->ifindex
1744 == ifp->ifindex)
1745 rinfo->metric_out =
1746 RIPNG_METRIC_INFINITY;
1747 }
1748
1749 /* Add RTE to the list */
1750 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
1751 }
1752
1753 /* Process the aggregated RTE entry */
1754 if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0
1755 && aggregate->suppress == 0) {
1756 /* If no route-map are applied, the RTE will be these
1757 * following
1758 * information.
1759 */
1760 p = (struct prefix_ipv6 *)&rp->p;
1761 aggregate->metric_set = 0;
1762 aggregate->metric_out = aggregate->metric;
1763 aggregate->tag_out = aggregate->tag;
1764 memset(&aggregate->nexthop_out, 0,
1765 sizeof(aggregate->nexthop_out));
1766
1767 /* Apply output filters.*/
1768 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1769 if (ret < 0)
1770 continue;
1771
1772 /* Interface route-map */
1773 if (ri->routemap[RIPNG_FILTER_OUT]) {
1774 struct ripng_info newinfo;
1775
1776 /* let's cast the aggregate structure to
1777 * ripng_info */
1778 memset(&newinfo, 0, sizeof(struct ripng_info));
1779 /* the nexthop is :: */
1780 newinfo.metric = aggregate->metric;
1781 newinfo.metric_out = aggregate->metric_out;
1782 newinfo.tag = aggregate->tag;
1783 newinfo.tag_out = aggregate->tag_out;
1784
1785 ret = route_map_apply(
1786 ri->routemap[RIPNG_FILTER_OUT],
1787 (struct prefix *)p, RMAP_RIPNG,
1788 &newinfo);
1789
1790 if (ret == RMAP_DENYMATCH) {
1791 if (IS_RIPNG_DEBUG_PACKET)
1792 zlog_debug(
1793 "RIPng %s/%d is filtered by route-map out",
1794 inet6_ntoa(p->prefix),
1795 p->prefixlen);
1796 continue;
1797 }
1798
1799 aggregate->metric_out = newinfo.metric_out;
1800 aggregate->tag_out = newinfo.tag_out;
1801 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1802 aggregate->nexthop_out =
1803 newinfo.nexthop_out;
1804 }
1805
1806 /* There is no redistribute routemap for the aggregated
1807 * RTE */
1808
1809 /* Changed route only output. */
1810 /* XXX, vincent, in order to increase time convergence,
1811 * it should be announced if a child has changed.
1812 */
1813 if (route_type == ripng_changed_route)
1814 continue;
1815
1816 /* Apply offset-list */
1817 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1818 ripng_offset_list_apply_out(
1819 ripng, p, ifp, &aggregate->metric_out);
1820
1821 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1822 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1823
1824 /* Add RTE to the list */
1825 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
1826 }
1827 }
1828
1829 /* Flush the list */
1830 ripng_rte_send(ripng_rte_list, ifp, to);
1831 ripng_rte_free(ripng_rte_list);
1832 }
1833
1834 struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id)
1835 {
1836 struct vrf *vrf;
1837
1838 vrf = vrf_lookup_by_id(vrf_id);
1839 if (!vrf)
1840 return NULL;
1841
1842 return vrf->info;
1843 }
1844
1845 struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name)
1846 {
1847 struct ripng ripng;
1848
1849 ripng.vrf_name = (char *)vrf_name;
1850
1851 return RB_FIND(ripng_instance_head, &ripng_instances, &ripng);
1852 }
1853
1854 /* Create new RIPng instance and set it to global variable. */
1855 struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket)
1856 {
1857 struct ripng *ripng;
1858
1859 /* Allocaste RIPng instance. */
1860 ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
1861 ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf_name);
1862
1863 /* Default version and timer values. */
1864 ripng->version = RIPNG_V1;
1865 ripng->update_time = yang_get_default_uint32(
1866 "%s/timers/update-interval", RIPNG_INSTANCE);
1867 ripng->timeout_time = yang_get_default_uint32(
1868 "%s/timers/holddown-interval", RIPNG_INSTANCE);
1869 ripng->garbage_time = yang_get_default_uint32(
1870 "%s/timers/flush-interval", RIPNG_INSTANCE);
1871 ripng->default_metric =
1872 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE);
1873 ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE);
1874
1875 /* Make buffer. */
1876 ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
1877 ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
1878
1879 /* Initialize RIPng data structures. */
1880 ripng->table = agg_table_init();
1881 agg_set_table_info(ripng->table, ripng);
1882 ripng->peer_list = list_new();
1883 ripng->peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp;
1884 ripng->peer_list->del = ripng_peer_list_del;
1885 ripng->enable_if = vector_init(1);
1886 ripng->enable_network = agg_table_init();
1887 ripng->passive_interface = vector_init(1);
1888 ripng->offset_list_master = list_new();
1889 ripng->offset_list_master->cmp =
1890 (int (*)(void *, void *))offset_list_cmp;
1891 ripng->offset_list_master->del =
1892 (void (*)(void *))ripng_offset_list_free;
1893 ripng->distribute_ctx = distribute_list_ctx_create(vrf);
1894 distribute_list_add_hook(ripng->distribute_ctx,
1895 ripng_distribute_update);
1896 distribute_list_delete_hook(ripng->distribute_ctx,
1897 ripng_distribute_update);
1898
1899 /* if rmap install. */
1900 ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
1901 if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update);
1902 if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update);
1903
1904 /* Enable the routing instance if possible. */
1905 if (vrf && vrf_is_enabled(vrf))
1906 ripng_instance_enable(ripng, vrf, socket);
1907 else {
1908 ripng->vrf = NULL;
1909 ripng->sock = -1;
1910 }
1911
1912 RB_INSERT(ripng_instance_head, &ripng_instances, ripng);
1913
1914 return ripng;
1915 }
1916
1917 /* Send RIPng request to the interface. */
1918 int ripng_request(struct interface *ifp)
1919 {
1920 struct rte *rte;
1921 struct ripng_packet ripng_packet;
1922
1923 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1924 */
1925 if (if_is_loopback(ifp))
1926 return 0;
1927
1928 /* If interface is down, don't send RIP packet. */
1929 if (!if_is_up(ifp))
1930 return 0;
1931
1932 if (IS_RIPNG_DEBUG_EVENT)
1933 zlog_debug("RIPng send request to %s", ifp->name);
1934
1935 memset(&ripng_packet, 0, sizeof(ripng_packet));
1936 ripng_packet.command = RIPNG_REQUEST;
1937 ripng_packet.version = RIPNG_V1;
1938 rte = ripng_packet.rte;
1939 rte->metric = RIPNG_METRIC_INFINITY;
1940
1941 return ripng_send_packet((caddr_t)&ripng_packet, sizeof(ripng_packet),
1942 NULL, ifp);
1943 }
1944
1945
1946 static int ripng_update_jitter(int time)
1947 {
1948 return ((random() % (time + 1)) - (time / 2));
1949 }
1950
1951 void ripng_event(struct ripng *ripng, enum ripng_event event, int sock)
1952 {
1953 int jitter = 0;
1954
1955 switch (event) {
1956 case RIPNG_READ:
1957 thread_add_read(master, ripng_read, ripng, sock,
1958 &ripng->t_read);
1959 break;
1960 case RIPNG_UPDATE_EVENT:
1961 if (ripng->t_update) {
1962 thread_cancel(ripng->t_update);
1963 ripng->t_update = NULL;
1964 }
1965 /* Update timer jitter. */
1966 jitter = ripng_update_jitter(ripng->update_time);
1967
1968 ripng->t_update = NULL;
1969 thread_add_timer(master, ripng_update, ripng,
1970 sock ? 2 : ripng->update_time + jitter,
1971 &ripng->t_update);
1972 break;
1973 case RIPNG_TRIGGERED_UPDATE:
1974 if (ripng->t_triggered_interval)
1975 ripng->trigger = 1;
1976 else
1977 thread_add_event(master, ripng_triggered_update, ripng,
1978 0, &ripng->t_triggered_update);
1979 break;
1980 default:
1981 break;
1982 }
1983 }
1984
1985
1986 /* Print out routes update time. */
1987 static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
1988 {
1989 time_t clock;
1990 struct tm *tm;
1991 #define TIME_BUF 25
1992 char timebuf[TIME_BUF];
1993 struct thread *thread;
1994
1995 if ((thread = rinfo->t_timeout) != NULL) {
1996 clock = thread_timer_remain_second(thread);
1997 tm = gmtime(&clock);
1998 strftime(timebuf, TIME_BUF, "%M:%S", tm);
1999 vty_out(vty, "%5s", timebuf);
2000 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
2001 clock = thread_timer_remain_second(thread);
2002 tm = gmtime(&clock);
2003 strftime(timebuf, TIME_BUF, "%M:%S", tm);
2004 vty_out(vty, "%5s", timebuf);
2005 }
2006 }
2007
2008 static char *ripng_route_subtype_print(struct ripng_info *rinfo)
2009 {
2010 static char str[3];
2011 memset(str, 0, 3);
2012
2013 if (rinfo->suppress)
2014 strcat(str, "S");
2015
2016 switch (rinfo->sub_type) {
2017 case RIPNG_ROUTE_RTE:
2018 strcat(str, "n");
2019 break;
2020 case RIPNG_ROUTE_STATIC:
2021 strcat(str, "s");
2022 break;
2023 case RIPNG_ROUTE_DEFAULT:
2024 strcat(str, "d");
2025 break;
2026 case RIPNG_ROUTE_REDISTRIBUTE:
2027 strcat(str, "r");
2028 break;
2029 case RIPNG_ROUTE_INTERFACE:
2030 strcat(str, "i");
2031 break;
2032 default:
2033 strcat(str, "?");
2034 break;
2035 }
2036
2037 return str;
2038 }
2039
2040 DEFUN (show_ipv6_ripng,
2041 show_ipv6_ripng_cmd,
2042 "show ipv6 ripng [vrf NAME]",
2043 SHOW_STR
2044 IPV6_STR
2045 "Show RIPng routes\n"
2046 VRF_CMD_HELP_STR)
2047 {
2048 struct ripng *ripng;
2049 struct agg_node *rp;
2050 struct ripng_info *rinfo;
2051 struct ripng_aggregate *aggregate;
2052 struct prefix_ipv6 *p;
2053 struct list *list = NULL;
2054 struct listnode *listnode = NULL;
2055 int len;
2056 const char *vrf_name;
2057 int idx = 0;
2058
2059 if (argv_find(argv, argc, "vrf", &idx))
2060 vrf_name = argv[idx + 1]->arg;
2061 else
2062 vrf_name = VRF_DEFAULT_NAME;
2063
2064 ripng = ripng_lookup_by_vrf_name(vrf_name);
2065 if (!ripng) {
2066 vty_out(vty, "%% RIPng instance not found\n");
2067 return CMD_SUCCESS;
2068 }
2069 if (!ripng->enabled) {
2070 vty_out(vty, "%% RIPng instance is disabled\n");
2071 return CMD_SUCCESS;
2072 }
2073
2074 /* Header of display. */
2075 vty_out(vty,
2076 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2077 "Sub-codes:\n"
2078 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2079 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2080 " Network Next Hop Via Metric Tag Time\n");
2081
2082 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2083 if ((aggregate = rp->aggregate) != NULL) {
2084 p = (struct prefix_ipv6 *)&rp->p;
2085
2086 #ifdef DEBUG
2087 vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count,
2088 aggregate->suppress, inet6_ntoa(p->prefix),
2089 p->prefixlen);
2090 #else
2091 vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix),
2092 p->prefixlen);
2093 #endif /* DEBUG */
2094 vty_out(vty, "\n");
2095 vty_out(vty, "%*s", 18, " ");
2096
2097 vty_out(vty, "%*s", 28, " ");
2098 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "\n",
2099 aggregate->metric, (route_tag_t)aggregate->tag);
2100 }
2101
2102 if ((list = rp->info) != NULL)
2103 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2104 p = (struct prefix_ipv6 *)&rp->p;
2105
2106 #ifdef DEBUG
2107 vty_out(vty, "%c(%s) 0/%d %s/%d ",
2108 zebra_route_char(rinfo->type),
2109 ripng_route_subtype_print(rinfo),
2110 rinfo->suppress, inet6_ntoa(p->prefix),
2111 p->prefixlen);
2112 #else
2113 vty_out(vty, "%c(%s) %s/%d ",
2114 zebra_route_char(rinfo->type),
2115 ripng_route_subtype_print(rinfo),
2116 inet6_ntoa(p->prefix), p->prefixlen);
2117 #endif /* DEBUG */
2118 vty_out(vty, "\n");
2119 vty_out(vty, "%*s", 18, " ");
2120 len = vty_out(vty, "%s",
2121 inet6_ntoa(rinfo->nexthop));
2122
2123 len = 28 - len;
2124 if (len > 0)
2125 vty_out(vty, "%*s", len, " ");
2126
2127 /* from */
2128 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2129 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2130 len = vty_out(
2131 vty, "%s",
2132 ifindex2ifname(
2133 rinfo->ifindex,
2134 ripng->vrf->vrf_id));
2135 } else if (rinfo->metric
2136 == RIPNG_METRIC_INFINITY) {
2137 len = vty_out(vty, "kill");
2138 } else
2139 len = vty_out(vty, "self");
2140
2141 len = 9 - len;
2142 if (len > 0)
2143 vty_out(vty, "%*s", len, " ");
2144
2145 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2146 rinfo->metric, (route_tag_t)rinfo->tag);
2147
2148 /* time */
2149 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2150 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2151 /* RTE from remote RIP routers */
2152 ripng_vty_out_uptime(vty, rinfo);
2153 } else if (rinfo->metric
2154 == RIPNG_METRIC_INFINITY) {
2155 /* poisonous reversed routes (gc) */
2156 ripng_vty_out_uptime(vty, rinfo);
2157 }
2158
2159 vty_out(vty, "\n");
2160 }
2161 }
2162
2163 return CMD_SUCCESS;
2164 }
2165
2166 DEFUN (show_ipv6_ripng_status,
2167 show_ipv6_ripng_status_cmd,
2168 "show ipv6 ripng [vrf NAME] status",
2169 SHOW_STR
2170 IPV6_STR
2171 "Show RIPng routes\n"
2172 VRF_CMD_HELP_STR
2173 "IPv6 routing protocol process parameters and statistics\n")
2174 {
2175 struct ripng *ripng;
2176 struct interface *ifp;
2177 const char *vrf_name;
2178 int idx = 0;
2179
2180 if (argv_find(argv, argc, "vrf", &idx))
2181 vrf_name = argv[idx + 1]->arg;
2182 else
2183 vrf_name = VRF_DEFAULT_NAME;
2184
2185 ripng = ripng_lookup_by_vrf_name(vrf_name);
2186 if (!ripng) {
2187 vty_out(vty, "%% RIPng instance not found\n");
2188 return CMD_SUCCESS;
2189 }
2190 if (!ripng->enabled) {
2191 vty_out(vty, "%% RIPng instance is disabled\n");
2192 return CMD_SUCCESS;
2193 }
2194
2195 vty_out(vty, "Routing Protocol is \"RIPng\"\n");
2196 vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
2197 ripng->update_time);
2198 vty_out(vty, " next due in %lu seconds\n",
2199 thread_timer_remain_second(ripng->t_update));
2200 vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time);
2201 vty_out(vty, " garbage collect after %u seconds\n",
2202 ripng->garbage_time);
2203
2204 /* Filtering status show. */
2205 config_show_distribute(vty, ripng->distribute_ctx);
2206
2207 /* Default metric information. */
2208 vty_out(vty, " Default redistribution metric is %d\n",
2209 ripng->default_metric);
2210
2211 /* Redistribute information. */
2212 vty_out(vty, " Redistributing:");
2213 ripng_redistribute_write(vty, ripng);
2214 vty_out(vty, "\n");
2215
2216 vty_out(vty, " Default version control: send version %d,",
2217 ripng->version);
2218 vty_out(vty, " receive version %d \n", ripng->version);
2219
2220 vty_out(vty, " Interface Send Recv\n");
2221
2222 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
2223 struct ripng_interface *ri;
2224
2225 ri = ifp->info;
2226
2227 if (ri->enable_network || ri->enable_interface) {
2228
2229 vty_out(vty, " %-17s%-3d %-3d\n", ifp->name,
2230 ripng->version, ripng->version);
2231 }
2232 }
2233
2234 vty_out(vty, " Routing for Networks:\n");
2235 ripng_network_write(vty, ripng);
2236
2237 vty_out(vty, " Routing Information Sources:\n");
2238 vty_out(vty,
2239 " Gateway BadPackets BadRoutes Distance Last Update\n");
2240 ripng_peer_display(vty, ripng);
2241
2242 return CMD_SUCCESS;
2243 }
2244
2245 #if 0
2246 /* RIPng update timer setup. */
2247 DEFUN (ripng_update_timer,
2248 ripng_update_timer_cmd,
2249 "update-timer SECOND",
2250 "Set RIPng update timer in seconds\n"
2251 "Seconds\n")
2252 {
2253 unsigned long update;
2254 char *endptr = NULL;
2255
2256 update = strtoul (argv[0], &endptr, 10);
2257 if (update == ULONG_MAX || *endptr != '\0')
2258 {
2259 vty_out (vty, "update timer value error\n");
2260 return CMD_WARNING_CONFIG_FAILED;
2261 }
2262
2263 ripng->update_time = update;
2264
2265 ripng_event (RIPNG_UPDATE_EVENT, 0);
2266 return CMD_SUCCESS;
2267 }
2268
2269 DEFUN (no_ripng_update_timer,
2270 no_ripng_update_timer_cmd,
2271 "no update-timer SECOND",
2272 NO_STR
2273 "Unset RIPng update timer in seconds\n"
2274 "Seconds\n")
2275 {
2276 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2277 ripng_event (RIPNG_UPDATE_EVENT, 0);
2278 return CMD_SUCCESS;
2279 }
2280
2281 /* RIPng timeout timer setup. */
2282 DEFUN (ripng_timeout_timer,
2283 ripng_timeout_timer_cmd,
2284 "timeout-timer SECOND",
2285 "Set RIPng timeout timer in seconds\n"
2286 "Seconds\n")
2287 {
2288 unsigned long timeout;
2289 char *endptr = NULL;
2290
2291 timeout = strtoul (argv[0], &endptr, 10);
2292 if (timeout == ULONG_MAX || *endptr != '\0')
2293 {
2294 vty_out (vty, "timeout timer value error\n");
2295 return CMD_WARNING_CONFIG_FAILED;
2296 }
2297
2298 ripng->timeout_time = timeout;
2299
2300 return CMD_SUCCESS;
2301 }
2302
2303 DEFUN (no_ripng_timeout_timer,
2304 no_ripng_timeout_timer_cmd,
2305 "no timeout-timer SECOND",
2306 NO_STR
2307 "Unset RIPng timeout timer in seconds\n"
2308 "Seconds\n")
2309 {
2310 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2311 return CMD_SUCCESS;
2312 }
2313
2314 /* RIPng garbage timer setup. */
2315 DEFUN (ripng_garbage_timer,
2316 ripng_garbage_timer_cmd,
2317 "garbage-timer SECOND",
2318 "Set RIPng garbage timer in seconds\n"
2319 "Seconds\n")
2320 {
2321 unsigned long garbage;
2322 char *endptr = NULL;
2323
2324 garbage = strtoul (argv[0], &endptr, 10);
2325 if (garbage == ULONG_MAX || *endptr != '\0')
2326 {
2327 vty_out (vty, "garbage timer value error\n");
2328 return CMD_WARNING_CONFIG_FAILED;
2329 }
2330
2331 ripng->garbage_time = garbage;
2332
2333 return CMD_SUCCESS;
2334 }
2335
2336 DEFUN (no_ripng_garbage_timer,
2337 no_ripng_garbage_timer_cmd,
2338 "no garbage-timer SECOND",
2339 NO_STR
2340 "Unset RIPng garbage timer in seconds\n"
2341 "Seconds\n")
2342 {
2343 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2344 return CMD_SUCCESS;
2345 }
2346 #endif /* 0 */
2347
2348 #if 0
2349 DEFUN (show_ipv6_protocols,
2350 show_ipv6_protocols_cmd,
2351 "show ipv6 protocols",
2352 SHOW_STR
2353 IPV6_STR
2354 "Routing protocol information\n")
2355 {
2356 if (! ripng)
2357 return CMD_SUCCESS;
2358
2359 vty_out (vty, "Routing Protocol is \"ripng\"\n");
2360
2361 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds\n",
2362 ripng->update_time, 0);
2363
2364 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld\n",
2365 ripng->timeout_time,
2366 ripng->garbage_time);
2367
2368 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2369 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2370
2371 return CMD_SUCCESS;
2372 }
2373 #endif
2374
2375 /* Update ECMP routes to zebra when ECMP is disabled. */
2376 void ripng_ecmp_disable(struct ripng *ripng)
2377 {
2378 struct agg_node *rp;
2379 struct ripng_info *rinfo, *tmp_rinfo;
2380 struct list *list;
2381 struct listnode *node, *nextnode;
2382
2383 if (!ripng)
2384 return;
2385
2386 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
2387 if ((list = rp->info) != NULL && listcount(list) > 1) {
2388 rinfo = listgetdata(listhead(list));
2389 if (!ripng_route_rte(rinfo))
2390 continue;
2391
2392 /* Drop all other entries, except the first one. */
2393 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2394 if (tmp_rinfo != rinfo) {
2395 RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
2396 RIPNG_TIMER_OFF(
2397 tmp_rinfo->t_garbage_collect);
2398 list_delete_node(list, node);
2399 ripng_info_free(tmp_rinfo);
2400 }
2401
2402 /* Update zebra. */
2403 ripng_zebra_ipv6_add(ripng, rp);
2404
2405 /* Set the route change flag. */
2406 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2407
2408 /* Signal the output process to trigger an update. */
2409 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
2410 }
2411 }
2412
2413 /* RIPng configuration write function. */
2414 static int ripng_config_write(struct vty *vty)
2415 {
2416 struct ripng *ripng;
2417 int write = 0;
2418
2419 RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
2420 char xpath[XPATH_MAXLEN];
2421 struct lyd_node *dnode;
2422
2423 snprintf(xpath, sizeof(xpath),
2424 "/frr-ripngd:ripngd/instance[vrf='%s']",
2425 ripng->vrf_name);
2426
2427 dnode = yang_dnode_get(running_config->dnode, xpath);
2428 assert(dnode);
2429
2430 nb_cli_show_dnode_cmds(vty, dnode, false);
2431
2432 config_write_distribute(vty, ripng->distribute_ctx);
2433 config_write_if_rmap(vty, ripng->if_rmap_ctx);
2434
2435 write = 1;
2436 }
2437
2438 return write;
2439 }
2440
2441 /* RIPng node structure. */
2442 static struct cmd_node cmd_ripng_node = {
2443 RIPNG_NODE, "%s(config-router)# ", 1,
2444 };
2445
2446 static void ripng_distribute_update(struct distribute_ctx *ctx,
2447 struct distribute *dist)
2448 {
2449 struct interface *ifp;
2450 struct ripng_interface *ri;
2451 struct access_list *alist;
2452 struct prefix_list *plist;
2453
2454 if (!ctx->vrf || !dist->ifname)
2455 return;
2456
2457 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
2458 if (ifp == NULL)
2459 return;
2460
2461 ri = ifp->info;
2462
2463 if (dist->list[DISTRIBUTE_V6_IN]) {
2464 alist = access_list_lookup(AFI_IP6,
2465 dist->list[DISTRIBUTE_V6_IN]);
2466 if (alist)
2467 ri->list[RIPNG_FILTER_IN] = alist;
2468 else
2469 ri->list[RIPNG_FILTER_IN] = NULL;
2470 } else
2471 ri->list[RIPNG_FILTER_IN] = NULL;
2472
2473 if (dist->list[DISTRIBUTE_V6_OUT]) {
2474 alist = access_list_lookup(AFI_IP6,
2475 dist->list[DISTRIBUTE_V6_OUT]);
2476 if (alist)
2477 ri->list[RIPNG_FILTER_OUT] = alist;
2478 else
2479 ri->list[RIPNG_FILTER_OUT] = NULL;
2480 } else
2481 ri->list[RIPNG_FILTER_OUT] = NULL;
2482
2483 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2484 plist = prefix_list_lookup(AFI_IP6,
2485 dist->prefix[DISTRIBUTE_V6_IN]);
2486 if (plist)
2487 ri->prefix[RIPNG_FILTER_IN] = plist;
2488 else
2489 ri->prefix[RIPNG_FILTER_IN] = NULL;
2490 } else
2491 ri->prefix[RIPNG_FILTER_IN] = NULL;
2492
2493 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2494 plist = prefix_list_lookup(AFI_IP6,
2495 dist->prefix[DISTRIBUTE_V6_OUT]);
2496 if (plist)
2497 ri->prefix[RIPNG_FILTER_OUT] = plist;
2498 else
2499 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2500 } else
2501 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2502 }
2503
2504 void ripng_distribute_update_interface(struct interface *ifp)
2505 {
2506 struct ripng_interface *ri = ifp->info;
2507 struct ripng *ripng = ri->ripng;
2508 struct distribute *dist;
2509
2510 if (!ripng)
2511 return;
2512 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
2513 if (dist)
2514 ripng_distribute_update(ripng->distribute_ctx, dist);
2515 }
2516
2517 /* Update all interface's distribute list. */
2518 static void ripng_distribute_update_all(struct prefix_list *notused)
2519 {
2520 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2521 struct interface *ifp;
2522
2523 FOR_ALL_INTERFACES (vrf, ifp)
2524 ripng_distribute_update_interface(ifp);
2525 }
2526
2527 static void ripng_distribute_update_all_wrapper(struct access_list *notused)
2528 {
2529 ripng_distribute_update_all(NULL);
2530 }
2531
2532 /* delete all the added ripng routes. */
2533 void ripng_clean(struct ripng *ripng)
2534 {
2535 if (ripng->enabled)
2536 ripng_instance_disable(ripng);
2537
2538 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
2539 if (ripng->redist[i].route_map.name)
2540 free(ripng->redist[i].route_map.name);
2541
2542 agg_table_finish(ripng->table);
2543 list_delete(&ripng->peer_list);
2544 distribute_list_delete(&ripng->distribute_ctx);
2545 if_rmap_ctx_delete(ripng->if_rmap_ctx);
2546
2547 stream_free(ripng->ibuf);
2548 stream_free(ripng->obuf);
2549
2550 ripng_clean_network(ripng);
2551 ripng_passive_interface_clean(ripng);
2552 vector_free(ripng->enable_if);
2553 agg_table_finish(ripng->enable_network);
2554 vector_free(ripng->passive_interface);
2555 list_delete(&ripng->offset_list_master);
2556 ripng_interface_clean(ripng);
2557
2558 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2559 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
2560 XFREE(MTYPE_RIPNG, ripng);
2561 }
2562
2563 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2564 struct if_rmap *if_rmap)
2565 {
2566 struct interface *ifp = NULL;
2567 struct ripng_interface *ri;
2568 struct route_map *rmap;
2569 struct vrf *vrf = NULL;
2570
2571 if (ctx->name)
2572 vrf = vrf_lookup_by_name(ctx->name);
2573 if (vrf)
2574 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
2575 if (ifp == NULL)
2576 return;
2577
2578 ri = ifp->info;
2579
2580 if (if_rmap->routemap[IF_RMAP_IN]) {
2581 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2582 if (rmap)
2583 ri->routemap[IF_RMAP_IN] = rmap;
2584 else
2585 ri->routemap[IF_RMAP_IN] = NULL;
2586 } else
2587 ri->routemap[RIPNG_FILTER_IN] = NULL;
2588
2589 if (if_rmap->routemap[IF_RMAP_OUT]) {
2590 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2591 if (rmap)
2592 ri->routemap[IF_RMAP_OUT] = rmap;
2593 else
2594 ri->routemap[IF_RMAP_OUT] = NULL;
2595 } else
2596 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2597 }
2598
2599 void ripng_if_rmap_update_interface(struct interface *ifp)
2600 {
2601 struct ripng_interface *ri = ifp->info;
2602 struct ripng *ripng = ri->ripng;
2603 struct if_rmap *if_rmap;
2604 struct if_rmap_ctx *ctx;
2605
2606 if (!ripng)
2607 return;
2608 ctx = ripng->if_rmap_ctx;
2609 if (!ctx)
2610 return;
2611 if_rmap = if_rmap_lookup(ctx, ifp->name);
2612 if (if_rmap)
2613 ripng_if_rmap_update(ctx, if_rmap);
2614 }
2615
2616 static void ripng_routemap_update_redistribute(struct ripng *ripng)
2617 {
2618 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2619 if (ripng->redist[i].route_map.name) {
2620 ripng->redist[i].route_map.map =
2621 route_map_lookup_by_name(
2622 ripng->redist[i].route_map.name);
2623 route_map_counter_increment(
2624 ripng->redist[i].route_map.map);
2625 }
2626 }
2627 }
2628
2629 static void ripng_routemap_update(const char *unused)
2630 {
2631 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2632 struct ripng *ripng;
2633 struct interface *ifp;
2634
2635 FOR_ALL_INTERFACES (vrf, ifp)
2636 ripng_if_rmap_update_interface(ifp);
2637
2638 ripng = vrf->info;
2639 if (ripng)
2640 ripng_routemap_update_redistribute(ripng);
2641 }
2642
2643 /* Link RIPng instance to VRF. */
2644 static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2645 {
2646 struct interface *ifp;
2647
2648 ripng->vrf = vrf;
2649 ripng->distribute_ctx->vrf = vrf;
2650 vrf->info = ripng;
2651
2652 FOR_ALL_INTERFACES (vrf, ifp)
2653 ripng_interface_sync(ifp);
2654 }
2655
2656 /* Unlink RIPng instance from VRF. */
2657 static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2658 {
2659 struct interface *ifp;
2660
2661 ripng->vrf = NULL;
2662 ripng->distribute_ctx->vrf = NULL;
2663 vrf->info = NULL;
2664
2665 FOR_ALL_INTERFACES (vrf, ifp)
2666 ripng_interface_sync(ifp);
2667 }
2668
2669 static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2670 int sock)
2671 {
2672 ripng->sock = sock;
2673
2674 ripng_vrf_link(ripng, vrf);
2675 ripng->enabled = true;
2676
2677 /* Resend all redistribute requests. */
2678 ripng_redistribute_enable(ripng);
2679
2680 /* Create read and timer thread. */
2681 ripng_event(ripng, RIPNG_READ, ripng->sock);
2682 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2683
2684 ripng_zebra_vrf_register(vrf);
2685 }
2686
2687 static void ripng_instance_disable(struct ripng *ripng)
2688 {
2689 struct vrf *vrf = ripng->vrf;
2690 struct agg_node *rp;
2691
2692 /* Clear RIPng routes */
2693 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2694 struct ripng_aggregate *aggregate;
2695 struct list *list;
2696
2697 if ((list = rp->info) != NULL) {
2698 struct ripng_info *rinfo;
2699 struct listnode *listnode;
2700
2701 rinfo = listgetdata(listhead(list));
2702 if (ripng_route_rte(rinfo))
2703 ripng_zebra_ipv6_delete(ripng, rp);
2704
2705 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2706 RIPNG_TIMER_OFF(rinfo->t_timeout);
2707 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
2708 ripng_info_free(rinfo);
2709 }
2710 list_delete(&list);
2711 rp->info = NULL;
2712 agg_unlock_node(rp);
2713 }
2714
2715 if ((aggregate = rp->aggregate) != NULL) {
2716 ripng_aggregate_free(aggregate);
2717 rp->aggregate = NULL;
2718 agg_unlock_node(rp);
2719 }
2720 }
2721
2722 /* Flush all redistribute requests. */
2723 ripng_redistribute_disable(ripng);
2724
2725 /* Cancel the RIPng timers */
2726 RIPNG_TIMER_OFF(ripng->t_update);
2727 RIPNG_TIMER_OFF(ripng->t_triggered_update);
2728 RIPNG_TIMER_OFF(ripng->t_triggered_interval);
2729
2730 /* Cancel the read thread */
2731 if (ripng->t_read) {
2732 thread_cancel(ripng->t_read);
2733 ripng->t_read = NULL;
2734 }
2735
2736 /* Close the RIPng socket */
2737 if (ripng->sock >= 0) {
2738 close(ripng->sock);
2739 ripng->sock = -1;
2740 }
2741
2742 /* Clear existing peers. */
2743 list_delete_all_node(ripng->peer_list);
2744
2745 ripng_zebra_vrf_deregister(vrf);
2746
2747 ripng_vrf_unlink(ripng, vrf);
2748 ripng->enabled = false;
2749 }
2750
2751 static int ripng_vrf_new(struct vrf *vrf)
2752 {
2753 if (IS_RIPNG_DEBUG_EVENT)
2754 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2755 vrf->vrf_id);
2756
2757 return 0;
2758 }
2759
2760 static int ripng_vrf_delete(struct vrf *vrf)
2761 {
2762 if (IS_RIPNG_DEBUG_EVENT)
2763 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2764 vrf->vrf_id);
2765
2766 return 0;
2767 }
2768
2769 static int ripng_vrf_enable(struct vrf *vrf)
2770 {
2771 struct ripng *ripng;
2772 int socket;
2773
2774 ripng = ripng_lookup_by_vrf_name(vrf->name);
2775 if (!ripng || ripng->enabled)
2776 return 0;
2777
2778 if (IS_RIPNG_DEBUG_EVENT)
2779 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2780 vrf->vrf_id);
2781
2782 /* Activate the VRF RIPng instance. */
2783 if (!ripng->enabled) {
2784 socket = ripng_make_socket(vrf);
2785 if (socket < 0)
2786 return -1;
2787
2788 ripng_instance_enable(ripng, vrf, socket);
2789 }
2790
2791 return 0;
2792 }
2793
2794 static int ripng_vrf_disable(struct vrf *vrf)
2795 {
2796 struct ripng *ripng;
2797
2798 ripng = ripng_lookup_by_vrf_name(vrf->name);
2799 if (!ripng || !ripng->enabled)
2800 return 0;
2801
2802 if (IS_RIPNG_DEBUG_EVENT)
2803 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2804 vrf->vrf_id);
2805
2806 /* Deactivate the VRF RIPng instance. */
2807 if (ripng->enabled)
2808 ripng_instance_disable(ripng);
2809
2810 return 0;
2811 }
2812
2813 void ripng_vrf_init(void)
2814 {
2815 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
2816 ripng_vrf_delete, NULL);
2817 }
2818
2819 void ripng_vrf_terminate(void)
2820 {
2821 vrf_terminate();
2822 }
2823
2824 /* Initialize ripng structure and set commands. */
2825 void ripng_init(void)
2826 {
2827 /* Install RIPNG_NODE. */
2828 install_node(&cmd_ripng_node, ripng_config_write);
2829
2830 /* Install ripng commands. */
2831 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2832 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
2833
2834 install_default(RIPNG_NODE);
2835
2836 #if 0
2837 install_element (VIEW_NODE, &show_ipv6_protocols_cmd);
2838 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2839 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2840 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2841 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2842 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2843 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2844 #endif /* 0 */
2845
2846 ripng_if_init();
2847 ripng_debug_init();
2848
2849 /* Access list install. */
2850 access_list_init();
2851 access_list_add_hook(ripng_distribute_update_all_wrapper);
2852 access_list_delete_hook(ripng_distribute_update_all_wrapper);
2853
2854 /* Prefix list initialize.*/
2855 prefix_list_init();
2856 prefix_list_add_hook(ripng_distribute_update_all);
2857 prefix_list_delete_hook(ripng_distribute_update_all);
2858
2859 /* Distribute list install. */
2860 distribute_list_init(RIPNG_NODE);
2861
2862 /* Route-map for interface. */
2863 ripng_route_map_init();
2864
2865 route_map_add_hook(ripng_routemap_update);
2866 route_map_delete_hook(ripng_routemap_update);
2867
2868 if_rmap_init(RIPNG_NODE);
2869 }