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 ripng_info
*rinfo_exist
= NULL
;
447 struct list
*list
= NULL
;
448 struct listnode
*node
= NULL
;
449 struct listnode
*nnode
= NULL
;
451 if (rp
->info
== NULL
)
452 rp
->info
= list_new();
453 list
= (struct list
*)rp
->info
;
455 /* If ECMP is not allowed and some entry already exists in the list,
457 if (listcount(list
) && !ripng
->ecmp
)
460 /* Add or replace an existing ECMP path with lower neighbor IP */
461 if (listcount(list
) && listcount(list
) >= ripng
->ecmp
) {
462 struct ripng_info
*from_highest
= NULL
;
464 /* Find the rip_info struct that has the highest nexthop IP */
465 for (ALL_LIST_ELEMENTS(list
, node
, nnode
, rinfo_exist
))
468 IPV6_ADDR_CMP(&rinfo_exist
->from
,
469 &from_highest
->from
) > 0)) {
470 from_highest
= rinfo_exist
;
473 /* If we have a route in ECMP group, delete the old
474 * one that has a higher next-hop address. Lower IP is
477 if (ripng
->ecmp
> 1 && from_highest
&&
478 IPV6_ADDR_CMP(&from_highest
->from
, &rinfo_new
->from
) > 0) {
479 ripng_ecmp_delete(ripng
, from_highest
);
487 rinfo
= ripng_info_new();
488 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
489 listnode_add(list
, rinfo
);
491 if (ripng_route_rte(rinfo
)) {
492 ripng_timeout_update(ripng
, rinfo
);
493 ripng_zebra_ipv6_add(ripng
, rp
);
496 ripng_aggregate_increment(rp
, rinfo
);
498 /* Set the route change flag on the first entry. */
499 rinfo
= listgetdata(listhead(list
));
500 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
502 /* Signal the output process to trigger an update. */
503 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
508 /* Update ECMP routes to zebra when `allow-ecmp` changed. */
509 void ripng_ecmp_change(struct ripng
*ripng
)
512 struct ripng_info
*rinfo
;
514 struct listnode
*node
, *nextnode
;
516 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
518 if (list
&& listcount(list
) > 1) {
519 while (listcount(list
) > ripng
->ecmp
) {
520 struct ripng_info
*from_highest
= NULL
;
522 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
,
528 &from_highest
->from
) > 0))
529 from_highest
= rinfo
;
532 ripng_ecmp_delete(ripng
, from_highest
);
538 /* Replace the ECMP list with the new route.
539 * RETURN: the new entry added in the list
541 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
542 struct ripng_info
*rinfo_new
)
544 struct agg_node
*rp
= rinfo_new
->rp
;
545 struct list
*list
= (struct list
*)rp
->info
;
546 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
547 struct listnode
*node
= NULL
, *nextnode
= NULL
;
549 if (list
== NULL
|| listcount(list
) == 0)
550 return ripng_ecmp_add(ripng
, rinfo_new
);
552 /* Get the first entry */
553 rinfo
= listgetdata(listhead(list
));
555 /* Learnt route replaced by a local one. Delete it from zebra. */
556 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
557 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
558 ripng_zebra_ipv6_delete(ripng
, rp
);
560 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
561 ripng_aggregate_decrement_list(rp
, list
);
563 /* Re-use the first entry, and delete the others. */
564 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
565 if (tmp_rinfo
!= rinfo
) {
566 EVENT_OFF(tmp_rinfo
->t_timeout
);
567 EVENT_OFF(tmp_rinfo
->t_garbage_collect
);
568 list_delete_node(list
, node
);
569 ripng_info_free(tmp_rinfo
);
572 EVENT_OFF(rinfo
->t_timeout
);
573 EVENT_OFF(rinfo
->t_garbage_collect
);
574 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
576 if (ripng_route_rte(rinfo
)) {
577 ripng_timeout_update(ripng
, rinfo
);
578 /* The ADD message implies an update. */
579 ripng_zebra_ipv6_add(ripng
, rp
);
582 ripng_aggregate_increment(rp
, rinfo
);
584 /* Set the route change flag. */
585 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
587 /* Signal the output process to trigger an update. */
588 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
593 /* Delete one route from the ECMP list.
595 * null - the entry is freed, and other entries exist in the list
596 * the entry - the entry is the last one in the list; its metric is set
597 * to INFINITY, and the garbage collector is started for it
599 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
600 struct ripng_info
*rinfo
)
602 struct agg_node
*rp
= rinfo
->rp
;
603 struct list
*list
= (struct list
*)rp
->info
;
605 EVENT_OFF(rinfo
->t_timeout
);
607 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
608 ripng_aggregate_decrement(rp
, rinfo
);
610 if (listcount(list
) > 1) {
611 /* Some other ECMP entries still exist. Just delete this entry.
613 EVENT_OFF(rinfo
->t_garbage_collect
);
614 listnode_delete(list
, rinfo
);
615 if (ripng_route_rte(rinfo
)
616 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
617 /* The ADD message implies the update. */
618 ripng_zebra_ipv6_add(ripng
, rp
);
619 ripng_info_free(rinfo
);
622 assert(rinfo
== listgetdata(listhead(list
)));
624 /* This is the only entry left in the list. We must keep it in
625 * the list for garbage collection time, with INFINITY metric.
628 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
629 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
630 ripng
->garbage_time
);
632 if (ripng_route_rte(rinfo
)
633 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
634 ripng_zebra_ipv6_delete(ripng
, rp
);
637 /* Set the route change flag on the first entry. */
638 rinfo
= listgetdata(listhead(list
));
639 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
641 /* Signal the output process to trigger an update. */
642 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
647 /* Timeout RIPng routes. */
648 static void ripng_timeout(struct event
*t
)
650 struct ripng_info
*rinfo
= EVENT_ARG(t
);
651 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
653 ripng_ecmp_delete(ripng
, rinfo
);
656 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
658 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
659 EVENT_OFF(rinfo
->t_timeout
);
660 event_add_timer(master
, ripng_timeout
, rinfo
,
661 ripng
->timeout_time
, &rinfo
->t_timeout
);
665 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
666 struct ripng_interface
*ri
)
668 struct distribute
*dist
;
669 struct access_list
*alist
;
670 struct prefix_list
*plist
;
671 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
674 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
676 /* Input distribute-list filtering. */
677 if (ri
->list
[ripng_distribute
]) {
678 if (access_list_apply(ri
->list
[ripng_distribute
],
681 if (IS_RIPNG_DEBUG_PACKET
)
682 zlog_debug("%pFX filtered by distribute %s", p
,
687 if (ri
->prefix
[ripng_distribute
]) {
688 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
691 if (IS_RIPNG_DEBUG_PACKET
)
692 zlog_debug("%pFX filtered by prefix-list %s", p
,
698 /* All interface filter check. */
699 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
701 if (dist
->list
[distribute
]) {
702 alist
= access_list_lookup(AFI_IP6
,
703 dist
->list
[distribute
]);
706 if (access_list_apply(alist
, (struct prefix
*)p
)
708 if (IS_RIPNG_DEBUG_PACKET
)
710 "%pFX filtered by distribute %s",
716 if (dist
->prefix
[distribute
]) {
717 plist
= prefix_list_lookup(AFI_IP6
,
718 dist
->prefix
[distribute
]);
721 if (prefix_list_apply(plist
, (struct prefix
*)p
)
723 if (IS_RIPNG_DEBUG_PACKET
)
725 "%pFX filtered by prefix-list %s",
735 /* Process RIPng route according to RFC2080. */
736 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
737 struct ripng_nexthop
*ripng_nexthop
,
738 struct interface
*ifp
)
741 struct prefix_ipv6 p
;
743 struct ripng_info
*rinfo
= NULL
, newinfo
;
744 struct ripng_interface
*ri
;
746 struct in6_addr
*nexthop
;
748 struct list
*list
= NULL
;
749 struct listnode
*node
= NULL
;
751 /* Make prefix structure. */
752 memset(&p
, 0, sizeof(struct prefix_ipv6
));
754 /* p.prefix = rte->addr; */
755 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
756 p
.prefixlen
= rte
->prefixlen
;
758 /* Make sure mask is applied. */
759 /* XXX We have to check the prefix is valid or not before call
766 /* Apply input filters. */
767 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
771 memset(&newinfo
, 0, sizeof(newinfo
));
772 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
773 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
774 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
775 newinfo
.nexthop
= ripng_nexthop
->address
;
777 newinfo
.nexthop
= from
->sin6_addr
;
778 newinfo
.from
= from
->sin6_addr
;
779 newinfo
.ifindex
= ifp
->ifindex
;
780 newinfo
.metric
= rte
->metric
;
781 newinfo
.metric_out
= rte
->metric
; /* XXX */
782 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
785 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
786 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
787 (struct prefix
*)&p
, &newinfo
);
789 if (ret
== RMAP_DENYMATCH
) {
790 if (IS_RIPNG_DEBUG_PACKET
)
792 "RIPng %pFX is filtered by route-map in",
797 /* Get back the object */
798 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
799 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
800 &ripng_nexthop
->address
)) {
801 /* the nexthop get changed by the routemap */
802 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
803 ripng_nexthop
->address
=
806 ripng_nexthop
->address
= in6addr_any
;
809 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
811 /* the nexthop get changed by the routemap */
812 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
813 ripng_nexthop
->flag
=
814 RIPNG_NEXTHOP_ADDRESS
;
815 ripng_nexthop
->address
=
820 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
822 newinfo
.metric_out
; /* XXX: the routemap uses the
826 /* Once the entry has been validated, update the metric by
827 * adding the cost of the network on wich the message
828 * arrived. If the result is greater than infinity, use infinity
829 * (RFC2453 Sec. 3.9.2)
832 /* Zebra ripngd can handle offset-list in. */
833 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
835 /* If offset-list does not modify the metric use interface's
838 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
840 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
841 rte
->metric
= RIPNG_METRIC_INFINITY
;
843 /* Set nexthop pointer. */
844 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
845 nexthop
= &ripng_nexthop
->address
;
847 nexthop
= &from
->sin6_addr
;
849 /* Lookup RIPng routing table. */
850 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
853 newinfo
.nexthop
= *nexthop
;
854 newinfo
.metric
= rte
->metric
;
855 newinfo
.tag
= ntohs(rte
->tag
);
857 /* Check to see whether there is already RIPng route on the table. */
858 if ((list
= rp
->info
) != NULL
)
859 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
860 /* Need to compare with redistributed entry or local
862 if (!ripng_route_rte(rinfo
))
865 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
866 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
869 if (!listnextnode(node
)) {
870 /* Not found in the list */
872 if (rte
->metric
> rinfo
->metric
) {
873 /* New route has a greater metric.
879 if (rte
->metric
< rinfo
->metric
)
880 /* New route has a smaller metric.
881 * Replace the ECMP list
882 * with the new one in below. */
885 /* Metrics are same. Unless ECMP is disabled,
886 * keep "rinfo" null and
887 * the new route is added in the ECMP list in
895 /* Redistributed route check. */
896 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
897 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
902 /* Local static route. */
903 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
904 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
905 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
906 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
913 /* Now, check to see whether there is already an explicit route
914 for the destination prefix. If there is no such route, add
915 this route to the routing table, unless the metric is
916 infinity (there is no point in adding a route which
918 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
919 ripng_ecmp_add(ripng
, &newinfo
);
923 /* If there is an existing route, compare the next hop address
924 to the address of the router from which the datagram came.
925 If this datagram is from the same router as the existing
926 route, reinitialize the timeout. */
927 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
928 && (rinfo
->ifindex
== ifp
->ifindex
));
931 * RFC 2080 - Section 2.4.2:
932 * "If the new metric is the same as the old one, examine the
934 * for the existing route. If it is at least halfway to the
936 * point, switch to the new route. This heuristic is optional,
938 * highly recommended".
940 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
&&
942 (event_timer_remain_second(rinfo
->t_timeout
) <
943 (ripng
->timeout_time
/ 2))) {
944 ripng_ecmp_replace(ripng
, &newinfo
);
946 /* Next, compare the metrics. If the datagram is from the same
947 router as the existing route, and the new metric is different
948 than the old one; or, if the new metric is lower than the old
949 one; do the following actions: */
950 else if ((same
&& rinfo
->metric
!= rte
->metric
) ||
951 rte
->metric
< rinfo
->metric
) {
952 if (listcount(list
) == 1) {
953 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
954 ripng_ecmp_replace(ripng
, &newinfo
);
956 ripng_ecmp_delete(ripng
, rinfo
);
958 if (newinfo
.metric
< rinfo
->metric
)
959 ripng_ecmp_replace(ripng
, &newinfo
);
960 else /* newinfo.metric > rinfo->metric */
961 ripng_ecmp_delete(ripng
, rinfo
);
963 } else /* same & no change */
964 ripng_timeout_update(ripng
, rinfo
);
966 /* Unlock tempolary lock of the route. */
971 /* Add redistributed route to RIPng table. */
972 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
973 struct prefix_ipv6
*p
, ifindex_t ifindex
,
974 struct in6_addr
*nexthop
, route_tag_t tag
)
977 struct ripng_info
*rinfo
= NULL
, newinfo
;
978 struct list
*list
= NULL
;
980 /* Redistribute route */
981 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
983 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
986 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
988 memset(&newinfo
, 0, sizeof(newinfo
));
990 newinfo
.sub_type
= sub_type
;
991 newinfo
.ifindex
= ifindex
;
993 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
996 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
997 newinfo
.nexthop
= *nexthop
;
999 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
1000 rinfo
= listgetdata(listhead(list
));
1002 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
1003 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
1004 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1005 agg_unlock_node(rp
);
1009 /* Manually configured RIPng route check.
1010 * They have the precedence on all the other entries.
1012 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
1013 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
1014 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
1015 if (type
!= ZEBRA_ROUTE_RIPNG
1016 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
1017 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
1018 agg_unlock_node(rp
);
1023 ripng_ecmp_replace(ripng
, &newinfo
);
1024 agg_unlock_node(rp
);
1026 ripng_ecmp_add(ripng
, &newinfo
);
1028 if (IS_RIPNG_DEBUG_EVENT
) {
1031 "Redistribute new prefix %pFX on the interface %s",
1032 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1035 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
1037 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1040 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1043 /* Delete redistributed route to RIPng table. */
1044 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1045 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1047 struct agg_node
*rp
;
1048 struct ripng_info
*rinfo
;
1050 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1052 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1055 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1058 struct list
*list
= rp
->info
;
1060 if (list
!= NULL
&& listcount(list
) != 0) {
1061 rinfo
= listgetdata(listhead(list
));
1062 if (rinfo
!= NULL
&& rinfo
->type
== type
1063 && rinfo
->sub_type
== sub_type
1064 && rinfo
->ifindex
== ifindex
) {
1065 /* Perform poisoned reverse. */
1066 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1067 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1068 ripng_garbage_collect
,
1069 ripng
->garbage_time
);
1070 EVENT_OFF(rinfo
->t_timeout
);
1072 /* Aggregate count decrement. */
1073 ripng_aggregate_decrement(rp
, rinfo
);
1075 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1077 if (IS_RIPNG_DEBUG_EVENT
)
1079 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1083 ripng
->vrf
->vrf_id
));
1085 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1088 agg_unlock_node(rp
);
1092 /* Withdraw redistributed route. */
1093 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1095 struct agg_node
*rp
;
1096 struct ripng_info
*rinfo
= NULL
;
1097 struct list
*list
= NULL
;
1099 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1100 if ((list
= rp
->info
) != NULL
) {
1101 rinfo
= listgetdata(listhead(list
));
1102 if ((rinfo
->type
== type
)
1103 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1104 /* Perform poisoned reverse. */
1105 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1106 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1107 ripng_garbage_collect
,
1108 ripng
->garbage_time
);
1109 EVENT_OFF(rinfo
->t_timeout
);
1111 /* Aggregate count decrement. */
1112 ripng_aggregate_decrement(rp
, rinfo
);
1114 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1116 if (IS_RIPNG_DEBUG_EVENT
) {
1117 struct prefix_ipv6
*p
=
1118 (struct prefix_ipv6
*)
1119 agg_node_get_prefix(rp
);
1122 "Poisone %pFX on the interface %s [withdraw]",
1126 ripng
->vrf
->vrf_id
));
1129 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1134 /* RIP routing information. */
1135 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1136 struct sockaddr_in6
*from
,
1137 struct interface
*ifp
, int hoplimit
)
1139 struct ripng_interface
*ri
= ifp
->info
;
1140 struct ripng
*ripng
= ri
->ripng
;
1143 struct ripng_nexthop nexthop
;
1145 /* RFC2080 2.4.2 Response Messages:
1146 The Response must be ignored if it is not from the RIPng port. */
1147 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1148 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
1149 ntohs(from
->sin6_port
), &from
->sin6_addr
);
1150 ripng_peer_bad_packet(ripng
, from
);
1154 /* The datagram's IPv6 source address should be checked to see
1155 whether the datagram is from a valid neighbor; the source of the
1156 datagram must be a link-local address. */
1157 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1158 zlog_warn("RIPng packet comes from non link local address %pI6",
1160 ripng_peer_bad_packet(ripng
, from
);
1164 /* It is also worth checking to see whether the response is from one
1165 of the router's own addresses. Interfaces on broadcast networks
1166 may receive copies of their own multicasts immediately. If a
1167 router processes its own output as new input, confusion is likely,
1168 and such datagrams must be ignored. */
1169 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1171 "RIPng packet comes from my own link local address %pI6",
1173 ripng_peer_bad_packet(ripng
, from
);
1177 /* As an additional check, periodic advertisements must have their
1178 hop counts set to 255, and inbound, multicast packets sent from the
1179 RIPng port (i.e. periodic advertisement or triggered update
1180 packets) must be examined to ensure that the hop count is 255. */
1181 if (hoplimit
>= 0 && hoplimit
!= 255) {
1183 "RIPng packet comes with non 255 hop count %d from %pI6",
1184 hoplimit
, &from
->sin6_addr
);
1185 ripng_peer_bad_packet(ripng
, from
);
1189 /* Update RIPng peer. */
1190 ripng_peer_update(ripng
, from
, packet
->version
);
1192 /* Reset nexthop. */
1193 memset(&nexthop
, 0, sizeof(nexthop
));
1194 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1196 /* Set RTE pointer. */
1199 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1200 /* First of all, we have to check this RTE is next hop RTE or
1201 not. Next hop RTE is completely different with normal RTE so
1202 we need special treatment. */
1203 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1204 ripng_nexthop_rte(rte
, from
, &nexthop
);
1208 /* RTE information validation. */
1210 /* - is the destination prefix valid (e.g., not a multicast
1211 prefix and not a link-local address) A link-local address
1212 should never be present in an RTE. */
1213 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1215 "Destination prefix is a multicast address %pI6/%d [%d]",
1216 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1217 ripng_peer_bad_route(ripng
, from
);
1220 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1222 "Destination prefix is a link-local address %pI6/%d [%d]",
1223 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1224 ripng_peer_bad_route(ripng
, from
);
1227 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1229 "Destination prefix is a loopback address %pI6/%d [%d]",
1230 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1231 ripng_peer_bad_route(ripng
, from
);
1235 /* - is the prefix length valid (i.e., between 0 and 128,
1237 if (rte
->prefixlen
> IPV6_MAX_BITLEN
) {
1238 zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
1239 &rte
->addr
, rte
->prefixlen
,
1240 &from
->sin6_addr
, ifp
->name
);
1241 ripng_peer_bad_route(ripng
, from
);
1245 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1246 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1247 zlog_warn("Invalid metric %d from %pI6%%%s",
1248 rte
->metric
, &from
->sin6_addr
, ifp
->name
);
1249 ripng_peer_bad_route(ripng
, from
);
1253 /* Vincent: XXX Should we compute the direclty reachable nexthop
1254 * for our RIPng network ?
1257 /* Routing table updates. */
1258 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1262 /* Response to request message. */
1263 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1264 struct sockaddr_in6
*from
,
1265 struct interface
*ifp
)
1267 struct ripng
*ripng
;
1270 struct prefix_ipv6 p
;
1271 struct agg_node
*rp
;
1272 struct ripng_info
*rinfo
;
1273 struct ripng_interface
*ri
;
1275 /* Does not reponse to the requests on the loopback interfaces */
1276 if (if_is_loopback(ifp
))
1279 /* Check RIPng process is enabled on this interface. */
1285 /* When passive interface is specified, suppress responses */
1289 /* RIPng peer update. */
1290 ripng_peer_update(ripng
, from
, packet
->version
);
1292 lim
= ((caddr_t
)packet
) + size
;
1295 /* The Request is processed entry by entry. If there are no
1296 entries, no response is given. */
1297 if (lim
== (caddr_t
)rte
)
1300 /* There is one special case. If there is exactly one entry in the
1301 request, and it has a destination prefix of zero, a prefix length
1302 of zero, and a metric of infinity (i.e., 16), then this is a
1303 request to send the entire routing table. In that case, a call
1304 is made to the output process to send the routing table to the
1305 requesting address/port. */
1306 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1307 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1308 /* All route with split horizon */
1309 ripng_output_process(ifp
, from
, ripng_all_route
);
1311 /* Except for this special case, processing is quite simple.
1312 Examine the list of RTEs in the Request one by one. For each
1313 entry, look up the destination in the router's routing
1314 database and, if there is a route, put that route's metric in
1315 the metric field of the RTE. If there is no explicit route
1316 to the specified destination, put infinity in the metric
1317 field. Once all the entries have been filled in, change the
1318 command from Request to Response and send the datagram back
1319 to the requestor. */
1320 memset(&p
, 0, sizeof(p
));
1321 p
.family
= AF_INET6
;
1323 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1324 p
.prefix
= rte
->addr
;
1325 p
.prefixlen
= rte
->prefixlen
;
1326 apply_mask_ipv6(&p
);
1328 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1331 rinfo
= listgetdata(
1332 listhead((struct list
*)rp
->info
));
1333 rte
->metric
= rinfo
->metric
;
1334 agg_unlock_node(rp
);
1336 rte
->metric
= RIPNG_METRIC_INFINITY
;
1338 packet
->command
= RIPNG_RESPONSE
;
1340 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1344 /* First entry point of reading RIPng packet. */
1345 static void ripng_read(struct event
*thread
)
1347 struct ripng
*ripng
= EVENT_ARG(thread
);
1350 struct sockaddr_in6 from
;
1351 struct ripng_packet
*packet
;
1352 ifindex_t ifindex
= 0;
1353 struct interface
*ifp
;
1356 /* Check ripng is active and alive. */
1357 assert(ripng
!= NULL
);
1358 assert(ripng
->sock
>= 0);
1360 /* Fetch thread data and set read pointer to empty for event
1361 managing. `sock' sould be same as ripng->sock. */
1362 sock
= EVENT_FD(thread
);
1364 /* Add myself to the next event. */
1365 ripng_event(ripng
, RIPNG_READ
, sock
);
1367 /* Read RIPng packet. */
1368 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1369 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1372 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1373 ripng
->vrf_name
, safe_strerror(errno
));
1377 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1378 (4)) must be multiple size of one RTE size (20). */
1379 if (((len
- 4) % 20) != 0) {
1380 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
1381 len
, &from
.sin6_addr
, ripng
->vrf_name
);
1382 ripng_peer_bad_packet(ripng
, &from
);
1386 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1387 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1389 /* RIPng packet received. */
1390 if (IS_RIPNG_DEBUG_EVENT
)
1392 "RIPng packet received from %pI6 port %d on %s (VRF %s)",
1393 &from
.sin6_addr
, ntohs(from
.sin6_port
),
1394 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1396 /* Logging before packet checking. */
1397 if (IS_RIPNG_DEBUG_RECV
)
1398 ripng_packet_dump(packet
, len
, "RECV");
1400 /* Packet comes from unknown interface. */
1403 "RIPng packet comes from unknown interface %d (VRF %s)",
1404 ifindex
, ripng
->vrf_name
);
1408 /* Packet version mismatch checking. */
1409 if (packet
->version
!= ripng
->version
) {
1411 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1412 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1413 ripng_peer_bad_packet(ripng
, &from
);
1417 /* Process RIPng packet. */
1418 switch (packet
->command
) {
1420 ripng_request_process(packet
, len
, &from
, ifp
);
1422 case RIPNG_RESPONSE
:
1423 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1426 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1428 ripng_peer_bad_packet(ripng
, &from
);
1433 /* Walk down the RIPng routing table then clear changed flag. */
1434 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1436 struct agg_node
*rp
;
1437 struct ripng_info
*rinfo
= NULL
;
1438 struct list
*list
= NULL
;
1439 struct listnode
*listnode
= NULL
;
1441 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1442 if ((list
= rp
->info
) != NULL
)
1443 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1444 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1445 /* This flag can be set only on the first entry.
1451 /* Regular update of RIPng route. Send all routing formation to RIPng
1452 enabled interface. */
1453 static void ripng_update(struct event
*t
)
1455 struct ripng
*ripng
= EVENT_ARG(t
);
1456 struct interface
*ifp
;
1457 struct ripng_interface
*ri
;
1459 /* Logging update event. */
1460 if (IS_RIPNG_DEBUG_EVENT
)
1461 zlog_debug("RIPng update timer expired!");
1463 /* Supply routes to each interface. */
1464 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1467 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1473 /* When passive interface is specified, suppress announce to the
1478 #ifdef RIPNG_ADVANCED
1479 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1480 if (IS_RIPNG_DEBUG_EVENT
)
1482 "[Event] RIPng send to if %d is suppressed by config",
1486 #endif /* RIPNG_ADVANCED */
1488 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1491 /* Triggered updates may be suppressed if a regular update is due by
1492 the time the triggered update would be sent. */
1493 EVENT_OFF(ripng
->t_triggered_interval
);
1496 /* Reset flush event. */
1497 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1500 /* Triggered update interval timer. */
1501 static void ripng_triggered_interval(struct event
*t
)
1503 struct ripng
*ripng
= EVENT_ARG(t
);
1505 if (ripng
->trigger
) {
1507 ripng_triggered_update(t
);
1511 /* Execute triggered update. */
1512 void ripng_triggered_update(struct event
*t
)
1514 struct ripng
*ripng
= EVENT_ARG(t
);
1515 struct interface
*ifp
;
1516 struct ripng_interface
*ri
;
1519 /* Cancel interval timer. */
1520 EVENT_OFF(ripng
->t_triggered_interval
);
1523 /* Logging triggered update. */
1524 if (IS_RIPNG_DEBUG_EVENT
)
1525 zlog_debug("RIPng triggered update!");
1527 /* Split Horizon processing is done when generating triggered
1528 updates as well as normal updates (see section 2.6). */
1529 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1532 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1538 /* When passive interface is specified, suppress announce to the
1543 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1546 /* Once all of the triggered updates have been generated, the route
1547 change flags should be cleared. */
1548 ripng_clear_changed_flag(ripng
);
1550 /* After a triggered update is sent, a timer should be set for a
1551 random interval between 1 and 5 seconds. If other changes that
1552 would trigger updates occur before the timer expires, a single
1553 update is triggered when the timer expires. */
1554 interval
= (frr_weak_random() % 5) + 1;
1556 event_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1557 &ripng
->t_triggered_interval
);
1560 /* Write routing table entry to the stream and return next index of
1561 the routing table entry in the stream. */
1562 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1563 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1565 /* RIPng packet header. */
1567 stream_putc(s
, RIPNG_RESPONSE
);
1568 stream_putc(s
, RIPNG_V1
);
1572 /* Write routing table entry. */
1575 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1577 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1578 stream_putw(s
, tag
);
1580 stream_putc(s
, p
->prefixlen
);
1583 stream_putc(s
, metric
);
1588 /* Send RESPONSE message to specified destination. */
1589 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1592 struct ripng
*ripng
;
1594 struct agg_node
*rp
;
1595 struct ripng_info
*rinfo
;
1596 struct ripng_interface
*ri
;
1597 struct ripng_aggregate
*aggregate
;
1598 struct prefix_ipv6
*p
;
1599 struct list
*ripng_rte_list
;
1600 struct list
*list
= NULL
;
1601 struct listnode
*listnode
= NULL
;
1603 if (IS_RIPNG_DEBUG_EVENT
) {
1605 zlog_debug("RIPng update routes to neighbor %pI6",
1608 zlog_debug("RIPng update routes on interface %s",
1612 /* Get RIPng interface and instance. */
1616 ripng_rte_list
= ripng_rte_new();
1618 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1619 if ((list
= rp
->info
) != NULL
1620 && (rinfo
= listgetdata(listhead(list
))) != NULL
1621 && rinfo
->suppress
== 0) {
1622 /* If no route-map are applied, the RTE will be these
1626 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1627 rinfo
->metric_out
= rinfo
->metric
;
1628 rinfo
->tag_out
= rinfo
->tag
;
1629 memset(&rinfo
->nexthop_out
, 0,
1630 sizeof(rinfo
->nexthop_out
));
1631 /* In order to avoid some local loops,
1632 * if the RIPng route has a nexthop via this interface,
1634 * otherwise set it to 0. The nexthop should not be
1636 * beyond the local broadcast/multicast area in order
1637 * to avoid an IGP multi-level recursive look-up.
1639 if (rinfo
->ifindex
== ifp
->ifindex
)
1640 rinfo
->nexthop_out
= rinfo
->nexthop
;
1642 /* Apply output filters. */
1643 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1647 /* Changed route only output. */
1648 if (route_type
== ripng_changed_route
1649 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1652 /* Split horizon. */
1653 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1654 /* We perform split horizon for RIPng routes. */
1656 struct ripng_info
*tmp_rinfo
= NULL
;
1658 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1660 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1661 && tmp_rinfo
->ifindex
1670 /* Preparation for route-map. */
1671 rinfo
->metric_set
= 0;
1674 * and tag_out are already initialized.
1677 /* Interface route-map */
1678 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1679 ret
= route_map_apply(
1680 ri
->routemap
[RIPNG_FILTER_OUT
],
1681 (struct prefix
*)p
, rinfo
);
1683 if (ret
== RMAP_DENYMATCH
) {
1684 if (IS_RIPNG_DEBUG_PACKET
)
1686 "RIPng %pFX is filtered by route-map out",
1692 /* Redistribute route-map. */
1693 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1694 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1699 if (ret
== RMAP_DENYMATCH
) {
1700 if (IS_RIPNG_DEBUG_PACKET
)
1702 "RIPng %pFX is filtered by route-map",
1708 /* When the route-map does not set metric. */
1709 if (!rinfo
->metric_set
) {
1710 /* If the redistribute metric is set. */
1711 if (ripng
->redist
[rinfo
->type
].metric_config
1712 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1714 ripng
->redist
[rinfo
->type
]
1717 /* If the route is not connected or
1719 one, use default-metric value */
1720 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1722 != ZEBRA_ROUTE_CONNECT
1724 != RIPNG_METRIC_INFINITY
)
1726 ripng
->default_metric
;
1730 /* Apply offset-list */
1731 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1732 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1733 &rinfo
->metric_out
);
1735 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1736 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1738 /* Perform split-horizon with poisoned reverse
1741 if (ri
->split_horizon
1742 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1743 struct ripng_info
*tmp_rinfo
= NULL
;
1745 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1747 if ((tmp_rinfo
->type
1748 == ZEBRA_ROUTE_RIPNG
)
1749 && tmp_rinfo
->ifindex
1752 RIPNG_METRIC_INFINITY
;
1755 /* Add RTE to the list */
1756 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1759 /* Process the aggregated RTE entry */
1760 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1761 && aggregate
->suppress
== 0) {
1762 /* If no route-map are applied, the RTE will be these
1766 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1767 aggregate
->metric_set
= 0;
1768 aggregate
->metric_out
= aggregate
->metric
;
1769 aggregate
->tag_out
= aggregate
->tag
;
1770 memset(&aggregate
->nexthop_out
, 0,
1771 sizeof(aggregate
->nexthop_out
));
1773 /* Apply output filters.*/
1774 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1778 /* Interface route-map */
1779 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1780 struct ripng_info newinfo
;
1782 /* let's cast the aggregate structure to
1784 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1785 /* the nexthop is :: */
1786 newinfo
.metric
= aggregate
->metric
;
1787 newinfo
.metric_out
= aggregate
->metric_out
;
1788 newinfo
.tag
= aggregate
->tag
;
1789 newinfo
.tag_out
= aggregate
->tag_out
;
1791 ret
= route_map_apply(
1792 ri
->routemap
[RIPNG_FILTER_OUT
],
1793 (struct prefix
*)p
, &newinfo
);
1795 if (ret
== RMAP_DENYMATCH
) {
1796 if (IS_RIPNG_DEBUG_PACKET
)
1798 "RIPng %pFX is filtered by route-map out",
1803 aggregate
->metric_out
= newinfo
.metric_out
;
1804 aggregate
->tag_out
= newinfo
.tag_out
;
1805 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1806 aggregate
->nexthop_out
=
1807 newinfo
.nexthop_out
;
1810 /* There is no redistribute routemap for the aggregated
1813 /* Changed route only output. */
1814 /* XXX, vincent, in order to increase time convergence,
1815 * it should be announced if a child has changed.
1817 if (route_type
== ripng_changed_route
)
1820 /* Apply offset-list */
1821 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1822 ripng_offset_list_apply_out(
1823 ripng
, p
, ifp
, &aggregate
->metric_out
);
1825 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1826 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1828 /* Add RTE to the list */
1829 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1833 /* Flush the list */
1834 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1835 ripng_rte_free(ripng_rte_list
);
1838 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1842 vrf
= vrf_lookup_by_id(vrf_id
);
1849 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1853 ripng
.vrf_name
= (char *)vrf_name
;
1855 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1858 /* Create new RIPng instance and set it to global variable. */
1859 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1861 struct ripng
*ripng
;
1863 /* Allocaste RIPng instance. */
1864 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1865 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1867 /* Default version and timer values. */
1868 ripng
->version
= RIPNG_V1
;
1869 ripng
->update_time
= yang_get_default_uint32(
1870 "%s/timers/update-interval", RIPNG_INSTANCE
);
1871 ripng
->timeout_time
= yang_get_default_uint32(
1872 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1873 ripng
->garbage_time
= yang_get_default_uint32(
1874 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1875 ripng
->default_metric
=
1876 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1877 ripng
->ecmp
= yang_get_default_uint8("%s/allow-ecmp", RIPNG_INSTANCE
);
1880 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1881 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1883 /* Initialize RIPng data structures. */
1884 ripng
->table
= agg_table_init();
1885 agg_set_table_info(ripng
->table
, ripng
);
1886 ripng
->peer_list
= list_new();
1887 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1888 ripng
->peer_list
->del
= ripng_peer_list_del
;
1889 ripng
->enable_if
= vector_init(1);
1890 ripng
->enable_network
= agg_table_init();
1891 ripng
->passive_interface
= vector_init(1);
1892 ripng
->offset_list_master
= list_new();
1893 ripng
->offset_list_master
->cmp
=
1894 (int (*)(void *, void *))offset_list_cmp
;
1895 ripng
->offset_list_master
->del
=
1896 (void (*)(void *))ripng_offset_list_free
;
1897 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1898 distribute_list_add_hook(ripng
->distribute_ctx
,
1899 ripng_distribute_update
);
1900 distribute_list_delete_hook(ripng
->distribute_ctx
,
1901 ripng_distribute_update
);
1903 /* if rmap install. */
1904 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1905 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1906 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1908 /* Enable the routing instance if possible. */
1909 if (vrf
&& vrf_is_enabled(vrf
))
1910 ripng_instance_enable(ripng
, vrf
, socket
);
1916 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1921 /* Send RIPng request to the interface. */
1922 int ripng_request(struct interface
*ifp
)
1925 struct ripng_packet ripng_packet
;
1927 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1929 if (if_is_loopback(ifp
))
1932 /* If interface is down, don't send RIP packet. */
1936 if (IS_RIPNG_DEBUG_EVENT
)
1937 zlog_debug("RIPng send request to %s", ifp
->name
);
1939 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1940 ripng_packet
.command
= RIPNG_REQUEST
;
1941 ripng_packet
.version
= RIPNG_V1
;
1942 rte
= ripng_packet
.rte
;
1943 rte
->metric
= RIPNG_METRIC_INFINITY
;
1945 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1950 static int ripng_update_jitter(int time
)
1952 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1955 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1961 event_add_read(master
, ripng_read
, ripng
, sock
, &ripng
->t_read
);
1963 case RIPNG_UPDATE_EVENT
:
1964 EVENT_OFF(ripng
->t_update
);
1966 /* Update timer jitter. */
1967 jitter
= ripng_update_jitter(ripng
->update_time
);
1969 event_add_timer(master
, ripng_update
, ripng
,
1970 sock
? 2 : ripng
->update_time
+ jitter
,
1973 case RIPNG_TRIGGERED_UPDATE
:
1974 if (ripng
->t_triggered_interval
)
1977 event_add_event(master
, ripng_triggered_update
, ripng
,
1978 0, &ripng
->t_triggered_update
);
1981 case RIPNG_REQUEST_EVENT
:
1987 /* Print out routes update time. */
1988 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1993 char timebuf
[TIME_BUF
];
1994 struct event
*thread
;
1996 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1997 clock
= event_timer_remain_second(thread
);
1998 gmtime_r(&clock
, &tm
);
1999 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
2000 vty_out(vty
, "%5s", timebuf
);
2001 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
2002 clock
= event_timer_remain_second(thread
);
2003 gmtime_r(&clock
, &tm
);
2004 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
2005 vty_out(vty
, "%5s", timebuf
);
2009 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
2014 if (rinfo
->suppress
)
2015 strlcat(str
, "S", sizeof(str
));
2017 switch (rinfo
->sub_type
) {
2018 case RIPNG_ROUTE_RTE
:
2019 strlcat(str
, "n", sizeof(str
));
2021 case RIPNG_ROUTE_STATIC
:
2022 strlcat(str
, "s", sizeof(str
));
2024 case RIPNG_ROUTE_DEFAULT
:
2025 strlcat(str
, "d", sizeof(str
));
2027 case RIPNG_ROUTE_REDISTRIBUTE
:
2028 strlcat(str
, "r", sizeof(str
));
2030 case RIPNG_ROUTE_INTERFACE
:
2031 strlcat(str
, "i", sizeof(str
));
2034 strlcat(str
, "?", sizeof(str
));
2041 DEFUN (show_ipv6_ripng
,
2042 show_ipv6_ripng_cmd
,
2043 "show ipv6 ripng [vrf NAME]",
2046 "Show RIPng routes\n"
2049 struct ripng
*ripng
;
2050 struct agg_node
*rp
;
2051 struct ripng_info
*rinfo
;
2052 struct ripng_aggregate
*aggregate
;
2053 struct list
*list
= NULL
;
2054 struct listnode
*listnode
= NULL
;
2056 const char *vrf_name
;
2059 if (argv_find(argv
, argc
, "vrf", &idx
))
2060 vrf_name
= argv
[idx
+ 1]->arg
;
2062 vrf_name
= VRF_DEFAULT_NAME
;
2064 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2066 vty_out(vty
, "%% RIPng instance not found\n");
2069 if (!ripng
->enabled
) {
2070 vty_out(vty
, "%% RIPng instance is disabled\n");
2074 /* Header of display. */
2076 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2078 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2079 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2080 " Network Next Hop Via Metric Tag Time\n");
2082 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2083 if ((aggregate
= rp
->aggregate
) != NULL
) {
2085 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2086 aggregate
->suppress
, rp
);
2088 vty_out(vty
, "R(a) %pRN ", rp
);
2091 vty_out(vty
, "%*s", 18, " ");
2093 vty_out(vty
, "%*s", 28, " ");
2094 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2095 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2098 if ((list
= rp
->info
) != NULL
)
2099 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2101 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2102 zebra_route_char(rinfo
->type
),
2103 ripng_route_subtype_print(rinfo
),
2104 rinfo
->suppress
, rp
);
2106 vty_out(vty
, "%c(%s) %pRN ",
2107 zebra_route_char(rinfo
->type
),
2108 ripng_route_subtype_print(rinfo
), rp
);
2111 vty_out(vty
, "%*s", 18, " ");
2112 len
= vty_out(vty
, "%pI6",
2117 vty_out(vty
, "%*s", len
, " ");
2120 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2121 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2126 ripng
->vrf
->vrf_id
));
2127 } else if (rinfo
->metric
2128 == RIPNG_METRIC_INFINITY
) {
2129 len
= vty_out(vty
, "kill");
2131 len
= vty_out(vty
, "self");
2135 vty_out(vty
, "%*s", len
, " ");
2137 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2138 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2141 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2142 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2143 /* RTE from remote RIP routers */
2144 ripng_vty_out_uptime(vty
, rinfo
);
2145 } else if (rinfo
->metric
2146 == RIPNG_METRIC_INFINITY
) {
2147 /* poisonous reversed routes (gc) */
2148 ripng_vty_out_uptime(vty
, rinfo
);
2158 DEFUN (show_ipv6_ripng_status
,
2159 show_ipv6_ripng_status_cmd
,
2160 "show ipv6 ripng [vrf NAME] status",
2163 "Show RIPng routes\n"
2165 "IPv6 routing protocol process parameters and statistics\n")
2167 struct ripng
*ripng
;
2168 struct interface
*ifp
;
2169 const char *vrf_name
;
2172 if (argv_find(argv
, argc
, "vrf", &idx
))
2173 vrf_name
= argv
[idx
+ 1]->arg
;
2175 vrf_name
= VRF_DEFAULT_NAME
;
2177 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2179 vty_out(vty
, "%% RIPng instance not found\n");
2182 if (!ripng
->enabled
) {
2183 vty_out(vty
, "%% RIPng instance is disabled\n");
2187 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2188 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2189 ripng
->update_time
);
2190 vty_out(vty
, " next due in %lu seconds\n",
2191 event_timer_remain_second(ripng
->t_update
));
2192 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2193 vty_out(vty
, " garbage collect after %u seconds\n",
2194 ripng
->garbage_time
);
2196 /* Filtering status show. */
2197 config_show_distribute(vty
, ripng
->distribute_ctx
);
2199 /* Default metric information. */
2200 vty_out(vty
, " Default redistribution metric is %d\n",
2201 ripng
->default_metric
);
2203 /* Redistribute information. */
2204 vty_out(vty
, " Redistributing:");
2205 ripng_redistribute_write(vty
, ripng
);
2208 vty_out(vty
, " Default version control: send version %d,",
2210 vty_out(vty
, " receive version %d \n", ripng
->version
);
2212 vty_out(vty
, " Interface Send Recv\n");
2214 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2215 struct ripng_interface
*ri
;
2219 if (ri
->enable_network
|| ri
->enable_interface
) {
2221 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2222 ripng
->version
, ripng
->version
);
2226 vty_out(vty
, " Routing for Networks:\n");
2227 ripng_network_write(vty
, ripng
);
2229 vty_out(vty
, " Routing Information Sources:\n");
2231 " Gateway BadPackets BadRoutes Distance Last Update\n");
2232 ripng_peer_display(vty
, ripng
);
2237 /* Update ECMP routes to zebra when ECMP is disabled. */
2238 void ripng_ecmp_disable(struct ripng
*ripng
)
2240 struct agg_node
*rp
;
2241 struct ripng_info
*rinfo
, *tmp_rinfo
;
2243 struct listnode
*node
, *nextnode
;
2248 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2249 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2250 rinfo
= listgetdata(listhead(list
));
2251 if (!ripng_route_rte(rinfo
))
2254 /* Drop all other entries, except the first one. */
2255 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2256 if (tmp_rinfo
!= rinfo
) {
2257 EVENT_OFF(tmp_rinfo
->t_timeout
);
2258 EVENT_OFF(tmp_rinfo
->t_garbage_collect
);
2259 list_delete_node(list
, node
);
2260 ripng_info_free(tmp_rinfo
);
2264 ripng_zebra_ipv6_add(ripng
, rp
);
2266 /* Set the route change flag. */
2267 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2269 /* Signal the output process to trigger an update. */
2270 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2274 /* RIPng configuration write function. */
2275 static int ripng_config_write(struct vty
*vty
)
2277 struct ripng
*ripng
;
2280 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2281 char xpath
[XPATH_MAXLEN
];
2282 struct lyd_node
*dnode
;
2284 snprintf(xpath
, sizeof(xpath
),
2285 "/frr-ripngd:ripngd/instance[vrf='%s']",
2288 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2291 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2293 config_write_distribute(vty
, ripng
->distribute_ctx
);
2295 vty_out(vty
, "exit\n");
2303 static int ripng_config_write(struct vty
*vty
);
2304 /* RIPng node structure. */
2305 static struct cmd_node cmd_ripng_node
= {
2308 .parent_node
= CONFIG_NODE
,
2309 .prompt
= "%s(config-router)# ",
2310 .config_write
= ripng_config_write
,
2313 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2314 struct distribute
*dist
)
2316 struct interface
*ifp
;
2317 struct ripng_interface
*ri
;
2318 struct access_list
*alist
;
2319 struct prefix_list
*plist
;
2321 if (!ctx
->vrf
|| !dist
->ifname
)
2324 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2330 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2331 alist
= access_list_lookup(AFI_IP6
,
2332 dist
->list
[DISTRIBUTE_V6_IN
]);
2334 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2336 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2338 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2340 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2341 alist
= access_list_lookup(AFI_IP6
,
2342 dist
->list
[DISTRIBUTE_V6_OUT
]);
2344 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2346 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2348 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2350 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2351 plist
= prefix_list_lookup(AFI_IP6
,
2352 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2354 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2356 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2358 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2360 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2361 plist
= prefix_list_lookup(AFI_IP6
,
2362 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2364 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2366 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2368 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2371 void ripng_distribute_update_interface(struct interface
*ifp
)
2373 struct ripng_interface
*ri
= ifp
->info
;
2374 struct ripng
*ripng
= ri
->ripng
;
2375 struct distribute
*dist
;
2379 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2381 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2384 /* Update all interface's distribute list. */
2385 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2387 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2388 struct interface
*ifp
;
2390 FOR_ALL_INTERFACES (vrf
, ifp
)
2391 ripng_distribute_update_interface(ifp
);
2394 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2396 ripng_distribute_update_all(NULL
);
2399 /* delete all the added ripng routes. */
2400 void ripng_clean(struct ripng
*ripng
)
2402 ripng_interface_clean(ripng
);
2405 ripng_instance_disable(ripng
);
2407 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2408 if (ripng
->redist
[i
].route_map
.name
)
2409 free(ripng
->redist
[i
].route_map
.name
);
2411 agg_table_finish(ripng
->table
);
2412 list_delete(&ripng
->peer_list
);
2413 distribute_list_delete(&ripng
->distribute_ctx
);
2414 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2416 stream_free(ripng
->ibuf
);
2417 stream_free(ripng
->obuf
);
2419 ripng_clean_network(ripng
);
2420 ripng_passive_interface_clean(ripng
);
2421 vector_free(ripng
->enable_if
);
2422 agg_table_finish(ripng
->enable_network
);
2423 vector_free(ripng
->passive_interface
);
2424 list_delete(&ripng
->offset_list_master
);
2426 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2427 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2428 XFREE(MTYPE_RIPNG
, ripng
);
2431 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2432 struct if_rmap
*if_rmap
)
2434 struct interface
*ifp
= NULL
;
2435 struct ripng_interface
*ri
;
2436 struct route_map
*rmap
;
2437 struct vrf
*vrf
= NULL
;
2440 vrf
= vrf_lookup_by_name(ctx
->name
);
2442 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2448 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2449 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2451 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2453 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2455 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2457 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2458 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2460 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2462 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2464 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2467 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2469 struct ripng_interface
*ri
= ifp
->info
;
2470 struct ripng
*ripng
= ri
->ripng
;
2471 struct if_rmap
*if_rmap
;
2472 struct if_rmap_ctx
*ctx
;
2476 ctx
= ripng
->if_rmap_ctx
;
2479 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2481 ripng_if_rmap_update(ctx
, if_rmap
);
2484 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2486 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2487 if (ripng
->redist
[i
].route_map
.name
) {
2488 ripng
->redist
[i
].route_map
.map
=
2489 route_map_lookup_by_name(
2490 ripng
->redist
[i
].route_map
.name
);
2491 route_map_counter_increment(
2492 ripng
->redist
[i
].route_map
.map
);
2497 static void ripng_routemap_update(const char *unused
)
2499 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2500 struct ripng
*ripng
;
2501 struct interface
*ifp
;
2503 FOR_ALL_INTERFACES (vrf
, ifp
)
2504 ripng_if_rmap_update_interface(ifp
);
2508 ripng_routemap_update_redistribute(ripng
);
2511 /* Link RIPng instance to VRF. */
2512 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2514 struct interface
*ifp
;
2517 ripng
->distribute_ctx
->vrf
= vrf
;
2520 FOR_ALL_INTERFACES (vrf
, ifp
)
2521 ripng_interface_sync(ifp
);
2524 /* Unlink RIPng instance from VRF. */
2525 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2527 struct interface
*ifp
;
2530 ripng
->distribute_ctx
->vrf
= NULL
;
2533 FOR_ALL_INTERFACES (vrf
, ifp
)
2534 ripng_interface_sync(ifp
);
2537 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2542 ripng_vrf_link(ripng
, vrf
);
2543 ripng
->enabled
= true;
2545 /* Resend all redistribute requests. */
2546 ripng_redistribute_enable(ripng
);
2548 /* Create read and timer thread. */
2549 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2550 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2552 ripng_zebra_vrf_register(vrf
);
2555 static void ripng_instance_disable(struct ripng
*ripng
)
2557 struct vrf
*vrf
= ripng
->vrf
;
2558 struct agg_node
*rp
;
2560 /* Clear RIPng routes */
2561 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2562 struct ripng_aggregate
*aggregate
;
2565 if ((list
= rp
->info
) != NULL
) {
2566 struct ripng_info
*rinfo
;
2567 struct listnode
*listnode
;
2569 rinfo
= listgetdata(listhead(list
));
2570 if (ripng_route_rte(rinfo
))
2571 ripng_zebra_ipv6_delete(ripng
, rp
);
2573 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2574 EVENT_OFF(rinfo
->t_timeout
);
2575 EVENT_OFF(rinfo
->t_garbage_collect
);
2576 ripng_info_free(rinfo
);
2580 agg_unlock_node(rp
);
2583 if ((aggregate
= rp
->aggregate
) != NULL
) {
2584 ripng_aggregate_free(aggregate
);
2585 rp
->aggregate
= NULL
;
2586 agg_unlock_node(rp
);
2590 /* Flush all redistribute requests. */
2591 ripng_redistribute_disable(ripng
);
2593 /* Cancel the RIPng timers */
2594 EVENT_OFF(ripng
->t_update
);
2595 EVENT_OFF(ripng
->t_triggered_update
);
2596 EVENT_OFF(ripng
->t_triggered_interval
);
2598 /* Cancel the read thread */
2599 EVENT_OFF(ripng
->t_read
);
2601 /* Close the RIPng socket */
2602 if (ripng
->sock
>= 0) {
2607 /* Clear existing peers. */
2608 list_delete_all_node(ripng
->peer_list
);
2610 ripng_zebra_vrf_deregister(vrf
);
2612 ripng_vrf_unlink(ripng
, vrf
);
2613 ripng
->enabled
= false;
2616 static int ripng_vrf_new(struct vrf
*vrf
)
2618 if (IS_RIPNG_DEBUG_EVENT
)
2619 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2625 static int ripng_vrf_delete(struct vrf
*vrf
)
2627 struct ripng
*ripng
;
2629 if (IS_RIPNG_DEBUG_EVENT
)
2630 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2633 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2641 static int ripng_vrf_enable(struct vrf
*vrf
)
2643 struct ripng
*ripng
;
2646 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2647 if (!ripng
|| ripng
->enabled
)
2650 if (IS_RIPNG_DEBUG_EVENT
)
2651 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2654 /* Activate the VRF RIPng instance. */
2655 socket
= ripng_make_socket(vrf
);
2659 ripng_instance_enable(ripng
, vrf
, socket
);
2664 static int ripng_vrf_disable(struct vrf
*vrf
)
2666 struct ripng
*ripng
;
2668 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2669 if (!ripng
|| !ripng
->enabled
)
2672 if (IS_RIPNG_DEBUG_EVENT
)
2673 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2676 /* Deactivate the VRF RIPng instance. */
2678 ripng_instance_disable(ripng
);
2683 void ripng_vrf_init(void)
2685 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2691 void ripng_vrf_terminate(void)
2696 /* Initialize ripng structure and set commands. */
2697 void ripng_init(void)
2699 /* Install RIPNG_NODE. */
2700 install_node(&cmd_ripng_node
);
2702 /* Install ripng commands. */
2703 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2704 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2706 install_default(RIPNG_NODE
);
2711 /* Access list install. */
2713 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2714 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2716 /* Prefix list initialize.*/
2718 prefix_list_add_hook(ripng_distribute_update_all
);
2719 prefix_list_delete_hook(ripng_distribute_update_all
);
2721 /* Route-map for interface. */
2722 ripng_route_map_init();
2724 route_map_add_hook(ripng_routemap_update
);
2725 route_map_delete_hook(ripng_routemap_update
);
2727 if_rmap_init(RIPNG_NODE
);