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 %s", inet6_ntoa(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 %s: %s",
241 ifp
->name
, inet6_ntoa(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 %s/%d", inet6_ntoa(rte
->addr
),
344 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
345 inet6_ntoa(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 %s tag %" ROUTE_TAG_PRI
358 inet6_ntoa(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
),
369 inet6_ntoa(from
->sin6_addr
));
371 if (rte
->prefixlen
!= 0)
373 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
374 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
376 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
377 next hop RTE indicates that the next hop address should be the
378 originator of the RIPng advertisement. An address specified as a
379 next hop must be a link-local address. */
380 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
381 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
382 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
386 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
387 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
388 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
392 /* The purpose of the next hop RTE is to eliminate packets being
393 routed through extra hops in the system. It is particularly useful
394 when RIPng is not being run on all of the routers on a network.
395 Note that next hop RTE is "advisory". That is, if the provided
396 information is ignored, a possibly sub-optimal, but absolutely
397 valid, route may be taken. If the received next hop address is not
398 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
399 zlog_warn("RIPng nexthop RTE with non link-local address %s from %pI6",
400 inet6_ntoa(rte
->addr
), &from
->sin6_addr
);
402 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
403 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
408 /* If ifp has same link-local address then return 1. */
409 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
411 struct listnode
*node
;
412 struct connected
*connected
;
415 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
416 p
= connected
->address
;
418 if (p
->family
== AF_INET6
419 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
420 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
426 /* RIPng route garbage collect timer. */
427 static int ripng_garbage_collect(struct thread
*t
)
429 struct ripng_info
*rinfo
;
432 rinfo
= THREAD_ARG(t
);
433 rinfo
->t_garbage_collect
= NULL
;
435 /* Off timeout timer. */
436 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
438 /* Get route_node pointer. */
441 /* Unlock route_node. */
442 listnode_delete(rp
->info
, rinfo
);
443 if (list_isempty((struct list
*)rp
->info
)) {
444 list_delete((struct list
**)&rp
->info
);
448 /* Free RIPng routing information. */
449 ripng_info_free(rinfo
);
454 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
456 /* Add new route to the ECMP list.
457 * RETURN: the new entry added in the list, or NULL if it is not the first
458 * entry and ECMP is not allowed.
460 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
461 struct ripng_info
*rinfo_new
)
463 struct agg_node
*rp
= rinfo_new
->rp
;
464 struct ripng_info
*rinfo
= NULL
;
465 struct list
*list
= NULL
;
467 if (rp
->info
== NULL
)
468 rp
->info
= list_new();
469 list
= (struct list
*)rp
->info
;
471 /* If ECMP is not allowed and some entry already exists in the list,
473 if (listcount(list
) && !ripng
->ecmp
)
476 rinfo
= ripng_info_new();
477 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
478 listnode_add(list
, rinfo
);
480 if (ripng_route_rte(rinfo
)) {
481 ripng_timeout_update(ripng
, rinfo
);
482 ripng_zebra_ipv6_add(ripng
, rp
);
485 ripng_aggregate_increment(rp
, rinfo
);
487 /* Set the route change flag on the first entry. */
488 rinfo
= listgetdata(listhead(list
));
489 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
491 /* Signal the output process to trigger an update. */
492 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
497 /* Replace the ECMP list with the new route.
498 * RETURN: the new entry added in the list
500 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
501 struct ripng_info
*rinfo_new
)
503 struct agg_node
*rp
= rinfo_new
->rp
;
504 struct list
*list
= (struct list
*)rp
->info
;
505 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
506 struct listnode
*node
= NULL
, *nextnode
= NULL
;
508 if (list
== NULL
|| listcount(list
) == 0)
509 return ripng_ecmp_add(ripng
, rinfo_new
);
511 /* Get the first entry */
512 rinfo
= listgetdata(listhead(list
));
514 /* Learnt route replaced by a local one. Delete it from zebra. */
515 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
516 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
517 ripng_zebra_ipv6_delete(ripng
, rp
);
519 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
520 ripng_aggregate_decrement_list(rp
, list
);
522 /* Re-use the first entry, and delete the others. */
523 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
524 if (tmp_rinfo
!= rinfo
) {
525 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
526 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
527 list_delete_node(list
, node
);
528 ripng_info_free(tmp_rinfo
);
531 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
532 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
533 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
535 if (ripng_route_rte(rinfo
)) {
536 ripng_timeout_update(ripng
, rinfo
);
537 /* The ADD message implies an update. */
538 ripng_zebra_ipv6_add(ripng
, rp
);
541 ripng_aggregate_increment(rp
, rinfo
);
543 /* Set the route change flag. */
544 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
546 /* Signal the output process to trigger an update. */
547 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
552 /* Delete one route from the ECMP list.
554 * null - the entry is freed, and other entries exist in the list
555 * the entry - the entry is the last one in the list; its metric is set
556 * to INFINITY, and the garbage collector is started for it
558 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
559 struct ripng_info
*rinfo
)
561 struct agg_node
*rp
= rinfo
->rp
;
562 struct list
*list
= (struct list
*)rp
->info
;
564 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
566 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
567 ripng_aggregate_decrement(rp
, rinfo
);
569 if (listcount(list
) > 1) {
570 /* Some other ECMP entries still exist. Just delete this entry.
572 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
573 listnode_delete(list
, rinfo
);
574 if (ripng_route_rte(rinfo
)
575 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
576 /* The ADD message implies the update. */
577 ripng_zebra_ipv6_add(ripng
, rp
);
578 ripng_info_free(rinfo
);
581 assert(rinfo
== listgetdata(listhead(list
)));
583 /* This is the only entry left in the list. We must keep it in
584 * the list for garbage collection time, with INFINITY metric.
587 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
588 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
589 ripng
->garbage_time
);
591 if (ripng_route_rte(rinfo
)
592 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
593 ripng_zebra_ipv6_delete(ripng
, rp
);
596 /* Set the route change flag on the first entry. */
597 rinfo
= listgetdata(listhead(list
));
598 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
600 /* Signal the output process to trigger an update. */
601 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
606 /* Timeout RIPng routes. */
607 static int ripng_timeout(struct thread
*t
)
609 struct ripng_info
*rinfo
= THREAD_ARG(t
);
610 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
612 ripng_ecmp_delete(ripng
, rinfo
);
617 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
619 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
620 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
621 thread_add_timer(master
, ripng_timeout
, rinfo
,
622 ripng
->timeout_time
, &rinfo
->t_timeout
);
626 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
627 struct ripng_interface
*ri
)
629 struct distribute
*dist
;
630 struct access_list
*alist
;
631 struct prefix_list
*plist
;
632 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
635 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
637 /* Input distribute-list filtering. */
638 if (ri
->list
[ripng_distribute
]) {
639 if (access_list_apply(ri
->list
[ripng_distribute
],
642 if (IS_RIPNG_DEBUG_PACKET
)
643 zlog_debug("%pFX filtered by distribute %s", p
,
648 if (ri
->prefix
[ripng_distribute
]) {
649 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
652 if (IS_RIPNG_DEBUG_PACKET
)
653 zlog_debug("%pFX filtered by prefix-list %s", p
,
659 /* All interface filter check. */
660 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
662 if (dist
->list
[distribute
]) {
663 alist
= access_list_lookup(AFI_IP6
,
664 dist
->list
[distribute
]);
667 if (access_list_apply(alist
, (struct prefix
*)p
)
669 if (IS_RIPNG_DEBUG_PACKET
)
671 "%pFX filtered by distribute %s",
677 if (dist
->prefix
[distribute
]) {
678 plist
= prefix_list_lookup(AFI_IP6
,
679 dist
->prefix
[distribute
]);
682 if (prefix_list_apply(plist
, (struct prefix
*)p
)
684 if (IS_RIPNG_DEBUG_PACKET
)
686 "%pFX filtered by prefix-list %s",
696 /* Process RIPng route according to RFC2080. */
697 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
698 struct ripng_nexthop
*ripng_nexthop
,
699 struct interface
*ifp
)
702 struct prefix_ipv6 p
;
704 struct ripng_info
*rinfo
= NULL
, newinfo
;
705 struct ripng_interface
*ri
;
707 struct in6_addr
*nexthop
;
709 struct list
*list
= NULL
;
710 struct listnode
*node
= NULL
;
712 /* Make prefix structure. */
713 memset(&p
, 0, sizeof(struct prefix_ipv6
));
715 /* p.prefix = rte->addr; */
716 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
717 p
.prefixlen
= rte
->prefixlen
;
719 /* Make sure mask is applied. */
720 /* XXX We have to check the prefix is valid or not before call
727 /* Apply input filters. */
728 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
732 memset(&newinfo
, 0, sizeof(newinfo
));
733 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
734 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
735 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
736 newinfo
.nexthop
= ripng_nexthop
->address
;
738 newinfo
.nexthop
= from
->sin6_addr
;
739 newinfo
.from
= from
->sin6_addr
;
740 newinfo
.ifindex
= ifp
->ifindex
;
741 newinfo
.metric
= rte
->metric
;
742 newinfo
.metric_out
= rte
->metric
; /* XXX */
743 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
746 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
747 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
748 (struct prefix
*)&p
, &newinfo
);
750 if (ret
== RMAP_DENYMATCH
) {
751 if (IS_RIPNG_DEBUG_PACKET
)
753 "RIPng %s/%d is filtered by route-map in",
754 inet6_ntoa(p
.prefix
), p
.prefixlen
);
758 /* Get back the object */
759 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
760 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
761 &ripng_nexthop
->address
)) {
762 /* the nexthop get changed by the routemap */
763 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
764 ripng_nexthop
->address
=
767 ripng_nexthop
->address
= in6addr_any
;
770 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
772 /* the nexthop get changed by the routemap */
773 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
774 ripng_nexthop
->flag
=
775 RIPNG_NEXTHOP_ADDRESS
;
776 ripng_nexthop
->address
=
781 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
783 newinfo
.metric_out
; /* XXX: the routemap uses the
787 /* Once the entry has been validated, update the metric by
788 * adding the cost of the network on wich the message
789 * arrived. If the result is greater than infinity, use infinity
790 * (RFC2453 Sec. 3.9.2)
793 /* Zebra ripngd can handle offset-list in. */
794 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
796 /* If offset-list does not modify the metric use interface's
799 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
801 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
802 rte
->metric
= RIPNG_METRIC_INFINITY
;
804 /* Set nexthop pointer. */
805 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
806 nexthop
= &ripng_nexthop
->address
;
808 nexthop
= &from
->sin6_addr
;
810 /* Lookup RIPng routing table. */
811 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
814 newinfo
.nexthop
= *nexthop
;
815 newinfo
.metric
= rte
->metric
;
816 newinfo
.tag
= ntohs(rte
->tag
);
818 /* Check to see whether there is already RIPng route on the table. */
819 if ((list
= rp
->info
) != NULL
)
820 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
821 /* Need to compare with redistributed entry or local
823 if (!ripng_route_rte(rinfo
))
826 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
827 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
830 if (!listnextnode(node
)) {
831 /* Not found in the list */
833 if (rte
->metric
> rinfo
->metric
) {
834 /* New route has a greater metric.
840 if (rte
->metric
< rinfo
->metric
)
841 /* New route has a smaller metric.
842 * Replace the ECMP list
843 * with the new one in below. */
846 /* Metrics are same. Unless ECMP is disabled,
847 * keep "rinfo" null and
848 * the new route is added in the ECMP list in
856 /* Redistributed route check. */
857 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
858 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
863 /* Local static route. */
864 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
865 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
866 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
867 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
874 /* Now, check to see whether there is already an explicit route
875 for the destination prefix. If there is no such route, add
876 this route to the routing table, unless the metric is
877 infinity (there is no point in adding a route which
879 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
880 ripng_ecmp_add(ripng
, &newinfo
);
884 /* If there is an existing route, compare the next hop address
885 to the address of the router from which the datagram came.
886 If this datagram is from the same router as the existing
887 route, reinitialize the timeout. */
888 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
889 && (rinfo
->ifindex
== ifp
->ifindex
));
892 * RFC 2080 - Section 2.4.2:
893 * "If the new metric is the same as the old one, examine the
895 * for the existing route. If it is at least halfway to the
897 * point, switch to the new route. This heuristic is optional,
899 * highly recommended".
901 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
903 && (thread_timer_remain_second(rinfo
->t_timeout
)
904 < (ripng
->timeout_time
/ 2))) {
905 ripng_ecmp_replace(ripng
, &newinfo
);
907 /* Next, compare the metrics. If the datagram is from the same
908 router as the existing route, and the new metric is different
909 than the old one; or, if the new metric is lower than the old
910 one; do the following actions: */
911 else if ((same
&& rinfo
->metric
!= rte
->metric
)
912 || rte
->metric
< rinfo
->metric
) {
913 if (listcount(list
) == 1) {
914 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
915 ripng_ecmp_replace(ripng
, &newinfo
);
917 ripng_ecmp_delete(ripng
, rinfo
);
919 if (newinfo
.metric
< rinfo
->metric
)
920 ripng_ecmp_replace(ripng
, &newinfo
);
921 else /* newinfo.metric > rinfo->metric */
922 ripng_ecmp_delete(ripng
, rinfo
);
924 } else /* same & no change */
925 ripng_timeout_update(ripng
, rinfo
);
927 /* Unlock tempolary lock of the route. */
932 /* Add redistributed route to RIPng table. */
933 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
934 struct prefix_ipv6
*p
, ifindex_t ifindex
,
935 struct in6_addr
*nexthop
, route_tag_t tag
)
938 struct ripng_info
*rinfo
= NULL
, newinfo
;
939 struct list
*list
= NULL
;
941 /* Redistribute route */
942 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
944 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
947 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
949 memset(&newinfo
, 0, sizeof(struct ripng_info
));
951 newinfo
.sub_type
= sub_type
;
952 newinfo
.ifindex
= ifindex
;
954 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
957 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
958 newinfo
.nexthop
= *nexthop
;
960 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
961 rinfo
= listgetdata(listhead(list
));
963 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
964 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
965 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
970 /* Manually configured RIPng route check.
971 * They have the precedence on all the other entries.
973 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
974 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
975 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
976 if (type
!= ZEBRA_ROUTE_RIPNG
977 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
978 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
984 ripng_ecmp_replace(ripng
, &newinfo
);
987 ripng_ecmp_add(ripng
, &newinfo
);
989 if (IS_RIPNG_DEBUG_EVENT
) {
992 "Redistribute new prefix %pFX on the interface %s",
993 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
996 "Redistribute new prefix %pFX with nexthop %s on the interface %s",
997 p
, inet6_ntoa(*nexthop
),
998 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1001 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1004 /* Delete redistributed route to RIPng table. */
1005 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1006 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1008 struct agg_node
*rp
;
1009 struct ripng_info
*rinfo
;
1011 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1013 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1016 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1019 struct list
*list
= rp
->info
;
1021 if (list
!= NULL
&& listcount(list
) != 0) {
1022 rinfo
= listgetdata(listhead(list
));
1023 if (rinfo
!= NULL
&& rinfo
->type
== type
1024 && rinfo
->sub_type
== sub_type
1025 && rinfo
->ifindex
== ifindex
) {
1026 /* Perform poisoned reverse. */
1027 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1028 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1029 ripng_garbage_collect
,
1030 ripng
->garbage_time
);
1031 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1033 /* Aggregate count decrement. */
1034 ripng_aggregate_decrement(rp
, rinfo
);
1036 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1038 if (IS_RIPNG_DEBUG_EVENT
)
1040 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1044 ripng
->vrf
->vrf_id
));
1046 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1049 agg_unlock_node(rp
);
1053 /* Withdraw redistributed route. */
1054 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1056 struct agg_node
*rp
;
1057 struct ripng_info
*rinfo
= NULL
;
1058 struct list
*list
= NULL
;
1060 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1061 if ((list
= rp
->info
) != NULL
) {
1062 rinfo
= listgetdata(listhead(list
));
1063 if ((rinfo
->type
== type
)
1064 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1065 /* Perform poisoned reverse. */
1066 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1067 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1068 ripng_garbage_collect
,
1069 ripng
->garbage_time
);
1070 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1072 /* Aggregate count decrement. */
1073 ripng_aggregate_decrement(rp
, rinfo
);
1075 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1077 if (IS_RIPNG_DEBUG_EVENT
) {
1078 struct prefix_ipv6
*p
=
1079 (struct prefix_ipv6
*)
1080 agg_node_get_prefix(rp
);
1083 "Poisone %pFX on the interface %s [withdraw]",
1087 ripng
->vrf
->vrf_id
));
1090 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1095 /* RIP routing information. */
1096 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1097 struct sockaddr_in6
*from
,
1098 struct interface
*ifp
, int hoplimit
)
1100 struct ripng_interface
*ri
= ifp
->info
;
1101 struct ripng
*ripng
= ri
->ripng
;
1104 struct ripng_nexthop nexthop
;
1106 /* RFC2080 2.4.2 Response Messages:
1107 The Response must be ignored if it is not from the RIPng port. */
1108 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1109 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1110 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1111 ripng_peer_bad_packet(ripng
, from
);
1115 /* The datagram's IPv6 source address should be checked to see
1116 whether the datagram is from a valid neighbor; the source of the
1117 datagram must be a link-local address. */
1118 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1119 zlog_warn("RIPng packet comes from non link local address %s",
1120 inet6_ntoa(from
->sin6_addr
));
1121 ripng_peer_bad_packet(ripng
, from
);
1125 /* It is also worth checking to see whether the response is from one
1126 of the router's own addresses. Interfaces on broadcast networks
1127 may receive copies of their own multicasts immediately. If a
1128 router processes its own output as new input, confusion is likely,
1129 and such datagrams must be ignored. */
1130 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1132 "RIPng packet comes from my own link local address %s",
1133 inet6_ntoa(from
->sin6_addr
));
1134 ripng_peer_bad_packet(ripng
, from
);
1138 /* As an additional check, periodic advertisements must have their
1139 hop counts set to 255, and inbound, multicast packets sent from the
1140 RIPng port (i.e. periodic advertisement or triggered update
1141 packets) must be examined to ensure that the hop count is 255. */
1142 if (hoplimit
>= 0 && hoplimit
!= 255) {
1144 "RIPng packet comes with non 255 hop count %d from %s",
1145 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1146 ripng_peer_bad_packet(ripng
, from
);
1150 /* Update RIPng peer. */
1151 ripng_peer_update(ripng
, from
, packet
->version
);
1153 /* Reset nexthop. */
1154 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1155 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1157 /* Set RTE pointer. */
1160 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1161 /* First of all, we have to check this RTE is next hop RTE or
1162 not. Next hop RTE is completely different with normal RTE so
1163 we need special treatment. */
1164 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1165 ripng_nexthop_rte(rte
, from
, &nexthop
);
1169 /* RTE information validation. */
1171 /* - is the destination prefix valid (e.g., not a multicast
1172 prefix and not a link-local address) A link-local address
1173 should never be present in an RTE. */
1174 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1176 "Destination prefix is a multicast address %s/%d [%d]",
1177 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1179 ripng_peer_bad_route(ripng
, from
);
1182 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1184 "Destination prefix is a link-local address %s/%d [%d]",
1185 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1187 ripng_peer_bad_route(ripng
, from
);
1190 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1192 "Destination prefix is a loopback address %s/%d [%d]",
1193 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1195 ripng_peer_bad_route(ripng
, from
);
1199 /* - is the prefix length valid (i.e., between 0 and 128,
1201 if (rte
->prefixlen
> 128) {
1202 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1203 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1204 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1205 ripng_peer_bad_route(ripng
, from
);
1209 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1210 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1211 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1212 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1213 ripng_peer_bad_route(ripng
, from
);
1217 /* Vincent: XXX Should we compute the direclty reachable nexthop
1218 * for our RIPng network ?
1221 /* Routing table updates. */
1222 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1226 /* Response to request message. */
1227 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1228 struct sockaddr_in6
*from
,
1229 struct interface
*ifp
)
1231 struct ripng
*ripng
;
1234 struct prefix_ipv6 p
;
1235 struct agg_node
*rp
;
1236 struct ripng_info
*rinfo
;
1237 struct ripng_interface
*ri
;
1239 /* Does not reponse to the requests on the loopback interfaces */
1240 if (if_is_loopback(ifp
))
1243 /* Check RIPng process is enabled on this interface. */
1249 /* When passive interface is specified, suppress responses */
1253 /* RIPng peer update. */
1254 ripng_peer_update(ripng
, from
, packet
->version
);
1256 lim
= ((caddr_t
)packet
) + size
;
1259 /* The Request is processed entry by entry. If there are no
1260 entries, no response is given. */
1261 if (lim
== (caddr_t
)rte
)
1264 /* There is one special case. If there is exactly one entry in the
1265 request, and it has a destination prefix of zero, a prefix length
1266 of zero, and a metric of infinity (i.e., 16), then this is a
1267 request to send the entire routing table. In that case, a call
1268 is made to the output process to send the routing table to the
1269 requesting address/port. */
1270 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1271 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1272 /* All route with split horizon */
1273 ripng_output_process(ifp
, from
, ripng_all_route
);
1275 /* Except for this special case, processing is quite simple.
1276 Examine the list of RTEs in the Request one by one. For each
1277 entry, look up the destination in the router's routing
1278 database and, if there is a route, put that route's metric in
1279 the metric field of the RTE. If there is no explicit route
1280 to the specified destination, put infinity in the metric
1281 field. Once all the entries have been filled in, change the
1282 command from Request to Response and send the datagram back
1283 to the requestor. */
1284 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1285 p
.family
= AF_INET6
;
1287 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1288 p
.prefix
= rte
->addr
;
1289 p
.prefixlen
= rte
->prefixlen
;
1290 apply_mask_ipv6(&p
);
1292 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1295 rinfo
= listgetdata(
1296 listhead((struct list
*)rp
->info
));
1297 rte
->metric
= rinfo
->metric
;
1298 agg_unlock_node(rp
);
1300 rte
->metric
= RIPNG_METRIC_INFINITY
;
1302 packet
->command
= RIPNG_RESPONSE
;
1304 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1308 /* First entry point of reading RIPng packet. */
1309 static int ripng_read(struct thread
*thread
)
1311 struct ripng
*ripng
= THREAD_ARG(thread
);
1314 struct sockaddr_in6 from
;
1315 struct ripng_packet
*packet
;
1316 ifindex_t ifindex
= 0;
1317 struct interface
*ifp
;
1320 /* Check ripng is active and alive. */
1321 assert(ripng
!= NULL
);
1322 assert(ripng
->sock
>= 0);
1324 /* Fetch thread data and set read pointer to empty for event
1325 managing. `sock' sould be same as ripng->sock. */
1326 sock
= THREAD_FD(thread
);
1327 ripng
->t_read
= NULL
;
1329 /* Add myself to the next event. */
1330 ripng_event(ripng
, RIPNG_READ
, sock
);
1332 /* Read RIPng packet. */
1333 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1334 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1337 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1338 ripng
->vrf_name
, safe_strerror(errno
));
1342 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1343 (4)) must be multiple size of one RTE size (20). */
1344 if (((len
- 4) % 20) != 0) {
1345 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1346 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1347 ripng_peer_bad_packet(ripng
, &from
);
1351 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1352 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1354 /* RIPng packet received. */
1355 if (IS_RIPNG_DEBUG_EVENT
)
1357 "RIPng packet received from %s port %d on %s (VRF %s)",
1358 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1359 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1361 /* Logging before packet checking. */
1362 if (IS_RIPNG_DEBUG_RECV
)
1363 ripng_packet_dump(packet
, len
, "RECV");
1365 /* Packet comes from unknown interface. */
1368 "RIPng packet comes from unknown interface %d (VRF %s)",
1369 ifindex
, ripng
->vrf_name
);
1373 /* Packet version mismatch checking. */
1374 if (packet
->version
!= ripng
->version
) {
1376 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1377 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1378 ripng_peer_bad_packet(ripng
, &from
);
1382 /* Process RIPng packet. */
1383 switch (packet
->command
) {
1385 ripng_request_process(packet
, len
, &from
, ifp
);
1387 case RIPNG_RESPONSE
:
1388 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1391 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1393 ripng_peer_bad_packet(ripng
, &from
);
1399 /* Walk down the RIPng routing table then clear changed flag. */
1400 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1402 struct agg_node
*rp
;
1403 struct ripng_info
*rinfo
= NULL
;
1404 struct list
*list
= NULL
;
1405 struct listnode
*listnode
= NULL
;
1407 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1408 if ((list
= rp
->info
) != NULL
)
1409 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1410 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1411 /* This flag can be set only on the first entry.
1417 /* Regular update of RIPng route. Send all routing formation to RIPng
1418 enabled interface. */
1419 static int ripng_update(struct thread
*t
)
1421 struct ripng
*ripng
= THREAD_ARG(t
);
1422 struct interface
*ifp
;
1423 struct ripng_interface
*ri
;
1425 /* Clear update timer thread. */
1426 ripng
->t_update
= NULL
;
1428 /* Logging update event. */
1429 if (IS_RIPNG_DEBUG_EVENT
)
1430 zlog_debug("RIPng update timer expired!");
1432 /* Supply routes to each interface. */
1433 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1436 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1442 /* When passive interface is specified, suppress announce to the
1447 #ifdef RIPNG_ADVANCED
1448 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1449 if (IS_RIPNG_DEBUG_EVENT
)
1451 "[Event] RIPng send to if %d is suppressed by config",
1455 #endif /* RIPNG_ADVANCED */
1457 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1460 /* Triggered updates may be suppressed if a regular update is due by
1461 the time the triggered update would be sent. */
1462 thread_cancel(&ripng
->t_triggered_interval
);
1465 /* Reset flush event. */
1466 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1471 /* Triggered update interval timer. */
1472 static int ripng_triggered_interval(struct thread
*t
)
1474 struct ripng
*ripng
= THREAD_ARG(t
);
1476 ripng
->t_triggered_interval
= NULL
;
1478 if (ripng
->trigger
) {
1480 ripng_triggered_update(t
);
1485 /* Execute triggered update. */
1486 int ripng_triggered_update(struct thread
*t
)
1488 struct ripng
*ripng
= THREAD_ARG(t
);
1489 struct interface
*ifp
;
1490 struct ripng_interface
*ri
;
1493 ripng
->t_triggered_update
= NULL
;
1495 /* Cancel interval timer. */
1496 thread_cancel(&ripng
->t_triggered_interval
);
1499 /* Logging triggered update. */
1500 if (IS_RIPNG_DEBUG_EVENT
)
1501 zlog_debug("RIPng triggered update!");
1503 /* Split Horizon processing is done when generating triggered
1504 updates as well as normal updates (see section 2.6). */
1505 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1508 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1514 /* When passive interface is specified, suppress announce to the
1519 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1522 /* Once all of the triggered updates have been generated, the route
1523 change flags should be cleared. */
1524 ripng_clear_changed_flag(ripng
);
1526 /* After a triggered update is sent, a timer should be set for a
1527 random interval between 1 and 5 seconds. If other changes that
1528 would trigger updates occur before the timer expires, a single
1529 update is triggered when the timer expires. */
1530 interval
= (frr_weak_random() % 5) + 1;
1532 ripng
->t_triggered_interval
= NULL
;
1533 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1534 &ripng
->t_triggered_interval
);
1539 /* Write routing table entry to the stream and return next index of
1540 the routing table entry in the stream. */
1541 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1542 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1544 /* RIPng packet header. */
1546 stream_putc(s
, RIPNG_RESPONSE
);
1547 stream_putc(s
, RIPNG_V1
);
1551 /* Write routing table entry. */
1554 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1556 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1557 stream_putw(s
, tag
);
1559 stream_putc(s
, p
->prefixlen
);
1562 stream_putc(s
, metric
);
1567 /* Send RESPONSE message to specified destination. */
1568 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1571 struct ripng
*ripng
;
1573 struct agg_node
*rp
;
1574 struct ripng_info
*rinfo
;
1575 struct ripng_interface
*ri
;
1576 struct ripng_aggregate
*aggregate
;
1577 struct prefix_ipv6
*p
;
1578 struct list
*ripng_rte_list
;
1579 struct list
*list
= NULL
;
1580 struct listnode
*listnode
= NULL
;
1582 if (IS_RIPNG_DEBUG_EVENT
) {
1584 zlog_debug("RIPng update routes to neighbor %s",
1585 inet6_ntoa(to
->sin6_addr
));
1587 zlog_debug("RIPng update routes on interface %s",
1591 /* Get RIPng interface and instance. */
1595 ripng_rte_list
= ripng_rte_new();
1597 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1598 if ((list
= rp
->info
) != NULL
1599 && (rinfo
= listgetdata(listhead(list
))) != NULL
1600 && rinfo
->suppress
== 0) {
1601 /* If no route-map are applied, the RTE will be these
1605 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1606 rinfo
->metric_out
= rinfo
->metric
;
1607 rinfo
->tag_out
= rinfo
->tag
;
1608 memset(&rinfo
->nexthop_out
, 0,
1609 sizeof(rinfo
->nexthop_out
));
1610 /* In order to avoid some local loops,
1611 * if the RIPng route has a nexthop via this interface,
1613 * otherwise set it to 0. The nexthop should not be
1615 * beyond the local broadcast/multicast area in order
1616 * to avoid an IGP multi-level recursive look-up.
1618 if (rinfo
->ifindex
== ifp
->ifindex
)
1619 rinfo
->nexthop_out
= rinfo
->nexthop
;
1621 /* Apply output filters. */
1622 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1626 /* Changed route only output. */
1627 if (route_type
== ripng_changed_route
1628 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1631 /* Split horizon. */
1632 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1633 /* We perform split horizon for RIPng routes. */
1635 struct ripng_info
*tmp_rinfo
= NULL
;
1637 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1639 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1640 && tmp_rinfo
->ifindex
1649 /* Preparation for route-map. */
1650 rinfo
->metric_set
= 0;
1653 * and tag_out are already initialized.
1656 /* Interface route-map */
1657 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1658 ret
= route_map_apply(
1659 ri
->routemap
[RIPNG_FILTER_OUT
],
1660 (struct prefix
*)p
, rinfo
);
1662 if (ret
== RMAP_DENYMATCH
) {
1663 if (IS_RIPNG_DEBUG_PACKET
)
1665 "RIPng %pFX is filtered by route-map out",
1671 /* Redistribute route-map. */
1672 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1673 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1678 if (ret
== RMAP_DENYMATCH
) {
1679 if (IS_RIPNG_DEBUG_PACKET
)
1681 "RIPng %pFX is filtered by route-map",
1687 /* When the route-map does not set metric. */
1688 if (!rinfo
->metric_set
) {
1689 /* If the redistribute metric is set. */
1690 if (ripng
->redist
[rinfo
->type
].metric_config
1691 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1693 ripng
->redist
[rinfo
->type
]
1696 /* If the route is not connected or
1698 one, use default-metric value */
1699 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1701 != ZEBRA_ROUTE_CONNECT
1703 != RIPNG_METRIC_INFINITY
)
1705 ripng
->default_metric
;
1709 /* Apply offset-list */
1710 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1711 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1712 &rinfo
->metric_out
);
1714 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1715 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1717 /* Perform split-horizon with poisoned reverse
1720 if (ri
->split_horizon
1721 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1722 struct ripng_info
*tmp_rinfo
= NULL
;
1724 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1726 if ((tmp_rinfo
->type
1727 == ZEBRA_ROUTE_RIPNG
)
1728 && tmp_rinfo
->ifindex
1731 RIPNG_METRIC_INFINITY
;
1734 /* Add RTE to the list */
1735 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1738 /* Process the aggregated RTE entry */
1739 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1740 && aggregate
->suppress
== 0) {
1741 /* If no route-map are applied, the RTE will be these
1745 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1746 aggregate
->metric_set
= 0;
1747 aggregate
->metric_out
= aggregate
->metric
;
1748 aggregate
->tag_out
= aggregate
->tag
;
1749 memset(&aggregate
->nexthop_out
, 0,
1750 sizeof(aggregate
->nexthop_out
));
1752 /* Apply output filters.*/
1753 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1757 /* Interface route-map */
1758 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1759 struct ripng_info newinfo
;
1761 /* let's cast the aggregate structure to
1763 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1764 /* the nexthop is :: */
1765 newinfo
.metric
= aggregate
->metric
;
1766 newinfo
.metric_out
= aggregate
->metric_out
;
1767 newinfo
.tag
= aggregate
->tag
;
1768 newinfo
.tag_out
= aggregate
->tag_out
;
1770 ret
= route_map_apply(
1771 ri
->routemap
[RIPNG_FILTER_OUT
],
1772 (struct prefix
*)p
, &newinfo
);
1774 if (ret
== RMAP_DENYMATCH
) {
1775 if (IS_RIPNG_DEBUG_PACKET
)
1777 "RIPng %pFX is filtered by route-map out",
1782 aggregate
->metric_out
= newinfo
.metric_out
;
1783 aggregate
->tag_out
= newinfo
.tag_out
;
1784 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1785 aggregate
->nexthop_out
=
1786 newinfo
.nexthop_out
;
1789 /* There is no redistribute routemap for the aggregated
1792 /* Changed route only output. */
1793 /* XXX, vincent, in order to increase time convergence,
1794 * it should be announced if a child has changed.
1796 if (route_type
== ripng_changed_route
)
1799 /* Apply offset-list */
1800 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1801 ripng_offset_list_apply_out(
1802 ripng
, p
, ifp
, &aggregate
->metric_out
);
1804 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1805 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1807 /* Add RTE to the list */
1808 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1812 /* Flush the list */
1813 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1814 ripng_rte_free(ripng_rte_list
);
1817 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1821 vrf
= vrf_lookup_by_id(vrf_id
);
1828 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1832 ripng
.vrf_name
= (char *)vrf_name
;
1834 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1837 /* Create new RIPng instance and set it to global variable. */
1838 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1840 struct ripng
*ripng
;
1842 /* Allocaste RIPng instance. */
1843 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1844 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1846 /* Default version and timer values. */
1847 ripng
->version
= RIPNG_V1
;
1848 ripng
->update_time
= yang_get_default_uint32(
1849 "%s/timers/update-interval", RIPNG_INSTANCE
);
1850 ripng
->timeout_time
= yang_get_default_uint32(
1851 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1852 ripng
->garbage_time
= yang_get_default_uint32(
1853 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1854 ripng
->default_metric
=
1855 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1856 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1859 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1860 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1862 /* Initialize RIPng data structures. */
1863 ripng
->table
= agg_table_init();
1864 agg_set_table_info(ripng
->table
, ripng
);
1865 ripng
->peer_list
= list_new();
1866 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1867 ripng
->peer_list
->del
= ripng_peer_list_del
;
1868 ripng
->enable_if
= vector_init(1);
1869 ripng
->enable_network
= agg_table_init();
1870 ripng
->passive_interface
= vector_init(1);
1871 ripng
->offset_list_master
= list_new();
1872 ripng
->offset_list_master
->cmp
=
1873 (int (*)(void *, void *))offset_list_cmp
;
1874 ripng
->offset_list_master
->del
=
1875 (void (*)(void *))ripng_offset_list_free
;
1876 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1877 distribute_list_add_hook(ripng
->distribute_ctx
,
1878 ripng_distribute_update
);
1879 distribute_list_delete_hook(ripng
->distribute_ctx
,
1880 ripng_distribute_update
);
1882 /* if rmap install. */
1883 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1884 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1885 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1887 /* Enable the routing instance if possible. */
1888 if (vrf
&& vrf_is_enabled(vrf
))
1889 ripng_instance_enable(ripng
, vrf
, socket
);
1895 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1900 /* Send RIPng request to the interface. */
1901 int ripng_request(struct interface
*ifp
)
1904 struct ripng_packet ripng_packet
;
1906 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1908 if (if_is_loopback(ifp
))
1911 /* If interface is down, don't send RIP packet. */
1915 if (IS_RIPNG_DEBUG_EVENT
)
1916 zlog_debug("RIPng send request to %s", ifp
->name
);
1918 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1919 ripng_packet
.command
= RIPNG_REQUEST
;
1920 ripng_packet
.version
= RIPNG_V1
;
1921 rte
= ripng_packet
.rte
;
1922 rte
->metric
= RIPNG_METRIC_INFINITY
;
1924 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1929 static int ripng_update_jitter(int time
)
1931 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1934 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1940 thread_add_read(master
, ripng_read
, ripng
, sock
,
1943 case RIPNG_UPDATE_EVENT
:
1944 thread_cancel(&ripng
->t_update
);
1946 /* Update timer jitter. */
1947 jitter
= ripng_update_jitter(ripng
->update_time
);
1949 ripng
->t_update
= NULL
;
1950 thread_add_timer(master
, ripng_update
, ripng
,
1951 sock
? 2 : ripng
->update_time
+ jitter
,
1954 case RIPNG_TRIGGERED_UPDATE
:
1955 if (ripng
->t_triggered_interval
)
1958 thread_add_event(master
, ripng_triggered_update
, ripng
,
1959 0, &ripng
->t_triggered_update
);
1967 /* Print out routes update time. */
1968 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1973 char timebuf
[TIME_BUF
];
1974 struct thread
*thread
;
1976 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1977 clock
= thread_timer_remain_second(thread
);
1978 gmtime_r(&clock
, &tm
);
1979 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1980 vty_out(vty
, "%5s", timebuf
);
1981 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1982 clock
= thread_timer_remain_second(thread
);
1983 gmtime_r(&clock
, &tm
);
1984 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1985 vty_out(vty
, "%5s", timebuf
);
1989 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1994 if (rinfo
->suppress
)
1995 strlcat(str
, "S", sizeof(str
));
1997 switch (rinfo
->sub_type
) {
1998 case RIPNG_ROUTE_RTE
:
1999 strlcat(str
, "n", sizeof(str
));
2001 case RIPNG_ROUTE_STATIC
:
2002 strlcat(str
, "s", sizeof(str
));
2004 case RIPNG_ROUTE_DEFAULT
:
2005 strlcat(str
, "d", sizeof(str
));
2007 case RIPNG_ROUTE_REDISTRIBUTE
:
2008 strlcat(str
, "r", sizeof(str
));
2010 case RIPNG_ROUTE_INTERFACE
:
2011 strlcat(str
, "i", sizeof(str
));
2014 strlcat(str
, "?", sizeof(str
));
2021 DEFUN (show_ipv6_ripng
,
2022 show_ipv6_ripng_cmd
,
2023 "show ipv6 ripng [vrf NAME]",
2026 "Show RIPng routes\n"
2029 struct ripng
*ripng
;
2030 struct agg_node
*rp
;
2031 struct ripng_info
*rinfo
;
2032 struct ripng_aggregate
*aggregate
;
2033 struct list
*list
= NULL
;
2034 struct listnode
*listnode
= NULL
;
2036 const char *vrf_name
;
2039 if (argv_find(argv
, argc
, "vrf", &idx
))
2040 vrf_name
= argv
[idx
+ 1]->arg
;
2042 vrf_name
= VRF_DEFAULT_NAME
;
2044 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2046 vty_out(vty
, "%% RIPng instance not found\n");
2049 if (!ripng
->enabled
) {
2050 vty_out(vty
, "%% RIPng instance is disabled\n");
2054 /* Header of display. */
2056 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2058 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2059 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2060 " Network Next Hop Via Metric Tag Time\n");
2062 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2063 if ((aggregate
= rp
->aggregate
) != NULL
) {
2065 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2066 aggregate
->suppress
, rp
);
2068 vty_out(vty
, "R(a) %pRN ", rp
);
2071 vty_out(vty
, "%*s", 18, " ");
2073 vty_out(vty
, "%*s", 28, " ");
2074 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2075 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2078 if ((list
= rp
->info
) != NULL
)
2079 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2081 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2082 zebra_route_char(rinfo
->type
),
2083 ripng_route_subtype_print(rinfo
),
2084 rinfo
->suppress
, rp
);
2086 vty_out(vty
, "%c(%s) %pRN ",
2087 zebra_route_char(rinfo
->type
),
2088 ripng_route_subtype_print(rinfo
), rp
);
2091 vty_out(vty
, "%*s", 18, " ");
2092 len
= vty_out(vty
, "%s",
2093 inet6_ntoa(rinfo
->nexthop
));
2097 vty_out(vty
, "%*s", len
, " ");
2100 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2101 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2106 ripng
->vrf
->vrf_id
));
2107 } else if (rinfo
->metric
2108 == RIPNG_METRIC_INFINITY
) {
2109 len
= vty_out(vty
, "kill");
2111 len
= vty_out(vty
, "self");
2115 vty_out(vty
, "%*s", len
, " ");
2117 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2118 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2121 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2122 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2123 /* RTE from remote RIP routers */
2124 ripng_vty_out_uptime(vty
, rinfo
);
2125 } else if (rinfo
->metric
2126 == RIPNG_METRIC_INFINITY
) {
2127 /* poisonous reversed routes (gc) */
2128 ripng_vty_out_uptime(vty
, rinfo
);
2138 DEFUN (show_ipv6_ripng_status
,
2139 show_ipv6_ripng_status_cmd
,
2140 "show ipv6 ripng [vrf NAME] status",
2143 "Show RIPng routes\n"
2145 "IPv6 routing protocol process parameters and statistics\n")
2147 struct ripng
*ripng
;
2148 struct interface
*ifp
;
2149 const char *vrf_name
;
2152 if (argv_find(argv
, argc
, "vrf", &idx
))
2153 vrf_name
= argv
[idx
+ 1]->arg
;
2155 vrf_name
= VRF_DEFAULT_NAME
;
2157 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2159 vty_out(vty
, "%% RIPng instance not found\n");
2162 if (!ripng
->enabled
) {
2163 vty_out(vty
, "%% RIPng instance is disabled\n");
2167 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2168 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2169 ripng
->update_time
);
2170 vty_out(vty
, " next due in %lu seconds\n",
2171 thread_timer_remain_second(ripng
->t_update
));
2172 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2173 vty_out(vty
, " garbage collect after %u seconds\n",
2174 ripng
->garbage_time
);
2176 /* Filtering status show. */
2177 config_show_distribute(vty
, ripng
->distribute_ctx
);
2179 /* Default metric information. */
2180 vty_out(vty
, " Default redistribution metric is %d\n",
2181 ripng
->default_metric
);
2183 /* Redistribute information. */
2184 vty_out(vty
, " Redistributing:");
2185 ripng_redistribute_write(vty
, ripng
);
2188 vty_out(vty
, " Default version control: send version %d,",
2190 vty_out(vty
, " receive version %d \n", ripng
->version
);
2192 vty_out(vty
, " Interface Send Recv\n");
2194 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2195 struct ripng_interface
*ri
;
2199 if (ri
->enable_network
|| ri
->enable_interface
) {
2201 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2202 ripng
->version
, ripng
->version
);
2206 vty_out(vty
, " Routing for Networks:\n");
2207 ripng_network_write(vty
, ripng
);
2209 vty_out(vty
, " Routing Information Sources:\n");
2211 " Gateway BadPackets BadRoutes Distance Last Update\n");
2212 ripng_peer_display(vty
, ripng
);
2217 /* Update ECMP routes to zebra when ECMP is disabled. */
2218 void ripng_ecmp_disable(struct ripng
*ripng
)
2220 struct agg_node
*rp
;
2221 struct ripng_info
*rinfo
, *tmp_rinfo
;
2223 struct listnode
*node
, *nextnode
;
2228 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2229 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2230 rinfo
= listgetdata(listhead(list
));
2231 if (!ripng_route_rte(rinfo
))
2234 /* Drop all other entries, except the first one. */
2235 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2236 if (tmp_rinfo
!= rinfo
) {
2237 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2239 tmp_rinfo
->t_garbage_collect
);
2240 list_delete_node(list
, node
);
2241 ripng_info_free(tmp_rinfo
);
2245 ripng_zebra_ipv6_add(ripng
, rp
);
2247 /* Set the route change flag. */
2248 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2250 /* Signal the output process to trigger an update. */
2251 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2255 /* RIPng configuration write function. */
2256 static int ripng_config_write(struct vty
*vty
)
2258 struct ripng
*ripng
;
2261 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2262 char xpath
[XPATH_MAXLEN
];
2263 struct lyd_node
*dnode
;
2265 snprintf(xpath
, sizeof(xpath
),
2266 "/frr-ripngd:ripngd/instance[vrf='%s']",
2269 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2272 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2274 config_write_distribute(vty
, ripng
->distribute_ctx
);
2275 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2283 static int ripng_config_write(struct vty
*vty
);
2284 /* RIPng node structure. */
2285 static struct cmd_node cmd_ripng_node
= {
2288 .parent_node
= CONFIG_NODE
,
2289 .prompt
= "%s(config-router)# ",
2290 .config_write
= ripng_config_write
,
2293 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2294 struct distribute
*dist
)
2296 struct interface
*ifp
;
2297 struct ripng_interface
*ri
;
2298 struct access_list
*alist
;
2299 struct prefix_list
*plist
;
2301 if (!ctx
->vrf
|| !dist
->ifname
)
2304 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2310 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2311 alist
= access_list_lookup(AFI_IP6
,
2312 dist
->list
[DISTRIBUTE_V6_IN
]);
2314 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2316 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2318 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2320 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2321 alist
= access_list_lookup(AFI_IP6
,
2322 dist
->list
[DISTRIBUTE_V6_OUT
]);
2324 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2326 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2328 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2330 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2331 plist
= prefix_list_lookup(AFI_IP6
,
2332 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2334 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2336 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2338 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2340 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2341 plist
= prefix_list_lookup(AFI_IP6
,
2342 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2344 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2346 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2348 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2351 void ripng_distribute_update_interface(struct interface
*ifp
)
2353 struct ripng_interface
*ri
= ifp
->info
;
2354 struct ripng
*ripng
= ri
->ripng
;
2355 struct distribute
*dist
;
2359 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2361 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2364 /* Update all interface's distribute list. */
2365 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2367 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2368 struct interface
*ifp
;
2370 FOR_ALL_INTERFACES (vrf
, ifp
)
2371 ripng_distribute_update_interface(ifp
);
2374 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2376 ripng_distribute_update_all(NULL
);
2379 /* delete all the added ripng routes. */
2380 void ripng_clean(struct ripng
*ripng
)
2382 ripng_interface_clean(ripng
);
2385 ripng_instance_disable(ripng
);
2387 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2388 if (ripng
->redist
[i
].route_map
.name
)
2389 free(ripng
->redist
[i
].route_map
.name
);
2391 agg_table_finish(ripng
->table
);
2392 list_delete(&ripng
->peer_list
);
2393 distribute_list_delete(&ripng
->distribute_ctx
);
2394 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2396 stream_free(ripng
->ibuf
);
2397 stream_free(ripng
->obuf
);
2399 ripng_clean_network(ripng
);
2400 ripng_passive_interface_clean(ripng
);
2401 vector_free(ripng
->enable_if
);
2402 agg_table_finish(ripng
->enable_network
);
2403 vector_free(ripng
->passive_interface
);
2404 list_delete(&ripng
->offset_list_master
);
2406 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2407 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2408 XFREE(MTYPE_RIPNG
, ripng
);
2411 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2412 struct if_rmap
*if_rmap
)
2414 struct interface
*ifp
= NULL
;
2415 struct ripng_interface
*ri
;
2416 struct route_map
*rmap
;
2417 struct vrf
*vrf
= NULL
;
2420 vrf
= vrf_lookup_by_name(ctx
->name
);
2422 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2428 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2429 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2431 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2433 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2435 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2437 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2438 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2440 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2442 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2444 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2447 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2449 struct ripng_interface
*ri
= ifp
->info
;
2450 struct ripng
*ripng
= ri
->ripng
;
2451 struct if_rmap
*if_rmap
;
2452 struct if_rmap_ctx
*ctx
;
2456 ctx
= ripng
->if_rmap_ctx
;
2459 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2461 ripng_if_rmap_update(ctx
, if_rmap
);
2464 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2466 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2467 if (ripng
->redist
[i
].route_map
.name
) {
2468 ripng
->redist
[i
].route_map
.map
=
2469 route_map_lookup_by_name(
2470 ripng
->redist
[i
].route_map
.name
);
2471 route_map_counter_increment(
2472 ripng
->redist
[i
].route_map
.map
);
2477 static void ripng_routemap_update(const char *unused
)
2479 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2480 struct ripng
*ripng
;
2481 struct interface
*ifp
;
2483 FOR_ALL_INTERFACES (vrf
, ifp
)
2484 ripng_if_rmap_update_interface(ifp
);
2488 ripng_routemap_update_redistribute(ripng
);
2491 /* Link RIPng instance to VRF. */
2492 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2494 struct interface
*ifp
;
2497 ripng
->distribute_ctx
->vrf
= vrf
;
2500 FOR_ALL_INTERFACES (vrf
, ifp
)
2501 ripng_interface_sync(ifp
);
2504 /* Unlink RIPng instance from VRF. */
2505 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2507 struct interface
*ifp
;
2510 ripng
->distribute_ctx
->vrf
= NULL
;
2513 FOR_ALL_INTERFACES (vrf
, ifp
)
2514 ripng_interface_sync(ifp
);
2517 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2522 ripng_vrf_link(ripng
, vrf
);
2523 ripng
->enabled
= true;
2525 /* Resend all redistribute requests. */
2526 ripng_redistribute_enable(ripng
);
2528 /* Create read and timer thread. */
2529 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2530 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2532 ripng_zebra_vrf_register(vrf
);
2535 static void ripng_instance_disable(struct ripng
*ripng
)
2537 struct vrf
*vrf
= ripng
->vrf
;
2538 struct agg_node
*rp
;
2540 /* Clear RIPng routes */
2541 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2542 struct ripng_aggregate
*aggregate
;
2545 if ((list
= rp
->info
) != NULL
) {
2546 struct ripng_info
*rinfo
;
2547 struct listnode
*listnode
;
2549 rinfo
= listgetdata(listhead(list
));
2550 if (ripng_route_rte(rinfo
))
2551 ripng_zebra_ipv6_delete(ripng
, rp
);
2553 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2554 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2555 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2556 ripng_info_free(rinfo
);
2560 agg_unlock_node(rp
);
2563 if ((aggregate
= rp
->aggregate
) != NULL
) {
2564 ripng_aggregate_free(aggregate
);
2565 rp
->aggregate
= NULL
;
2566 agg_unlock_node(rp
);
2570 /* Flush all redistribute requests. */
2571 ripng_redistribute_disable(ripng
);
2573 /* Cancel the RIPng timers */
2574 RIPNG_TIMER_OFF(ripng
->t_update
);
2575 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2576 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2578 /* Cancel the read thread */
2579 thread_cancel(&ripng
->t_read
);
2581 /* Close the RIPng socket */
2582 if (ripng
->sock
>= 0) {
2587 /* Clear existing peers. */
2588 list_delete_all_node(ripng
->peer_list
);
2590 ripng_zebra_vrf_deregister(vrf
);
2592 ripng_vrf_unlink(ripng
, vrf
);
2593 ripng
->enabled
= false;
2596 static int ripng_vrf_new(struct vrf
*vrf
)
2598 if (IS_RIPNG_DEBUG_EVENT
)
2599 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2605 static int ripng_vrf_delete(struct vrf
*vrf
)
2607 if (IS_RIPNG_DEBUG_EVENT
)
2608 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2614 static int ripng_vrf_enable(struct vrf
*vrf
)
2616 struct ripng
*ripng
;
2619 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2621 char *old_vrf_name
= NULL
;
2623 ripng
= (struct ripng
*)vrf
->info
;
2626 /* update vrf name */
2627 if (ripng
->vrf_name
)
2628 old_vrf_name
= ripng
->vrf_name
;
2629 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf
->name
);
2631 * HACK: Change the RIPng VRF in the running configuration directly,
2632 * bypassing the northbound layer. This is necessary to avoid deleting
2633 * the RIPng and readding it in the new VRF, which would have
2634 * several implications.
2636 if (yang_module_find("frr-ripngd") && old_vrf_name
) {
2637 struct lyd_node
*ripng_dnode
;
2638 char oldpath
[XPATH_MAXLEN
];
2639 char newpath
[XPATH_MAXLEN
];
2641 ripng_dnode
= yang_dnode_get(
2642 running_config
->dnode
,
2643 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2646 yang_dnode_get_path(ripng_dnode
->parent
, oldpath
,
2648 yang_dnode_change_leaf(ripng_dnode
, vrf
->name
);
2649 yang_dnode_get_path(ripng_dnode
->parent
, newpath
,
2651 nb_running_move_tree(oldpath
, newpath
);
2652 running_config
->version
++;
2655 XFREE(MTYPE_RIPNG_VRF_NAME
, old_vrf_name
);
2661 if (IS_RIPNG_DEBUG_EVENT
)
2662 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2665 /* Activate the VRF RIPng instance. */
2666 socket
= ripng_make_socket(vrf
);
2670 ripng_instance_enable(ripng
, vrf
, socket
);
2675 static int ripng_vrf_disable(struct vrf
*vrf
)
2677 struct ripng
*ripng
;
2679 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2680 if (!ripng
|| !ripng
->enabled
)
2683 if (IS_RIPNG_DEBUG_EVENT
)
2684 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2687 /* Deactivate the VRF RIPng instance. */
2689 ripng_instance_disable(ripng
);
2694 void ripng_vrf_init(void)
2696 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2697 ripng_vrf_delete
, ripng_vrf_enable
);
2700 void ripng_vrf_terminate(void)
2705 /* Initialize ripng structure and set commands. */
2706 void ripng_init(void)
2708 /* Install RIPNG_NODE. */
2709 install_node(&cmd_ripng_node
);
2711 /* Install ripng commands. */
2712 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2713 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2715 install_default(RIPNG_NODE
);
2720 /* Access list install. */
2722 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2723 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2725 /* Prefix list initialize.*/
2727 prefix_list_add_hook(ripng_distribute_update_all
);
2728 prefix_list_delete_hook(ripng_distribute_update_all
);
2730 /* Distribute list install. */
2731 distribute_list_init(RIPNG_NODE
);
2733 /* Route-map for interface. */
2734 ripng_route_map_init();
2736 route_map_add_hook(ripng_routemap_update
);
2737 route_map_delete_hook(ripng_routemap_update
);
2739 if_rmap_init(RIPNG_NODE
);