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 int 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(struct sockaddr_in6
));
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
= (void *)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(struct in6_addr
));
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 int ripng_garbage_collect(struct thread
*t
)
428 struct ripng_info
*rinfo
;
431 rinfo
= THREAD_ARG(t
);
432 rinfo
->t_garbage_collect
= NULL
;
434 /* Off timeout timer. */
435 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
437 /* Get route_node pointer. */
440 /* Unlock route_node. */
441 listnode_delete(rp
->info
, rinfo
);
442 if (list_isempty((struct list
*)rp
->info
)) {
443 list_delete((struct list
**)&rp
->info
);
447 /* Free RIPng routing information. */
448 ripng_info_free(rinfo
);
453 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
455 /* Add new route to the ECMP list.
456 * RETURN: the new entry added in the list, or NULL if it is not the first
457 * entry and ECMP is not allowed.
459 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
460 struct ripng_info
*rinfo_new
)
462 struct agg_node
*rp
= rinfo_new
->rp
;
463 struct ripng_info
*rinfo
= NULL
;
464 struct list
*list
= NULL
;
466 if (rp
->info
== NULL
)
467 rp
->info
= list_new();
468 list
= (struct list
*)rp
->info
;
470 /* If ECMP is not allowed and some entry already exists in the list,
472 if (listcount(list
) && !ripng
->ecmp
)
475 rinfo
= ripng_info_new();
476 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
477 listnode_add(list
, rinfo
);
479 if (ripng_route_rte(rinfo
)) {
480 ripng_timeout_update(ripng
, rinfo
);
481 ripng_zebra_ipv6_add(ripng
, rp
);
484 ripng_aggregate_increment(rp
, rinfo
);
486 /* Set the route change flag on the first entry. */
487 rinfo
= listgetdata(listhead(list
));
488 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
490 /* Signal the output process to trigger an update. */
491 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
496 /* Replace the ECMP list with the new route.
497 * RETURN: the new entry added in the list
499 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
500 struct ripng_info
*rinfo_new
)
502 struct agg_node
*rp
= rinfo_new
->rp
;
503 struct list
*list
= (struct list
*)rp
->info
;
504 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
505 struct listnode
*node
= NULL
, *nextnode
= NULL
;
507 if (list
== NULL
|| listcount(list
) == 0)
508 return ripng_ecmp_add(ripng
, rinfo_new
);
510 /* Get the first entry */
511 rinfo
= listgetdata(listhead(list
));
513 /* Learnt route replaced by a local one. Delete it from zebra. */
514 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
515 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
516 ripng_zebra_ipv6_delete(ripng
, rp
);
518 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
519 ripng_aggregate_decrement_list(rp
, list
);
521 /* Re-use the first entry, and delete the others. */
522 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
523 if (tmp_rinfo
!= rinfo
) {
524 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
525 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
526 list_delete_node(list
, node
);
527 ripng_info_free(tmp_rinfo
);
530 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
531 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
532 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
534 if (ripng_route_rte(rinfo
)) {
535 ripng_timeout_update(ripng
, rinfo
);
536 /* The ADD message implies an update. */
537 ripng_zebra_ipv6_add(ripng
, rp
);
540 ripng_aggregate_increment(rp
, rinfo
);
542 /* Set the route change flag. */
543 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
545 /* Signal the output process to trigger an update. */
546 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
551 /* Delete one route from the ECMP list.
553 * null - the entry is freed, and other entries exist in the list
554 * the entry - the entry is the last one in the list; its metric is set
555 * to INFINITY, and the garbage collector is started for it
557 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
558 struct ripng_info
*rinfo
)
560 struct agg_node
*rp
= rinfo
->rp
;
561 struct list
*list
= (struct list
*)rp
->info
;
563 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
565 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
566 ripng_aggregate_decrement(rp
, rinfo
);
568 if (listcount(list
) > 1) {
569 /* Some other ECMP entries still exist. Just delete this entry.
571 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
572 listnode_delete(list
, rinfo
);
573 if (ripng_route_rte(rinfo
)
574 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
575 /* The ADD message implies the update. */
576 ripng_zebra_ipv6_add(ripng
, rp
);
577 ripng_info_free(rinfo
);
580 assert(rinfo
== listgetdata(listhead(list
)));
582 /* This is the only entry left in the list. We must keep it in
583 * the list for garbage collection time, with INFINITY metric.
586 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
587 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
588 ripng
->garbage_time
);
590 if (ripng_route_rte(rinfo
)
591 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
592 ripng_zebra_ipv6_delete(ripng
, rp
);
595 /* Set the route change flag on the first entry. */
596 rinfo
= listgetdata(listhead(list
));
597 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
599 /* Signal the output process to trigger an update. */
600 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
605 /* Timeout RIPng routes. */
606 static int ripng_timeout(struct thread
*t
)
608 struct ripng_info
*rinfo
= THREAD_ARG(t
);
609 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
611 ripng_ecmp_delete(ripng
, rinfo
);
616 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
618 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
619 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
620 thread_add_timer(master
, ripng_timeout
, rinfo
,
621 ripng
->timeout_time
, &rinfo
->t_timeout
);
625 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
626 struct ripng_interface
*ri
)
628 struct distribute
*dist
;
629 struct access_list
*alist
;
630 struct prefix_list
*plist
;
631 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
634 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
636 /* Input distribute-list filtering. */
637 if (ri
->list
[ripng_distribute
]) {
638 if (access_list_apply(ri
->list
[ripng_distribute
],
641 if (IS_RIPNG_DEBUG_PACKET
)
642 zlog_debug("%pFX filtered by distribute %s", p
,
647 if (ri
->prefix
[ripng_distribute
]) {
648 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
651 if (IS_RIPNG_DEBUG_PACKET
)
652 zlog_debug("%pFX filtered by prefix-list %s", p
,
658 /* All interface filter check. */
659 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
661 if (dist
->list
[distribute
]) {
662 alist
= access_list_lookup(AFI_IP6
,
663 dist
->list
[distribute
]);
666 if (access_list_apply(alist
, (struct prefix
*)p
)
668 if (IS_RIPNG_DEBUG_PACKET
)
670 "%pFX filtered by distribute %s",
676 if (dist
->prefix
[distribute
]) {
677 plist
= prefix_list_lookup(AFI_IP6
,
678 dist
->prefix
[distribute
]);
681 if (prefix_list_apply(plist
, (struct prefix
*)p
)
683 if (IS_RIPNG_DEBUG_PACKET
)
685 "%pFX filtered by prefix-list %s",
695 /* Process RIPng route according to RFC2080. */
696 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
697 struct ripng_nexthop
*ripng_nexthop
,
698 struct interface
*ifp
)
701 struct prefix_ipv6 p
;
703 struct ripng_info
*rinfo
= NULL
, newinfo
;
704 struct ripng_interface
*ri
;
706 struct in6_addr
*nexthop
;
708 struct list
*list
= NULL
;
709 struct listnode
*node
= NULL
;
711 /* Make prefix structure. */
712 memset(&p
, 0, sizeof(struct prefix_ipv6
));
714 /* p.prefix = rte->addr; */
715 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
716 p
.prefixlen
= rte
->prefixlen
;
718 /* Make sure mask is applied. */
719 /* XXX We have to check the prefix is valid or not before call
726 /* Apply input filters. */
727 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
731 memset(&newinfo
, 0, sizeof(newinfo
));
732 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
733 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
734 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
735 newinfo
.nexthop
= ripng_nexthop
->address
;
737 newinfo
.nexthop
= from
->sin6_addr
;
738 newinfo
.from
= from
->sin6_addr
;
739 newinfo
.ifindex
= ifp
->ifindex
;
740 newinfo
.metric
= rte
->metric
;
741 newinfo
.metric_out
= rte
->metric
; /* XXX */
742 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
745 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
746 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
747 (struct prefix
*)&p
, &newinfo
);
749 if (ret
== RMAP_DENYMATCH
) {
750 if (IS_RIPNG_DEBUG_PACKET
)
752 "RIPng %pFX is filtered by route-map in",
757 /* Get back the object */
758 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
759 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
760 &ripng_nexthop
->address
)) {
761 /* the nexthop get changed by the routemap */
762 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
763 ripng_nexthop
->address
=
766 ripng_nexthop
->address
= in6addr_any
;
769 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
771 /* the nexthop get changed by the routemap */
772 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
773 ripng_nexthop
->flag
=
774 RIPNG_NEXTHOP_ADDRESS
;
775 ripng_nexthop
->address
=
780 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
782 newinfo
.metric_out
; /* XXX: the routemap uses the
786 /* Once the entry has been validated, update the metric by
787 * adding the cost of the network on wich the message
788 * arrived. If the result is greater than infinity, use infinity
789 * (RFC2453 Sec. 3.9.2)
792 /* Zebra ripngd can handle offset-list in. */
793 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
795 /* If offset-list does not modify the metric use interface's
798 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
800 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
801 rte
->metric
= RIPNG_METRIC_INFINITY
;
803 /* Set nexthop pointer. */
804 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
805 nexthop
= &ripng_nexthop
->address
;
807 nexthop
= &from
->sin6_addr
;
809 /* Lookup RIPng routing table. */
810 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
813 newinfo
.nexthop
= *nexthop
;
814 newinfo
.metric
= rte
->metric
;
815 newinfo
.tag
= ntohs(rte
->tag
);
817 /* Check to see whether there is already RIPng route on the table. */
818 if ((list
= rp
->info
) != NULL
)
819 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
820 /* Need to compare with redistributed entry or local
822 if (!ripng_route_rte(rinfo
))
825 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
826 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
829 if (!listnextnode(node
)) {
830 /* Not found in the list */
832 if (rte
->metric
> rinfo
->metric
) {
833 /* New route has a greater metric.
839 if (rte
->metric
< rinfo
->metric
)
840 /* New route has a smaller metric.
841 * Replace the ECMP list
842 * with the new one in below. */
845 /* Metrics are same. Unless ECMP is disabled,
846 * keep "rinfo" null and
847 * the new route is added in the ECMP list in
855 /* Redistributed route check. */
856 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
857 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
862 /* Local static route. */
863 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
864 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
865 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
866 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
873 /* Now, check to see whether there is already an explicit route
874 for the destination prefix. If there is no such route, add
875 this route to the routing table, unless the metric is
876 infinity (there is no point in adding a route which
878 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
879 ripng_ecmp_add(ripng
, &newinfo
);
883 /* If there is an existing route, compare the next hop address
884 to the address of the router from which the datagram came.
885 If this datagram is from the same router as the existing
886 route, reinitialize the timeout. */
887 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
888 && (rinfo
->ifindex
== ifp
->ifindex
));
891 * RFC 2080 - Section 2.4.2:
892 * "If the new metric is the same as the old one, examine the
894 * for the existing route. If it is at least halfway to the
896 * point, switch to the new route. This heuristic is optional,
898 * highly recommended".
900 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
902 && (thread_timer_remain_second(rinfo
->t_timeout
)
903 < (ripng
->timeout_time
/ 2))) {
904 ripng_ecmp_replace(ripng
, &newinfo
);
906 /* Next, compare the metrics. If the datagram is from the same
907 router as the existing route, and the new metric is different
908 than the old one; or, if the new metric is lower than the old
909 one; do the following actions: */
910 else if ((same
&& rinfo
->metric
!= rte
->metric
)
911 || rte
->metric
< rinfo
->metric
) {
912 if (listcount(list
) == 1) {
913 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
914 ripng_ecmp_replace(ripng
, &newinfo
);
916 ripng_ecmp_delete(ripng
, rinfo
);
918 if (newinfo
.metric
< rinfo
->metric
)
919 ripng_ecmp_replace(ripng
, &newinfo
);
920 else /* newinfo.metric > rinfo->metric */
921 ripng_ecmp_delete(ripng
, rinfo
);
923 } else /* same & no change */
924 ripng_timeout_update(ripng
, rinfo
);
926 /* Unlock tempolary lock of the route. */
931 /* Add redistributed route to RIPng table. */
932 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
933 struct prefix_ipv6
*p
, ifindex_t ifindex
,
934 struct in6_addr
*nexthop
, route_tag_t tag
)
937 struct ripng_info
*rinfo
= NULL
, newinfo
;
938 struct list
*list
= NULL
;
940 /* Redistribute route */
941 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
943 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
946 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
948 memset(&newinfo
, 0, sizeof(struct ripng_info
));
950 newinfo
.sub_type
= sub_type
;
951 newinfo
.ifindex
= ifindex
;
953 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
956 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
957 newinfo
.nexthop
= *nexthop
;
959 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
960 rinfo
= listgetdata(listhead(list
));
962 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
963 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
964 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
969 /* Manually configured RIPng route check.
970 * They have the precedence on all the other entries.
972 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
973 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
974 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
975 if (type
!= ZEBRA_ROUTE_RIPNG
976 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
977 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
983 ripng_ecmp_replace(ripng
, &newinfo
);
986 ripng_ecmp_add(ripng
, &newinfo
);
988 if (IS_RIPNG_DEBUG_EVENT
) {
991 "Redistribute new prefix %pFX on the interface %s",
992 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
995 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
997 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1000 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1003 /* Delete redistributed route to RIPng table. */
1004 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1005 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1007 struct agg_node
*rp
;
1008 struct ripng_info
*rinfo
;
1010 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1012 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1015 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1018 struct list
*list
= rp
->info
;
1020 if (list
!= NULL
&& listcount(list
) != 0) {
1021 rinfo
= listgetdata(listhead(list
));
1022 if (rinfo
!= NULL
&& rinfo
->type
== type
1023 && rinfo
->sub_type
== sub_type
1024 && rinfo
->ifindex
== ifindex
) {
1025 /* Perform poisoned reverse. */
1026 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1027 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1028 ripng_garbage_collect
,
1029 ripng
->garbage_time
);
1030 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1032 /* Aggregate count decrement. */
1033 ripng_aggregate_decrement(rp
, rinfo
);
1035 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1037 if (IS_RIPNG_DEBUG_EVENT
)
1039 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1043 ripng
->vrf
->vrf_id
));
1045 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1048 agg_unlock_node(rp
);
1052 /* Withdraw redistributed route. */
1053 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1055 struct agg_node
*rp
;
1056 struct ripng_info
*rinfo
= NULL
;
1057 struct list
*list
= NULL
;
1059 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1060 if ((list
= rp
->info
) != NULL
) {
1061 rinfo
= listgetdata(listhead(list
));
1062 if ((rinfo
->type
== type
)
1063 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1064 /* Perform poisoned reverse. */
1065 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1066 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1067 ripng_garbage_collect
,
1068 ripng
->garbage_time
);
1069 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1071 /* Aggregate count decrement. */
1072 ripng_aggregate_decrement(rp
, rinfo
);
1074 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1076 if (IS_RIPNG_DEBUG_EVENT
) {
1077 struct prefix_ipv6
*p
=
1078 (struct prefix_ipv6
*)
1079 agg_node_get_prefix(rp
);
1082 "Poisone %pFX on the interface %s [withdraw]",
1086 ripng
->vrf
->vrf_id
));
1089 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1094 /* RIP routing information. */
1095 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1096 struct sockaddr_in6
*from
,
1097 struct interface
*ifp
, int hoplimit
)
1099 struct ripng_interface
*ri
= ifp
->info
;
1100 struct ripng
*ripng
= ri
->ripng
;
1103 struct ripng_nexthop nexthop
;
1105 /* RFC2080 2.4.2 Response Messages:
1106 The Response must be ignored if it is not from the RIPng port. */
1107 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1108 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
1109 ntohs(from
->sin6_port
), &from
->sin6_addr
);
1110 ripng_peer_bad_packet(ripng
, from
);
1114 /* The datagram's IPv6 source address should be checked to see
1115 whether the datagram is from a valid neighbor; the source of the
1116 datagram must be a link-local address. */
1117 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1118 zlog_warn("RIPng packet comes from non link local address %pI6",
1120 ripng_peer_bad_packet(ripng
, from
);
1124 /* It is also worth checking to see whether the response is from one
1125 of the router's own addresses. Interfaces on broadcast networks
1126 may receive copies of their own multicasts immediately. If a
1127 router processes its own output as new input, confusion is likely,
1128 and such datagrams must be ignored. */
1129 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1131 "RIPng packet comes from my own link local address %pI6",
1133 ripng_peer_bad_packet(ripng
, from
);
1137 /* As an additional check, periodic advertisements must have their
1138 hop counts set to 255, and inbound, multicast packets sent from the
1139 RIPng port (i.e. periodic advertisement or triggered update
1140 packets) must be examined to ensure that the hop count is 255. */
1141 if (hoplimit
>= 0 && hoplimit
!= 255) {
1143 "RIPng packet comes with non 255 hop count %d from %pI6",
1144 hoplimit
, &from
->sin6_addr
);
1145 ripng_peer_bad_packet(ripng
, from
);
1149 /* Update RIPng peer. */
1150 ripng_peer_update(ripng
, from
, packet
->version
);
1152 /* Reset nexthop. */
1153 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1154 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1156 /* Set RTE pointer. */
1159 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1160 /* First of all, we have to check this RTE is next hop RTE or
1161 not. Next hop RTE is completely different with normal RTE so
1162 we need special treatment. */
1163 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1164 ripng_nexthop_rte(rte
, from
, &nexthop
);
1168 /* RTE information validation. */
1170 /* - is the destination prefix valid (e.g., not a multicast
1171 prefix and not a link-local address) A link-local address
1172 should never be present in an RTE. */
1173 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1175 "Destination prefix is a multicast address %pI6/%d [%d]",
1176 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1177 ripng_peer_bad_route(ripng
, from
);
1180 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1182 "Destination prefix is a link-local address %pI6/%d [%d]",
1183 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1184 ripng_peer_bad_route(ripng
, from
);
1187 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1189 "Destination prefix is a loopback address %pI6/%d [%d]",
1190 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1191 ripng_peer_bad_route(ripng
, from
);
1195 /* - is the prefix length valid (i.e., between 0 and 128,
1197 if (rte
->prefixlen
> 128) {
1198 zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
1199 &rte
->addr
, rte
->prefixlen
,
1200 &from
->sin6_addr
, ifp
->name
);
1201 ripng_peer_bad_route(ripng
, from
);
1205 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1206 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1207 zlog_warn("Invalid metric %d from %pI6%%%s",
1208 rte
->metric
, &from
->sin6_addr
, ifp
->name
);
1209 ripng_peer_bad_route(ripng
, from
);
1213 /* Vincent: XXX Should we compute the direclty reachable nexthop
1214 * for our RIPng network ?
1217 /* Routing table updates. */
1218 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1222 /* Response to request message. */
1223 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1224 struct sockaddr_in6
*from
,
1225 struct interface
*ifp
)
1227 struct ripng
*ripng
;
1230 struct prefix_ipv6 p
;
1231 struct agg_node
*rp
;
1232 struct ripng_info
*rinfo
;
1233 struct ripng_interface
*ri
;
1235 /* Does not reponse to the requests on the loopback interfaces */
1236 if (if_is_loopback(ifp
))
1239 /* Check RIPng process is enabled on this interface. */
1245 /* When passive interface is specified, suppress responses */
1249 /* RIPng peer update. */
1250 ripng_peer_update(ripng
, from
, packet
->version
);
1252 lim
= ((caddr_t
)packet
) + size
;
1255 /* The Request is processed entry by entry. If there are no
1256 entries, no response is given. */
1257 if (lim
== (caddr_t
)rte
)
1260 /* There is one special case. If there is exactly one entry in the
1261 request, and it has a destination prefix of zero, a prefix length
1262 of zero, and a metric of infinity (i.e., 16), then this is a
1263 request to send the entire routing table. In that case, a call
1264 is made to the output process to send the routing table to the
1265 requesting address/port. */
1266 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1267 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1268 /* All route with split horizon */
1269 ripng_output_process(ifp
, from
, ripng_all_route
);
1271 /* Except for this special case, processing is quite simple.
1272 Examine the list of RTEs in the Request one by one. For each
1273 entry, look up the destination in the router's routing
1274 database and, if there is a route, put that route's metric in
1275 the metric field of the RTE. If there is no explicit route
1276 to the specified destination, put infinity in the metric
1277 field. Once all the entries have been filled in, change the
1278 command from Request to Response and send the datagram back
1279 to the requestor. */
1280 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1281 p
.family
= AF_INET6
;
1283 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1284 p
.prefix
= rte
->addr
;
1285 p
.prefixlen
= rte
->prefixlen
;
1286 apply_mask_ipv6(&p
);
1288 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1291 rinfo
= listgetdata(
1292 listhead((struct list
*)rp
->info
));
1293 rte
->metric
= rinfo
->metric
;
1294 agg_unlock_node(rp
);
1296 rte
->metric
= RIPNG_METRIC_INFINITY
;
1298 packet
->command
= RIPNG_RESPONSE
;
1300 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1304 /* First entry point of reading RIPng packet. */
1305 static int ripng_read(struct thread
*thread
)
1307 struct ripng
*ripng
= THREAD_ARG(thread
);
1310 struct sockaddr_in6 from
;
1311 struct ripng_packet
*packet
;
1312 ifindex_t ifindex
= 0;
1313 struct interface
*ifp
;
1316 /* Check ripng is active and alive. */
1317 assert(ripng
!= NULL
);
1318 assert(ripng
->sock
>= 0);
1320 /* Fetch thread data and set read pointer to empty for event
1321 managing. `sock' sould be same as ripng->sock. */
1322 sock
= THREAD_FD(thread
);
1323 ripng
->t_read
= NULL
;
1325 /* Add myself to the next event. */
1326 ripng_event(ripng
, RIPNG_READ
, sock
);
1328 /* Read RIPng packet. */
1329 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1330 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1333 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1334 ripng
->vrf_name
, safe_strerror(errno
));
1338 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1339 (4)) must be multiple size of one RTE size (20). */
1340 if (((len
- 4) % 20) != 0) {
1341 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
1342 len
, &from
.sin6_addr
, ripng
->vrf_name
);
1343 ripng_peer_bad_packet(ripng
, &from
);
1347 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1348 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1350 /* RIPng packet received. */
1351 if (IS_RIPNG_DEBUG_EVENT
)
1353 "RIPng packet received from %pI6 port %d on %s (VRF %s)",
1354 &from
.sin6_addr
, ntohs(from
.sin6_port
),
1355 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1357 /* Logging before packet checking. */
1358 if (IS_RIPNG_DEBUG_RECV
)
1359 ripng_packet_dump(packet
, len
, "RECV");
1361 /* Packet comes from unknown interface. */
1364 "RIPng packet comes from unknown interface %d (VRF %s)",
1365 ifindex
, ripng
->vrf_name
);
1369 /* Packet version mismatch checking. */
1370 if (packet
->version
!= ripng
->version
) {
1372 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1373 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1374 ripng_peer_bad_packet(ripng
, &from
);
1378 /* Process RIPng packet. */
1379 switch (packet
->command
) {
1381 ripng_request_process(packet
, len
, &from
, ifp
);
1383 case RIPNG_RESPONSE
:
1384 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1387 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1389 ripng_peer_bad_packet(ripng
, &from
);
1395 /* Walk down the RIPng routing table then clear changed flag. */
1396 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1398 struct agg_node
*rp
;
1399 struct ripng_info
*rinfo
= NULL
;
1400 struct list
*list
= NULL
;
1401 struct listnode
*listnode
= NULL
;
1403 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1404 if ((list
= rp
->info
) != NULL
)
1405 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1406 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1407 /* This flag can be set only on the first entry.
1413 /* Regular update of RIPng route. Send all routing formation to RIPng
1414 enabled interface. */
1415 static int ripng_update(struct thread
*t
)
1417 struct ripng
*ripng
= THREAD_ARG(t
);
1418 struct interface
*ifp
;
1419 struct ripng_interface
*ri
;
1421 /* Clear update timer thread. */
1422 ripng
->t_update
= NULL
;
1424 /* Logging update event. */
1425 if (IS_RIPNG_DEBUG_EVENT
)
1426 zlog_debug("RIPng update timer expired!");
1428 /* Supply routes to each interface. */
1429 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1432 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1438 /* When passive interface is specified, suppress announce to the
1443 #ifdef RIPNG_ADVANCED
1444 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1445 if (IS_RIPNG_DEBUG_EVENT
)
1447 "[Event] RIPng send to if %d is suppressed by config",
1451 #endif /* RIPNG_ADVANCED */
1453 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1456 /* Triggered updates may be suppressed if a regular update is due by
1457 the time the triggered update would be sent. */
1458 thread_cancel(&ripng
->t_triggered_interval
);
1461 /* Reset flush event. */
1462 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1467 /* Triggered update interval timer. */
1468 static int ripng_triggered_interval(struct thread
*t
)
1470 struct ripng
*ripng
= THREAD_ARG(t
);
1472 ripng
->t_triggered_interval
= NULL
;
1474 if (ripng
->trigger
) {
1476 ripng_triggered_update(t
);
1481 /* Execute triggered update. */
1482 int ripng_triggered_update(struct thread
*t
)
1484 struct ripng
*ripng
= THREAD_ARG(t
);
1485 struct interface
*ifp
;
1486 struct ripng_interface
*ri
;
1489 ripng
->t_triggered_update
= NULL
;
1491 /* Cancel interval timer. */
1492 thread_cancel(&ripng
->t_triggered_interval
);
1495 /* Logging triggered update. */
1496 if (IS_RIPNG_DEBUG_EVENT
)
1497 zlog_debug("RIPng triggered update!");
1499 /* Split Horizon processing is done when generating triggered
1500 updates as well as normal updates (see section 2.6). */
1501 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1504 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1510 /* When passive interface is specified, suppress announce to the
1515 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1518 /* Once all of the triggered updates have been generated, the route
1519 change flags should be cleared. */
1520 ripng_clear_changed_flag(ripng
);
1522 /* After a triggered update is sent, a timer should be set for a
1523 random interval between 1 and 5 seconds. If other changes that
1524 would trigger updates occur before the timer expires, a single
1525 update is triggered when the timer expires. */
1526 interval
= (frr_weak_random() % 5) + 1;
1528 ripng
->t_triggered_interval
= NULL
;
1529 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1530 &ripng
->t_triggered_interval
);
1535 /* Write routing table entry to the stream and return next index of
1536 the routing table entry in the stream. */
1537 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1538 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1540 /* RIPng packet header. */
1542 stream_putc(s
, RIPNG_RESPONSE
);
1543 stream_putc(s
, RIPNG_V1
);
1547 /* Write routing table entry. */
1550 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1552 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1553 stream_putw(s
, tag
);
1555 stream_putc(s
, p
->prefixlen
);
1558 stream_putc(s
, metric
);
1563 /* Send RESPONSE message to specified destination. */
1564 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1567 struct ripng
*ripng
;
1569 struct agg_node
*rp
;
1570 struct ripng_info
*rinfo
;
1571 struct ripng_interface
*ri
;
1572 struct ripng_aggregate
*aggregate
;
1573 struct prefix_ipv6
*p
;
1574 struct list
*ripng_rte_list
;
1575 struct list
*list
= NULL
;
1576 struct listnode
*listnode
= NULL
;
1578 if (IS_RIPNG_DEBUG_EVENT
) {
1580 zlog_debug("RIPng update routes to neighbor %pI6",
1583 zlog_debug("RIPng update routes on interface %s",
1587 /* Get RIPng interface and instance. */
1591 ripng_rte_list
= ripng_rte_new();
1593 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1594 if ((list
= rp
->info
) != NULL
1595 && (rinfo
= listgetdata(listhead(list
))) != NULL
1596 && rinfo
->suppress
== 0) {
1597 /* If no route-map are applied, the RTE will be these
1601 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1602 rinfo
->metric_out
= rinfo
->metric
;
1603 rinfo
->tag_out
= rinfo
->tag
;
1604 memset(&rinfo
->nexthop_out
, 0,
1605 sizeof(rinfo
->nexthop_out
));
1606 /* In order to avoid some local loops,
1607 * if the RIPng route has a nexthop via this interface,
1609 * otherwise set it to 0. The nexthop should not be
1611 * beyond the local broadcast/multicast area in order
1612 * to avoid an IGP multi-level recursive look-up.
1614 if (rinfo
->ifindex
== ifp
->ifindex
)
1615 rinfo
->nexthop_out
= rinfo
->nexthop
;
1617 /* Apply output filters. */
1618 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1622 /* Changed route only output. */
1623 if (route_type
== ripng_changed_route
1624 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1627 /* Split horizon. */
1628 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1629 /* We perform split horizon for RIPng routes. */
1631 struct ripng_info
*tmp_rinfo
= NULL
;
1633 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1635 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1636 && tmp_rinfo
->ifindex
1645 /* Preparation for route-map. */
1646 rinfo
->metric_set
= 0;
1649 * and tag_out are already initialized.
1652 /* Interface route-map */
1653 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1654 ret
= route_map_apply(
1655 ri
->routemap
[RIPNG_FILTER_OUT
],
1656 (struct prefix
*)p
, rinfo
);
1658 if (ret
== RMAP_DENYMATCH
) {
1659 if (IS_RIPNG_DEBUG_PACKET
)
1661 "RIPng %pFX is filtered by route-map out",
1667 /* Redistribute route-map. */
1668 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1669 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1674 if (ret
== RMAP_DENYMATCH
) {
1675 if (IS_RIPNG_DEBUG_PACKET
)
1677 "RIPng %pFX is filtered by route-map",
1683 /* When the route-map does not set metric. */
1684 if (!rinfo
->metric_set
) {
1685 /* If the redistribute metric is set. */
1686 if (ripng
->redist
[rinfo
->type
].metric_config
1687 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1689 ripng
->redist
[rinfo
->type
]
1692 /* If the route is not connected or
1694 one, use default-metric value */
1695 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1697 != ZEBRA_ROUTE_CONNECT
1699 != RIPNG_METRIC_INFINITY
)
1701 ripng
->default_metric
;
1705 /* Apply offset-list */
1706 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1707 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1708 &rinfo
->metric_out
);
1710 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1711 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1713 /* Perform split-horizon with poisoned reverse
1716 if (ri
->split_horizon
1717 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1718 struct ripng_info
*tmp_rinfo
= NULL
;
1720 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1722 if ((tmp_rinfo
->type
1723 == ZEBRA_ROUTE_RIPNG
)
1724 && tmp_rinfo
->ifindex
1727 RIPNG_METRIC_INFINITY
;
1730 /* Add RTE to the list */
1731 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1734 /* Process the aggregated RTE entry */
1735 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1736 && aggregate
->suppress
== 0) {
1737 /* If no route-map are applied, the RTE will be these
1741 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1742 aggregate
->metric_set
= 0;
1743 aggregate
->metric_out
= aggregate
->metric
;
1744 aggregate
->tag_out
= aggregate
->tag
;
1745 memset(&aggregate
->nexthop_out
, 0,
1746 sizeof(aggregate
->nexthop_out
));
1748 /* Apply output filters.*/
1749 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1753 /* Interface route-map */
1754 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1755 struct ripng_info newinfo
;
1757 /* let's cast the aggregate structure to
1759 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1760 /* the nexthop is :: */
1761 newinfo
.metric
= aggregate
->metric
;
1762 newinfo
.metric_out
= aggregate
->metric_out
;
1763 newinfo
.tag
= aggregate
->tag
;
1764 newinfo
.tag_out
= aggregate
->tag_out
;
1766 ret
= route_map_apply(
1767 ri
->routemap
[RIPNG_FILTER_OUT
],
1768 (struct prefix
*)p
, &newinfo
);
1770 if (ret
== RMAP_DENYMATCH
) {
1771 if (IS_RIPNG_DEBUG_PACKET
)
1773 "RIPng %pFX is filtered by route-map out",
1778 aggregate
->metric_out
= newinfo
.metric_out
;
1779 aggregate
->tag_out
= newinfo
.tag_out
;
1780 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1781 aggregate
->nexthop_out
=
1782 newinfo
.nexthop_out
;
1785 /* There is no redistribute routemap for the aggregated
1788 /* Changed route only output. */
1789 /* XXX, vincent, in order to increase time convergence,
1790 * it should be announced if a child has changed.
1792 if (route_type
== ripng_changed_route
)
1795 /* Apply offset-list */
1796 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1797 ripng_offset_list_apply_out(
1798 ripng
, p
, ifp
, &aggregate
->metric_out
);
1800 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1801 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1803 /* Add RTE to the list */
1804 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1808 /* Flush the list */
1809 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1810 ripng_rte_free(ripng_rte_list
);
1813 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1817 vrf
= vrf_lookup_by_id(vrf_id
);
1824 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1828 ripng
.vrf_name
= (char *)vrf_name
;
1830 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1833 /* Create new RIPng instance and set it to global variable. */
1834 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1836 struct ripng
*ripng
;
1838 /* Allocaste RIPng instance. */
1839 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1840 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1842 /* Default version and timer values. */
1843 ripng
->version
= RIPNG_V1
;
1844 ripng
->update_time
= yang_get_default_uint32(
1845 "%s/timers/update-interval", RIPNG_INSTANCE
);
1846 ripng
->timeout_time
= yang_get_default_uint32(
1847 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1848 ripng
->garbage_time
= yang_get_default_uint32(
1849 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1850 ripng
->default_metric
=
1851 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1852 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1855 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1856 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1858 /* Initialize RIPng data structures. */
1859 ripng
->table
= agg_table_init();
1860 agg_set_table_info(ripng
->table
, ripng
);
1861 ripng
->peer_list
= list_new();
1862 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1863 ripng
->peer_list
->del
= ripng_peer_list_del
;
1864 ripng
->enable_if
= vector_init(1);
1865 ripng
->enable_network
= agg_table_init();
1866 ripng
->passive_interface
= vector_init(1);
1867 ripng
->offset_list_master
= list_new();
1868 ripng
->offset_list_master
->cmp
=
1869 (int (*)(void *, void *))offset_list_cmp
;
1870 ripng
->offset_list_master
->del
=
1871 (void (*)(void *))ripng_offset_list_free
;
1872 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1873 distribute_list_add_hook(ripng
->distribute_ctx
,
1874 ripng_distribute_update
);
1875 distribute_list_delete_hook(ripng
->distribute_ctx
,
1876 ripng_distribute_update
);
1878 /* if rmap install. */
1879 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1880 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1881 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1883 /* Enable the routing instance if possible. */
1884 if (vrf
&& vrf_is_enabled(vrf
))
1885 ripng_instance_enable(ripng
, vrf
, socket
);
1891 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1896 /* Send RIPng request to the interface. */
1897 int ripng_request(struct interface
*ifp
)
1900 struct ripng_packet ripng_packet
;
1902 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1904 if (if_is_loopback(ifp
))
1907 /* If interface is down, don't send RIP packet. */
1911 if (IS_RIPNG_DEBUG_EVENT
)
1912 zlog_debug("RIPng send request to %s", ifp
->name
);
1914 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1915 ripng_packet
.command
= RIPNG_REQUEST
;
1916 ripng_packet
.version
= RIPNG_V1
;
1917 rte
= ripng_packet
.rte
;
1918 rte
->metric
= RIPNG_METRIC_INFINITY
;
1920 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1925 static int ripng_update_jitter(int time
)
1927 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1930 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1936 thread_add_read(master
, ripng_read
, ripng
, sock
,
1939 case RIPNG_UPDATE_EVENT
:
1940 thread_cancel(&ripng
->t_update
);
1942 /* Update timer jitter. */
1943 jitter
= ripng_update_jitter(ripng
->update_time
);
1945 ripng
->t_update
= NULL
;
1946 thread_add_timer(master
, ripng_update
, ripng
,
1947 sock
? 2 : ripng
->update_time
+ jitter
,
1950 case RIPNG_TRIGGERED_UPDATE
:
1951 if (ripng
->t_triggered_interval
)
1954 thread_add_event(master
, ripng_triggered_update
, ripng
,
1955 0, &ripng
->t_triggered_update
);
1963 /* Print out routes update time. */
1964 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1969 char timebuf
[TIME_BUF
];
1970 struct thread
*thread
;
1972 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1973 clock
= thread_timer_remain_second(thread
);
1974 gmtime_r(&clock
, &tm
);
1975 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1976 vty_out(vty
, "%5s", timebuf
);
1977 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1978 clock
= thread_timer_remain_second(thread
);
1979 gmtime_r(&clock
, &tm
);
1980 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1981 vty_out(vty
, "%5s", timebuf
);
1985 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1990 if (rinfo
->suppress
)
1991 strlcat(str
, "S", sizeof(str
));
1993 switch (rinfo
->sub_type
) {
1994 case RIPNG_ROUTE_RTE
:
1995 strlcat(str
, "n", sizeof(str
));
1997 case RIPNG_ROUTE_STATIC
:
1998 strlcat(str
, "s", sizeof(str
));
2000 case RIPNG_ROUTE_DEFAULT
:
2001 strlcat(str
, "d", sizeof(str
));
2003 case RIPNG_ROUTE_REDISTRIBUTE
:
2004 strlcat(str
, "r", sizeof(str
));
2006 case RIPNG_ROUTE_INTERFACE
:
2007 strlcat(str
, "i", sizeof(str
));
2010 strlcat(str
, "?", sizeof(str
));
2017 DEFUN (show_ipv6_ripng
,
2018 show_ipv6_ripng_cmd
,
2019 "show ipv6 ripng [vrf NAME]",
2022 "Show RIPng routes\n"
2025 struct ripng
*ripng
;
2026 struct agg_node
*rp
;
2027 struct ripng_info
*rinfo
;
2028 struct ripng_aggregate
*aggregate
;
2029 struct list
*list
= NULL
;
2030 struct listnode
*listnode
= NULL
;
2032 const char *vrf_name
;
2035 if (argv_find(argv
, argc
, "vrf", &idx
))
2036 vrf_name
= argv
[idx
+ 1]->arg
;
2038 vrf_name
= VRF_DEFAULT_NAME
;
2040 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2042 vty_out(vty
, "%% RIPng instance not found\n");
2045 if (!ripng
->enabled
) {
2046 vty_out(vty
, "%% RIPng instance is disabled\n");
2050 /* Header of display. */
2052 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2054 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2055 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2056 " Network Next Hop Via Metric Tag Time\n");
2058 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2059 if ((aggregate
= rp
->aggregate
) != NULL
) {
2061 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2062 aggregate
->suppress
, rp
);
2064 vty_out(vty
, "R(a) %pRN ", rp
);
2067 vty_out(vty
, "%*s", 18, " ");
2069 vty_out(vty
, "%*s", 28, " ");
2070 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2071 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2074 if ((list
= rp
->info
) != NULL
)
2075 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2077 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2078 zebra_route_char(rinfo
->type
),
2079 ripng_route_subtype_print(rinfo
),
2080 rinfo
->suppress
, rp
);
2082 vty_out(vty
, "%c(%s) %pRN ",
2083 zebra_route_char(rinfo
->type
),
2084 ripng_route_subtype_print(rinfo
), rp
);
2087 vty_out(vty
, "%*s", 18, " ");
2088 len
= vty_out(vty
, "%pI6",
2093 vty_out(vty
, "%*s", len
, " ");
2096 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2097 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2102 ripng
->vrf
->vrf_id
));
2103 } else if (rinfo
->metric
2104 == RIPNG_METRIC_INFINITY
) {
2105 len
= vty_out(vty
, "kill");
2107 len
= vty_out(vty
, "self");
2111 vty_out(vty
, "%*s", len
, " ");
2113 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2114 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2117 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2118 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2119 /* RTE from remote RIP routers */
2120 ripng_vty_out_uptime(vty
, rinfo
);
2121 } else if (rinfo
->metric
2122 == RIPNG_METRIC_INFINITY
) {
2123 /* poisonous reversed routes (gc) */
2124 ripng_vty_out_uptime(vty
, rinfo
);
2134 DEFUN (show_ipv6_ripng_status
,
2135 show_ipv6_ripng_status_cmd
,
2136 "show ipv6 ripng [vrf NAME] status",
2139 "Show RIPng routes\n"
2141 "IPv6 routing protocol process parameters and statistics\n")
2143 struct ripng
*ripng
;
2144 struct interface
*ifp
;
2145 const char *vrf_name
;
2148 if (argv_find(argv
, argc
, "vrf", &idx
))
2149 vrf_name
= argv
[idx
+ 1]->arg
;
2151 vrf_name
= VRF_DEFAULT_NAME
;
2153 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2155 vty_out(vty
, "%% RIPng instance not found\n");
2158 if (!ripng
->enabled
) {
2159 vty_out(vty
, "%% RIPng instance is disabled\n");
2163 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2164 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2165 ripng
->update_time
);
2166 vty_out(vty
, " next due in %lu seconds\n",
2167 thread_timer_remain_second(ripng
->t_update
));
2168 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2169 vty_out(vty
, " garbage collect after %u seconds\n",
2170 ripng
->garbage_time
);
2172 /* Filtering status show. */
2173 config_show_distribute(vty
, ripng
->distribute_ctx
);
2175 /* Default metric information. */
2176 vty_out(vty
, " Default redistribution metric is %d\n",
2177 ripng
->default_metric
);
2179 /* Redistribute information. */
2180 vty_out(vty
, " Redistributing:");
2181 ripng_redistribute_write(vty
, ripng
);
2184 vty_out(vty
, " Default version control: send version %d,",
2186 vty_out(vty
, " receive version %d \n", ripng
->version
);
2188 vty_out(vty
, " Interface Send Recv\n");
2190 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2191 struct ripng_interface
*ri
;
2195 if (ri
->enable_network
|| ri
->enable_interface
) {
2197 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2198 ripng
->version
, ripng
->version
);
2202 vty_out(vty
, " Routing for Networks:\n");
2203 ripng_network_write(vty
, ripng
);
2205 vty_out(vty
, " Routing Information Sources:\n");
2207 " Gateway BadPackets BadRoutes Distance Last Update\n");
2208 ripng_peer_display(vty
, ripng
);
2213 /* Update ECMP routes to zebra when ECMP is disabled. */
2214 void ripng_ecmp_disable(struct ripng
*ripng
)
2216 struct agg_node
*rp
;
2217 struct ripng_info
*rinfo
, *tmp_rinfo
;
2219 struct listnode
*node
, *nextnode
;
2224 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2225 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2226 rinfo
= listgetdata(listhead(list
));
2227 if (!ripng_route_rte(rinfo
))
2230 /* Drop all other entries, except the first one. */
2231 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2232 if (tmp_rinfo
!= rinfo
) {
2233 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2235 tmp_rinfo
->t_garbage_collect
);
2236 list_delete_node(list
, node
);
2237 ripng_info_free(tmp_rinfo
);
2241 ripng_zebra_ipv6_add(ripng
, rp
);
2243 /* Set the route change flag. */
2244 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2246 /* Signal the output process to trigger an update. */
2247 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2251 /* RIPng configuration write function. */
2252 static int ripng_config_write(struct vty
*vty
)
2254 struct ripng
*ripng
;
2257 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2258 char xpath
[XPATH_MAXLEN
];
2259 struct lyd_node
*dnode
;
2261 snprintf(xpath
, sizeof(xpath
),
2262 "/frr-ripngd:ripngd/instance[vrf='%s']",
2265 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2268 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2270 config_write_distribute(vty
, ripng
->distribute_ctx
);
2271 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2279 static int ripng_config_write(struct vty
*vty
);
2280 /* RIPng node structure. */
2281 static struct cmd_node cmd_ripng_node
= {
2284 .parent_node
= CONFIG_NODE
,
2285 .prompt
= "%s(config-router)# ",
2286 .config_write
= ripng_config_write
,
2289 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2290 struct distribute
*dist
)
2292 struct interface
*ifp
;
2293 struct ripng_interface
*ri
;
2294 struct access_list
*alist
;
2295 struct prefix_list
*plist
;
2297 if (!ctx
->vrf
|| !dist
->ifname
)
2300 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2306 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2307 alist
= access_list_lookup(AFI_IP6
,
2308 dist
->list
[DISTRIBUTE_V6_IN
]);
2310 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2312 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2314 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2316 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2317 alist
= access_list_lookup(AFI_IP6
,
2318 dist
->list
[DISTRIBUTE_V6_OUT
]);
2320 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2322 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2324 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2326 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2327 plist
= prefix_list_lookup(AFI_IP6
,
2328 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2330 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2332 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2334 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2336 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2337 plist
= prefix_list_lookup(AFI_IP6
,
2338 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2340 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2342 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2344 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2347 void ripng_distribute_update_interface(struct interface
*ifp
)
2349 struct ripng_interface
*ri
= ifp
->info
;
2350 struct ripng
*ripng
= ri
->ripng
;
2351 struct distribute
*dist
;
2355 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2357 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2360 /* Update all interface's distribute list. */
2361 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2363 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2364 struct interface
*ifp
;
2366 FOR_ALL_INTERFACES (vrf
, ifp
)
2367 ripng_distribute_update_interface(ifp
);
2370 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2372 ripng_distribute_update_all(NULL
);
2375 /* delete all the added ripng routes. */
2376 void ripng_clean(struct ripng
*ripng
)
2378 ripng_interface_clean(ripng
);
2381 ripng_instance_disable(ripng
);
2383 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2384 if (ripng
->redist
[i
].route_map
.name
)
2385 free(ripng
->redist
[i
].route_map
.name
);
2387 agg_table_finish(ripng
->table
);
2388 list_delete(&ripng
->peer_list
);
2389 distribute_list_delete(&ripng
->distribute_ctx
);
2390 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2392 stream_free(ripng
->ibuf
);
2393 stream_free(ripng
->obuf
);
2395 ripng_clean_network(ripng
);
2396 ripng_passive_interface_clean(ripng
);
2397 vector_free(ripng
->enable_if
);
2398 agg_table_finish(ripng
->enable_network
);
2399 vector_free(ripng
->passive_interface
);
2400 list_delete(&ripng
->offset_list_master
);
2402 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2403 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2404 XFREE(MTYPE_RIPNG
, ripng
);
2407 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2408 struct if_rmap
*if_rmap
)
2410 struct interface
*ifp
= NULL
;
2411 struct ripng_interface
*ri
;
2412 struct route_map
*rmap
;
2413 struct vrf
*vrf
= NULL
;
2416 vrf
= vrf_lookup_by_name(ctx
->name
);
2418 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2424 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2425 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2427 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2429 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2431 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2433 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2434 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2436 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2438 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2440 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2443 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2445 struct ripng_interface
*ri
= ifp
->info
;
2446 struct ripng
*ripng
= ri
->ripng
;
2447 struct if_rmap
*if_rmap
;
2448 struct if_rmap_ctx
*ctx
;
2452 ctx
= ripng
->if_rmap_ctx
;
2455 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2457 ripng_if_rmap_update(ctx
, if_rmap
);
2460 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2462 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2463 if (ripng
->redist
[i
].route_map
.name
) {
2464 ripng
->redist
[i
].route_map
.map
=
2465 route_map_lookup_by_name(
2466 ripng
->redist
[i
].route_map
.name
);
2467 route_map_counter_increment(
2468 ripng
->redist
[i
].route_map
.map
);
2473 static void ripng_routemap_update(const char *unused
)
2475 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2476 struct ripng
*ripng
;
2477 struct interface
*ifp
;
2479 FOR_ALL_INTERFACES (vrf
, ifp
)
2480 ripng_if_rmap_update_interface(ifp
);
2484 ripng_routemap_update_redistribute(ripng
);
2487 /* Link RIPng instance to VRF. */
2488 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2490 struct interface
*ifp
;
2493 ripng
->distribute_ctx
->vrf
= vrf
;
2496 FOR_ALL_INTERFACES (vrf
, ifp
)
2497 ripng_interface_sync(ifp
);
2500 /* Unlink RIPng instance from VRF. */
2501 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2503 struct interface
*ifp
;
2506 ripng
->distribute_ctx
->vrf
= NULL
;
2509 FOR_ALL_INTERFACES (vrf
, ifp
)
2510 ripng_interface_sync(ifp
);
2513 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2518 ripng_vrf_link(ripng
, vrf
);
2519 ripng
->enabled
= true;
2521 /* Resend all redistribute requests. */
2522 ripng_redistribute_enable(ripng
);
2524 /* Create read and timer thread. */
2525 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2526 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2528 ripng_zebra_vrf_register(vrf
);
2531 static void ripng_instance_disable(struct ripng
*ripng
)
2533 struct vrf
*vrf
= ripng
->vrf
;
2534 struct agg_node
*rp
;
2536 /* Clear RIPng routes */
2537 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2538 struct ripng_aggregate
*aggregate
;
2541 if ((list
= rp
->info
) != NULL
) {
2542 struct ripng_info
*rinfo
;
2543 struct listnode
*listnode
;
2545 rinfo
= listgetdata(listhead(list
));
2546 if (ripng_route_rte(rinfo
))
2547 ripng_zebra_ipv6_delete(ripng
, rp
);
2549 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2550 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2551 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2552 ripng_info_free(rinfo
);
2556 agg_unlock_node(rp
);
2559 if ((aggregate
= rp
->aggregate
) != NULL
) {
2560 ripng_aggregate_free(aggregate
);
2561 rp
->aggregate
= NULL
;
2562 agg_unlock_node(rp
);
2566 /* Flush all redistribute requests. */
2567 ripng_redistribute_disable(ripng
);
2569 /* Cancel the RIPng timers */
2570 RIPNG_TIMER_OFF(ripng
->t_update
);
2571 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2572 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2574 /* Cancel the read thread */
2575 thread_cancel(&ripng
->t_read
);
2577 /* Close the RIPng socket */
2578 if (ripng
->sock
>= 0) {
2583 /* Clear existing peers. */
2584 list_delete_all_node(ripng
->peer_list
);
2586 ripng_zebra_vrf_deregister(vrf
);
2588 ripng_vrf_unlink(ripng
, vrf
);
2589 ripng
->enabled
= false;
2592 static int ripng_vrf_new(struct vrf
*vrf
)
2594 if (IS_RIPNG_DEBUG_EVENT
)
2595 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2601 static int ripng_vrf_delete(struct vrf
*vrf
)
2603 if (IS_RIPNG_DEBUG_EVENT
)
2604 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2610 static int ripng_vrf_enable(struct vrf
*vrf
)
2612 struct ripng
*ripng
;
2615 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2617 char *old_vrf_name
= NULL
;
2619 ripng
= (struct ripng
*)vrf
->info
;
2622 /* update vrf name */
2623 if (ripng
->vrf_name
)
2624 old_vrf_name
= ripng
->vrf_name
;
2625 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf
->name
);
2627 * HACK: Change the RIPng VRF in the running configuration directly,
2628 * bypassing the northbound layer. This is necessary to avoid deleting
2629 * the RIPng and readding it in the new VRF, which would have
2630 * several implications.
2632 if (yang_module_find("frr-ripngd") && old_vrf_name
) {
2633 struct lyd_node
*ripng_dnode
;
2634 char oldpath
[XPATH_MAXLEN
];
2635 char newpath
[XPATH_MAXLEN
];
2637 ripng_dnode
= yang_dnode_get(
2638 running_config
->dnode
,
2639 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2642 yang_dnode_get_path(ripng_dnode
->parent
, oldpath
,
2644 yang_dnode_change_leaf(ripng_dnode
, vrf
->name
);
2645 yang_dnode_get_path(ripng_dnode
->parent
, newpath
,
2647 nb_running_move_tree(oldpath
, newpath
);
2648 running_config
->version
++;
2651 XFREE(MTYPE_RIPNG_VRF_NAME
, old_vrf_name
);
2657 if (IS_RIPNG_DEBUG_EVENT
)
2658 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2661 /* Activate the VRF RIPng instance. */
2662 socket
= ripng_make_socket(vrf
);
2666 ripng_instance_enable(ripng
, vrf
, socket
);
2671 static int ripng_vrf_disable(struct vrf
*vrf
)
2673 struct ripng
*ripng
;
2675 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2676 if (!ripng
|| !ripng
->enabled
)
2679 if (IS_RIPNG_DEBUG_EVENT
)
2680 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2683 /* Deactivate the VRF RIPng instance. */
2685 ripng_instance_disable(ripng
);
2690 void ripng_vrf_init(void)
2692 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2693 ripng_vrf_delete
, ripng_vrf_enable
);
2696 void ripng_vrf_terminate(void)
2701 /* Initialize ripng structure and set commands. */
2702 void ripng_init(void)
2704 /* Install RIPNG_NODE. */
2705 install_node(&cmd_ripng_node
);
2707 /* Install ripng commands. */
2708 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2709 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2711 install_default(RIPNG_NODE
);
2716 /* Access list install. */
2718 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2719 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2721 /* Prefix list initialize.*/
2723 prefix_list_add_hook(ripng_distribute_update_all
);
2724 prefix_list_delete_hook(ripng_distribute_update_all
);
2726 /* Distribute list install. */
2727 distribute_list_init(RIPNG_NODE
);
2729 /* Route-map for interface. */
2730 ripng_route_map_init();
2732 route_map_add_hook(ripng_routemap_update
);
2733 route_map_delete_hook(ripng_routemap_update
);
2735 if_rmap_init(RIPNG_NODE
);