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