1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
15 #include "agg_table.h"
18 #include "distribute.h"
23 #include "lib_errors.h"
24 #include "northbound_cli.h"
27 #include "ripngd/ripngd.h"
28 #include "ripngd/ripng_route.h"
29 #include "ripngd/ripng_debug.h"
30 #include "ripngd/ripng_nexthop.h"
32 DEFINE_MGROUP(RIPNGD
, "ripngd");
33 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG
, "RIPng structure");
34 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_VRF_NAME
, "RIPng VRF name");
35 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_ROUTE
, "RIPng route info");
37 enum { ripng_all_route
,
41 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
42 struct distribute
*dist
);
45 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
46 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
48 static void ripng_instance_disable(struct ripng
*ripng
);
49 static void ripng_triggered_update(struct event
*);
50 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
51 struct if_rmap
*if_rmap
);
53 /* Generate rb-tree of RIPng instances. */
54 static inline int ripng_instance_compare(const struct ripng
*a
,
55 const struct ripng
*b
)
57 return strcmp(a
->vrf_name
, b
->vrf_name
);
59 RB_GENERATE(ripng_instance_head
, ripng
, entry
, ripng_instance_compare
)
61 struct ripng_instance_head ripng_instances
= RB_INITIALIZER(&ripng_instances
);
63 /* RIPng next hop specification. */
64 struct ripng_nexthop
{
65 enum ripng_nexthop_type
{
69 struct in6_addr address
;
72 int ripng_route_rte(struct ripng_info
*rinfo
)
74 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
75 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
78 /* Allocate new ripng information. */
79 struct ripng_info
*ripng_info_new(void)
81 struct ripng_info
*new;
83 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
87 /* Free ripng information. */
88 void ripng_info_free(struct ripng_info
*rinfo
)
90 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
93 struct ripng
*ripng_info_get_instance(const struct ripng_info
*rinfo
)
95 return agg_get_table_info(agg_get_table(rinfo
->rp
));
98 /* Create ripng socket. */
99 int ripng_make_socket(struct vrf
*vrf
)
103 struct sockaddr_in6 ripaddr
;
104 const char *vrf_dev
= NULL
;
106 /* Make datagram socket. */
107 if (vrf
->vrf_id
!= VRF_DEFAULT
)
109 frr_with_privs(&ripngd_privs
) {
110 sock
= vrf_socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
,
111 vrf
->vrf_id
, vrf_dev
);
113 flog_err_sys(EC_LIB_SOCKET
,
114 "Cannot create UDP socket: %s",
115 safe_strerror(errno
));
120 sockopt_reuseaddr(sock
);
121 sockopt_reuseport(sock
);
122 setsockopt_so_recvbuf(sock
, 8096);
123 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
126 #ifdef IPTOS_PREC_INTERNETCONTROL
127 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
131 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
134 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
137 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
141 memset(&ripaddr
, 0, sizeof(ripaddr
));
142 ripaddr
.sin6_family
= AF_INET6
;
144 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
145 #endif /* SIN6_LEN */
146 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
148 frr_with_privs(&ripngd_privs
) {
149 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
151 zlog_err("Can't bind ripng socket: %s.",
152 safe_strerror(errno
));
163 /* Send RIPng packet. */
164 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
165 struct interface
*ifp
)
167 struct ripng_interface
*ri
= ifp
->info
;
168 struct ripng
*ripng
= ri
->ripng
;
172 struct cmsghdr
*cmsgptr
;
173 char adata
[256] = {};
174 struct in6_pktinfo
*pkt
;
175 struct sockaddr_in6 addr
;
177 if (IS_RIPNG_DEBUG_SEND
) {
179 zlog_debug("send to %pI6", &to
->sin6_addr
);
180 zlog_debug(" send interface %s", ifp
->name
);
181 zlog_debug(" send packet size %d", bufsize
);
184 memset(&addr
, 0, sizeof(addr
));
185 addr
.sin6_family
= AF_INET6
;
187 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
188 #endif /* SIN6_LEN */
189 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
191 /* When destination is specified. */
193 addr
.sin6_addr
= to
->sin6_addr
;
194 addr
.sin6_port
= to
->sin6_port
;
196 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
197 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
200 memset(&msg
, 0, sizeof(msg
));
201 msg
.msg_name
= (void *)&addr
;
202 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
205 msg
.msg_control
= adata
;
206 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
209 iov
.iov_len
= bufsize
;
211 cmsgptr
= (struct cmsghdr
*)adata
;
212 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
213 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
214 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
216 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
217 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
218 pkt
->ipi6_ifindex
= ifp
->ifindex
;
220 ret
= sendmsg(ripng
->sock
, &msg
, 0);
224 flog_err_sys(EC_LIB_SOCKET
,
225 "RIPng send fail on %s to %pI6: %s",
226 ifp
->name
, &to
->sin6_addr
,
227 safe_strerror(errno
));
229 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
230 ifp
->name
, safe_strerror(errno
));
236 /* Receive UDP RIPng packet from socket. */
237 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
238 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
244 struct cmsghdr
*cmsgptr
;
245 struct in6_addr dst
= {.s6_addr
= {0}};
247 memset(&dst
, 0, sizeof(dst
));
249 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
250 point I can't determine size of cmsghdr */
253 /* Fill in message and iovec. */
254 memset(&msg
, 0, sizeof(msg
));
255 msg
.msg_name
= (void *)from
;
256 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
259 msg
.msg_control
= (void *)adata
;
260 msg
.msg_controllen
= sizeof(adata
);
262 iov
.iov_len
= bufsize
;
264 /* If recvmsg fail return minus value. */
265 ret
= recvmsg(sock
, &msg
, 0);
269 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
270 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
271 /* I want interface index which this packet comes from. */
272 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
273 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
274 struct in6_pktinfo
*ptr
;
276 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
277 *ifindex
= ptr
->ipi6_ifindex
;
278 dst
= ptr
->ipi6_addr
;
282 "Interface index returned by IPV6_PKTINFO is zero");
285 /* Incoming packet's multicast hop limit. */
286 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
287 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
288 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
289 *hoplimit
= *phoplimit
;
293 /* Hoplimit check shold be done when destination address is
294 multicast address. */
295 if (!IN6_IS_ADDR_MULTICAST(&dst
))
301 /* Dump rip packet */
302 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
307 const char *command_str
;
309 /* Set command string. */
310 if (packet
->command
== RIPNG_REQUEST
)
311 command_str
= "request";
312 else if (packet
->command
== RIPNG_RESPONSE
)
313 command_str
= "response";
315 command_str
= "unknown";
317 /* Dump packet header. */
318 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
319 packet
->version
, size
);
321 /* Dump each routing table entry. */
324 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
325 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
326 zlog_debug(" nexthop %pI6/%d", &rte
->addr
,
329 zlog_debug(" %pI6/%d metric %d tag %" ROUTE_TAG_PRI
,
330 &rte
->addr
, rte
->prefixlen
,
331 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
335 /* RIPng next hop address RTE (Route Table Entry). */
336 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
337 struct ripng_nexthop
*nexthop
)
339 /* Logging before checking RTE. */
340 if (IS_RIPNG_DEBUG_RECV
)
341 zlog_debug("RIPng nexthop RTE address %pI6 tag %" ROUTE_TAG_PRI
343 &rte
->addr
, (route_tag_t
)ntohs(rte
->tag
),
346 /* RFC2080 2.1.1 Next Hop:
347 The route tag and prefix length in the next hop RTE must be
348 set to zero on sending and ignored on receiption. */
349 if (ntohs(rte
->tag
) != 0)
351 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
353 (route_tag_t
)ntohs(rte
->tag
), &from
->sin6_addr
);
355 if (rte
->prefixlen
!= 0)
357 "RIPng nexthop RTE with non zero prefixlen value %d from %pI6",
358 rte
->prefixlen
, &from
->sin6_addr
);
360 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
361 next hop RTE indicates that the next hop address should be the
362 originator of the RIPng advertisement. An address specified as a
363 next hop must be a link-local address. */
364 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
365 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
366 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
370 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
371 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
372 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
376 /* The purpose of the next hop RTE is to eliminate packets being
377 routed through extra hops in the system. It is particularly useful
378 when RIPng is not being run on all of the routers on a network.
379 Note that next hop RTE is "advisory". That is, if the provided
380 information is ignored, a possibly sub-optimal, but absolutely
381 valid, route may be taken. If the received next hop address is not
382 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
383 zlog_warn("RIPng nexthop RTE with non link-local address %pI6 from %pI6",
384 &rte
->addr
, &from
->sin6_addr
);
386 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
387 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
392 /* If ifp has same link-local address then return 1. */
393 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
395 struct listnode
*node
;
396 struct connected
*connected
;
399 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
400 p
= connected
->address
;
402 if (p
->family
== AF_INET6
403 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
404 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
410 /* RIPng route garbage collect timer. */
411 static void ripng_garbage_collect(struct event
*t
)
413 struct ripng_info
*rinfo
;
416 rinfo
= EVENT_ARG(t
);
418 /* Off timeout timer. */
419 EVENT_OFF(rinfo
->t_timeout
);
421 /* Get route_node pointer. */
424 /* Unlock route_node. */
425 listnode_delete(rp
->info
, rinfo
);
426 if (list_isempty((struct list
*)rp
->info
)) {
427 list_delete((struct list
**)&rp
->info
);
431 /* Free RIPng routing information. */
432 ripng_info_free(rinfo
);
435 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
437 /* Add new route to the ECMP list.
438 * RETURN: the new entry added in the list, or NULL if it is not the first
439 * entry and ECMP is not allowed.
441 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
442 struct ripng_info
*rinfo_new
)
444 struct agg_node
*rp
= rinfo_new
->rp
;
445 struct ripng_info
*rinfo
= NULL
;
446 struct list
*list
= NULL
;
448 if (rp
->info
== NULL
)
449 rp
->info
= list_new();
450 list
= (struct list
*)rp
->info
;
452 /* If ECMP is not allowed and some entry already exists in the list,
454 if (listcount(list
) && !ripng
->ecmp
)
457 rinfo
= ripng_info_new();
458 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
459 listnode_add(list
, rinfo
);
461 if (ripng_route_rte(rinfo
)) {
462 ripng_timeout_update(ripng
, rinfo
);
463 ripng_zebra_ipv6_add(ripng
, rp
);
466 ripng_aggregate_increment(rp
, rinfo
);
468 /* Set the route change flag on the first entry. */
469 rinfo
= listgetdata(listhead(list
));
470 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
472 /* Signal the output process to trigger an update. */
473 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
478 /* Replace the ECMP list with the new route.
479 * RETURN: the new entry added in the list
481 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
482 struct ripng_info
*rinfo_new
)
484 struct agg_node
*rp
= rinfo_new
->rp
;
485 struct list
*list
= (struct list
*)rp
->info
;
486 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
487 struct listnode
*node
= NULL
, *nextnode
= NULL
;
489 if (list
== NULL
|| listcount(list
) == 0)
490 return ripng_ecmp_add(ripng
, rinfo_new
);
492 /* Get the first entry */
493 rinfo
= listgetdata(listhead(list
));
495 /* Learnt route replaced by a local one. Delete it from zebra. */
496 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
497 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
498 ripng_zebra_ipv6_delete(ripng
, rp
);
500 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
501 ripng_aggregate_decrement_list(rp
, list
);
503 /* Re-use the first entry, and delete the others. */
504 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
505 if (tmp_rinfo
!= rinfo
) {
506 EVENT_OFF(tmp_rinfo
->t_timeout
);
507 EVENT_OFF(tmp_rinfo
->t_garbage_collect
);
508 list_delete_node(list
, node
);
509 ripng_info_free(tmp_rinfo
);
512 EVENT_OFF(rinfo
->t_timeout
);
513 EVENT_OFF(rinfo
->t_garbage_collect
);
514 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
516 if (ripng_route_rte(rinfo
)) {
517 ripng_timeout_update(ripng
, rinfo
);
518 /* The ADD message implies an update. */
519 ripng_zebra_ipv6_add(ripng
, rp
);
522 ripng_aggregate_increment(rp
, rinfo
);
524 /* Set the route change flag. */
525 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
527 /* Signal the output process to trigger an update. */
528 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
533 /* Delete one route from the ECMP list.
535 * null - the entry is freed, and other entries exist in the list
536 * the entry - the entry is the last one in the list; its metric is set
537 * to INFINITY, and the garbage collector is started for it
539 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
540 struct ripng_info
*rinfo
)
542 struct agg_node
*rp
= rinfo
->rp
;
543 struct list
*list
= (struct list
*)rp
->info
;
545 EVENT_OFF(rinfo
->t_timeout
);
547 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
548 ripng_aggregate_decrement(rp
, rinfo
);
550 if (listcount(list
) > 1) {
551 /* Some other ECMP entries still exist. Just delete this entry.
553 EVENT_OFF(rinfo
->t_garbage_collect
);
554 listnode_delete(list
, rinfo
);
555 if (ripng_route_rte(rinfo
)
556 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
557 /* The ADD message implies the update. */
558 ripng_zebra_ipv6_add(ripng
, rp
);
559 ripng_info_free(rinfo
);
562 assert(rinfo
== listgetdata(listhead(list
)));
564 /* This is the only entry left in the list. We must keep it in
565 * the list for garbage collection time, with INFINITY metric.
568 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
569 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
570 ripng
->garbage_time
);
572 if (ripng_route_rte(rinfo
)
573 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
574 ripng_zebra_ipv6_delete(ripng
, rp
);
577 /* Set the route change flag on the first entry. */
578 rinfo
= listgetdata(listhead(list
));
579 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
581 /* Signal the output process to trigger an update. */
582 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
587 /* Timeout RIPng routes. */
588 static void ripng_timeout(struct event
*t
)
590 struct ripng_info
*rinfo
= EVENT_ARG(t
);
591 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
593 ripng_ecmp_delete(ripng
, rinfo
);
596 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
598 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
599 EVENT_OFF(rinfo
->t_timeout
);
600 event_add_timer(master
, ripng_timeout
, rinfo
,
601 ripng
->timeout_time
, &rinfo
->t_timeout
);
605 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
606 struct ripng_interface
*ri
)
608 struct distribute
*dist
;
609 struct access_list
*alist
;
610 struct prefix_list
*plist
;
611 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
614 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
616 /* Input distribute-list filtering. */
617 if (ri
->list
[ripng_distribute
]) {
618 if (access_list_apply(ri
->list
[ripng_distribute
],
621 if (IS_RIPNG_DEBUG_PACKET
)
622 zlog_debug("%pFX filtered by distribute %s", p
,
627 if (ri
->prefix
[ripng_distribute
]) {
628 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
631 if (IS_RIPNG_DEBUG_PACKET
)
632 zlog_debug("%pFX filtered by prefix-list %s", p
,
638 /* All interface filter check. */
639 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
641 if (dist
->list
[distribute
]) {
642 alist
= access_list_lookup(AFI_IP6
,
643 dist
->list
[distribute
]);
646 if (access_list_apply(alist
, (struct prefix
*)p
)
648 if (IS_RIPNG_DEBUG_PACKET
)
650 "%pFX filtered by distribute %s",
656 if (dist
->prefix
[distribute
]) {
657 plist
= prefix_list_lookup(AFI_IP6
,
658 dist
->prefix
[distribute
]);
661 if (prefix_list_apply(plist
, (struct prefix
*)p
)
663 if (IS_RIPNG_DEBUG_PACKET
)
665 "%pFX filtered by prefix-list %s",
675 /* Process RIPng route according to RFC2080. */
676 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
677 struct ripng_nexthop
*ripng_nexthop
,
678 struct interface
*ifp
)
681 struct prefix_ipv6 p
;
683 struct ripng_info
*rinfo
= NULL
, newinfo
;
684 struct ripng_interface
*ri
;
686 struct in6_addr
*nexthop
;
688 struct list
*list
= NULL
;
689 struct listnode
*node
= NULL
;
691 /* Make prefix structure. */
692 memset(&p
, 0, sizeof(struct prefix_ipv6
));
694 /* p.prefix = rte->addr; */
695 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
696 p
.prefixlen
= rte
->prefixlen
;
698 /* Make sure mask is applied. */
699 /* XXX We have to check the prefix is valid or not before call
706 /* Apply input filters. */
707 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
711 memset(&newinfo
, 0, sizeof(newinfo
));
712 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
713 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
714 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
715 newinfo
.nexthop
= ripng_nexthop
->address
;
717 newinfo
.nexthop
= from
->sin6_addr
;
718 newinfo
.from
= from
->sin6_addr
;
719 newinfo
.ifindex
= ifp
->ifindex
;
720 newinfo
.metric
= rte
->metric
;
721 newinfo
.metric_out
= rte
->metric
; /* XXX */
722 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
725 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
726 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
727 (struct prefix
*)&p
, &newinfo
);
729 if (ret
== RMAP_DENYMATCH
) {
730 if (IS_RIPNG_DEBUG_PACKET
)
732 "RIPng %pFX is filtered by route-map in",
737 /* Get back the object */
738 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
739 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
740 &ripng_nexthop
->address
)) {
741 /* the nexthop get changed by the routemap */
742 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
743 ripng_nexthop
->address
=
746 ripng_nexthop
->address
= in6addr_any
;
749 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
751 /* the nexthop get changed by the routemap */
752 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
753 ripng_nexthop
->flag
=
754 RIPNG_NEXTHOP_ADDRESS
;
755 ripng_nexthop
->address
=
760 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
762 newinfo
.metric_out
; /* XXX: the routemap uses the
766 /* Once the entry has been validated, update the metric by
767 * adding the cost of the network on wich the message
768 * arrived. If the result is greater than infinity, use infinity
769 * (RFC2453 Sec. 3.9.2)
772 /* Zebra ripngd can handle offset-list in. */
773 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
775 /* If offset-list does not modify the metric use interface's
778 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
780 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
781 rte
->metric
= RIPNG_METRIC_INFINITY
;
783 /* Set nexthop pointer. */
784 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
785 nexthop
= &ripng_nexthop
->address
;
787 nexthop
= &from
->sin6_addr
;
789 /* Lookup RIPng routing table. */
790 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
793 newinfo
.nexthop
= *nexthop
;
794 newinfo
.metric
= rte
->metric
;
795 newinfo
.tag
= ntohs(rte
->tag
);
797 /* Check to see whether there is already RIPng route on the table. */
798 if ((list
= rp
->info
) != NULL
)
799 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
800 /* Need to compare with redistributed entry or local
802 if (!ripng_route_rte(rinfo
))
805 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
806 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
809 if (!listnextnode(node
)) {
810 /* Not found in the list */
812 if (rte
->metric
> rinfo
->metric
) {
813 /* New route has a greater metric.
819 if (rte
->metric
< rinfo
->metric
)
820 /* New route has a smaller metric.
821 * Replace the ECMP list
822 * with the new one in below. */
825 /* Metrics are same. Unless ECMP is disabled,
826 * keep "rinfo" null and
827 * the new route is added in the ECMP list in
835 /* Redistributed route check. */
836 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
837 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
842 /* Local static route. */
843 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
844 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
845 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
846 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
853 /* Now, check to see whether there is already an explicit route
854 for the destination prefix. If there is no such route, add
855 this route to the routing table, unless the metric is
856 infinity (there is no point in adding a route which
858 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
859 ripng_ecmp_add(ripng
, &newinfo
);
863 /* If there is an existing route, compare the next hop address
864 to the address of the router from which the datagram came.
865 If this datagram is from the same router as the existing
866 route, reinitialize the timeout. */
867 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
868 && (rinfo
->ifindex
== ifp
->ifindex
));
871 * RFC 2080 - Section 2.4.2:
872 * "If the new metric is the same as the old one, examine the
874 * for the existing route. If it is at least halfway to the
876 * point, switch to the new route. This heuristic is optional,
878 * highly recommended".
880 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
&&
882 (event_timer_remain_second(rinfo
->t_timeout
) <
883 (ripng
->timeout_time
/ 2))) {
884 ripng_ecmp_replace(ripng
, &newinfo
);
886 /* Next, compare the metrics. If the datagram is from the same
887 router as the existing route, and the new metric is different
888 than the old one; or, if the new metric is lower than the old
889 one; do the following actions: */
890 else if ((same
&& rinfo
->metric
!= rte
->metric
) ||
891 rte
->metric
< rinfo
->metric
) {
892 if (listcount(list
) == 1) {
893 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
894 ripng_ecmp_replace(ripng
, &newinfo
);
896 ripng_ecmp_delete(ripng
, rinfo
);
898 if (newinfo
.metric
< rinfo
->metric
)
899 ripng_ecmp_replace(ripng
, &newinfo
);
900 else /* newinfo.metric > rinfo->metric */
901 ripng_ecmp_delete(ripng
, rinfo
);
903 } else /* same & no change */
904 ripng_timeout_update(ripng
, rinfo
);
906 /* Unlock tempolary lock of the route. */
911 /* Add redistributed route to RIPng table. */
912 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
913 struct prefix_ipv6
*p
, ifindex_t ifindex
,
914 struct in6_addr
*nexthop
, route_tag_t tag
)
917 struct ripng_info
*rinfo
= NULL
, newinfo
;
918 struct list
*list
= NULL
;
920 /* Redistribute route */
921 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
923 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
926 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
928 memset(&newinfo
, 0, sizeof(newinfo
));
930 newinfo
.sub_type
= sub_type
;
931 newinfo
.ifindex
= ifindex
;
933 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
936 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
937 newinfo
.nexthop
= *nexthop
;
939 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
940 rinfo
= listgetdata(listhead(list
));
942 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
943 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
944 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
949 /* Manually configured RIPng route check.
950 * They have the precedence on all the other entries.
952 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
953 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
954 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
955 if (type
!= ZEBRA_ROUTE_RIPNG
956 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
957 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
963 ripng_ecmp_replace(ripng
, &newinfo
);
966 ripng_ecmp_add(ripng
, &newinfo
);
968 if (IS_RIPNG_DEBUG_EVENT
) {
971 "Redistribute new prefix %pFX on the interface %s",
972 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
975 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
977 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
980 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
983 /* Delete redistributed route to RIPng table. */
984 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
985 struct prefix_ipv6
*p
, ifindex_t ifindex
)
988 struct ripng_info
*rinfo
;
990 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
992 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
995 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
998 struct list
*list
= rp
->info
;
1000 if (list
!= NULL
&& listcount(list
) != 0) {
1001 rinfo
= listgetdata(listhead(list
));
1002 if (rinfo
!= NULL
&& rinfo
->type
== type
1003 && rinfo
->sub_type
== sub_type
1004 && rinfo
->ifindex
== ifindex
) {
1005 /* Perform poisoned reverse. */
1006 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1007 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1008 ripng_garbage_collect
,
1009 ripng
->garbage_time
);
1010 EVENT_OFF(rinfo
->t_timeout
);
1012 /* Aggregate count decrement. */
1013 ripng_aggregate_decrement(rp
, rinfo
);
1015 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1017 if (IS_RIPNG_DEBUG_EVENT
)
1019 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1023 ripng
->vrf
->vrf_id
));
1025 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1028 agg_unlock_node(rp
);
1032 /* Withdraw redistributed route. */
1033 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1035 struct agg_node
*rp
;
1036 struct ripng_info
*rinfo
= NULL
;
1037 struct list
*list
= NULL
;
1039 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1040 if ((list
= rp
->info
) != NULL
) {
1041 rinfo
= listgetdata(listhead(list
));
1042 if ((rinfo
->type
== type
)
1043 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1044 /* Perform poisoned reverse. */
1045 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1046 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1047 ripng_garbage_collect
,
1048 ripng
->garbage_time
);
1049 EVENT_OFF(rinfo
->t_timeout
);
1051 /* Aggregate count decrement. */
1052 ripng_aggregate_decrement(rp
, rinfo
);
1054 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1056 if (IS_RIPNG_DEBUG_EVENT
) {
1057 struct prefix_ipv6
*p
=
1058 (struct prefix_ipv6
*)
1059 agg_node_get_prefix(rp
);
1062 "Poisone %pFX on the interface %s [withdraw]",
1066 ripng
->vrf
->vrf_id
));
1069 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1074 /* RIP routing information. */
1075 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1076 struct sockaddr_in6
*from
,
1077 struct interface
*ifp
, int hoplimit
)
1079 struct ripng_interface
*ri
= ifp
->info
;
1080 struct ripng
*ripng
= ri
->ripng
;
1083 struct ripng_nexthop nexthop
;
1085 /* RFC2080 2.4.2 Response Messages:
1086 The Response must be ignored if it is not from the RIPng port. */
1087 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1088 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
1089 ntohs(from
->sin6_port
), &from
->sin6_addr
);
1090 ripng_peer_bad_packet(ripng
, from
);
1094 /* The datagram's IPv6 source address should be checked to see
1095 whether the datagram is from a valid neighbor; the source of the
1096 datagram must be a link-local address. */
1097 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1098 zlog_warn("RIPng packet comes from non link local address %pI6",
1100 ripng_peer_bad_packet(ripng
, from
);
1104 /* It is also worth checking to see whether the response is from one
1105 of the router's own addresses. Interfaces on broadcast networks
1106 may receive copies of their own multicasts immediately. If a
1107 router processes its own output as new input, confusion is likely,
1108 and such datagrams must be ignored. */
1109 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1111 "RIPng packet comes from my own link local address %pI6",
1113 ripng_peer_bad_packet(ripng
, from
);
1117 /* As an additional check, periodic advertisements must have their
1118 hop counts set to 255, and inbound, multicast packets sent from the
1119 RIPng port (i.e. periodic advertisement or triggered update
1120 packets) must be examined to ensure that the hop count is 255. */
1121 if (hoplimit
>= 0 && hoplimit
!= 255) {
1123 "RIPng packet comes with non 255 hop count %d from %pI6",
1124 hoplimit
, &from
->sin6_addr
);
1125 ripng_peer_bad_packet(ripng
, from
);
1129 /* Update RIPng peer. */
1130 ripng_peer_update(ripng
, from
, packet
->version
);
1132 /* Reset nexthop. */
1133 memset(&nexthop
, 0, sizeof(nexthop
));
1134 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1136 /* Set RTE pointer. */
1139 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1140 /* First of all, we have to check this RTE is next hop RTE or
1141 not. Next hop RTE is completely different with normal RTE so
1142 we need special treatment. */
1143 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1144 ripng_nexthop_rte(rte
, from
, &nexthop
);
1148 /* RTE information validation. */
1150 /* - is the destination prefix valid (e.g., not a multicast
1151 prefix and not a link-local address) A link-local address
1152 should never be present in an RTE. */
1153 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1155 "Destination prefix is a multicast address %pI6/%d [%d]",
1156 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1157 ripng_peer_bad_route(ripng
, from
);
1160 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1162 "Destination prefix is a link-local address %pI6/%d [%d]",
1163 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1164 ripng_peer_bad_route(ripng
, from
);
1167 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1169 "Destination prefix is a loopback address %pI6/%d [%d]",
1170 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1171 ripng_peer_bad_route(ripng
, from
);
1175 /* - is the prefix length valid (i.e., between 0 and 128,
1177 if (rte
->prefixlen
> IPV6_MAX_BITLEN
) {
1178 zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
1179 &rte
->addr
, rte
->prefixlen
,
1180 &from
->sin6_addr
, ifp
->name
);
1181 ripng_peer_bad_route(ripng
, from
);
1185 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1186 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1187 zlog_warn("Invalid metric %d from %pI6%%%s",
1188 rte
->metric
, &from
->sin6_addr
, ifp
->name
);
1189 ripng_peer_bad_route(ripng
, from
);
1193 /* Vincent: XXX Should we compute the direclty reachable nexthop
1194 * for our RIPng network ?
1197 /* Routing table updates. */
1198 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1202 /* Response to request message. */
1203 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1204 struct sockaddr_in6
*from
,
1205 struct interface
*ifp
)
1207 struct ripng
*ripng
;
1210 struct prefix_ipv6 p
;
1211 struct agg_node
*rp
;
1212 struct ripng_info
*rinfo
;
1213 struct ripng_interface
*ri
;
1215 /* Does not reponse to the requests on the loopback interfaces */
1216 if (if_is_loopback(ifp
))
1219 /* Check RIPng process is enabled on this interface. */
1225 /* When passive interface is specified, suppress responses */
1229 /* RIPng peer update. */
1230 ripng_peer_update(ripng
, from
, packet
->version
);
1232 lim
= ((caddr_t
)packet
) + size
;
1235 /* The Request is processed entry by entry. If there are no
1236 entries, no response is given. */
1237 if (lim
== (caddr_t
)rte
)
1240 /* There is one special case. If there is exactly one entry in the
1241 request, and it has a destination prefix of zero, a prefix length
1242 of zero, and a metric of infinity (i.e., 16), then this is a
1243 request to send the entire routing table. In that case, a call
1244 is made to the output process to send the routing table to the
1245 requesting address/port. */
1246 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1247 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1248 /* All route with split horizon */
1249 ripng_output_process(ifp
, from
, ripng_all_route
);
1251 /* Except for this special case, processing is quite simple.
1252 Examine the list of RTEs in the Request one by one. For each
1253 entry, look up the destination in the router's routing
1254 database and, if there is a route, put that route's metric in
1255 the metric field of the RTE. If there is no explicit route
1256 to the specified destination, put infinity in the metric
1257 field. Once all the entries have been filled in, change the
1258 command from Request to Response and send the datagram back
1259 to the requestor. */
1260 memset(&p
, 0, sizeof(p
));
1261 p
.family
= AF_INET6
;
1263 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1264 p
.prefix
= rte
->addr
;
1265 p
.prefixlen
= rte
->prefixlen
;
1266 apply_mask_ipv6(&p
);
1268 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1271 rinfo
= listgetdata(
1272 listhead((struct list
*)rp
->info
));
1273 rte
->metric
= rinfo
->metric
;
1274 agg_unlock_node(rp
);
1276 rte
->metric
= RIPNG_METRIC_INFINITY
;
1278 packet
->command
= RIPNG_RESPONSE
;
1280 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1284 /* First entry point of reading RIPng packet. */
1285 static void ripng_read(struct event
*thread
)
1287 struct ripng
*ripng
= EVENT_ARG(thread
);
1290 struct sockaddr_in6 from
;
1291 struct ripng_packet
*packet
;
1292 ifindex_t ifindex
= 0;
1293 struct interface
*ifp
;
1296 /* Check ripng is active and alive. */
1297 assert(ripng
!= NULL
);
1298 assert(ripng
->sock
>= 0);
1300 /* Fetch thread data and set read pointer to empty for event
1301 managing. `sock' sould be same as ripng->sock. */
1302 sock
= EVENT_FD(thread
);
1304 /* Add myself to the next event. */
1305 ripng_event(ripng
, RIPNG_READ
, sock
);
1307 /* Read RIPng packet. */
1308 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1309 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1312 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1313 ripng
->vrf_name
, safe_strerror(errno
));
1317 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1318 (4)) must be multiple size of one RTE size (20). */
1319 if (((len
- 4) % 20) != 0) {
1320 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
1321 len
, &from
.sin6_addr
, ripng
->vrf_name
);
1322 ripng_peer_bad_packet(ripng
, &from
);
1326 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1327 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1329 /* RIPng packet received. */
1330 if (IS_RIPNG_DEBUG_EVENT
)
1332 "RIPng packet received from %pI6 port %d on %s (VRF %s)",
1333 &from
.sin6_addr
, ntohs(from
.sin6_port
),
1334 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1336 /* Logging before packet checking. */
1337 if (IS_RIPNG_DEBUG_RECV
)
1338 ripng_packet_dump(packet
, len
, "RECV");
1340 /* Packet comes from unknown interface. */
1343 "RIPng packet comes from unknown interface %d (VRF %s)",
1344 ifindex
, ripng
->vrf_name
);
1348 /* Packet version mismatch checking. */
1349 if (packet
->version
!= ripng
->version
) {
1351 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1352 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1353 ripng_peer_bad_packet(ripng
, &from
);
1357 /* Process RIPng packet. */
1358 switch (packet
->command
) {
1360 ripng_request_process(packet
, len
, &from
, ifp
);
1362 case RIPNG_RESPONSE
:
1363 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1366 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1368 ripng_peer_bad_packet(ripng
, &from
);
1373 /* Walk down the RIPng routing table then clear changed flag. */
1374 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1376 struct agg_node
*rp
;
1377 struct ripng_info
*rinfo
= NULL
;
1378 struct list
*list
= NULL
;
1379 struct listnode
*listnode
= NULL
;
1381 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1382 if ((list
= rp
->info
) != NULL
)
1383 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1384 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1385 /* This flag can be set only on the first entry.
1391 /* Regular update of RIPng route. Send all routing formation to RIPng
1392 enabled interface. */
1393 static void ripng_update(struct event
*t
)
1395 struct ripng
*ripng
= EVENT_ARG(t
);
1396 struct interface
*ifp
;
1397 struct ripng_interface
*ri
;
1399 /* Logging update event. */
1400 if (IS_RIPNG_DEBUG_EVENT
)
1401 zlog_debug("RIPng update timer expired!");
1403 /* Supply routes to each interface. */
1404 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1407 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1413 /* When passive interface is specified, suppress announce to the
1418 #ifdef RIPNG_ADVANCED
1419 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1420 if (IS_RIPNG_DEBUG_EVENT
)
1422 "[Event] RIPng send to if %d is suppressed by config",
1426 #endif /* RIPNG_ADVANCED */
1428 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1431 /* Triggered updates may be suppressed if a regular update is due by
1432 the time the triggered update would be sent. */
1433 EVENT_OFF(ripng
->t_triggered_interval
);
1436 /* Reset flush event. */
1437 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1440 /* Triggered update interval timer. */
1441 static void ripng_triggered_interval(struct event
*t
)
1443 struct ripng
*ripng
= EVENT_ARG(t
);
1445 if (ripng
->trigger
) {
1447 ripng_triggered_update(t
);
1451 /* Execute triggered update. */
1452 void ripng_triggered_update(struct event
*t
)
1454 struct ripng
*ripng
= EVENT_ARG(t
);
1455 struct interface
*ifp
;
1456 struct ripng_interface
*ri
;
1459 /* Cancel interval timer. */
1460 EVENT_OFF(ripng
->t_triggered_interval
);
1463 /* Logging triggered update. */
1464 if (IS_RIPNG_DEBUG_EVENT
)
1465 zlog_debug("RIPng triggered update!");
1467 /* Split Horizon processing is done when generating triggered
1468 updates as well as normal updates (see section 2.6). */
1469 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1472 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1478 /* When passive interface is specified, suppress announce to the
1483 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1486 /* Once all of the triggered updates have been generated, the route
1487 change flags should be cleared. */
1488 ripng_clear_changed_flag(ripng
);
1490 /* After a triggered update is sent, a timer should be set for a
1491 random interval between 1 and 5 seconds. If other changes that
1492 would trigger updates occur before the timer expires, a single
1493 update is triggered when the timer expires. */
1494 interval
= (frr_weak_random() % 5) + 1;
1496 event_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1497 &ripng
->t_triggered_interval
);
1500 /* Write routing table entry to the stream and return next index of
1501 the routing table entry in the stream. */
1502 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1503 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1505 /* RIPng packet header. */
1507 stream_putc(s
, RIPNG_RESPONSE
);
1508 stream_putc(s
, RIPNG_V1
);
1512 /* Write routing table entry. */
1515 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1517 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1518 stream_putw(s
, tag
);
1520 stream_putc(s
, p
->prefixlen
);
1523 stream_putc(s
, metric
);
1528 /* Send RESPONSE message to specified destination. */
1529 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1532 struct ripng
*ripng
;
1534 struct agg_node
*rp
;
1535 struct ripng_info
*rinfo
;
1536 struct ripng_interface
*ri
;
1537 struct ripng_aggregate
*aggregate
;
1538 struct prefix_ipv6
*p
;
1539 struct list
*ripng_rte_list
;
1540 struct list
*list
= NULL
;
1541 struct listnode
*listnode
= NULL
;
1543 if (IS_RIPNG_DEBUG_EVENT
) {
1545 zlog_debug("RIPng update routes to neighbor %pI6",
1548 zlog_debug("RIPng update routes on interface %s",
1552 /* Get RIPng interface and instance. */
1556 ripng_rte_list
= ripng_rte_new();
1558 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1559 if ((list
= rp
->info
) != NULL
1560 && (rinfo
= listgetdata(listhead(list
))) != NULL
1561 && rinfo
->suppress
== 0) {
1562 /* If no route-map are applied, the RTE will be these
1566 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1567 rinfo
->metric_out
= rinfo
->metric
;
1568 rinfo
->tag_out
= rinfo
->tag
;
1569 memset(&rinfo
->nexthop_out
, 0,
1570 sizeof(rinfo
->nexthop_out
));
1571 /* In order to avoid some local loops,
1572 * if the RIPng route has a nexthop via this interface,
1574 * otherwise set it to 0. The nexthop should not be
1576 * beyond the local broadcast/multicast area in order
1577 * to avoid an IGP multi-level recursive look-up.
1579 if (rinfo
->ifindex
== ifp
->ifindex
)
1580 rinfo
->nexthop_out
= rinfo
->nexthop
;
1582 /* Apply output filters. */
1583 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1587 /* Changed route only output. */
1588 if (route_type
== ripng_changed_route
1589 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1592 /* Split horizon. */
1593 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1594 /* We perform split horizon for RIPng routes. */
1596 struct ripng_info
*tmp_rinfo
= NULL
;
1598 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1600 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1601 && tmp_rinfo
->ifindex
1610 /* Preparation for route-map. */
1611 rinfo
->metric_set
= 0;
1614 * and tag_out are already initialized.
1617 /* Interface route-map */
1618 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1619 ret
= route_map_apply(
1620 ri
->routemap
[RIPNG_FILTER_OUT
],
1621 (struct prefix
*)p
, rinfo
);
1623 if (ret
== RMAP_DENYMATCH
) {
1624 if (IS_RIPNG_DEBUG_PACKET
)
1626 "RIPng %pFX is filtered by route-map out",
1632 /* Redistribute route-map. */
1633 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1634 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1639 if (ret
== RMAP_DENYMATCH
) {
1640 if (IS_RIPNG_DEBUG_PACKET
)
1642 "RIPng %pFX is filtered by route-map",
1648 /* When the route-map does not set metric. */
1649 if (!rinfo
->metric_set
) {
1650 /* If the redistribute metric is set. */
1651 if (ripng
->redist
[rinfo
->type
].metric_config
1652 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1654 ripng
->redist
[rinfo
->type
]
1657 /* If the route is not connected or
1659 one, use default-metric value */
1660 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1662 != ZEBRA_ROUTE_CONNECT
1664 != RIPNG_METRIC_INFINITY
)
1666 ripng
->default_metric
;
1670 /* Apply offset-list */
1671 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1672 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1673 &rinfo
->metric_out
);
1675 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1676 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1678 /* Perform split-horizon with poisoned reverse
1681 if (ri
->split_horizon
1682 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1683 struct ripng_info
*tmp_rinfo
= NULL
;
1685 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1687 if ((tmp_rinfo
->type
1688 == ZEBRA_ROUTE_RIPNG
)
1689 && tmp_rinfo
->ifindex
1692 RIPNG_METRIC_INFINITY
;
1695 /* Add RTE to the list */
1696 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1699 /* Process the aggregated RTE entry */
1700 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1701 && aggregate
->suppress
== 0) {
1702 /* If no route-map are applied, the RTE will be these
1706 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1707 aggregate
->metric_set
= 0;
1708 aggregate
->metric_out
= aggregate
->metric
;
1709 aggregate
->tag_out
= aggregate
->tag
;
1710 memset(&aggregate
->nexthop_out
, 0,
1711 sizeof(aggregate
->nexthop_out
));
1713 /* Apply output filters.*/
1714 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1718 /* Interface route-map */
1719 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1720 struct ripng_info newinfo
;
1722 /* let's cast the aggregate structure to
1724 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1725 /* the nexthop is :: */
1726 newinfo
.metric
= aggregate
->metric
;
1727 newinfo
.metric_out
= aggregate
->metric_out
;
1728 newinfo
.tag
= aggregate
->tag
;
1729 newinfo
.tag_out
= aggregate
->tag_out
;
1731 ret
= route_map_apply(
1732 ri
->routemap
[RIPNG_FILTER_OUT
],
1733 (struct prefix
*)p
, &newinfo
);
1735 if (ret
== RMAP_DENYMATCH
) {
1736 if (IS_RIPNG_DEBUG_PACKET
)
1738 "RIPng %pFX is filtered by route-map out",
1743 aggregate
->metric_out
= newinfo
.metric_out
;
1744 aggregate
->tag_out
= newinfo
.tag_out
;
1745 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1746 aggregate
->nexthop_out
=
1747 newinfo
.nexthop_out
;
1750 /* There is no redistribute routemap for the aggregated
1753 /* Changed route only output. */
1754 /* XXX, vincent, in order to increase time convergence,
1755 * it should be announced if a child has changed.
1757 if (route_type
== ripng_changed_route
)
1760 /* Apply offset-list */
1761 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1762 ripng_offset_list_apply_out(
1763 ripng
, p
, ifp
, &aggregate
->metric_out
);
1765 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1766 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1768 /* Add RTE to the list */
1769 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1773 /* Flush the list */
1774 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1775 ripng_rte_free(ripng_rte_list
);
1778 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1782 vrf
= vrf_lookup_by_id(vrf_id
);
1789 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1793 ripng
.vrf_name
= (char *)vrf_name
;
1795 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1798 /* Create new RIPng instance and set it to global variable. */
1799 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1801 struct ripng
*ripng
;
1803 /* Allocaste RIPng instance. */
1804 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1805 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1807 /* Default version and timer values. */
1808 ripng
->version
= RIPNG_V1
;
1809 ripng
->update_time
= yang_get_default_uint32(
1810 "%s/timers/update-interval", RIPNG_INSTANCE
);
1811 ripng
->timeout_time
= yang_get_default_uint32(
1812 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1813 ripng
->garbage_time
= yang_get_default_uint32(
1814 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1815 ripng
->default_metric
=
1816 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1817 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1820 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1821 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1823 /* Initialize RIPng data structures. */
1824 ripng
->table
= agg_table_init();
1825 agg_set_table_info(ripng
->table
, ripng
);
1826 ripng
->peer_list
= list_new();
1827 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1828 ripng
->peer_list
->del
= ripng_peer_list_del
;
1829 ripng
->enable_if
= vector_init(1);
1830 ripng
->enable_network
= agg_table_init();
1831 ripng
->passive_interface
= vector_init(1);
1832 ripng
->offset_list_master
= list_new();
1833 ripng
->offset_list_master
->cmp
=
1834 (int (*)(void *, void *))offset_list_cmp
;
1835 ripng
->offset_list_master
->del
=
1836 (void (*)(void *))ripng_offset_list_free
;
1837 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1838 distribute_list_add_hook(ripng
->distribute_ctx
,
1839 ripng_distribute_update
);
1840 distribute_list_delete_hook(ripng
->distribute_ctx
,
1841 ripng_distribute_update
);
1843 /* if rmap install. */
1844 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1845 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1846 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1848 /* Enable the routing instance if possible. */
1849 if (vrf
&& vrf_is_enabled(vrf
))
1850 ripng_instance_enable(ripng
, vrf
, socket
);
1856 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1861 /* Send RIPng request to the interface. */
1862 int ripng_request(struct interface
*ifp
)
1865 struct ripng_packet ripng_packet
;
1867 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1869 if (if_is_loopback(ifp
))
1872 /* If interface is down, don't send RIP packet. */
1876 if (IS_RIPNG_DEBUG_EVENT
)
1877 zlog_debug("RIPng send request to %s", ifp
->name
);
1879 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1880 ripng_packet
.command
= RIPNG_REQUEST
;
1881 ripng_packet
.version
= RIPNG_V1
;
1882 rte
= ripng_packet
.rte
;
1883 rte
->metric
= RIPNG_METRIC_INFINITY
;
1885 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1890 static int ripng_update_jitter(int time
)
1892 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1895 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1901 event_add_read(master
, ripng_read
, ripng
, sock
, &ripng
->t_read
);
1903 case RIPNG_UPDATE_EVENT
:
1904 EVENT_OFF(ripng
->t_update
);
1906 /* Update timer jitter. */
1907 jitter
= ripng_update_jitter(ripng
->update_time
);
1909 event_add_timer(master
, ripng_update
, ripng
,
1910 sock
? 2 : ripng
->update_time
+ jitter
,
1913 case RIPNG_TRIGGERED_UPDATE
:
1914 if (ripng
->t_triggered_interval
)
1917 event_add_event(master
, ripng_triggered_update
, ripng
,
1918 0, &ripng
->t_triggered_update
);
1921 case RIPNG_REQUEST_EVENT
:
1927 /* Print out routes update time. */
1928 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1933 char timebuf
[TIME_BUF
];
1934 struct event
*thread
;
1936 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1937 clock
= event_timer_remain_second(thread
);
1938 gmtime_r(&clock
, &tm
);
1939 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1940 vty_out(vty
, "%5s", timebuf
);
1941 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1942 clock
= event_timer_remain_second(thread
);
1943 gmtime_r(&clock
, &tm
);
1944 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1945 vty_out(vty
, "%5s", timebuf
);
1949 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1954 if (rinfo
->suppress
)
1955 strlcat(str
, "S", sizeof(str
));
1957 switch (rinfo
->sub_type
) {
1958 case RIPNG_ROUTE_RTE
:
1959 strlcat(str
, "n", sizeof(str
));
1961 case RIPNG_ROUTE_STATIC
:
1962 strlcat(str
, "s", sizeof(str
));
1964 case RIPNG_ROUTE_DEFAULT
:
1965 strlcat(str
, "d", sizeof(str
));
1967 case RIPNG_ROUTE_REDISTRIBUTE
:
1968 strlcat(str
, "r", sizeof(str
));
1970 case RIPNG_ROUTE_INTERFACE
:
1971 strlcat(str
, "i", sizeof(str
));
1974 strlcat(str
, "?", sizeof(str
));
1981 DEFUN (show_ipv6_ripng
,
1982 show_ipv6_ripng_cmd
,
1983 "show ipv6 ripng [vrf NAME]",
1986 "Show RIPng routes\n"
1989 struct ripng
*ripng
;
1990 struct agg_node
*rp
;
1991 struct ripng_info
*rinfo
;
1992 struct ripng_aggregate
*aggregate
;
1993 struct list
*list
= NULL
;
1994 struct listnode
*listnode
= NULL
;
1996 const char *vrf_name
;
1999 if (argv_find(argv
, argc
, "vrf", &idx
))
2000 vrf_name
= argv
[idx
+ 1]->arg
;
2002 vrf_name
= VRF_DEFAULT_NAME
;
2004 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2006 vty_out(vty
, "%% RIPng instance not found\n");
2009 if (!ripng
->enabled
) {
2010 vty_out(vty
, "%% RIPng instance is disabled\n");
2014 /* Header of display. */
2016 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2018 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2019 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2020 " Network Next Hop Via Metric Tag Time\n");
2022 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2023 if ((aggregate
= rp
->aggregate
) != NULL
) {
2025 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2026 aggregate
->suppress
, rp
);
2028 vty_out(vty
, "R(a) %pRN ", rp
);
2031 vty_out(vty
, "%*s", 18, " ");
2033 vty_out(vty
, "%*s", 28, " ");
2034 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2035 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2038 if ((list
= rp
->info
) != NULL
)
2039 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2041 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2042 zebra_route_char(rinfo
->type
),
2043 ripng_route_subtype_print(rinfo
),
2044 rinfo
->suppress
, rp
);
2046 vty_out(vty
, "%c(%s) %pRN ",
2047 zebra_route_char(rinfo
->type
),
2048 ripng_route_subtype_print(rinfo
), rp
);
2051 vty_out(vty
, "%*s", 18, " ");
2052 len
= vty_out(vty
, "%pI6",
2057 vty_out(vty
, "%*s", len
, " ");
2060 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2061 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2066 ripng
->vrf
->vrf_id
));
2067 } else if (rinfo
->metric
2068 == RIPNG_METRIC_INFINITY
) {
2069 len
= vty_out(vty
, "kill");
2071 len
= vty_out(vty
, "self");
2075 vty_out(vty
, "%*s", len
, " ");
2077 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2078 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2081 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2082 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2083 /* RTE from remote RIP routers */
2084 ripng_vty_out_uptime(vty
, rinfo
);
2085 } else if (rinfo
->metric
2086 == RIPNG_METRIC_INFINITY
) {
2087 /* poisonous reversed routes (gc) */
2088 ripng_vty_out_uptime(vty
, rinfo
);
2098 DEFUN (show_ipv6_ripng_status
,
2099 show_ipv6_ripng_status_cmd
,
2100 "show ipv6 ripng [vrf NAME] status",
2103 "Show RIPng routes\n"
2105 "IPv6 routing protocol process parameters and statistics\n")
2107 struct ripng
*ripng
;
2108 struct interface
*ifp
;
2109 const char *vrf_name
;
2112 if (argv_find(argv
, argc
, "vrf", &idx
))
2113 vrf_name
= argv
[idx
+ 1]->arg
;
2115 vrf_name
= VRF_DEFAULT_NAME
;
2117 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2119 vty_out(vty
, "%% RIPng instance not found\n");
2122 if (!ripng
->enabled
) {
2123 vty_out(vty
, "%% RIPng instance is disabled\n");
2127 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2128 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2129 ripng
->update_time
);
2130 vty_out(vty
, " next due in %lu seconds\n",
2131 event_timer_remain_second(ripng
->t_update
));
2132 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2133 vty_out(vty
, " garbage collect after %u seconds\n",
2134 ripng
->garbage_time
);
2136 /* Filtering status show. */
2137 config_show_distribute(vty
, ripng
->distribute_ctx
);
2139 /* Default metric information. */
2140 vty_out(vty
, " Default redistribution metric is %d\n",
2141 ripng
->default_metric
);
2143 /* Redistribute information. */
2144 vty_out(vty
, " Redistributing:");
2145 ripng_redistribute_write(vty
, ripng
);
2148 vty_out(vty
, " Default version control: send version %d,",
2150 vty_out(vty
, " receive version %d \n", ripng
->version
);
2152 vty_out(vty
, " Interface Send Recv\n");
2154 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2155 struct ripng_interface
*ri
;
2159 if (ri
->enable_network
|| ri
->enable_interface
) {
2161 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2162 ripng
->version
, ripng
->version
);
2166 vty_out(vty
, " Routing for Networks:\n");
2167 ripng_network_write(vty
, ripng
);
2169 vty_out(vty
, " Routing Information Sources:\n");
2171 " Gateway BadPackets BadRoutes Distance Last Update\n");
2172 ripng_peer_display(vty
, ripng
);
2177 /* Update ECMP routes to zebra when ECMP is disabled. */
2178 void ripng_ecmp_disable(struct ripng
*ripng
)
2180 struct agg_node
*rp
;
2181 struct ripng_info
*rinfo
, *tmp_rinfo
;
2183 struct listnode
*node
, *nextnode
;
2188 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2189 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2190 rinfo
= listgetdata(listhead(list
));
2191 if (!ripng_route_rte(rinfo
))
2194 /* Drop all other entries, except the first one. */
2195 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2196 if (tmp_rinfo
!= rinfo
) {
2197 EVENT_OFF(tmp_rinfo
->t_timeout
);
2198 EVENT_OFF(tmp_rinfo
->t_garbage_collect
);
2199 list_delete_node(list
, node
);
2200 ripng_info_free(tmp_rinfo
);
2204 ripng_zebra_ipv6_add(ripng
, rp
);
2206 /* Set the route change flag. */
2207 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2209 /* Signal the output process to trigger an update. */
2210 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2214 /* RIPng configuration write function. */
2215 static int ripng_config_write(struct vty
*vty
)
2217 struct ripng
*ripng
;
2220 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2221 char xpath
[XPATH_MAXLEN
];
2222 struct lyd_node
*dnode
;
2224 snprintf(xpath
, sizeof(xpath
),
2225 "/frr-ripngd:ripngd/instance[vrf='%s']",
2228 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2231 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2233 config_write_distribute(vty
, ripng
->distribute_ctx
);
2234 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2236 vty_out(vty
, "exit\n");
2244 static int ripng_config_write(struct vty
*vty
);
2245 /* RIPng node structure. */
2246 static struct cmd_node cmd_ripng_node
= {
2249 .parent_node
= CONFIG_NODE
,
2250 .prompt
= "%s(config-router)# ",
2251 .config_write
= ripng_config_write
,
2254 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2255 struct distribute
*dist
)
2257 struct interface
*ifp
;
2258 struct ripng_interface
*ri
;
2259 struct access_list
*alist
;
2260 struct prefix_list
*plist
;
2262 if (!ctx
->vrf
|| !dist
->ifname
)
2265 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2271 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2272 alist
= access_list_lookup(AFI_IP6
,
2273 dist
->list
[DISTRIBUTE_V6_IN
]);
2275 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2277 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2279 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2281 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2282 alist
= access_list_lookup(AFI_IP6
,
2283 dist
->list
[DISTRIBUTE_V6_OUT
]);
2285 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2287 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2289 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2291 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2292 plist
= prefix_list_lookup(AFI_IP6
,
2293 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2295 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2297 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2299 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2301 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2302 plist
= prefix_list_lookup(AFI_IP6
,
2303 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2305 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2307 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2309 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2312 void ripng_distribute_update_interface(struct interface
*ifp
)
2314 struct ripng_interface
*ri
= ifp
->info
;
2315 struct ripng
*ripng
= ri
->ripng
;
2316 struct distribute
*dist
;
2320 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2322 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2325 /* Update all interface's distribute list. */
2326 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2328 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2329 struct interface
*ifp
;
2331 FOR_ALL_INTERFACES (vrf
, ifp
)
2332 ripng_distribute_update_interface(ifp
);
2335 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2337 ripng_distribute_update_all(NULL
);
2340 /* delete all the added ripng routes. */
2341 void ripng_clean(struct ripng
*ripng
)
2343 ripng_interface_clean(ripng
);
2346 ripng_instance_disable(ripng
);
2348 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2349 if (ripng
->redist
[i
].route_map
.name
)
2350 free(ripng
->redist
[i
].route_map
.name
);
2352 agg_table_finish(ripng
->table
);
2353 list_delete(&ripng
->peer_list
);
2354 distribute_list_delete(&ripng
->distribute_ctx
);
2355 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2357 stream_free(ripng
->ibuf
);
2358 stream_free(ripng
->obuf
);
2360 ripng_clean_network(ripng
);
2361 ripng_passive_interface_clean(ripng
);
2362 vector_free(ripng
->enable_if
);
2363 agg_table_finish(ripng
->enable_network
);
2364 vector_free(ripng
->passive_interface
);
2365 list_delete(&ripng
->offset_list_master
);
2367 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2368 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2369 XFREE(MTYPE_RIPNG
, ripng
);
2372 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2373 struct if_rmap
*if_rmap
)
2375 struct interface
*ifp
= NULL
;
2376 struct ripng_interface
*ri
;
2377 struct route_map
*rmap
;
2378 struct vrf
*vrf
= NULL
;
2381 vrf
= vrf_lookup_by_name(ctx
->name
);
2383 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2389 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2390 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2392 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2394 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2396 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2398 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2399 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2401 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2403 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2405 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2408 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2410 struct ripng_interface
*ri
= ifp
->info
;
2411 struct ripng
*ripng
= ri
->ripng
;
2412 struct if_rmap
*if_rmap
;
2413 struct if_rmap_ctx
*ctx
;
2417 ctx
= ripng
->if_rmap_ctx
;
2420 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2422 ripng_if_rmap_update(ctx
, if_rmap
);
2425 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2427 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2428 if (ripng
->redist
[i
].route_map
.name
) {
2429 ripng
->redist
[i
].route_map
.map
=
2430 route_map_lookup_by_name(
2431 ripng
->redist
[i
].route_map
.name
);
2432 route_map_counter_increment(
2433 ripng
->redist
[i
].route_map
.map
);
2438 static void ripng_routemap_update(const char *unused
)
2440 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2441 struct ripng
*ripng
;
2442 struct interface
*ifp
;
2444 FOR_ALL_INTERFACES (vrf
, ifp
)
2445 ripng_if_rmap_update_interface(ifp
);
2449 ripng_routemap_update_redistribute(ripng
);
2452 /* Link RIPng instance to VRF. */
2453 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2455 struct interface
*ifp
;
2458 ripng
->distribute_ctx
->vrf
= vrf
;
2461 FOR_ALL_INTERFACES (vrf
, ifp
)
2462 ripng_interface_sync(ifp
);
2465 /* Unlink RIPng instance from VRF. */
2466 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2468 struct interface
*ifp
;
2471 ripng
->distribute_ctx
->vrf
= NULL
;
2474 FOR_ALL_INTERFACES (vrf
, ifp
)
2475 ripng_interface_sync(ifp
);
2478 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2483 ripng_vrf_link(ripng
, vrf
);
2484 ripng
->enabled
= true;
2486 /* Resend all redistribute requests. */
2487 ripng_redistribute_enable(ripng
);
2489 /* Create read and timer thread. */
2490 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2491 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2493 ripng_zebra_vrf_register(vrf
);
2496 static void ripng_instance_disable(struct ripng
*ripng
)
2498 struct vrf
*vrf
= ripng
->vrf
;
2499 struct agg_node
*rp
;
2501 /* Clear RIPng routes */
2502 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2503 struct ripng_aggregate
*aggregate
;
2506 if ((list
= rp
->info
) != NULL
) {
2507 struct ripng_info
*rinfo
;
2508 struct listnode
*listnode
;
2510 rinfo
= listgetdata(listhead(list
));
2511 if (ripng_route_rte(rinfo
))
2512 ripng_zebra_ipv6_delete(ripng
, rp
);
2514 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2515 EVENT_OFF(rinfo
->t_timeout
);
2516 EVENT_OFF(rinfo
->t_garbage_collect
);
2517 ripng_info_free(rinfo
);
2521 agg_unlock_node(rp
);
2524 if ((aggregate
= rp
->aggregate
) != NULL
) {
2525 ripng_aggregate_free(aggregate
);
2526 rp
->aggregate
= NULL
;
2527 agg_unlock_node(rp
);
2531 /* Flush all redistribute requests. */
2532 ripng_redistribute_disable(ripng
);
2534 /* Cancel the RIPng timers */
2535 EVENT_OFF(ripng
->t_update
);
2536 EVENT_OFF(ripng
->t_triggered_update
);
2537 EVENT_OFF(ripng
->t_triggered_interval
);
2539 /* Cancel the read thread */
2540 EVENT_OFF(ripng
->t_read
);
2542 /* Close the RIPng socket */
2543 if (ripng
->sock
>= 0) {
2548 /* Clear existing peers. */
2549 list_delete_all_node(ripng
->peer_list
);
2551 ripng_zebra_vrf_deregister(vrf
);
2553 ripng_vrf_unlink(ripng
, vrf
);
2554 ripng
->enabled
= false;
2557 static int ripng_vrf_new(struct vrf
*vrf
)
2559 if (IS_RIPNG_DEBUG_EVENT
)
2560 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2566 static int ripng_vrf_delete(struct vrf
*vrf
)
2568 struct ripng
*ripng
;
2570 if (IS_RIPNG_DEBUG_EVENT
)
2571 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2574 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2582 static int ripng_vrf_enable(struct vrf
*vrf
)
2584 struct ripng
*ripng
;
2587 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2588 if (!ripng
|| ripng
->enabled
)
2591 if (IS_RIPNG_DEBUG_EVENT
)
2592 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2595 /* Activate the VRF RIPng instance. */
2596 socket
= ripng_make_socket(vrf
);
2600 ripng_instance_enable(ripng
, vrf
, socket
);
2605 static int ripng_vrf_disable(struct vrf
*vrf
)
2607 struct ripng
*ripng
;
2609 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2610 if (!ripng
|| !ripng
->enabled
)
2613 if (IS_RIPNG_DEBUG_EVENT
)
2614 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2617 /* Deactivate the VRF RIPng instance. */
2619 ripng_instance_disable(ripng
);
2624 void ripng_vrf_init(void)
2626 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2632 void ripng_vrf_terminate(void)
2637 /* Initialize ripng structure and set commands. */
2638 void ripng_init(void)
2640 /* Install RIPNG_NODE. */
2641 install_node(&cmd_ripng_node
);
2643 /* Install ripng commands. */
2644 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2645 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2647 install_default(RIPNG_NODE
);
2652 /* Access list install. */
2654 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2655 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2657 /* Prefix list initialize.*/
2659 prefix_list_add_hook(ripng_distribute_update_all
);
2660 prefix_list_delete_hook(ripng_distribute_update_all
);
2662 /* Route-map for interface. */
2663 ripng_route_map_init();
2665 route_map_add_hook(ripng_routemap_update
);
2666 route_map_delete_hook(ripng_routemap_update
);
2668 if_rmap_init(RIPNG_NODE
);