2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "agg_table.h"
33 #include "distribute.h"
38 #include "lib_errors.h"
39 #include "northbound_cli.h"
42 #include "ripngd/ripngd.h"
43 #include "ripngd/ripng_route.h"
44 #include "ripngd/ripng_debug.h"
45 #include "ripngd/ripng_nexthop.h"
47 DEFINE_MGROUP(RIPNGD
, "ripngd");
48 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG
, "RIPng structure");
49 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_VRF_NAME
, "RIPng VRF name");
50 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_ROUTE
, "RIPng route info");
52 enum { ripng_all_route
,
56 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
57 struct distribute
*dist
);
60 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
61 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
63 static void ripng_instance_disable(struct ripng
*ripng
);
64 static void ripng_triggered_update(struct thread
*);
65 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
66 struct if_rmap
*if_rmap
);
68 /* Generate rb-tree of RIPng instances. */
69 static inline int ripng_instance_compare(const struct ripng
*a
,
70 const struct ripng
*b
)
72 return strcmp(a
->vrf_name
, b
->vrf_name
);
74 RB_GENERATE(ripng_instance_head
, ripng
, entry
, ripng_instance_compare
)
76 struct ripng_instance_head ripng_instances
= RB_INITIALIZER(&ripng_instances
);
78 /* RIPng next hop specification. */
79 struct ripng_nexthop
{
80 enum ripng_nexthop_type
{
84 struct in6_addr address
;
87 int ripng_route_rte(struct ripng_info
*rinfo
)
89 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
90 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
93 /* Allocate new ripng information. */
94 struct ripng_info
*ripng_info_new(void)
96 struct ripng_info
*new;
98 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
102 /* Free ripng information. */
103 void ripng_info_free(struct ripng_info
*rinfo
)
105 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
108 struct ripng
*ripng_info_get_instance(const struct ripng_info
*rinfo
)
110 return agg_get_table_info(agg_get_table(rinfo
->rp
));
113 /* Create ripng socket. */
114 int ripng_make_socket(struct vrf
*vrf
)
118 struct sockaddr_in6 ripaddr
;
119 const char *vrf_dev
= NULL
;
121 /* Make datagram socket. */
122 if (vrf
->vrf_id
!= VRF_DEFAULT
)
124 frr_with_privs(&ripngd_privs
) {
125 sock
= vrf_socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
,
126 vrf
->vrf_id
, vrf_dev
);
128 flog_err_sys(EC_LIB_SOCKET
,
129 "Cannot create UDP socket: %s",
130 safe_strerror(errno
));
135 sockopt_reuseaddr(sock
);
136 sockopt_reuseport(sock
);
137 setsockopt_so_recvbuf(sock
, 8096);
138 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
141 #ifdef IPTOS_PREC_INTERNETCONTROL
142 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
146 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
149 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
152 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
156 memset(&ripaddr
, 0, sizeof(ripaddr
));
157 ripaddr
.sin6_family
= AF_INET6
;
159 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
160 #endif /* SIN6_LEN */
161 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
163 frr_with_privs(&ripngd_privs
) {
164 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
166 zlog_err("Can't bind ripng socket: %s.",
167 safe_strerror(errno
));
178 /* Send RIPng packet. */
179 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
180 struct interface
*ifp
)
182 struct ripng_interface
*ri
= ifp
->info
;
183 struct ripng
*ripng
= ri
->ripng
;
187 struct cmsghdr
*cmsgptr
;
188 char adata
[256] = {};
189 struct in6_pktinfo
*pkt
;
190 struct sockaddr_in6 addr
;
192 if (IS_RIPNG_DEBUG_SEND
) {
194 zlog_debug("send to %pI6", &to
->sin6_addr
);
195 zlog_debug(" send interface %s", ifp
->name
);
196 zlog_debug(" send packet size %d", bufsize
);
199 memset(&addr
, 0, sizeof(addr
));
200 addr
.sin6_family
= AF_INET6
;
202 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
203 #endif /* SIN6_LEN */
204 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
206 /* When destination is specified. */
208 addr
.sin6_addr
= to
->sin6_addr
;
209 addr
.sin6_port
= to
->sin6_port
;
211 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
212 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
215 memset(&msg
, 0, sizeof(msg
));
216 msg
.msg_name
= (void *)&addr
;
217 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
220 msg
.msg_control
= adata
;
221 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
224 iov
.iov_len
= bufsize
;
226 cmsgptr
= (struct cmsghdr
*)adata
;
227 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
228 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
229 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
231 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
232 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
233 pkt
->ipi6_ifindex
= ifp
->ifindex
;
235 ret
= sendmsg(ripng
->sock
, &msg
, 0);
239 flog_err_sys(EC_LIB_SOCKET
,
240 "RIPng send fail on %s to %pI6: %s",
241 ifp
->name
, &to
->sin6_addr
,
242 safe_strerror(errno
));
244 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
245 ifp
->name
, safe_strerror(errno
));
251 /* Receive UDP RIPng packet from socket. */
252 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
253 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
259 struct cmsghdr
*cmsgptr
;
260 struct in6_addr dst
= {.s6_addr
= {0}};
262 memset(&dst
, 0, sizeof(dst
));
264 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
265 point I can't determine size of cmsghdr */
268 /* Fill in message and iovec. */
269 memset(&msg
, 0, sizeof(msg
));
270 msg
.msg_name
= (void *)from
;
271 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
274 msg
.msg_control
= (void *)adata
;
275 msg
.msg_controllen
= sizeof(adata
);
277 iov
.iov_len
= bufsize
;
279 /* If recvmsg fail return minus value. */
280 ret
= recvmsg(sock
, &msg
, 0);
284 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
285 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
286 /* I want interface index which this packet comes from. */
287 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
288 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
289 struct in6_pktinfo
*ptr
;
291 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
292 *ifindex
= ptr
->ipi6_ifindex
;
293 dst
= ptr
->ipi6_addr
;
297 "Interface index returned by IPV6_PKTINFO is zero");
300 /* Incoming packet's multicast hop limit. */
301 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
302 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
303 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
304 *hoplimit
= *phoplimit
;
308 /* Hoplimit check shold be done when destination address is
309 multicast address. */
310 if (!IN6_IS_ADDR_MULTICAST(&dst
))
316 /* Dump rip packet */
317 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
322 const char *command_str
;
324 /* Set command string. */
325 if (packet
->command
== RIPNG_REQUEST
)
326 command_str
= "request";
327 else if (packet
->command
== RIPNG_RESPONSE
)
328 command_str
= "response";
330 command_str
= "unknown";
332 /* Dump packet header. */
333 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
334 packet
->version
, size
);
336 /* Dump each routing table entry. */
339 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
340 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
341 zlog_debug(" nexthop %pI6/%d", &rte
->addr
,
344 zlog_debug(" %pI6/%d metric %d tag %" ROUTE_TAG_PRI
,
345 &rte
->addr
, rte
->prefixlen
,
346 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
350 /* RIPng next hop address RTE (Route Table Entry). */
351 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
352 struct ripng_nexthop
*nexthop
)
354 /* Logging before checking RTE. */
355 if (IS_RIPNG_DEBUG_RECV
)
356 zlog_debug("RIPng nexthop RTE address %pI6 tag %" ROUTE_TAG_PRI
358 &rte
->addr
, (route_tag_t
)ntohs(rte
->tag
),
361 /* RFC2080 2.1.1 Next Hop:
362 The route tag and prefix length in the next hop RTE must be
363 set to zero on sending and ignored on receiption. */
364 if (ntohs(rte
->tag
) != 0)
366 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
368 (route_tag_t
)ntohs(rte
->tag
), &from
->sin6_addr
);
370 if (rte
->prefixlen
!= 0)
372 "RIPng nexthop RTE with non zero prefixlen value %d from %pI6",
373 rte
->prefixlen
, &from
->sin6_addr
);
375 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
376 next hop RTE indicates that the next hop address should be the
377 originator of the RIPng advertisement. An address specified as a
378 next hop must be a link-local address. */
379 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
380 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
381 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
385 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
386 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
387 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
391 /* The purpose of the next hop RTE is to eliminate packets being
392 routed through extra hops in the system. It is particularly useful
393 when RIPng is not being run on all of the routers on a network.
394 Note that next hop RTE is "advisory". That is, if the provided
395 information is ignored, a possibly sub-optimal, but absolutely
396 valid, route may be taken. If the received next hop address is not
397 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
398 zlog_warn("RIPng nexthop RTE with non link-local address %pI6 from %pI6",
399 &rte
->addr
, &from
->sin6_addr
);
401 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
402 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
407 /* If ifp has same link-local address then return 1. */
408 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
410 struct listnode
*node
;
411 struct connected
*connected
;
414 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
415 p
= connected
->address
;
417 if (p
->family
== AF_INET6
418 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
419 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
425 /* RIPng route garbage collect timer. */
426 static void ripng_garbage_collect(struct thread
*t
)
428 struct ripng_info
*rinfo
;
431 rinfo
= THREAD_ARG(t
);
433 /* Off timeout timer. */
434 THREAD_OFF(rinfo
->t_timeout
);
436 /* Get route_node pointer. */
439 /* Unlock route_node. */
440 listnode_delete(rp
->info
, rinfo
);
441 if (list_isempty((struct list
*)rp
->info
)) {
442 list_delete((struct list
**)&rp
->info
);
446 /* Free RIPng routing information. */
447 ripng_info_free(rinfo
);
450 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
452 /* Add new route to the ECMP list.
453 * RETURN: the new entry added in the list, or NULL if it is not the first
454 * entry and ECMP is not allowed.
456 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
457 struct ripng_info
*rinfo_new
)
459 struct agg_node
*rp
= rinfo_new
->rp
;
460 struct ripng_info
*rinfo
= NULL
;
461 struct list
*list
= NULL
;
463 if (rp
->info
== NULL
)
464 rp
->info
= list_new();
465 list
= (struct list
*)rp
->info
;
467 /* If ECMP is not allowed and some entry already exists in the list,
469 if (listcount(list
) && !ripng
->ecmp
)
472 rinfo
= ripng_info_new();
473 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
474 listnode_add(list
, rinfo
);
476 if (ripng_route_rte(rinfo
)) {
477 ripng_timeout_update(ripng
, rinfo
);
478 ripng_zebra_ipv6_add(ripng
, rp
);
481 ripng_aggregate_increment(rp
, rinfo
);
483 /* Set the route change flag on the first entry. */
484 rinfo
= listgetdata(listhead(list
));
485 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
487 /* Signal the output process to trigger an update. */
488 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
493 /* Replace the ECMP list with the new route.
494 * RETURN: the new entry added in the list
496 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
497 struct ripng_info
*rinfo_new
)
499 struct agg_node
*rp
= rinfo_new
->rp
;
500 struct list
*list
= (struct list
*)rp
->info
;
501 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
502 struct listnode
*node
= NULL
, *nextnode
= NULL
;
504 if (list
== NULL
|| listcount(list
) == 0)
505 return ripng_ecmp_add(ripng
, rinfo_new
);
507 /* Get the first entry */
508 rinfo
= listgetdata(listhead(list
));
510 /* Learnt route replaced by a local one. Delete it from zebra. */
511 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
512 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
513 ripng_zebra_ipv6_delete(ripng
, rp
);
515 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
516 ripng_aggregate_decrement_list(rp
, list
);
518 /* Re-use the first entry, and delete the others. */
519 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
520 if (tmp_rinfo
!= rinfo
) {
521 THREAD_OFF(tmp_rinfo
->t_timeout
);
522 THREAD_OFF(tmp_rinfo
->t_garbage_collect
);
523 list_delete_node(list
, node
);
524 ripng_info_free(tmp_rinfo
);
527 THREAD_OFF(rinfo
->t_timeout
);
528 THREAD_OFF(rinfo
->t_garbage_collect
);
529 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
531 if (ripng_route_rte(rinfo
)) {
532 ripng_timeout_update(ripng
, rinfo
);
533 /* The ADD message implies an update. */
534 ripng_zebra_ipv6_add(ripng
, rp
);
537 ripng_aggregate_increment(rp
, rinfo
);
539 /* Set the route change flag. */
540 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
542 /* Signal the output process to trigger an update. */
543 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
548 /* Delete one route from the ECMP list.
550 * null - the entry is freed, and other entries exist in the list
551 * the entry - the entry is the last one in the list; its metric is set
552 * to INFINITY, and the garbage collector is started for it
554 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
555 struct ripng_info
*rinfo
)
557 struct agg_node
*rp
= rinfo
->rp
;
558 struct list
*list
= (struct list
*)rp
->info
;
560 THREAD_OFF(rinfo
->t_timeout
);
562 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
563 ripng_aggregate_decrement(rp
, rinfo
);
565 if (listcount(list
) > 1) {
566 /* Some other ECMP entries still exist. Just delete this entry.
568 THREAD_OFF(rinfo
->t_garbage_collect
);
569 listnode_delete(list
, rinfo
);
570 if (ripng_route_rte(rinfo
)
571 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
572 /* The ADD message implies the update. */
573 ripng_zebra_ipv6_add(ripng
, rp
);
574 ripng_info_free(rinfo
);
577 assert(rinfo
== listgetdata(listhead(list
)));
579 /* This is the only entry left in the list. We must keep it in
580 * the list for garbage collection time, with INFINITY metric.
583 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
584 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
585 ripng
->garbage_time
);
587 if (ripng_route_rte(rinfo
)
588 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
589 ripng_zebra_ipv6_delete(ripng
, rp
);
592 /* Set the route change flag on the first entry. */
593 rinfo
= listgetdata(listhead(list
));
594 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
596 /* Signal the output process to trigger an update. */
597 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
602 /* Timeout RIPng routes. */
603 static void ripng_timeout(struct thread
*t
)
605 struct ripng_info
*rinfo
= THREAD_ARG(t
);
606 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
608 ripng_ecmp_delete(ripng
, rinfo
);
611 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
613 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
614 THREAD_OFF(rinfo
->t_timeout
);
615 thread_add_timer(master
, ripng_timeout
, rinfo
,
616 ripng
->timeout_time
, &rinfo
->t_timeout
);
620 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
621 struct ripng_interface
*ri
)
623 struct distribute
*dist
;
624 struct access_list
*alist
;
625 struct prefix_list
*plist
;
626 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
629 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
631 /* Input distribute-list filtering. */
632 if (ri
->list
[ripng_distribute
]) {
633 if (access_list_apply(ri
->list
[ripng_distribute
],
636 if (IS_RIPNG_DEBUG_PACKET
)
637 zlog_debug("%pFX filtered by distribute %s", p
,
642 if (ri
->prefix
[ripng_distribute
]) {
643 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
646 if (IS_RIPNG_DEBUG_PACKET
)
647 zlog_debug("%pFX filtered by prefix-list %s", p
,
653 /* All interface filter check. */
654 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
656 if (dist
->list
[distribute
]) {
657 alist
= access_list_lookup(AFI_IP6
,
658 dist
->list
[distribute
]);
661 if (access_list_apply(alist
, (struct prefix
*)p
)
663 if (IS_RIPNG_DEBUG_PACKET
)
665 "%pFX filtered by distribute %s",
671 if (dist
->prefix
[distribute
]) {
672 plist
= prefix_list_lookup(AFI_IP6
,
673 dist
->prefix
[distribute
]);
676 if (prefix_list_apply(plist
, (struct prefix
*)p
)
678 if (IS_RIPNG_DEBUG_PACKET
)
680 "%pFX filtered by prefix-list %s",
690 /* Process RIPng route according to RFC2080. */
691 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
692 struct ripng_nexthop
*ripng_nexthop
,
693 struct interface
*ifp
)
696 struct prefix_ipv6 p
;
698 struct ripng_info
*rinfo
= NULL
, newinfo
;
699 struct ripng_interface
*ri
;
701 struct in6_addr
*nexthop
;
703 struct list
*list
= NULL
;
704 struct listnode
*node
= NULL
;
706 /* Make prefix structure. */
707 memset(&p
, 0, sizeof(struct prefix_ipv6
));
709 /* p.prefix = rte->addr; */
710 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
711 p
.prefixlen
= rte
->prefixlen
;
713 /* Make sure mask is applied. */
714 /* XXX We have to check the prefix is valid or not before call
721 /* Apply input filters. */
722 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
726 memset(&newinfo
, 0, sizeof(newinfo
));
727 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
728 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
729 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
730 newinfo
.nexthop
= ripng_nexthop
->address
;
732 newinfo
.nexthop
= from
->sin6_addr
;
733 newinfo
.from
= from
->sin6_addr
;
734 newinfo
.ifindex
= ifp
->ifindex
;
735 newinfo
.metric
= rte
->metric
;
736 newinfo
.metric_out
= rte
->metric
; /* XXX */
737 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
740 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
741 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
742 (struct prefix
*)&p
, &newinfo
);
744 if (ret
== RMAP_DENYMATCH
) {
745 if (IS_RIPNG_DEBUG_PACKET
)
747 "RIPng %pFX is filtered by route-map in",
752 /* Get back the object */
753 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
754 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
755 &ripng_nexthop
->address
)) {
756 /* the nexthop get changed by the routemap */
757 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
758 ripng_nexthop
->address
=
761 ripng_nexthop
->address
= in6addr_any
;
764 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
766 /* the nexthop get changed by the routemap */
767 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
768 ripng_nexthop
->flag
=
769 RIPNG_NEXTHOP_ADDRESS
;
770 ripng_nexthop
->address
=
775 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
777 newinfo
.metric_out
; /* XXX: the routemap uses the
781 /* Once the entry has been validated, update the metric by
782 * adding the cost of the network on wich the message
783 * arrived. If the result is greater than infinity, use infinity
784 * (RFC2453 Sec. 3.9.2)
787 /* Zebra ripngd can handle offset-list in. */
788 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
790 /* If offset-list does not modify the metric use interface's
793 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
795 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
796 rte
->metric
= RIPNG_METRIC_INFINITY
;
798 /* Set nexthop pointer. */
799 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
800 nexthop
= &ripng_nexthop
->address
;
802 nexthop
= &from
->sin6_addr
;
804 /* Lookup RIPng routing table. */
805 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
808 newinfo
.nexthop
= *nexthop
;
809 newinfo
.metric
= rte
->metric
;
810 newinfo
.tag
= ntohs(rte
->tag
);
812 /* Check to see whether there is already RIPng route on the table. */
813 if ((list
= rp
->info
) != NULL
)
814 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
815 /* Need to compare with redistributed entry or local
817 if (!ripng_route_rte(rinfo
))
820 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
821 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
824 if (!listnextnode(node
)) {
825 /* Not found in the list */
827 if (rte
->metric
> rinfo
->metric
) {
828 /* New route has a greater metric.
834 if (rte
->metric
< rinfo
->metric
)
835 /* New route has a smaller metric.
836 * Replace the ECMP list
837 * with the new one in below. */
840 /* Metrics are same. Unless ECMP is disabled,
841 * keep "rinfo" null and
842 * the new route is added in the ECMP list in
850 /* Redistributed route check. */
851 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
852 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
857 /* Local static route. */
858 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
859 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
860 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
861 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
868 /* Now, check to see whether there is already an explicit route
869 for the destination prefix. If there is no such route, add
870 this route to the routing table, unless the metric is
871 infinity (there is no point in adding a route which
873 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
874 ripng_ecmp_add(ripng
, &newinfo
);
878 /* If there is an existing route, compare the next hop address
879 to the address of the router from which the datagram came.
880 If this datagram is from the same router as the existing
881 route, reinitialize the timeout. */
882 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
883 && (rinfo
->ifindex
== ifp
->ifindex
));
886 * RFC 2080 - Section 2.4.2:
887 * "If the new metric is the same as the old one, examine the
889 * for the existing route. If it is at least halfway to the
891 * point, switch to the new route. This heuristic is optional,
893 * highly recommended".
895 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
897 && (thread_timer_remain_second(rinfo
->t_timeout
)
898 < (ripng
->timeout_time
/ 2))) {
899 ripng_ecmp_replace(ripng
, &newinfo
);
901 /* Next, compare the metrics. If the datagram is from the same
902 router as the existing route, and the new metric is different
903 than the old one; or, if the new metric is lower than the old
904 one; do the following actions: */
905 else if ((same
&& rinfo
->metric
!= rte
->metric
)
906 || rte
->metric
< rinfo
->metric
) {
907 if (listcount(list
) == 1) {
908 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
909 ripng_ecmp_replace(ripng
, &newinfo
);
911 ripng_ecmp_delete(ripng
, rinfo
);
913 if (newinfo
.metric
< rinfo
->metric
)
914 ripng_ecmp_replace(ripng
, &newinfo
);
915 else /* newinfo.metric > rinfo->metric */
916 ripng_ecmp_delete(ripng
, rinfo
);
918 } else /* same & no change */
919 ripng_timeout_update(ripng
, rinfo
);
921 /* Unlock tempolary lock of the route. */
926 /* Add redistributed route to RIPng table. */
927 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
928 struct prefix_ipv6
*p
, ifindex_t ifindex
,
929 struct in6_addr
*nexthop
, route_tag_t tag
)
932 struct ripng_info
*rinfo
= NULL
, newinfo
;
933 struct list
*list
= NULL
;
935 /* Redistribute route */
936 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
938 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
941 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
943 memset(&newinfo
, 0, sizeof(newinfo
));
945 newinfo
.sub_type
= sub_type
;
946 newinfo
.ifindex
= ifindex
;
948 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
951 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
952 newinfo
.nexthop
= *nexthop
;
954 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
955 rinfo
= listgetdata(listhead(list
));
957 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
958 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
959 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
964 /* Manually configured RIPng route check.
965 * They have the precedence on all the other entries.
967 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
968 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
969 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
970 if (type
!= ZEBRA_ROUTE_RIPNG
971 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
972 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
978 ripng_ecmp_replace(ripng
, &newinfo
);
981 ripng_ecmp_add(ripng
, &newinfo
);
983 if (IS_RIPNG_DEBUG_EVENT
) {
986 "Redistribute new prefix %pFX on the interface %s",
987 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
990 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
992 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
995 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
998 /* Delete redistributed route to RIPng table. */
999 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1000 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1002 struct agg_node
*rp
;
1003 struct ripng_info
*rinfo
;
1005 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1007 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1010 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1013 struct list
*list
= rp
->info
;
1015 if (list
!= NULL
&& listcount(list
) != 0) {
1016 rinfo
= listgetdata(listhead(list
));
1017 if (rinfo
!= NULL
&& rinfo
->type
== type
1018 && rinfo
->sub_type
== sub_type
1019 && rinfo
->ifindex
== ifindex
) {
1020 /* Perform poisoned reverse. */
1021 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1022 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1023 ripng_garbage_collect
,
1024 ripng
->garbage_time
);
1025 THREAD_OFF(rinfo
->t_timeout
);
1027 /* Aggregate count decrement. */
1028 ripng_aggregate_decrement(rp
, rinfo
);
1030 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1032 if (IS_RIPNG_DEBUG_EVENT
)
1034 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1038 ripng
->vrf
->vrf_id
));
1040 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1043 agg_unlock_node(rp
);
1047 /* Withdraw redistributed route. */
1048 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1050 struct agg_node
*rp
;
1051 struct ripng_info
*rinfo
= NULL
;
1052 struct list
*list
= NULL
;
1054 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1055 if ((list
= rp
->info
) != NULL
) {
1056 rinfo
= listgetdata(listhead(list
));
1057 if ((rinfo
->type
== type
)
1058 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1059 /* Perform poisoned reverse. */
1060 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1061 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1062 ripng_garbage_collect
,
1063 ripng
->garbage_time
);
1064 THREAD_OFF(rinfo
->t_timeout
);
1066 /* Aggregate count decrement. */
1067 ripng_aggregate_decrement(rp
, rinfo
);
1069 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1071 if (IS_RIPNG_DEBUG_EVENT
) {
1072 struct prefix_ipv6
*p
=
1073 (struct prefix_ipv6
*)
1074 agg_node_get_prefix(rp
);
1077 "Poisone %pFX on the interface %s [withdraw]",
1081 ripng
->vrf
->vrf_id
));
1084 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1089 /* RIP routing information. */
1090 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1091 struct sockaddr_in6
*from
,
1092 struct interface
*ifp
, int hoplimit
)
1094 struct ripng_interface
*ri
= ifp
->info
;
1095 struct ripng
*ripng
= ri
->ripng
;
1098 struct ripng_nexthop nexthop
;
1100 /* RFC2080 2.4.2 Response Messages:
1101 The Response must be ignored if it is not from the RIPng port. */
1102 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1103 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
1104 ntohs(from
->sin6_port
), &from
->sin6_addr
);
1105 ripng_peer_bad_packet(ripng
, from
);
1109 /* The datagram's IPv6 source address should be checked to see
1110 whether the datagram is from a valid neighbor; the source of the
1111 datagram must be a link-local address. */
1112 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1113 zlog_warn("RIPng packet comes from non link local address %pI6",
1115 ripng_peer_bad_packet(ripng
, from
);
1119 /* It is also worth checking to see whether the response is from one
1120 of the router's own addresses. Interfaces on broadcast networks
1121 may receive copies of their own multicasts immediately. If a
1122 router processes its own output as new input, confusion is likely,
1123 and such datagrams must be ignored. */
1124 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1126 "RIPng packet comes from my own link local address %pI6",
1128 ripng_peer_bad_packet(ripng
, from
);
1132 /* As an additional check, periodic advertisements must have their
1133 hop counts set to 255, and inbound, multicast packets sent from the
1134 RIPng port (i.e. periodic advertisement or triggered update
1135 packets) must be examined to ensure that the hop count is 255. */
1136 if (hoplimit
>= 0 && hoplimit
!= 255) {
1138 "RIPng packet comes with non 255 hop count %d from %pI6",
1139 hoplimit
, &from
->sin6_addr
);
1140 ripng_peer_bad_packet(ripng
, from
);
1144 /* Update RIPng peer. */
1145 ripng_peer_update(ripng
, from
, packet
->version
);
1147 /* Reset nexthop. */
1148 memset(&nexthop
, 0, sizeof(nexthop
));
1149 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1151 /* Set RTE pointer. */
1154 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1155 /* First of all, we have to check this RTE is next hop RTE or
1156 not. Next hop RTE is completely different with normal RTE so
1157 we need special treatment. */
1158 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1159 ripng_nexthop_rte(rte
, from
, &nexthop
);
1163 /* RTE information validation. */
1165 /* - is the destination prefix valid (e.g., not a multicast
1166 prefix and not a link-local address) A link-local address
1167 should never be present in an RTE. */
1168 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1170 "Destination prefix is a multicast address %pI6/%d [%d]",
1171 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1172 ripng_peer_bad_route(ripng
, from
);
1175 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1177 "Destination prefix is a link-local address %pI6/%d [%d]",
1178 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1179 ripng_peer_bad_route(ripng
, from
);
1182 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1184 "Destination prefix is a loopback address %pI6/%d [%d]",
1185 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1186 ripng_peer_bad_route(ripng
, from
);
1190 /* - is the prefix length valid (i.e., between 0 and 128,
1192 if (rte
->prefixlen
> IPV6_MAX_BITLEN
) {
1193 zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
1194 &rte
->addr
, rte
->prefixlen
,
1195 &from
->sin6_addr
, ifp
->name
);
1196 ripng_peer_bad_route(ripng
, from
);
1200 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1201 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1202 zlog_warn("Invalid metric %d from %pI6%%%s",
1203 rte
->metric
, &from
->sin6_addr
, ifp
->name
);
1204 ripng_peer_bad_route(ripng
, from
);
1208 /* Vincent: XXX Should we compute the direclty reachable nexthop
1209 * for our RIPng network ?
1212 /* Routing table updates. */
1213 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1217 /* Response to request message. */
1218 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1219 struct sockaddr_in6
*from
,
1220 struct interface
*ifp
)
1222 struct ripng
*ripng
;
1225 struct prefix_ipv6 p
;
1226 struct agg_node
*rp
;
1227 struct ripng_info
*rinfo
;
1228 struct ripng_interface
*ri
;
1230 /* Does not reponse to the requests on the loopback interfaces */
1231 if (if_is_loopback(ifp
))
1234 /* Check RIPng process is enabled on this interface. */
1240 /* When passive interface is specified, suppress responses */
1244 /* RIPng peer update. */
1245 ripng_peer_update(ripng
, from
, packet
->version
);
1247 lim
= ((caddr_t
)packet
) + size
;
1250 /* The Request is processed entry by entry. If there are no
1251 entries, no response is given. */
1252 if (lim
== (caddr_t
)rte
)
1255 /* There is one special case. If there is exactly one entry in the
1256 request, and it has a destination prefix of zero, a prefix length
1257 of zero, and a metric of infinity (i.e., 16), then this is a
1258 request to send the entire routing table. In that case, a call
1259 is made to the output process to send the routing table to the
1260 requesting address/port. */
1261 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1262 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1263 /* All route with split horizon */
1264 ripng_output_process(ifp
, from
, ripng_all_route
);
1266 /* Except for this special case, processing is quite simple.
1267 Examine the list of RTEs in the Request one by one. For each
1268 entry, look up the destination in the router's routing
1269 database and, if there is a route, put that route's metric in
1270 the metric field of the RTE. If there is no explicit route
1271 to the specified destination, put infinity in the metric
1272 field. Once all the entries have been filled in, change the
1273 command from Request to Response and send the datagram back
1274 to the requestor. */
1275 memset(&p
, 0, sizeof(p
));
1276 p
.family
= AF_INET6
;
1278 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1279 p
.prefix
= rte
->addr
;
1280 p
.prefixlen
= rte
->prefixlen
;
1281 apply_mask_ipv6(&p
);
1283 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1286 rinfo
= listgetdata(
1287 listhead((struct list
*)rp
->info
));
1288 rte
->metric
= rinfo
->metric
;
1289 agg_unlock_node(rp
);
1291 rte
->metric
= RIPNG_METRIC_INFINITY
;
1293 packet
->command
= RIPNG_RESPONSE
;
1295 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1299 /* First entry point of reading RIPng packet. */
1300 static void ripng_read(struct thread
*thread
)
1302 struct ripng
*ripng
= THREAD_ARG(thread
);
1305 struct sockaddr_in6 from
;
1306 struct ripng_packet
*packet
;
1307 ifindex_t ifindex
= 0;
1308 struct interface
*ifp
;
1311 /* Check ripng is active and alive. */
1312 assert(ripng
!= NULL
);
1313 assert(ripng
->sock
>= 0);
1315 /* Fetch thread data and set read pointer to empty for event
1316 managing. `sock' sould be same as ripng->sock. */
1317 sock
= THREAD_FD(thread
);
1319 /* Add myself to the next event. */
1320 ripng_event(ripng
, RIPNG_READ
, sock
);
1322 /* Read RIPng packet. */
1323 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1324 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1327 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1328 ripng
->vrf_name
, safe_strerror(errno
));
1332 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1333 (4)) must be multiple size of one RTE size (20). */
1334 if (((len
- 4) % 20) != 0) {
1335 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
1336 len
, &from
.sin6_addr
, ripng
->vrf_name
);
1337 ripng_peer_bad_packet(ripng
, &from
);
1341 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1342 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1344 /* RIPng packet received. */
1345 if (IS_RIPNG_DEBUG_EVENT
)
1347 "RIPng packet received from %pI6 port %d on %s (VRF %s)",
1348 &from
.sin6_addr
, ntohs(from
.sin6_port
),
1349 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1351 /* Logging before packet checking. */
1352 if (IS_RIPNG_DEBUG_RECV
)
1353 ripng_packet_dump(packet
, len
, "RECV");
1355 /* Packet comes from unknown interface. */
1358 "RIPng packet comes from unknown interface %d (VRF %s)",
1359 ifindex
, ripng
->vrf_name
);
1363 /* Packet version mismatch checking. */
1364 if (packet
->version
!= ripng
->version
) {
1366 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1367 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1368 ripng_peer_bad_packet(ripng
, &from
);
1372 /* Process RIPng packet. */
1373 switch (packet
->command
) {
1375 ripng_request_process(packet
, len
, &from
, ifp
);
1377 case RIPNG_RESPONSE
:
1378 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1381 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1383 ripng_peer_bad_packet(ripng
, &from
);
1388 /* Walk down the RIPng routing table then clear changed flag. */
1389 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1391 struct agg_node
*rp
;
1392 struct ripng_info
*rinfo
= NULL
;
1393 struct list
*list
= NULL
;
1394 struct listnode
*listnode
= NULL
;
1396 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1397 if ((list
= rp
->info
) != NULL
)
1398 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1399 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1400 /* This flag can be set only on the first entry.
1406 /* Regular update of RIPng route. Send all routing formation to RIPng
1407 enabled interface. */
1408 static void ripng_update(struct thread
*t
)
1410 struct ripng
*ripng
= THREAD_ARG(t
);
1411 struct interface
*ifp
;
1412 struct ripng_interface
*ri
;
1414 /* Logging update event. */
1415 if (IS_RIPNG_DEBUG_EVENT
)
1416 zlog_debug("RIPng update timer expired!");
1418 /* Supply routes to each interface. */
1419 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1422 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1428 /* When passive interface is specified, suppress announce to the
1433 #ifdef RIPNG_ADVANCED
1434 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1435 if (IS_RIPNG_DEBUG_EVENT
)
1437 "[Event] RIPng send to if %d is suppressed by config",
1441 #endif /* RIPNG_ADVANCED */
1443 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1446 /* Triggered updates may be suppressed if a regular update is due by
1447 the time the triggered update would be sent. */
1448 THREAD_OFF(ripng
->t_triggered_interval
);
1451 /* Reset flush event. */
1452 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1455 /* Triggered update interval timer. */
1456 static void ripng_triggered_interval(struct thread
*t
)
1458 struct ripng
*ripng
= THREAD_ARG(t
);
1460 if (ripng
->trigger
) {
1462 ripng_triggered_update(t
);
1466 /* Execute triggered update. */
1467 void ripng_triggered_update(struct thread
*t
)
1469 struct ripng
*ripng
= THREAD_ARG(t
);
1470 struct interface
*ifp
;
1471 struct ripng_interface
*ri
;
1474 /* Cancel interval timer. */
1475 THREAD_OFF(ripng
->t_triggered_interval
);
1478 /* Logging triggered update. */
1479 if (IS_RIPNG_DEBUG_EVENT
)
1480 zlog_debug("RIPng triggered update!");
1482 /* Split Horizon processing is done when generating triggered
1483 updates as well as normal updates (see section 2.6). */
1484 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1487 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1493 /* When passive interface is specified, suppress announce to the
1498 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1501 /* Once all of the triggered updates have been generated, the route
1502 change flags should be cleared. */
1503 ripng_clear_changed_flag(ripng
);
1505 /* After a triggered update is sent, a timer should be set for a
1506 random interval between 1 and 5 seconds. If other changes that
1507 would trigger updates occur before the timer expires, a single
1508 update is triggered when the timer expires. */
1509 interval
= (frr_weak_random() % 5) + 1;
1511 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1512 &ripng
->t_triggered_interval
);
1515 /* Write routing table entry to the stream and return next index of
1516 the routing table entry in the stream. */
1517 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1518 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1520 /* RIPng packet header. */
1522 stream_putc(s
, RIPNG_RESPONSE
);
1523 stream_putc(s
, RIPNG_V1
);
1527 /* Write routing table entry. */
1530 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1532 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1533 stream_putw(s
, tag
);
1535 stream_putc(s
, p
->prefixlen
);
1538 stream_putc(s
, metric
);
1543 /* Send RESPONSE message to specified destination. */
1544 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1547 struct ripng
*ripng
;
1549 struct agg_node
*rp
;
1550 struct ripng_info
*rinfo
;
1551 struct ripng_interface
*ri
;
1552 struct ripng_aggregate
*aggregate
;
1553 struct prefix_ipv6
*p
;
1554 struct list
*ripng_rte_list
;
1555 struct list
*list
= NULL
;
1556 struct listnode
*listnode
= NULL
;
1558 if (IS_RIPNG_DEBUG_EVENT
) {
1560 zlog_debug("RIPng update routes to neighbor %pI6",
1563 zlog_debug("RIPng update routes on interface %s",
1567 /* Get RIPng interface and instance. */
1571 ripng_rte_list
= ripng_rte_new();
1573 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1574 if ((list
= rp
->info
) != NULL
1575 && (rinfo
= listgetdata(listhead(list
))) != NULL
1576 && rinfo
->suppress
== 0) {
1577 /* If no route-map are applied, the RTE will be these
1581 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1582 rinfo
->metric_out
= rinfo
->metric
;
1583 rinfo
->tag_out
= rinfo
->tag
;
1584 memset(&rinfo
->nexthop_out
, 0,
1585 sizeof(rinfo
->nexthop_out
));
1586 /* In order to avoid some local loops,
1587 * if the RIPng route has a nexthop via this interface,
1589 * otherwise set it to 0. The nexthop should not be
1591 * beyond the local broadcast/multicast area in order
1592 * to avoid an IGP multi-level recursive look-up.
1594 if (rinfo
->ifindex
== ifp
->ifindex
)
1595 rinfo
->nexthop_out
= rinfo
->nexthop
;
1597 /* Apply output filters. */
1598 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1602 /* Changed route only output. */
1603 if (route_type
== ripng_changed_route
1604 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1607 /* Split horizon. */
1608 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1609 /* We perform split horizon for RIPng routes. */
1611 struct ripng_info
*tmp_rinfo
= NULL
;
1613 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1615 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1616 && tmp_rinfo
->ifindex
1625 /* Preparation for route-map. */
1626 rinfo
->metric_set
= 0;
1629 * and tag_out are already initialized.
1632 /* Interface route-map */
1633 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1634 ret
= route_map_apply(
1635 ri
->routemap
[RIPNG_FILTER_OUT
],
1636 (struct prefix
*)p
, rinfo
);
1638 if (ret
== RMAP_DENYMATCH
) {
1639 if (IS_RIPNG_DEBUG_PACKET
)
1641 "RIPng %pFX is filtered by route-map out",
1647 /* Redistribute route-map. */
1648 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1649 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1654 if (ret
== RMAP_DENYMATCH
) {
1655 if (IS_RIPNG_DEBUG_PACKET
)
1657 "RIPng %pFX is filtered by route-map",
1663 /* When the route-map does not set metric. */
1664 if (!rinfo
->metric_set
) {
1665 /* If the redistribute metric is set. */
1666 if (ripng
->redist
[rinfo
->type
].metric_config
1667 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1669 ripng
->redist
[rinfo
->type
]
1672 /* If the route is not connected or
1674 one, use default-metric value */
1675 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1677 != ZEBRA_ROUTE_CONNECT
1679 != RIPNG_METRIC_INFINITY
)
1681 ripng
->default_metric
;
1685 /* Apply offset-list */
1686 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1687 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1688 &rinfo
->metric_out
);
1690 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1691 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1693 /* Perform split-horizon with poisoned reverse
1696 if (ri
->split_horizon
1697 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1698 struct ripng_info
*tmp_rinfo
= NULL
;
1700 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1702 if ((tmp_rinfo
->type
1703 == ZEBRA_ROUTE_RIPNG
)
1704 && tmp_rinfo
->ifindex
1707 RIPNG_METRIC_INFINITY
;
1710 /* Add RTE to the list */
1711 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1714 /* Process the aggregated RTE entry */
1715 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1716 && aggregate
->suppress
== 0) {
1717 /* If no route-map are applied, the RTE will be these
1721 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1722 aggregate
->metric_set
= 0;
1723 aggregate
->metric_out
= aggregate
->metric
;
1724 aggregate
->tag_out
= aggregate
->tag
;
1725 memset(&aggregate
->nexthop_out
, 0,
1726 sizeof(aggregate
->nexthop_out
));
1728 /* Apply output filters.*/
1729 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1733 /* Interface route-map */
1734 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1735 struct ripng_info newinfo
;
1737 /* let's cast the aggregate structure to
1739 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1740 /* the nexthop is :: */
1741 newinfo
.metric
= aggregate
->metric
;
1742 newinfo
.metric_out
= aggregate
->metric_out
;
1743 newinfo
.tag
= aggregate
->tag
;
1744 newinfo
.tag_out
= aggregate
->tag_out
;
1746 ret
= route_map_apply(
1747 ri
->routemap
[RIPNG_FILTER_OUT
],
1748 (struct prefix
*)p
, &newinfo
);
1750 if (ret
== RMAP_DENYMATCH
) {
1751 if (IS_RIPNG_DEBUG_PACKET
)
1753 "RIPng %pFX is filtered by route-map out",
1758 aggregate
->metric_out
= newinfo
.metric_out
;
1759 aggregate
->tag_out
= newinfo
.tag_out
;
1760 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1761 aggregate
->nexthop_out
=
1762 newinfo
.nexthop_out
;
1765 /* There is no redistribute routemap for the aggregated
1768 /* Changed route only output. */
1769 /* XXX, vincent, in order to increase time convergence,
1770 * it should be announced if a child has changed.
1772 if (route_type
== ripng_changed_route
)
1775 /* Apply offset-list */
1776 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1777 ripng_offset_list_apply_out(
1778 ripng
, p
, ifp
, &aggregate
->metric_out
);
1780 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1781 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1783 /* Add RTE to the list */
1784 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1788 /* Flush the list */
1789 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1790 ripng_rte_free(ripng_rte_list
);
1793 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1797 vrf
= vrf_lookup_by_id(vrf_id
);
1804 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1808 ripng
.vrf_name
= (char *)vrf_name
;
1810 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1813 /* Create new RIPng instance and set it to global variable. */
1814 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1816 struct ripng
*ripng
;
1818 /* Allocaste RIPng instance. */
1819 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1820 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1822 /* Default version and timer values. */
1823 ripng
->version
= RIPNG_V1
;
1824 ripng
->update_time
= yang_get_default_uint32(
1825 "%s/timers/update-interval", RIPNG_INSTANCE
);
1826 ripng
->timeout_time
= yang_get_default_uint32(
1827 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1828 ripng
->garbage_time
= yang_get_default_uint32(
1829 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1830 ripng
->default_metric
=
1831 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1832 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1835 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1836 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1838 /* Initialize RIPng data structures. */
1839 ripng
->table
= agg_table_init();
1840 agg_set_table_info(ripng
->table
, ripng
);
1841 ripng
->peer_list
= list_new();
1842 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1843 ripng
->peer_list
->del
= ripng_peer_list_del
;
1844 ripng
->enable_if
= vector_init(1);
1845 ripng
->enable_network
= agg_table_init();
1846 ripng
->passive_interface
= vector_init(1);
1847 ripng
->offset_list_master
= list_new();
1848 ripng
->offset_list_master
->cmp
=
1849 (int (*)(void *, void *))offset_list_cmp
;
1850 ripng
->offset_list_master
->del
=
1851 (void (*)(void *))ripng_offset_list_free
;
1852 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1853 distribute_list_add_hook(ripng
->distribute_ctx
,
1854 ripng_distribute_update
);
1855 distribute_list_delete_hook(ripng
->distribute_ctx
,
1856 ripng_distribute_update
);
1858 /* if rmap install. */
1859 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1860 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1861 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1863 /* Enable the routing instance if possible. */
1864 if (vrf
&& vrf_is_enabled(vrf
))
1865 ripng_instance_enable(ripng
, vrf
, socket
);
1871 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1876 /* Send RIPng request to the interface. */
1877 int ripng_request(struct interface
*ifp
)
1880 struct ripng_packet ripng_packet
;
1882 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1884 if (if_is_loopback(ifp
))
1887 /* If interface is down, don't send RIP packet. */
1891 if (IS_RIPNG_DEBUG_EVENT
)
1892 zlog_debug("RIPng send request to %s", ifp
->name
);
1894 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1895 ripng_packet
.command
= RIPNG_REQUEST
;
1896 ripng_packet
.version
= RIPNG_V1
;
1897 rte
= ripng_packet
.rte
;
1898 rte
->metric
= RIPNG_METRIC_INFINITY
;
1900 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1905 static int ripng_update_jitter(int time
)
1907 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1910 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1916 thread_add_read(master
, ripng_read
, ripng
, sock
,
1919 case RIPNG_UPDATE_EVENT
:
1920 THREAD_OFF(ripng
->t_update
);
1922 /* Update timer jitter. */
1923 jitter
= ripng_update_jitter(ripng
->update_time
);
1925 thread_add_timer(master
, ripng_update
, ripng
,
1926 sock
? 2 : ripng
->update_time
+ jitter
,
1929 case RIPNG_TRIGGERED_UPDATE
:
1930 if (ripng
->t_triggered_interval
)
1933 thread_add_event(master
, ripng_triggered_update
, ripng
,
1934 0, &ripng
->t_triggered_update
);
1937 case RIPNG_REQUEST_EVENT
:
1943 /* Print out routes update time. */
1944 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1949 char timebuf
[TIME_BUF
];
1950 struct thread
*thread
;
1952 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1953 clock
= thread_timer_remain_second(thread
);
1954 gmtime_r(&clock
, &tm
);
1955 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1956 vty_out(vty
, "%5s", timebuf
);
1957 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1958 clock
= thread_timer_remain_second(thread
);
1959 gmtime_r(&clock
, &tm
);
1960 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1961 vty_out(vty
, "%5s", timebuf
);
1965 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1970 if (rinfo
->suppress
)
1971 strlcat(str
, "S", sizeof(str
));
1973 switch (rinfo
->sub_type
) {
1974 case RIPNG_ROUTE_RTE
:
1975 strlcat(str
, "n", sizeof(str
));
1977 case RIPNG_ROUTE_STATIC
:
1978 strlcat(str
, "s", sizeof(str
));
1980 case RIPNG_ROUTE_DEFAULT
:
1981 strlcat(str
, "d", sizeof(str
));
1983 case RIPNG_ROUTE_REDISTRIBUTE
:
1984 strlcat(str
, "r", sizeof(str
));
1986 case RIPNG_ROUTE_INTERFACE
:
1987 strlcat(str
, "i", sizeof(str
));
1990 strlcat(str
, "?", sizeof(str
));
1997 DEFUN (show_ipv6_ripng
,
1998 show_ipv6_ripng_cmd
,
1999 "show ipv6 ripng [vrf NAME]",
2002 "Show RIPng routes\n"
2005 struct ripng
*ripng
;
2006 struct agg_node
*rp
;
2007 struct ripng_info
*rinfo
;
2008 struct ripng_aggregate
*aggregate
;
2009 struct list
*list
= NULL
;
2010 struct listnode
*listnode
= NULL
;
2012 const char *vrf_name
;
2015 if (argv_find(argv
, argc
, "vrf", &idx
))
2016 vrf_name
= argv
[idx
+ 1]->arg
;
2018 vrf_name
= VRF_DEFAULT_NAME
;
2020 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2022 vty_out(vty
, "%% RIPng instance not found\n");
2025 if (!ripng
->enabled
) {
2026 vty_out(vty
, "%% RIPng instance is disabled\n");
2030 /* Header of display. */
2032 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2034 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2035 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2036 " Network Next Hop Via Metric Tag Time\n");
2038 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2039 if ((aggregate
= rp
->aggregate
) != NULL
) {
2041 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2042 aggregate
->suppress
, rp
);
2044 vty_out(vty
, "R(a) %pRN ", rp
);
2047 vty_out(vty
, "%*s", 18, " ");
2049 vty_out(vty
, "%*s", 28, " ");
2050 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2051 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2054 if ((list
= rp
->info
) != NULL
)
2055 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2057 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2058 zebra_route_char(rinfo
->type
),
2059 ripng_route_subtype_print(rinfo
),
2060 rinfo
->suppress
, rp
);
2062 vty_out(vty
, "%c(%s) %pRN ",
2063 zebra_route_char(rinfo
->type
),
2064 ripng_route_subtype_print(rinfo
), rp
);
2067 vty_out(vty
, "%*s", 18, " ");
2068 len
= vty_out(vty
, "%pI6",
2073 vty_out(vty
, "%*s", len
, " ");
2076 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2077 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2082 ripng
->vrf
->vrf_id
));
2083 } else if (rinfo
->metric
2084 == RIPNG_METRIC_INFINITY
) {
2085 len
= vty_out(vty
, "kill");
2087 len
= vty_out(vty
, "self");
2091 vty_out(vty
, "%*s", len
, " ");
2093 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2094 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2097 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2098 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2099 /* RTE from remote RIP routers */
2100 ripng_vty_out_uptime(vty
, rinfo
);
2101 } else if (rinfo
->metric
2102 == RIPNG_METRIC_INFINITY
) {
2103 /* poisonous reversed routes (gc) */
2104 ripng_vty_out_uptime(vty
, rinfo
);
2114 DEFUN (show_ipv6_ripng_status
,
2115 show_ipv6_ripng_status_cmd
,
2116 "show ipv6 ripng [vrf NAME] status",
2119 "Show RIPng routes\n"
2121 "IPv6 routing protocol process parameters and statistics\n")
2123 struct ripng
*ripng
;
2124 struct interface
*ifp
;
2125 const char *vrf_name
;
2128 if (argv_find(argv
, argc
, "vrf", &idx
))
2129 vrf_name
= argv
[idx
+ 1]->arg
;
2131 vrf_name
= VRF_DEFAULT_NAME
;
2133 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2135 vty_out(vty
, "%% RIPng instance not found\n");
2138 if (!ripng
->enabled
) {
2139 vty_out(vty
, "%% RIPng instance is disabled\n");
2143 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2144 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2145 ripng
->update_time
);
2146 vty_out(vty
, " next due in %lu seconds\n",
2147 thread_timer_remain_second(ripng
->t_update
));
2148 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2149 vty_out(vty
, " garbage collect after %u seconds\n",
2150 ripng
->garbage_time
);
2152 /* Filtering status show. */
2153 config_show_distribute(vty
, ripng
->distribute_ctx
);
2155 /* Default metric information. */
2156 vty_out(vty
, " Default redistribution metric is %d\n",
2157 ripng
->default_metric
);
2159 /* Redistribute information. */
2160 vty_out(vty
, " Redistributing:");
2161 ripng_redistribute_write(vty
, ripng
);
2164 vty_out(vty
, " Default version control: send version %d,",
2166 vty_out(vty
, " receive version %d \n", ripng
->version
);
2168 vty_out(vty
, " Interface Send Recv\n");
2170 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2171 struct ripng_interface
*ri
;
2175 if (ri
->enable_network
|| ri
->enable_interface
) {
2177 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2178 ripng
->version
, ripng
->version
);
2182 vty_out(vty
, " Routing for Networks:\n");
2183 ripng_network_write(vty
, ripng
);
2185 vty_out(vty
, " Routing Information Sources:\n");
2187 " Gateway BadPackets BadRoutes Distance Last Update\n");
2188 ripng_peer_display(vty
, ripng
);
2193 /* Update ECMP routes to zebra when ECMP is disabled. */
2194 void ripng_ecmp_disable(struct ripng
*ripng
)
2196 struct agg_node
*rp
;
2197 struct ripng_info
*rinfo
, *tmp_rinfo
;
2199 struct listnode
*node
, *nextnode
;
2204 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2205 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2206 rinfo
= listgetdata(listhead(list
));
2207 if (!ripng_route_rte(rinfo
))
2210 /* Drop all other entries, except the first one. */
2211 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2212 if (tmp_rinfo
!= rinfo
) {
2213 THREAD_OFF(tmp_rinfo
->t_timeout
);
2215 tmp_rinfo
->t_garbage_collect
);
2216 list_delete_node(list
, node
);
2217 ripng_info_free(tmp_rinfo
);
2221 ripng_zebra_ipv6_add(ripng
, rp
);
2223 /* Set the route change flag. */
2224 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2226 /* Signal the output process to trigger an update. */
2227 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2231 /* RIPng configuration write function. */
2232 static int ripng_config_write(struct vty
*vty
)
2234 struct ripng
*ripng
;
2237 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2238 char xpath
[XPATH_MAXLEN
];
2239 struct lyd_node
*dnode
;
2241 snprintf(xpath
, sizeof(xpath
),
2242 "/frr-ripngd:ripngd/instance[vrf='%s']",
2245 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2248 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2250 config_write_distribute(vty
, ripng
->distribute_ctx
);
2251 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2253 vty_out(vty
, "exit\n");
2261 static int ripng_config_write(struct vty
*vty
);
2262 /* RIPng node structure. */
2263 static struct cmd_node cmd_ripng_node
= {
2266 .parent_node
= CONFIG_NODE
,
2267 .prompt
= "%s(config-router)# ",
2268 .config_write
= ripng_config_write
,
2271 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2272 struct distribute
*dist
)
2274 struct interface
*ifp
;
2275 struct ripng_interface
*ri
;
2276 struct access_list
*alist
;
2277 struct prefix_list
*plist
;
2279 if (!ctx
->vrf
|| !dist
->ifname
)
2282 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2288 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2289 alist
= access_list_lookup(AFI_IP6
,
2290 dist
->list
[DISTRIBUTE_V6_IN
]);
2292 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2294 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2296 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2298 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2299 alist
= access_list_lookup(AFI_IP6
,
2300 dist
->list
[DISTRIBUTE_V6_OUT
]);
2302 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2304 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2306 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2308 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2309 plist
= prefix_list_lookup(AFI_IP6
,
2310 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2312 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2314 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2316 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2318 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2319 plist
= prefix_list_lookup(AFI_IP6
,
2320 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2322 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2324 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2326 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2329 void ripng_distribute_update_interface(struct interface
*ifp
)
2331 struct ripng_interface
*ri
= ifp
->info
;
2332 struct ripng
*ripng
= ri
->ripng
;
2333 struct distribute
*dist
;
2337 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2339 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2342 /* Update all interface's distribute list. */
2343 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2345 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2346 struct interface
*ifp
;
2348 FOR_ALL_INTERFACES (vrf
, ifp
)
2349 ripng_distribute_update_interface(ifp
);
2352 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2354 ripng_distribute_update_all(NULL
);
2357 /* delete all the added ripng routes. */
2358 void ripng_clean(struct ripng
*ripng
)
2360 ripng_interface_clean(ripng
);
2363 ripng_instance_disable(ripng
);
2365 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2366 if (ripng
->redist
[i
].route_map
.name
)
2367 free(ripng
->redist
[i
].route_map
.name
);
2369 agg_table_finish(ripng
->table
);
2370 list_delete(&ripng
->peer_list
);
2371 distribute_list_delete(&ripng
->distribute_ctx
);
2372 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2374 stream_free(ripng
->ibuf
);
2375 stream_free(ripng
->obuf
);
2377 ripng_clean_network(ripng
);
2378 ripng_passive_interface_clean(ripng
);
2379 vector_free(ripng
->enable_if
);
2380 agg_table_finish(ripng
->enable_network
);
2381 vector_free(ripng
->passive_interface
);
2382 list_delete(&ripng
->offset_list_master
);
2384 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2385 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2386 XFREE(MTYPE_RIPNG
, ripng
);
2389 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2390 struct if_rmap
*if_rmap
)
2392 struct interface
*ifp
= NULL
;
2393 struct ripng_interface
*ri
;
2394 struct route_map
*rmap
;
2395 struct vrf
*vrf
= NULL
;
2398 vrf
= vrf_lookup_by_name(ctx
->name
);
2400 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2406 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2407 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2409 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2411 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2413 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2415 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2416 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2418 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2420 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2422 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2425 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2427 struct ripng_interface
*ri
= ifp
->info
;
2428 struct ripng
*ripng
= ri
->ripng
;
2429 struct if_rmap
*if_rmap
;
2430 struct if_rmap_ctx
*ctx
;
2434 ctx
= ripng
->if_rmap_ctx
;
2437 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2439 ripng_if_rmap_update(ctx
, if_rmap
);
2442 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2444 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2445 if (ripng
->redist
[i
].route_map
.name
) {
2446 ripng
->redist
[i
].route_map
.map
=
2447 route_map_lookup_by_name(
2448 ripng
->redist
[i
].route_map
.name
);
2449 route_map_counter_increment(
2450 ripng
->redist
[i
].route_map
.map
);
2455 static void ripng_routemap_update(const char *unused
)
2457 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2458 struct ripng
*ripng
;
2459 struct interface
*ifp
;
2461 FOR_ALL_INTERFACES (vrf
, ifp
)
2462 ripng_if_rmap_update_interface(ifp
);
2466 ripng_routemap_update_redistribute(ripng
);
2469 /* Link RIPng instance to VRF. */
2470 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2472 struct interface
*ifp
;
2475 ripng
->distribute_ctx
->vrf
= vrf
;
2478 FOR_ALL_INTERFACES (vrf
, ifp
)
2479 ripng_interface_sync(ifp
);
2482 /* Unlink RIPng instance from VRF. */
2483 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2485 struct interface
*ifp
;
2488 ripng
->distribute_ctx
->vrf
= NULL
;
2491 FOR_ALL_INTERFACES (vrf
, ifp
)
2492 ripng_interface_sync(ifp
);
2495 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2500 ripng_vrf_link(ripng
, vrf
);
2501 ripng
->enabled
= true;
2503 /* Resend all redistribute requests. */
2504 ripng_redistribute_enable(ripng
);
2506 /* Create read and timer thread. */
2507 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2508 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2510 ripng_zebra_vrf_register(vrf
);
2513 static void ripng_instance_disable(struct ripng
*ripng
)
2515 struct vrf
*vrf
= ripng
->vrf
;
2516 struct agg_node
*rp
;
2518 /* Clear RIPng routes */
2519 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2520 struct ripng_aggregate
*aggregate
;
2523 if ((list
= rp
->info
) != NULL
) {
2524 struct ripng_info
*rinfo
;
2525 struct listnode
*listnode
;
2527 rinfo
= listgetdata(listhead(list
));
2528 if (ripng_route_rte(rinfo
))
2529 ripng_zebra_ipv6_delete(ripng
, rp
);
2531 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2532 THREAD_OFF(rinfo
->t_timeout
);
2533 THREAD_OFF(rinfo
->t_garbage_collect
);
2534 ripng_info_free(rinfo
);
2538 agg_unlock_node(rp
);
2541 if ((aggregate
= rp
->aggregate
) != NULL
) {
2542 ripng_aggregate_free(aggregate
);
2543 rp
->aggregate
= NULL
;
2544 agg_unlock_node(rp
);
2548 /* Flush all redistribute requests. */
2549 ripng_redistribute_disable(ripng
);
2551 /* Cancel the RIPng timers */
2552 THREAD_OFF(ripng
->t_update
);
2553 THREAD_OFF(ripng
->t_triggered_update
);
2554 THREAD_OFF(ripng
->t_triggered_interval
);
2556 /* Cancel the read thread */
2557 THREAD_OFF(ripng
->t_read
);
2559 /* Close the RIPng socket */
2560 if (ripng
->sock
>= 0) {
2565 /* Clear existing peers. */
2566 list_delete_all_node(ripng
->peer_list
);
2568 ripng_zebra_vrf_deregister(vrf
);
2570 ripng_vrf_unlink(ripng
, vrf
);
2571 ripng
->enabled
= false;
2574 static int ripng_vrf_new(struct vrf
*vrf
)
2576 if (IS_RIPNG_DEBUG_EVENT
)
2577 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2583 static int ripng_vrf_delete(struct vrf
*vrf
)
2585 struct ripng
*ripng
;
2587 if (IS_RIPNG_DEBUG_EVENT
)
2588 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2591 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2599 static int ripng_vrf_enable(struct vrf
*vrf
)
2601 struct ripng
*ripng
;
2604 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2605 if (!ripng
|| ripng
->enabled
)
2608 if (IS_RIPNG_DEBUG_EVENT
)
2609 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2612 /* Activate the VRF RIPng instance. */
2613 socket
= ripng_make_socket(vrf
);
2617 ripng_instance_enable(ripng
, vrf
, socket
);
2622 static int ripng_vrf_disable(struct vrf
*vrf
)
2624 struct ripng
*ripng
;
2626 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2627 if (!ripng
|| !ripng
->enabled
)
2630 if (IS_RIPNG_DEBUG_EVENT
)
2631 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2634 /* Deactivate the VRF RIPng instance. */
2636 ripng_instance_disable(ripng
);
2641 void ripng_vrf_init(void)
2643 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2649 void ripng_vrf_terminate(void)
2654 /* Initialize ripng structure and set commands. */
2655 void ripng_init(void)
2657 /* Install RIPNG_NODE. */
2658 install_node(&cmd_ripng_node
);
2660 /* Install ripng commands. */
2661 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2662 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2664 install_default(RIPNG_NODE
);
2669 /* Access list install. */
2671 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2672 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2674 /* Prefix list initialize.*/
2676 prefix_list_add_hook(ripng_distribute_update_all
);
2677 prefix_list_delete_hook(ripng_distribute_update_all
);
2679 /* Route-map for interface. */
2680 ripng_route_map_init();
2682 route_map_add_hook(ripng_routemap_update
);
2683 route_map_delete_hook(ripng_routemap_update
);
2685 if_rmap_init(RIPNG_NODE
);