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