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
);
433 /* Off timeout timer. */
434 RIPNG_TIMER_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
);
452 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
454 /* Add new route to the ECMP list.
455 * RETURN: the new entry added in the list, or NULL if it is not the first
456 * entry and ECMP is not allowed.
458 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
459 struct ripng_info
*rinfo_new
)
461 struct agg_node
*rp
= rinfo_new
->rp
;
462 struct ripng_info
*rinfo
= NULL
;
463 struct list
*list
= NULL
;
465 if (rp
->info
== NULL
)
466 rp
->info
= list_new();
467 list
= (struct list
*)rp
->info
;
469 /* If ECMP is not allowed and some entry already exists in the list,
471 if (listcount(list
) && !ripng
->ecmp
)
474 rinfo
= ripng_info_new();
475 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
476 listnode_add(list
, rinfo
);
478 if (ripng_route_rte(rinfo
)) {
479 ripng_timeout_update(ripng
, rinfo
);
480 ripng_zebra_ipv6_add(ripng
, rp
);
483 ripng_aggregate_increment(rp
, rinfo
);
485 /* Set the route change flag on the first entry. */
486 rinfo
= listgetdata(listhead(list
));
487 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
489 /* Signal the output process to trigger an update. */
490 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
495 /* Replace the ECMP list with the new route.
496 * RETURN: the new entry added in the list
498 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
499 struct ripng_info
*rinfo_new
)
501 struct agg_node
*rp
= rinfo_new
->rp
;
502 struct list
*list
= (struct list
*)rp
->info
;
503 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
504 struct listnode
*node
= NULL
, *nextnode
= NULL
;
506 if (list
== NULL
|| listcount(list
) == 0)
507 return ripng_ecmp_add(ripng
, rinfo_new
);
509 /* Get the first entry */
510 rinfo
= listgetdata(listhead(list
));
512 /* Learnt route replaced by a local one. Delete it from zebra. */
513 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
514 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
515 ripng_zebra_ipv6_delete(ripng
, rp
);
517 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
518 ripng_aggregate_decrement_list(rp
, list
);
520 /* Re-use the first entry, and delete the others. */
521 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
522 if (tmp_rinfo
!= rinfo
) {
523 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
524 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
525 list_delete_node(list
, node
);
526 ripng_info_free(tmp_rinfo
);
529 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
530 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
531 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
533 if (ripng_route_rte(rinfo
)) {
534 ripng_timeout_update(ripng
, rinfo
);
535 /* The ADD message implies an update. */
536 ripng_zebra_ipv6_add(ripng
, rp
);
539 ripng_aggregate_increment(rp
, rinfo
);
541 /* Set the route change flag. */
542 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
544 /* Signal the output process to trigger an update. */
545 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
550 /* Delete one route from the ECMP list.
552 * null - the entry is freed, and other entries exist in the list
553 * the entry - the entry is the last one in the list; its metric is set
554 * to INFINITY, and the garbage collector is started for it
556 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
557 struct ripng_info
*rinfo
)
559 struct agg_node
*rp
= rinfo
->rp
;
560 struct list
*list
= (struct list
*)rp
->info
;
562 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
564 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
565 ripng_aggregate_decrement(rp
, rinfo
);
567 if (listcount(list
) > 1) {
568 /* Some other ECMP entries still exist. Just delete this entry.
570 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
571 listnode_delete(list
, rinfo
);
572 if (ripng_route_rte(rinfo
)
573 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
574 /* The ADD message implies the update. */
575 ripng_zebra_ipv6_add(ripng
, rp
);
576 ripng_info_free(rinfo
);
579 assert(rinfo
== listgetdata(listhead(list
)));
581 /* This is the only entry left in the list. We must keep it in
582 * the list for garbage collection time, with INFINITY metric.
585 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
586 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
587 ripng
->garbage_time
);
589 if (ripng_route_rte(rinfo
)
590 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
591 ripng_zebra_ipv6_delete(ripng
, rp
);
594 /* Set the route change flag on the first entry. */
595 rinfo
= listgetdata(listhead(list
));
596 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
598 /* Signal the output process to trigger an update. */
599 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
604 /* Timeout RIPng routes. */
605 static int ripng_timeout(struct thread
*t
)
607 struct ripng_info
*rinfo
= THREAD_ARG(t
);
608 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
610 ripng_ecmp_delete(ripng
, rinfo
);
615 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
617 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
618 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
619 thread_add_timer(master
, ripng_timeout
, rinfo
,
620 ripng
->timeout_time
, &rinfo
->t_timeout
);
624 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
625 struct ripng_interface
*ri
)
627 struct distribute
*dist
;
628 struct access_list
*alist
;
629 struct prefix_list
*plist
;
630 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
633 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
635 /* Input distribute-list filtering. */
636 if (ri
->list
[ripng_distribute
]) {
637 if (access_list_apply(ri
->list
[ripng_distribute
],
640 if (IS_RIPNG_DEBUG_PACKET
)
641 zlog_debug("%pFX filtered by distribute %s", p
,
646 if (ri
->prefix
[ripng_distribute
]) {
647 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
650 if (IS_RIPNG_DEBUG_PACKET
)
651 zlog_debug("%pFX filtered by prefix-list %s", p
,
657 /* All interface filter check. */
658 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
660 if (dist
->list
[distribute
]) {
661 alist
= access_list_lookup(AFI_IP6
,
662 dist
->list
[distribute
]);
665 if (access_list_apply(alist
, (struct prefix
*)p
)
667 if (IS_RIPNG_DEBUG_PACKET
)
669 "%pFX filtered by distribute %s",
675 if (dist
->prefix
[distribute
]) {
676 plist
= prefix_list_lookup(AFI_IP6
,
677 dist
->prefix
[distribute
]);
680 if (prefix_list_apply(plist
, (struct prefix
*)p
)
682 if (IS_RIPNG_DEBUG_PACKET
)
684 "%pFX filtered by prefix-list %s",
694 /* Process RIPng route according to RFC2080. */
695 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
696 struct ripng_nexthop
*ripng_nexthop
,
697 struct interface
*ifp
)
700 struct prefix_ipv6 p
;
702 struct ripng_info
*rinfo
= NULL
, newinfo
;
703 struct ripng_interface
*ri
;
705 struct in6_addr
*nexthop
;
707 struct list
*list
= NULL
;
708 struct listnode
*node
= NULL
;
710 /* Make prefix structure. */
711 memset(&p
, 0, sizeof(struct prefix_ipv6
));
713 /* p.prefix = rte->addr; */
714 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
715 p
.prefixlen
= rte
->prefixlen
;
717 /* Make sure mask is applied. */
718 /* XXX We have to check the prefix is valid or not before call
725 /* Apply input filters. */
726 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
730 memset(&newinfo
, 0, sizeof(newinfo
));
731 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
732 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
733 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
734 newinfo
.nexthop
= ripng_nexthop
->address
;
736 newinfo
.nexthop
= from
->sin6_addr
;
737 newinfo
.from
= from
->sin6_addr
;
738 newinfo
.ifindex
= ifp
->ifindex
;
739 newinfo
.metric
= rte
->metric
;
740 newinfo
.metric_out
= rte
->metric
; /* XXX */
741 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
744 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
745 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
746 (struct prefix
*)&p
, &newinfo
);
748 if (ret
== RMAP_DENYMATCH
) {
749 if (IS_RIPNG_DEBUG_PACKET
)
751 "RIPng %pFX is filtered by route-map in",
756 /* Get back the object */
757 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
758 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
759 &ripng_nexthop
->address
)) {
760 /* the nexthop get changed by the routemap */
761 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
762 ripng_nexthop
->address
=
765 ripng_nexthop
->address
= in6addr_any
;
768 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
770 /* the nexthop get changed by the routemap */
771 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
772 ripng_nexthop
->flag
=
773 RIPNG_NEXTHOP_ADDRESS
;
774 ripng_nexthop
->address
=
779 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
781 newinfo
.metric_out
; /* XXX: the routemap uses the
785 /* Once the entry has been validated, update the metric by
786 * adding the cost of the network on wich the message
787 * arrived. If the result is greater than infinity, use infinity
788 * (RFC2453 Sec. 3.9.2)
791 /* Zebra ripngd can handle offset-list in. */
792 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
794 /* If offset-list does not modify the metric use interface's
797 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
799 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
800 rte
->metric
= RIPNG_METRIC_INFINITY
;
802 /* Set nexthop pointer. */
803 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
804 nexthop
= &ripng_nexthop
->address
;
806 nexthop
= &from
->sin6_addr
;
808 /* Lookup RIPng routing table. */
809 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
812 newinfo
.nexthop
= *nexthop
;
813 newinfo
.metric
= rte
->metric
;
814 newinfo
.tag
= ntohs(rte
->tag
);
816 /* Check to see whether there is already RIPng route on the table. */
817 if ((list
= rp
->info
) != NULL
)
818 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
819 /* Need to compare with redistributed entry or local
821 if (!ripng_route_rte(rinfo
))
824 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
825 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
828 if (!listnextnode(node
)) {
829 /* Not found in the list */
831 if (rte
->metric
> rinfo
->metric
) {
832 /* New route has a greater metric.
838 if (rte
->metric
< rinfo
->metric
)
839 /* New route has a smaller metric.
840 * Replace the ECMP list
841 * with the new one in below. */
844 /* Metrics are same. Unless ECMP is disabled,
845 * keep "rinfo" null and
846 * the new route is added in the ECMP list in
854 /* Redistributed route check. */
855 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
856 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
861 /* Local static route. */
862 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
863 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
864 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
865 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
872 /* Now, check to see whether there is already an explicit route
873 for the destination prefix. If there is no such route, add
874 this route to the routing table, unless the metric is
875 infinity (there is no point in adding a route which
877 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
878 ripng_ecmp_add(ripng
, &newinfo
);
882 /* If there is an existing route, compare the next hop address
883 to the address of the router from which the datagram came.
884 If this datagram is from the same router as the existing
885 route, reinitialize the timeout. */
886 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
887 && (rinfo
->ifindex
== ifp
->ifindex
));
890 * RFC 2080 - Section 2.4.2:
891 * "If the new metric is the same as the old one, examine the
893 * for the existing route. If it is at least halfway to the
895 * point, switch to the new route. This heuristic is optional,
897 * highly recommended".
899 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
901 && (thread_timer_remain_second(rinfo
->t_timeout
)
902 < (ripng
->timeout_time
/ 2))) {
903 ripng_ecmp_replace(ripng
, &newinfo
);
905 /* Next, compare the metrics. If the datagram is from the same
906 router as the existing route, and the new metric is different
907 than the old one; or, if the new metric is lower than the old
908 one; do the following actions: */
909 else if ((same
&& rinfo
->metric
!= rte
->metric
)
910 || rte
->metric
< rinfo
->metric
) {
911 if (listcount(list
) == 1) {
912 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
913 ripng_ecmp_replace(ripng
, &newinfo
);
915 ripng_ecmp_delete(ripng
, rinfo
);
917 if (newinfo
.metric
< rinfo
->metric
)
918 ripng_ecmp_replace(ripng
, &newinfo
);
919 else /* newinfo.metric > rinfo->metric */
920 ripng_ecmp_delete(ripng
, rinfo
);
922 } else /* same & no change */
923 ripng_timeout_update(ripng
, rinfo
);
925 /* Unlock tempolary lock of the route. */
930 /* Add redistributed route to RIPng table. */
931 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
932 struct prefix_ipv6
*p
, ifindex_t ifindex
,
933 struct in6_addr
*nexthop
, route_tag_t tag
)
936 struct ripng_info
*rinfo
= NULL
, newinfo
;
937 struct list
*list
= NULL
;
939 /* Redistribute route */
940 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
942 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
945 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
947 memset(&newinfo
, 0, sizeof(struct ripng_info
));
949 newinfo
.sub_type
= sub_type
;
950 newinfo
.ifindex
= ifindex
;
952 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
955 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
956 newinfo
.nexthop
= *nexthop
;
958 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
959 rinfo
= listgetdata(listhead(list
));
961 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
962 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
963 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
968 /* Manually configured RIPng route check.
969 * They have the precedence on all the other entries.
971 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
972 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
973 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
974 if (type
!= ZEBRA_ROUTE_RIPNG
975 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
976 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
982 ripng_ecmp_replace(ripng
, &newinfo
);
985 ripng_ecmp_add(ripng
, &newinfo
);
987 if (IS_RIPNG_DEBUG_EVENT
) {
990 "Redistribute new prefix %pFX on the interface %s",
991 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
994 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
996 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
999 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1002 /* Delete redistributed route to RIPng table. */
1003 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1004 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1006 struct agg_node
*rp
;
1007 struct ripng_info
*rinfo
;
1009 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1011 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1014 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1017 struct list
*list
= rp
->info
;
1019 if (list
!= NULL
&& listcount(list
) != 0) {
1020 rinfo
= listgetdata(listhead(list
));
1021 if (rinfo
!= NULL
&& rinfo
->type
== type
1022 && rinfo
->sub_type
== sub_type
1023 && rinfo
->ifindex
== ifindex
) {
1024 /* Perform poisoned reverse. */
1025 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1026 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1027 ripng_garbage_collect
,
1028 ripng
->garbage_time
);
1029 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1031 /* Aggregate count decrement. */
1032 ripng_aggregate_decrement(rp
, rinfo
);
1034 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1036 if (IS_RIPNG_DEBUG_EVENT
)
1038 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1042 ripng
->vrf
->vrf_id
));
1044 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1047 agg_unlock_node(rp
);
1051 /* Withdraw redistributed route. */
1052 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1054 struct agg_node
*rp
;
1055 struct ripng_info
*rinfo
= NULL
;
1056 struct list
*list
= NULL
;
1058 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1059 if ((list
= rp
->info
) != NULL
) {
1060 rinfo
= listgetdata(listhead(list
));
1061 if ((rinfo
->type
== type
)
1062 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1063 /* Perform poisoned reverse. */
1064 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1065 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1066 ripng_garbage_collect
,
1067 ripng
->garbage_time
);
1068 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1070 /* Aggregate count decrement. */
1071 ripng_aggregate_decrement(rp
, rinfo
);
1073 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1075 if (IS_RIPNG_DEBUG_EVENT
) {
1076 struct prefix_ipv6
*p
=
1077 (struct prefix_ipv6
*)
1078 agg_node_get_prefix(rp
);
1081 "Poisone %pFX on the interface %s [withdraw]",
1085 ripng
->vrf
->vrf_id
));
1088 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1093 /* RIP routing information. */
1094 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1095 struct sockaddr_in6
*from
,
1096 struct interface
*ifp
, int hoplimit
)
1098 struct ripng_interface
*ri
= ifp
->info
;
1099 struct ripng
*ripng
= ri
->ripng
;
1102 struct ripng_nexthop nexthop
;
1104 /* RFC2080 2.4.2 Response Messages:
1105 The Response must be ignored if it is not from the RIPng port. */
1106 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1107 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
1108 ntohs(from
->sin6_port
), &from
->sin6_addr
);
1109 ripng_peer_bad_packet(ripng
, from
);
1113 /* The datagram's IPv6 source address should be checked to see
1114 whether the datagram is from a valid neighbor; the source of the
1115 datagram must be a link-local address. */
1116 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1117 zlog_warn("RIPng packet comes from non link local address %pI6",
1119 ripng_peer_bad_packet(ripng
, from
);
1123 /* It is also worth checking to see whether the response is from one
1124 of the router's own addresses. Interfaces on broadcast networks
1125 may receive copies of their own multicasts immediately. If a
1126 router processes its own output as new input, confusion is likely,
1127 and such datagrams must be ignored. */
1128 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1130 "RIPng packet comes from my own link local address %pI6",
1132 ripng_peer_bad_packet(ripng
, from
);
1136 /* As an additional check, periodic advertisements must have their
1137 hop counts set to 255, and inbound, multicast packets sent from the
1138 RIPng port (i.e. periodic advertisement or triggered update
1139 packets) must be examined to ensure that the hop count is 255. */
1140 if (hoplimit
>= 0 && hoplimit
!= 255) {
1142 "RIPng packet comes with non 255 hop count %d from %pI6",
1143 hoplimit
, &from
->sin6_addr
);
1144 ripng_peer_bad_packet(ripng
, from
);
1148 /* Update RIPng peer. */
1149 ripng_peer_update(ripng
, from
, packet
->version
);
1151 /* Reset nexthop. */
1152 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1153 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1155 /* Set RTE pointer. */
1158 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1159 /* First of all, we have to check this RTE is next hop RTE or
1160 not. Next hop RTE is completely different with normal RTE so
1161 we need special treatment. */
1162 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1163 ripng_nexthop_rte(rte
, from
, &nexthop
);
1167 /* RTE information validation. */
1169 /* - is the destination prefix valid (e.g., not a multicast
1170 prefix and not a link-local address) A link-local address
1171 should never be present in an RTE. */
1172 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1174 "Destination prefix is a multicast address %pI6/%d [%d]",
1175 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1176 ripng_peer_bad_route(ripng
, from
);
1179 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1181 "Destination prefix is a link-local address %pI6/%d [%d]",
1182 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1183 ripng_peer_bad_route(ripng
, from
);
1186 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1188 "Destination prefix is a loopback address %pI6/%d [%d]",
1189 &rte
->addr
, rte
->prefixlen
, rte
->metric
);
1190 ripng_peer_bad_route(ripng
, from
);
1194 /* - is the prefix length valid (i.e., between 0 and 128,
1196 if (rte
->prefixlen
> IPV6_MAX_BITLEN
) {
1197 zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
1198 &rte
->addr
, rte
->prefixlen
,
1199 &from
->sin6_addr
, ifp
->name
);
1200 ripng_peer_bad_route(ripng
, from
);
1204 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1205 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1206 zlog_warn("Invalid metric %d from %pI6%%%s",
1207 rte
->metric
, &from
->sin6_addr
, ifp
->name
);
1208 ripng_peer_bad_route(ripng
, from
);
1212 /* Vincent: XXX Should we compute the direclty reachable nexthop
1213 * for our RIPng network ?
1216 /* Routing table updates. */
1217 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1221 /* Response to request message. */
1222 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1223 struct sockaddr_in6
*from
,
1224 struct interface
*ifp
)
1226 struct ripng
*ripng
;
1229 struct prefix_ipv6 p
;
1230 struct agg_node
*rp
;
1231 struct ripng_info
*rinfo
;
1232 struct ripng_interface
*ri
;
1234 /* Does not reponse to the requests on the loopback interfaces */
1235 if (if_is_loopback(ifp
))
1238 /* Check RIPng process is enabled on this interface. */
1244 /* When passive interface is specified, suppress responses */
1248 /* RIPng peer update. */
1249 ripng_peer_update(ripng
, from
, packet
->version
);
1251 lim
= ((caddr_t
)packet
) + size
;
1254 /* The Request is processed entry by entry. If there are no
1255 entries, no response is given. */
1256 if (lim
== (caddr_t
)rte
)
1259 /* There is one special case. If there is exactly one entry in the
1260 request, and it has a destination prefix of zero, a prefix length
1261 of zero, and a metric of infinity (i.e., 16), then this is a
1262 request to send the entire routing table. In that case, a call
1263 is made to the output process to send the routing table to the
1264 requesting address/port. */
1265 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1266 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1267 /* All route with split horizon */
1268 ripng_output_process(ifp
, from
, ripng_all_route
);
1270 /* Except for this special case, processing is quite simple.
1271 Examine the list of RTEs in the Request one by one. For each
1272 entry, look up the destination in the router's routing
1273 database and, if there is a route, put that route's metric in
1274 the metric field of the RTE. If there is no explicit route
1275 to the specified destination, put infinity in the metric
1276 field. Once all the entries have been filled in, change the
1277 command from Request to Response and send the datagram back
1278 to the requestor. */
1279 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1280 p
.family
= AF_INET6
;
1282 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1283 p
.prefix
= rte
->addr
;
1284 p
.prefixlen
= rte
->prefixlen
;
1285 apply_mask_ipv6(&p
);
1287 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1290 rinfo
= listgetdata(
1291 listhead((struct list
*)rp
->info
));
1292 rte
->metric
= rinfo
->metric
;
1293 agg_unlock_node(rp
);
1295 rte
->metric
= RIPNG_METRIC_INFINITY
;
1297 packet
->command
= RIPNG_RESPONSE
;
1299 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1303 /* First entry point of reading RIPng packet. */
1304 static int ripng_read(struct thread
*thread
)
1306 struct ripng
*ripng
= THREAD_ARG(thread
);
1309 struct sockaddr_in6 from
;
1310 struct ripng_packet
*packet
;
1311 ifindex_t ifindex
= 0;
1312 struct interface
*ifp
;
1315 /* Check ripng is active and alive. */
1316 assert(ripng
!= NULL
);
1317 assert(ripng
->sock
>= 0);
1319 /* Fetch thread data and set read pointer to empty for event
1320 managing. `sock' sould be same as ripng->sock. */
1321 sock
= THREAD_FD(thread
);
1323 /* Add myself to the next event. */
1324 ripng_event(ripng
, RIPNG_READ
, sock
);
1326 /* Read RIPng packet. */
1327 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1328 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1331 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1332 ripng
->vrf_name
, safe_strerror(errno
));
1336 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1337 (4)) must be multiple size of one RTE size (20). */
1338 if (((len
- 4) % 20) != 0) {
1339 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
1340 len
, &from
.sin6_addr
, ripng
->vrf_name
);
1341 ripng_peer_bad_packet(ripng
, &from
);
1345 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1346 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1348 /* RIPng packet received. */
1349 if (IS_RIPNG_DEBUG_EVENT
)
1351 "RIPng packet received from %pI6 port %d on %s (VRF %s)",
1352 &from
.sin6_addr
, ntohs(from
.sin6_port
),
1353 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1355 /* Logging before packet checking. */
1356 if (IS_RIPNG_DEBUG_RECV
)
1357 ripng_packet_dump(packet
, len
, "RECV");
1359 /* Packet comes from unknown interface. */
1362 "RIPng packet comes from unknown interface %d (VRF %s)",
1363 ifindex
, ripng
->vrf_name
);
1367 /* Packet version mismatch checking. */
1368 if (packet
->version
!= ripng
->version
) {
1370 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1371 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1372 ripng_peer_bad_packet(ripng
, &from
);
1376 /* Process RIPng packet. */
1377 switch (packet
->command
) {
1379 ripng_request_process(packet
, len
, &from
, ifp
);
1381 case RIPNG_RESPONSE
:
1382 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1385 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1387 ripng_peer_bad_packet(ripng
, &from
);
1393 /* Walk down the RIPng routing table then clear changed flag. */
1394 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1396 struct agg_node
*rp
;
1397 struct ripng_info
*rinfo
= NULL
;
1398 struct list
*list
= NULL
;
1399 struct listnode
*listnode
= NULL
;
1401 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1402 if ((list
= rp
->info
) != NULL
)
1403 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1404 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1405 /* This flag can be set only on the first entry.
1411 /* Regular update of RIPng route. Send all routing formation to RIPng
1412 enabled interface. */
1413 static int ripng_update(struct thread
*t
)
1415 struct ripng
*ripng
= THREAD_ARG(t
);
1416 struct interface
*ifp
;
1417 struct ripng_interface
*ri
;
1419 /* Logging update event. */
1420 if (IS_RIPNG_DEBUG_EVENT
)
1421 zlog_debug("RIPng update timer expired!");
1423 /* Supply routes to each interface. */
1424 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1427 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1433 /* When passive interface is specified, suppress announce to the
1438 #ifdef RIPNG_ADVANCED
1439 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1440 if (IS_RIPNG_DEBUG_EVENT
)
1442 "[Event] RIPng send to if %d is suppressed by config",
1446 #endif /* RIPNG_ADVANCED */
1448 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1451 /* Triggered updates may be suppressed if a regular update is due by
1452 the time the triggered update would be sent. */
1453 thread_cancel(&ripng
->t_triggered_interval
);
1456 /* Reset flush event. */
1457 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1462 /* Triggered update interval timer. */
1463 static int ripng_triggered_interval(struct thread
*t
)
1465 struct ripng
*ripng
= THREAD_ARG(t
);
1467 if (ripng
->trigger
) {
1469 ripng_triggered_update(t
);
1474 /* Execute triggered update. */
1475 int ripng_triggered_update(struct thread
*t
)
1477 struct ripng
*ripng
= THREAD_ARG(t
);
1478 struct interface
*ifp
;
1479 struct ripng_interface
*ri
;
1482 /* Cancel interval timer. */
1483 thread_cancel(&ripng
->t_triggered_interval
);
1486 /* Logging triggered update. */
1487 if (IS_RIPNG_DEBUG_EVENT
)
1488 zlog_debug("RIPng triggered update!");
1490 /* Split Horizon processing is done when generating triggered
1491 updates as well as normal updates (see section 2.6). */
1492 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1495 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1501 /* When passive interface is specified, suppress announce to the
1506 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1509 /* Once all of the triggered updates have been generated, the route
1510 change flags should be cleared. */
1511 ripng_clear_changed_flag(ripng
);
1513 /* After a triggered update is sent, a timer should be set for a
1514 random interval between 1 and 5 seconds. If other changes that
1515 would trigger updates occur before the timer expires, a single
1516 update is triggered when the timer expires. */
1517 interval
= (frr_weak_random() % 5) + 1;
1519 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1520 &ripng
->t_triggered_interval
);
1525 /* Write routing table entry to the stream and return next index of
1526 the routing table entry in the stream. */
1527 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1528 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1530 /* RIPng packet header. */
1532 stream_putc(s
, RIPNG_RESPONSE
);
1533 stream_putc(s
, RIPNG_V1
);
1537 /* Write routing table entry. */
1540 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1542 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1543 stream_putw(s
, tag
);
1545 stream_putc(s
, p
->prefixlen
);
1548 stream_putc(s
, metric
);
1553 /* Send RESPONSE message to specified destination. */
1554 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1557 struct ripng
*ripng
;
1559 struct agg_node
*rp
;
1560 struct ripng_info
*rinfo
;
1561 struct ripng_interface
*ri
;
1562 struct ripng_aggregate
*aggregate
;
1563 struct prefix_ipv6
*p
;
1564 struct list
*ripng_rte_list
;
1565 struct list
*list
= NULL
;
1566 struct listnode
*listnode
= NULL
;
1568 if (IS_RIPNG_DEBUG_EVENT
) {
1570 zlog_debug("RIPng update routes to neighbor %pI6",
1573 zlog_debug("RIPng update routes on interface %s",
1577 /* Get RIPng interface and instance. */
1581 ripng_rte_list
= ripng_rte_new();
1583 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1584 if ((list
= rp
->info
) != NULL
1585 && (rinfo
= listgetdata(listhead(list
))) != NULL
1586 && rinfo
->suppress
== 0) {
1587 /* If no route-map are applied, the RTE will be these
1591 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1592 rinfo
->metric_out
= rinfo
->metric
;
1593 rinfo
->tag_out
= rinfo
->tag
;
1594 memset(&rinfo
->nexthop_out
, 0,
1595 sizeof(rinfo
->nexthop_out
));
1596 /* In order to avoid some local loops,
1597 * if the RIPng route has a nexthop via this interface,
1599 * otherwise set it to 0. The nexthop should not be
1601 * beyond the local broadcast/multicast area in order
1602 * to avoid an IGP multi-level recursive look-up.
1604 if (rinfo
->ifindex
== ifp
->ifindex
)
1605 rinfo
->nexthop_out
= rinfo
->nexthop
;
1607 /* Apply output filters. */
1608 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1612 /* Changed route only output. */
1613 if (route_type
== ripng_changed_route
1614 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1617 /* Split horizon. */
1618 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1619 /* We perform split horizon for RIPng routes. */
1621 struct ripng_info
*tmp_rinfo
= NULL
;
1623 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1625 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1626 && tmp_rinfo
->ifindex
1635 /* Preparation for route-map. */
1636 rinfo
->metric_set
= 0;
1639 * and tag_out are already initialized.
1642 /* Interface route-map */
1643 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1644 ret
= route_map_apply(
1645 ri
->routemap
[RIPNG_FILTER_OUT
],
1646 (struct prefix
*)p
, rinfo
);
1648 if (ret
== RMAP_DENYMATCH
) {
1649 if (IS_RIPNG_DEBUG_PACKET
)
1651 "RIPng %pFX is filtered by route-map out",
1657 /* Redistribute route-map. */
1658 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1659 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1664 if (ret
== RMAP_DENYMATCH
) {
1665 if (IS_RIPNG_DEBUG_PACKET
)
1667 "RIPng %pFX is filtered by route-map",
1673 /* When the route-map does not set metric. */
1674 if (!rinfo
->metric_set
) {
1675 /* If the redistribute metric is set. */
1676 if (ripng
->redist
[rinfo
->type
].metric_config
1677 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1679 ripng
->redist
[rinfo
->type
]
1682 /* If the route is not connected or
1684 one, use default-metric value */
1685 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1687 != ZEBRA_ROUTE_CONNECT
1689 != RIPNG_METRIC_INFINITY
)
1691 ripng
->default_metric
;
1695 /* Apply offset-list */
1696 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1697 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1698 &rinfo
->metric_out
);
1700 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1701 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1703 /* Perform split-horizon with poisoned reverse
1706 if (ri
->split_horizon
1707 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1708 struct ripng_info
*tmp_rinfo
= NULL
;
1710 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1712 if ((tmp_rinfo
->type
1713 == ZEBRA_ROUTE_RIPNG
)
1714 && tmp_rinfo
->ifindex
1717 RIPNG_METRIC_INFINITY
;
1720 /* Add RTE to the list */
1721 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1724 /* Process the aggregated RTE entry */
1725 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1726 && aggregate
->suppress
== 0) {
1727 /* If no route-map are applied, the RTE will be these
1731 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1732 aggregate
->metric_set
= 0;
1733 aggregate
->metric_out
= aggregate
->metric
;
1734 aggregate
->tag_out
= aggregate
->tag
;
1735 memset(&aggregate
->nexthop_out
, 0,
1736 sizeof(aggregate
->nexthop_out
));
1738 /* Apply output filters.*/
1739 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1743 /* Interface route-map */
1744 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1745 struct ripng_info newinfo
;
1747 /* let's cast the aggregate structure to
1749 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1750 /* the nexthop is :: */
1751 newinfo
.metric
= aggregate
->metric
;
1752 newinfo
.metric_out
= aggregate
->metric_out
;
1753 newinfo
.tag
= aggregate
->tag
;
1754 newinfo
.tag_out
= aggregate
->tag_out
;
1756 ret
= route_map_apply(
1757 ri
->routemap
[RIPNG_FILTER_OUT
],
1758 (struct prefix
*)p
, &newinfo
);
1760 if (ret
== RMAP_DENYMATCH
) {
1761 if (IS_RIPNG_DEBUG_PACKET
)
1763 "RIPng %pFX is filtered by route-map out",
1768 aggregate
->metric_out
= newinfo
.metric_out
;
1769 aggregate
->tag_out
= newinfo
.tag_out
;
1770 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1771 aggregate
->nexthop_out
=
1772 newinfo
.nexthop_out
;
1775 /* There is no redistribute routemap for the aggregated
1778 /* Changed route only output. */
1779 /* XXX, vincent, in order to increase time convergence,
1780 * it should be announced if a child has changed.
1782 if (route_type
== ripng_changed_route
)
1785 /* Apply offset-list */
1786 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1787 ripng_offset_list_apply_out(
1788 ripng
, p
, ifp
, &aggregate
->metric_out
);
1790 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1791 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1793 /* Add RTE to the list */
1794 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1798 /* Flush the list */
1799 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1800 ripng_rte_free(ripng_rte_list
);
1803 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1807 vrf
= vrf_lookup_by_id(vrf_id
);
1814 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1818 ripng
.vrf_name
= (char *)vrf_name
;
1820 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1823 /* Create new RIPng instance and set it to global variable. */
1824 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1826 struct ripng
*ripng
;
1828 /* Allocaste RIPng instance. */
1829 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1830 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1832 /* Default version and timer values. */
1833 ripng
->version
= RIPNG_V1
;
1834 ripng
->update_time
= yang_get_default_uint32(
1835 "%s/timers/update-interval", RIPNG_INSTANCE
);
1836 ripng
->timeout_time
= yang_get_default_uint32(
1837 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1838 ripng
->garbage_time
= yang_get_default_uint32(
1839 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1840 ripng
->default_metric
=
1841 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1842 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1845 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1846 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1848 /* Initialize RIPng data structures. */
1849 ripng
->table
= agg_table_init();
1850 agg_set_table_info(ripng
->table
, ripng
);
1851 ripng
->peer_list
= list_new();
1852 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1853 ripng
->peer_list
->del
= ripng_peer_list_del
;
1854 ripng
->enable_if
= vector_init(1);
1855 ripng
->enable_network
= agg_table_init();
1856 ripng
->passive_interface
= vector_init(1);
1857 ripng
->offset_list_master
= list_new();
1858 ripng
->offset_list_master
->cmp
=
1859 (int (*)(void *, void *))offset_list_cmp
;
1860 ripng
->offset_list_master
->del
=
1861 (void (*)(void *))ripng_offset_list_free
;
1862 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1863 distribute_list_add_hook(ripng
->distribute_ctx
,
1864 ripng_distribute_update
);
1865 distribute_list_delete_hook(ripng
->distribute_ctx
,
1866 ripng_distribute_update
);
1868 /* if rmap install. */
1869 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1870 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1871 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1873 /* Enable the routing instance if possible. */
1874 if (vrf
&& vrf_is_enabled(vrf
))
1875 ripng_instance_enable(ripng
, vrf
, socket
);
1881 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1886 /* Send RIPng request to the interface. */
1887 int ripng_request(struct interface
*ifp
)
1890 struct ripng_packet ripng_packet
;
1892 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1894 if (if_is_loopback(ifp
))
1897 /* If interface is down, don't send RIP packet. */
1901 if (IS_RIPNG_DEBUG_EVENT
)
1902 zlog_debug("RIPng send request to %s", ifp
->name
);
1904 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1905 ripng_packet
.command
= RIPNG_REQUEST
;
1906 ripng_packet
.version
= RIPNG_V1
;
1907 rte
= ripng_packet
.rte
;
1908 rte
->metric
= RIPNG_METRIC_INFINITY
;
1910 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1915 static int ripng_update_jitter(int time
)
1917 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1920 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1926 thread_add_read(master
, ripng_read
, ripng
, sock
,
1929 case RIPNG_UPDATE_EVENT
:
1930 thread_cancel(&ripng
->t_update
);
1932 /* Update timer jitter. */
1933 jitter
= ripng_update_jitter(ripng
->update_time
);
1935 thread_add_timer(master
, ripng_update
, ripng
,
1936 sock
? 2 : ripng
->update_time
+ jitter
,
1939 case RIPNG_TRIGGERED_UPDATE
:
1940 if (ripng
->t_triggered_interval
)
1943 thread_add_event(master
, ripng_triggered_update
, ripng
,
1944 0, &ripng
->t_triggered_update
);
1952 /* Print out routes update time. */
1953 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1958 char timebuf
[TIME_BUF
];
1959 struct thread
*thread
;
1961 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1962 clock
= thread_timer_remain_second(thread
);
1963 gmtime_r(&clock
, &tm
);
1964 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1965 vty_out(vty
, "%5s", timebuf
);
1966 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1967 clock
= thread_timer_remain_second(thread
);
1968 gmtime_r(&clock
, &tm
);
1969 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1970 vty_out(vty
, "%5s", timebuf
);
1974 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1979 if (rinfo
->suppress
)
1980 strlcat(str
, "S", sizeof(str
));
1982 switch (rinfo
->sub_type
) {
1983 case RIPNG_ROUTE_RTE
:
1984 strlcat(str
, "n", sizeof(str
));
1986 case RIPNG_ROUTE_STATIC
:
1987 strlcat(str
, "s", sizeof(str
));
1989 case RIPNG_ROUTE_DEFAULT
:
1990 strlcat(str
, "d", sizeof(str
));
1992 case RIPNG_ROUTE_REDISTRIBUTE
:
1993 strlcat(str
, "r", sizeof(str
));
1995 case RIPNG_ROUTE_INTERFACE
:
1996 strlcat(str
, "i", sizeof(str
));
1999 strlcat(str
, "?", sizeof(str
));
2006 DEFUN (show_ipv6_ripng
,
2007 show_ipv6_ripng_cmd
,
2008 "show ipv6 ripng [vrf NAME]",
2011 "Show RIPng routes\n"
2014 struct ripng
*ripng
;
2015 struct agg_node
*rp
;
2016 struct ripng_info
*rinfo
;
2017 struct ripng_aggregate
*aggregate
;
2018 struct list
*list
= NULL
;
2019 struct listnode
*listnode
= NULL
;
2021 const char *vrf_name
;
2024 if (argv_find(argv
, argc
, "vrf", &idx
))
2025 vrf_name
= argv
[idx
+ 1]->arg
;
2027 vrf_name
= VRF_DEFAULT_NAME
;
2029 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2031 vty_out(vty
, "%% RIPng instance not found\n");
2034 if (!ripng
->enabled
) {
2035 vty_out(vty
, "%% RIPng instance is disabled\n");
2039 /* Header of display. */
2041 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2043 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2044 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2045 " Network Next Hop Via Metric Tag Time\n");
2047 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2048 if ((aggregate
= rp
->aggregate
) != NULL
) {
2050 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2051 aggregate
->suppress
, rp
);
2053 vty_out(vty
, "R(a) %pRN ", rp
);
2056 vty_out(vty
, "%*s", 18, " ");
2058 vty_out(vty
, "%*s", 28, " ");
2059 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2060 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2063 if ((list
= rp
->info
) != NULL
)
2064 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2066 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2067 zebra_route_char(rinfo
->type
),
2068 ripng_route_subtype_print(rinfo
),
2069 rinfo
->suppress
, rp
);
2071 vty_out(vty
, "%c(%s) %pRN ",
2072 zebra_route_char(rinfo
->type
),
2073 ripng_route_subtype_print(rinfo
), rp
);
2076 vty_out(vty
, "%*s", 18, " ");
2077 len
= vty_out(vty
, "%pI6",
2082 vty_out(vty
, "%*s", len
, " ");
2085 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2086 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2091 ripng
->vrf
->vrf_id
));
2092 } else if (rinfo
->metric
2093 == RIPNG_METRIC_INFINITY
) {
2094 len
= vty_out(vty
, "kill");
2096 len
= vty_out(vty
, "self");
2100 vty_out(vty
, "%*s", len
, " ");
2102 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2103 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2106 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2107 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2108 /* RTE from remote RIP routers */
2109 ripng_vty_out_uptime(vty
, rinfo
);
2110 } else if (rinfo
->metric
2111 == RIPNG_METRIC_INFINITY
) {
2112 /* poisonous reversed routes (gc) */
2113 ripng_vty_out_uptime(vty
, rinfo
);
2123 DEFUN (show_ipv6_ripng_status
,
2124 show_ipv6_ripng_status_cmd
,
2125 "show ipv6 ripng [vrf NAME] status",
2128 "Show RIPng routes\n"
2130 "IPv6 routing protocol process parameters and statistics\n")
2132 struct ripng
*ripng
;
2133 struct interface
*ifp
;
2134 const char *vrf_name
;
2137 if (argv_find(argv
, argc
, "vrf", &idx
))
2138 vrf_name
= argv
[idx
+ 1]->arg
;
2140 vrf_name
= VRF_DEFAULT_NAME
;
2142 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2144 vty_out(vty
, "%% RIPng instance not found\n");
2147 if (!ripng
->enabled
) {
2148 vty_out(vty
, "%% RIPng instance is disabled\n");
2152 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2153 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2154 ripng
->update_time
);
2155 vty_out(vty
, " next due in %lu seconds\n",
2156 thread_timer_remain_second(ripng
->t_update
));
2157 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2158 vty_out(vty
, " garbage collect after %u seconds\n",
2159 ripng
->garbage_time
);
2161 /* Filtering status show. */
2162 config_show_distribute(vty
, ripng
->distribute_ctx
);
2164 /* Default metric information. */
2165 vty_out(vty
, " Default redistribution metric is %d\n",
2166 ripng
->default_metric
);
2168 /* Redistribute information. */
2169 vty_out(vty
, " Redistributing:");
2170 ripng_redistribute_write(vty
, ripng
);
2173 vty_out(vty
, " Default version control: send version %d,",
2175 vty_out(vty
, " receive version %d \n", ripng
->version
);
2177 vty_out(vty
, " Interface Send Recv\n");
2179 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2180 struct ripng_interface
*ri
;
2184 if (ri
->enable_network
|| ri
->enable_interface
) {
2186 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2187 ripng
->version
, ripng
->version
);
2191 vty_out(vty
, " Routing for Networks:\n");
2192 ripng_network_write(vty
, ripng
);
2194 vty_out(vty
, " Routing Information Sources:\n");
2196 " Gateway BadPackets BadRoutes Distance Last Update\n");
2197 ripng_peer_display(vty
, ripng
);
2202 /* Update ECMP routes to zebra when ECMP is disabled. */
2203 void ripng_ecmp_disable(struct ripng
*ripng
)
2205 struct agg_node
*rp
;
2206 struct ripng_info
*rinfo
, *tmp_rinfo
;
2208 struct listnode
*node
, *nextnode
;
2213 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2214 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2215 rinfo
= listgetdata(listhead(list
));
2216 if (!ripng_route_rte(rinfo
))
2219 /* Drop all other entries, except the first one. */
2220 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2221 if (tmp_rinfo
!= rinfo
) {
2222 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2224 tmp_rinfo
->t_garbage_collect
);
2225 list_delete_node(list
, node
);
2226 ripng_info_free(tmp_rinfo
);
2230 ripng_zebra_ipv6_add(ripng
, rp
);
2232 /* Set the route change flag. */
2233 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2235 /* Signal the output process to trigger an update. */
2236 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2240 /* RIPng configuration write function. */
2241 static int ripng_config_write(struct vty
*vty
)
2243 struct ripng
*ripng
;
2246 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2247 char xpath
[XPATH_MAXLEN
];
2248 struct lyd_node
*dnode
;
2250 snprintf(xpath
, sizeof(xpath
),
2251 "/frr-ripngd:ripngd/instance[vrf='%s']",
2254 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2257 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2259 config_write_distribute(vty
, ripng
->distribute_ctx
);
2260 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2262 vty_out(vty
, "exit\n");
2270 static int ripng_config_write(struct vty
*vty
);
2271 /* RIPng node structure. */
2272 static struct cmd_node cmd_ripng_node
= {
2275 .parent_node
= CONFIG_NODE
,
2276 .prompt
= "%s(config-router)# ",
2277 .config_write
= ripng_config_write
,
2280 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2281 struct distribute
*dist
)
2283 struct interface
*ifp
;
2284 struct ripng_interface
*ri
;
2285 struct access_list
*alist
;
2286 struct prefix_list
*plist
;
2288 if (!ctx
->vrf
|| !dist
->ifname
)
2291 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2297 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2298 alist
= access_list_lookup(AFI_IP6
,
2299 dist
->list
[DISTRIBUTE_V6_IN
]);
2301 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2303 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2305 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2307 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2308 alist
= access_list_lookup(AFI_IP6
,
2309 dist
->list
[DISTRIBUTE_V6_OUT
]);
2311 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2313 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2315 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2317 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2318 plist
= prefix_list_lookup(AFI_IP6
,
2319 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2321 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2323 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2325 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2327 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2328 plist
= prefix_list_lookup(AFI_IP6
,
2329 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2331 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2333 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2335 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2338 void ripng_distribute_update_interface(struct interface
*ifp
)
2340 struct ripng_interface
*ri
= ifp
->info
;
2341 struct ripng
*ripng
= ri
->ripng
;
2342 struct distribute
*dist
;
2346 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2348 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2351 /* Update all interface's distribute list. */
2352 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2354 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2355 struct interface
*ifp
;
2357 FOR_ALL_INTERFACES (vrf
, ifp
)
2358 ripng_distribute_update_interface(ifp
);
2361 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2363 ripng_distribute_update_all(NULL
);
2366 /* delete all the added ripng routes. */
2367 void ripng_clean(struct ripng
*ripng
)
2369 ripng_interface_clean(ripng
);
2372 ripng_instance_disable(ripng
);
2374 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2375 if (ripng
->redist
[i
].route_map
.name
)
2376 free(ripng
->redist
[i
].route_map
.name
);
2378 agg_table_finish(ripng
->table
);
2379 list_delete(&ripng
->peer_list
);
2380 distribute_list_delete(&ripng
->distribute_ctx
);
2381 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2383 stream_free(ripng
->ibuf
);
2384 stream_free(ripng
->obuf
);
2386 ripng_clean_network(ripng
);
2387 ripng_passive_interface_clean(ripng
);
2388 vector_free(ripng
->enable_if
);
2389 agg_table_finish(ripng
->enable_network
);
2390 vector_free(ripng
->passive_interface
);
2391 list_delete(&ripng
->offset_list_master
);
2393 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2394 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2395 XFREE(MTYPE_RIPNG
, ripng
);
2398 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2399 struct if_rmap
*if_rmap
)
2401 struct interface
*ifp
= NULL
;
2402 struct ripng_interface
*ri
;
2403 struct route_map
*rmap
;
2404 struct vrf
*vrf
= NULL
;
2407 vrf
= vrf_lookup_by_name(ctx
->name
);
2409 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2415 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2416 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2418 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2420 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2422 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2424 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2425 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2427 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2429 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2431 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2434 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2436 struct ripng_interface
*ri
= ifp
->info
;
2437 struct ripng
*ripng
= ri
->ripng
;
2438 struct if_rmap
*if_rmap
;
2439 struct if_rmap_ctx
*ctx
;
2443 ctx
= ripng
->if_rmap_ctx
;
2446 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2448 ripng_if_rmap_update(ctx
, if_rmap
);
2451 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2453 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2454 if (ripng
->redist
[i
].route_map
.name
) {
2455 ripng
->redist
[i
].route_map
.map
=
2456 route_map_lookup_by_name(
2457 ripng
->redist
[i
].route_map
.name
);
2458 route_map_counter_increment(
2459 ripng
->redist
[i
].route_map
.map
);
2464 static void ripng_routemap_update(const char *unused
)
2466 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2467 struct ripng
*ripng
;
2468 struct interface
*ifp
;
2470 FOR_ALL_INTERFACES (vrf
, ifp
)
2471 ripng_if_rmap_update_interface(ifp
);
2475 ripng_routemap_update_redistribute(ripng
);
2478 /* Link RIPng instance to VRF. */
2479 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2481 struct interface
*ifp
;
2484 ripng
->distribute_ctx
->vrf
= vrf
;
2487 FOR_ALL_INTERFACES (vrf
, ifp
)
2488 ripng_interface_sync(ifp
);
2491 /* Unlink RIPng instance from VRF. */
2492 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2494 struct interface
*ifp
;
2497 ripng
->distribute_ctx
->vrf
= NULL
;
2500 FOR_ALL_INTERFACES (vrf
, ifp
)
2501 ripng_interface_sync(ifp
);
2504 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2509 ripng_vrf_link(ripng
, vrf
);
2510 ripng
->enabled
= true;
2512 /* Resend all redistribute requests. */
2513 ripng_redistribute_enable(ripng
);
2515 /* Create read and timer thread. */
2516 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2517 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2519 ripng_zebra_vrf_register(vrf
);
2522 static void ripng_instance_disable(struct ripng
*ripng
)
2524 struct vrf
*vrf
= ripng
->vrf
;
2525 struct agg_node
*rp
;
2527 /* Clear RIPng routes */
2528 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2529 struct ripng_aggregate
*aggregate
;
2532 if ((list
= rp
->info
) != NULL
) {
2533 struct ripng_info
*rinfo
;
2534 struct listnode
*listnode
;
2536 rinfo
= listgetdata(listhead(list
));
2537 if (ripng_route_rte(rinfo
))
2538 ripng_zebra_ipv6_delete(ripng
, rp
);
2540 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2541 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2542 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2543 ripng_info_free(rinfo
);
2547 agg_unlock_node(rp
);
2550 if ((aggregate
= rp
->aggregate
) != NULL
) {
2551 ripng_aggregate_free(aggregate
);
2552 rp
->aggregate
= NULL
;
2553 agg_unlock_node(rp
);
2557 /* Flush all redistribute requests. */
2558 ripng_redistribute_disable(ripng
);
2560 /* Cancel the RIPng timers */
2561 RIPNG_TIMER_OFF(ripng
->t_update
);
2562 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2563 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2565 /* Cancel the read thread */
2566 thread_cancel(&ripng
->t_read
);
2568 /* Close the RIPng socket */
2569 if (ripng
->sock
>= 0) {
2574 /* Clear existing peers. */
2575 list_delete_all_node(ripng
->peer_list
);
2577 ripng_zebra_vrf_deregister(vrf
);
2579 ripng_vrf_unlink(ripng
, vrf
);
2580 ripng
->enabled
= false;
2583 static int ripng_vrf_new(struct vrf
*vrf
)
2585 if (IS_RIPNG_DEBUG_EVENT
)
2586 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2592 static int ripng_vrf_delete(struct vrf
*vrf
)
2594 if (IS_RIPNG_DEBUG_EVENT
)
2595 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2601 static int ripng_vrf_enable(struct vrf
*vrf
)
2603 struct ripng
*ripng
;
2606 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2607 if (!ripng
|| ripng
->enabled
)
2610 if (IS_RIPNG_DEBUG_EVENT
)
2611 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2614 /* Activate the VRF RIPng instance. */
2615 socket
= ripng_make_socket(vrf
);
2619 ripng_instance_enable(ripng
, vrf
, socket
);
2624 static int ripng_vrf_disable(struct vrf
*vrf
)
2626 struct ripng
*ripng
;
2628 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2629 if (!ripng
|| !ripng
->enabled
)
2632 if (IS_RIPNG_DEBUG_EVENT
)
2633 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2636 /* Deactivate the VRF RIPng instance. */
2638 ripng_instance_disable(ripng
);
2643 void ripng_vrf_init(void)
2645 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2651 void ripng_vrf_terminate(void)
2656 /* Initialize ripng structure and set commands. */
2657 void ripng_init(void)
2659 /* Install RIPNG_NODE. */
2660 install_node(&cmd_ripng_node
);
2662 /* Install ripng commands. */
2663 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2664 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2666 install_default(RIPNG_NODE
);
2671 /* Access list install. */
2673 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2674 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2676 /* Prefix list initialize.*/
2678 prefix_list_add_hook(ripng_distribute_update_all
);
2679 prefix_list_delete_hook(ripng_distribute_update_all
);
2681 /* Route-map for interface. */
2682 ripng_route_map_init();
2684 route_map_add_hook(ripng_routemap_update
);
2685 route_map_delete_hook(ripng_routemap_update
);
2687 if_rmap_init(RIPNG_NODE
);