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"
41 #include "ripngd/ripngd.h"
42 #include "ripngd/ripng_route.h"
43 #include "ripngd/ripng_debug.h"
44 #include "ripngd/ripng_nexthop.h"
46 DEFINE_MGROUP(RIPNGD
, "ripngd")
47 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG
, "RIPng structure")
48 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_VRF_NAME
, "RIPng VRF name")
49 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_ROUTE
, "RIPng route info")
51 enum { ripng_all_route
,
55 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
56 struct distribute
*dist
);
59 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
60 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
62 static void ripng_instance_disable(struct ripng
*ripng
);
63 int ripng_triggered_update(struct thread
*);
64 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
65 struct if_rmap
*if_rmap
);
67 /* Generate rb-tree of RIPng instances. */
68 static inline int ripng_instance_compare(const struct ripng
*a
,
69 const struct ripng
*b
)
71 return strcmp(a
->vrf_name
, b
->vrf_name
);
73 RB_GENERATE(ripng_instance_head
, ripng
, entry
, ripng_instance_compare
)
75 struct ripng_instance_head ripng_instances
= RB_INITIALIZER(&ripng_instances
);
77 /* RIPng next hop specification. */
78 struct ripng_nexthop
{
79 enum ripng_nexthop_type
{
83 struct in6_addr address
;
86 int ripng_route_rte(struct ripng_info
*rinfo
)
88 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
89 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
92 /* Allocate new ripng information. */
93 struct ripng_info
*ripng_info_new(void)
95 struct ripng_info
*new;
97 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
101 /* Free ripng information. */
102 void ripng_info_free(struct ripng_info
*rinfo
)
104 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
107 struct ripng
*ripng_info_get_instance(const struct ripng_info
*rinfo
)
109 return agg_get_table_info(agg_get_table(rinfo
->rp
));
112 /* Create ripng socket. */
113 int ripng_make_socket(struct vrf
*vrf
)
117 struct sockaddr_in6 ripaddr
;
118 const char *vrf_dev
= NULL
;
120 /* Make datagram socket. */
121 if (vrf
->vrf_id
!= VRF_DEFAULT
)
123 frr_with_privs(&ripngd_privs
) {
124 sock
= vrf_socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
,
125 vrf
->vrf_id
, vrf_dev
);
127 flog_err_sys(EC_LIB_SOCKET
,
128 "Cannot create UDP socket: %s",
129 safe_strerror(errno
));
134 sockopt_reuseaddr(sock
);
135 sockopt_reuseport(sock
);
136 setsockopt_so_recvbuf(sock
, 8096);
137 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
140 #ifdef IPTOS_PREC_INTERNETCONTROL
141 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
145 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
148 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
151 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
155 memset(&ripaddr
, 0, sizeof(ripaddr
));
156 ripaddr
.sin6_family
= AF_INET6
;
158 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
159 #endif /* SIN6_LEN */
160 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
162 frr_with_privs(&ripngd_privs
) {
163 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
165 zlog_err("Can't bind ripng socket: %s.",
166 safe_strerror(errno
));
177 /* Send RIPng packet. */
178 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
179 struct interface
*ifp
)
181 struct ripng_interface
*ri
= ifp
->info
;
182 struct ripng
*ripng
= ri
->ripng
;
186 struct cmsghdr
*cmsgptr
;
187 char adata
[256] = {};
188 struct in6_pktinfo
*pkt
;
189 struct sockaddr_in6 addr
;
191 if (IS_RIPNG_DEBUG_SEND
) {
193 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
194 zlog_debug(" send interface %s", ifp
->name
);
195 zlog_debug(" send packet size %d", bufsize
);
198 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
199 addr
.sin6_family
= AF_INET6
;
201 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
202 #endif /* SIN6_LEN */
203 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
205 /* When destination is specified. */
207 addr
.sin6_addr
= to
->sin6_addr
;
208 addr
.sin6_port
= to
->sin6_port
;
210 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
211 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
214 memset(&msg
, 0, sizeof(msg
));
215 msg
.msg_name
= (void *)&addr
;
216 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
219 msg
.msg_control
= (void *)adata
;
220 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
223 iov
.iov_len
= bufsize
;
225 cmsgptr
= (struct cmsghdr
*)adata
;
226 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
227 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
228 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
230 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
231 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
232 pkt
->ipi6_ifindex
= ifp
->ifindex
;
234 ret
= sendmsg(ripng
->sock
, &msg
, 0);
238 flog_err_sys(EC_LIB_SOCKET
,
239 "RIPng send fail on %s to %s: %s",
240 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
241 safe_strerror(errno
));
243 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
244 ifp
->name
, safe_strerror(errno
));
250 /* Receive UDP RIPng packet from socket. */
251 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
252 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
258 struct cmsghdr
*cmsgptr
;
259 struct in6_addr dst
= {.s6_addr
= {0}};
261 memset(&dst
, 0, sizeof(struct in6_addr
));
263 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
264 point I can't determine size of cmsghdr */
267 /* Fill in message and iovec. */
268 memset(&msg
, 0, sizeof(msg
));
269 msg
.msg_name
= (void *)from
;
270 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
273 msg
.msg_control
= (void *)adata
;
274 msg
.msg_controllen
= sizeof adata
;
276 iov
.iov_len
= bufsize
;
278 /* If recvmsg fail return minus value. */
279 ret
= recvmsg(sock
, &msg
, 0);
283 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
284 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
285 /* I want interface index which this packet comes from. */
286 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
287 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
288 struct in6_pktinfo
*ptr
;
290 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
291 *ifindex
= ptr
->ipi6_ifindex
;
292 dst
= ptr
->ipi6_addr
;
296 "Interface index returned by IPV6_PKTINFO is zero");
299 /* Incoming packet's multicast hop limit. */
300 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
301 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
302 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
303 *hoplimit
= *phoplimit
;
307 /* Hoplimit check shold be done when destination address is
308 multicast address. */
309 if (!IN6_IS_ADDR_MULTICAST(&dst
))
315 /* Dump rip packet */
316 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
321 const char *command_str
;
323 /* Set command string. */
324 if (packet
->command
== RIPNG_REQUEST
)
325 command_str
= "request";
326 else if (packet
->command
== RIPNG_RESPONSE
)
327 command_str
= "response";
329 command_str
= "unknown";
331 /* Dump packet header. */
332 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
333 packet
->version
, size
);
335 /* Dump each routing table entry. */
338 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
339 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
340 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
343 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
344 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
345 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
349 /* RIPng next hop address RTE (Route Table Entry). */
350 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
351 struct ripng_nexthop
*nexthop
)
353 char buf
[INET6_BUFSIZ
];
355 /* Logging before checking RTE. */
356 if (IS_RIPNG_DEBUG_RECV
)
357 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
359 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
362 /* RFC2080 2.1.1 Next Hop:
363 The route tag and prefix length in the next hop RTE must be
364 set to zero on sending and ignored on receiption. */
365 if (ntohs(rte
->tag
) != 0)
367 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
369 (route_tag_t
)ntohs(rte
->tag
),
370 inet6_ntoa(from
->sin6_addr
));
372 if (rte
->prefixlen
!= 0)
374 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
375 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
377 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
378 next hop RTE indicates that the next hop address should be the
379 originator of the RIPng advertisement. An address specified as a
380 next hop must be a link-local address. */
381 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
382 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
383 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
387 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
388 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
389 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
393 /* The purpose of the next hop RTE is to eliminate packets being
394 routed through extra hops in the system. It is particularly useful
395 when RIPng is not being run on all of the routers on a network.
396 Note that next hop RTE is "advisory". That is, if the provided
397 information is ignored, a possibly sub-optimal, but absolutely
398 valid, route may be taken. If the received next hop address is not
399 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
400 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
401 inet6_ntoa(rte
->addr
),
402 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
404 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
405 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
410 /* If ifp has same link-local address then return 1. */
411 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
413 struct listnode
*node
;
414 struct connected
*connected
;
417 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
418 p
= connected
->address
;
420 if (p
->family
== AF_INET6
421 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
422 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
428 /* RIPng route garbage collect timer. */
429 static int ripng_garbage_collect(struct thread
*t
)
431 struct ripng_info
*rinfo
;
434 rinfo
= THREAD_ARG(t
);
435 rinfo
->t_garbage_collect
= NULL
;
437 /* Off timeout timer. */
438 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
440 /* Get route_node pointer. */
443 /* Unlock route_node. */
444 listnode_delete(rp
->info
, rinfo
);
445 if (list_isempty((struct list
*)rp
->info
)) {
446 list_delete((struct list
**)&rp
->info
);
450 /* Free RIPng routing information. */
451 ripng_info_free(rinfo
);
456 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
458 /* Add new route to the ECMP list.
459 * RETURN: the new entry added in the list, or NULL if it is not the first
460 * entry and ECMP is not allowed.
462 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
463 struct ripng_info
*rinfo_new
)
465 struct agg_node
*rp
= rinfo_new
->rp
;
466 struct ripng_info
*rinfo
= NULL
;
467 struct list
*list
= NULL
;
469 if (rp
->info
== NULL
)
470 rp
->info
= list_new();
471 list
= (struct list
*)rp
->info
;
473 /* If ECMP is not allowed and some entry already exists in the list,
475 if (listcount(list
) && !ripng
->ecmp
)
478 rinfo
= ripng_info_new();
479 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
480 listnode_add(list
, rinfo
);
482 if (ripng_route_rte(rinfo
)) {
483 ripng_timeout_update(ripng
, rinfo
);
484 ripng_zebra_ipv6_add(ripng
, rp
);
487 ripng_aggregate_increment(rp
, rinfo
);
489 /* Set the route change flag on the first entry. */
490 rinfo
= listgetdata(listhead(list
));
491 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
493 /* Signal the output process to trigger an update. */
494 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
499 /* Replace the ECMP list with the new route.
500 * RETURN: the new entry added in the list
502 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
503 struct ripng_info
*rinfo_new
)
505 struct agg_node
*rp
= rinfo_new
->rp
;
506 struct list
*list
= (struct list
*)rp
->info
;
507 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
508 struct listnode
*node
= NULL
, *nextnode
= NULL
;
510 if (list
== NULL
|| listcount(list
) == 0)
511 return ripng_ecmp_add(ripng
, rinfo_new
);
513 /* Get the first entry */
514 rinfo
= listgetdata(listhead(list
));
516 /* Learnt route replaced by a local one. Delete it from zebra. */
517 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
518 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
519 ripng_zebra_ipv6_delete(ripng
, rp
);
521 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
522 ripng_aggregate_decrement_list(rp
, list
);
524 /* Re-use the first entry, and delete the others. */
525 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
526 if (tmp_rinfo
!= rinfo
) {
527 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
528 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
529 list_delete_node(list
, node
);
530 ripng_info_free(tmp_rinfo
);
533 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
534 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
535 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
537 if (ripng_route_rte(rinfo
)) {
538 ripng_timeout_update(ripng
, rinfo
);
539 /* The ADD message implies an update. */
540 ripng_zebra_ipv6_add(ripng
, rp
);
543 ripng_aggregate_increment(rp
, rinfo
);
545 /* Set the route change flag. */
546 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
548 /* Signal the output process to trigger an update. */
549 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
554 /* Delete one route from the ECMP list.
556 * null - the entry is freed, and other entries exist in the list
557 * the entry - the entry is the last one in the list; its metric is set
558 * to INFINITY, and the garbage collector is started for it
560 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
561 struct ripng_info
*rinfo
)
563 struct agg_node
*rp
= rinfo
->rp
;
564 struct list
*list
= (struct list
*)rp
->info
;
566 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
568 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
569 ripng_aggregate_decrement(rp
, rinfo
);
571 if (listcount(list
) > 1) {
572 /* Some other ECMP entries still exist. Just delete this entry.
574 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
575 listnode_delete(list
, rinfo
);
576 if (ripng_route_rte(rinfo
)
577 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
578 /* The ADD message implies the update. */
579 ripng_zebra_ipv6_add(ripng
, rp
);
580 ripng_info_free(rinfo
);
583 assert(rinfo
== listgetdata(listhead(list
)));
585 /* This is the only entry left in the list. We must keep it in
586 * the list for garbage collection time, with INFINITY metric.
589 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
590 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
591 ripng
->garbage_time
);
593 if (ripng_route_rte(rinfo
)
594 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
595 ripng_zebra_ipv6_delete(ripng
, rp
);
598 /* Set the route change flag on the first entry. */
599 rinfo
= listgetdata(listhead(list
));
600 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
602 /* Signal the output process to trigger an update. */
603 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
608 /* Timeout RIPng routes. */
609 static int ripng_timeout(struct thread
*t
)
611 struct ripng_info
*rinfo
= THREAD_ARG(t
);
612 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
614 ripng_ecmp_delete(ripng
, rinfo
);
619 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
621 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
622 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
623 thread_add_timer(master
, ripng_timeout
, rinfo
,
624 ripng
->timeout_time
, &rinfo
->t_timeout
);
628 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
629 struct ripng_interface
*ri
)
631 struct distribute
*dist
;
632 struct access_list
*alist
;
633 struct prefix_list
*plist
;
634 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
637 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
639 /* Input distribute-list filtering. */
640 if (ri
->list
[ripng_distribute
]) {
641 if (access_list_apply(ri
->list
[ripng_distribute
],
644 if (IS_RIPNG_DEBUG_PACKET
)
645 zlog_debug("%s/%d filtered by distribute %s",
646 inet6_ntoa(p
->prefix
), p
->prefixlen
,
651 if (ri
->prefix
[ripng_distribute
]) {
652 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
655 if (IS_RIPNG_DEBUG_PACKET
)
656 zlog_debug("%s/%d filtered by prefix-list %s",
657 inet6_ntoa(p
->prefix
), p
->prefixlen
,
663 /* All interface filter check. */
664 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
666 if (dist
->list
[distribute
]) {
667 alist
= access_list_lookup(AFI_IP6
,
668 dist
->list
[distribute
]);
671 if (access_list_apply(alist
, (struct prefix
*)p
)
673 if (IS_RIPNG_DEBUG_PACKET
)
675 "%s/%d filtered by distribute %s",
676 inet6_ntoa(p
->prefix
),
677 p
->prefixlen
, inout
);
682 if (dist
->prefix
[distribute
]) {
683 plist
= prefix_list_lookup(AFI_IP6
,
684 dist
->prefix
[distribute
]);
687 if (prefix_list_apply(plist
, (struct prefix
*)p
)
689 if (IS_RIPNG_DEBUG_PACKET
)
691 "%s/%d filtered by prefix-list %s",
692 inet6_ntoa(p
->prefix
),
693 p
->prefixlen
, inout
);
702 /* Process RIPng route according to RFC2080. */
703 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
704 struct ripng_nexthop
*ripng_nexthop
,
705 struct interface
*ifp
)
708 struct prefix_ipv6 p
;
710 struct ripng_info
*rinfo
= NULL
, newinfo
;
711 struct ripng_interface
*ri
;
713 struct in6_addr
*nexthop
;
715 struct list
*list
= NULL
;
716 struct listnode
*node
= NULL
;
718 /* Make prefix structure. */
719 memset(&p
, 0, sizeof(struct prefix_ipv6
));
721 /* p.prefix = rte->addr; */
722 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
723 p
.prefixlen
= rte
->prefixlen
;
725 /* Make sure mask is applied. */
726 /* XXX We have to check the prefix is valid or not before call
733 /* Apply input filters. */
734 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
738 memset(&newinfo
, 0, sizeof(newinfo
));
739 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
740 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
741 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
742 newinfo
.nexthop
= ripng_nexthop
->address
;
744 newinfo
.nexthop
= from
->sin6_addr
;
745 newinfo
.from
= from
->sin6_addr
;
746 newinfo
.ifindex
= ifp
->ifindex
;
747 newinfo
.metric
= rte
->metric
;
748 newinfo
.metric_out
= rte
->metric
; /* XXX */
749 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
752 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
753 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
754 (struct prefix
*)&p
, RMAP_RIPNG
,
757 if (ret
== RMAP_DENYMATCH
) {
758 if (IS_RIPNG_DEBUG_PACKET
)
760 "RIPng %s/%d is filtered by route-map in",
761 inet6_ntoa(p
.prefix
), p
.prefixlen
);
765 /* Get back the object */
766 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
767 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
768 &ripng_nexthop
->address
)) {
769 /* the nexthop get changed by the routemap */
770 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
771 ripng_nexthop
->address
=
774 ripng_nexthop
->address
= in6addr_any
;
777 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
779 /* the nexthop get changed by the routemap */
780 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
781 ripng_nexthop
->flag
=
782 RIPNG_NEXTHOP_ADDRESS
;
783 ripng_nexthop
->address
=
788 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
790 newinfo
.metric_out
; /* XXX: the routemap uses the
794 /* Once the entry has been validated, update the metric by
795 * adding the cost of the network on wich the message
796 * arrived. If the result is greater than infinity, use infinity
797 * (RFC2453 Sec. 3.9.2)
800 /* Zebra ripngd can handle offset-list in. */
801 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
803 /* If offset-list does not modify the metric use interface's
806 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
808 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
809 rte
->metric
= RIPNG_METRIC_INFINITY
;
811 /* Set nexthop pointer. */
812 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
813 nexthop
= &ripng_nexthop
->address
;
815 nexthop
= &from
->sin6_addr
;
817 /* Lookup RIPng routing table. */
818 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
821 newinfo
.nexthop
= *nexthop
;
822 newinfo
.metric
= rte
->metric
;
823 newinfo
.tag
= ntohs(rte
->tag
);
825 /* Check to see whether there is already RIPng route on the table. */
826 if ((list
= rp
->info
) != NULL
)
827 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
828 /* Need to compare with redistributed entry or local
830 if (!ripng_route_rte(rinfo
))
833 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
834 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
837 if (!listnextnode(node
)) {
838 /* Not found in the list */
840 if (rte
->metric
> rinfo
->metric
) {
841 /* New route has a greater metric.
847 if (rte
->metric
< rinfo
->metric
)
848 /* New route has a smaller metric.
849 * Replace the ECMP list
850 * with the new one in below. */
853 /* Metrics are same. Unless ECMP is disabled,
854 * keep "rinfo" null and
855 * the new route is added in the ECMP list in
863 /* Redistributed route check. */
864 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
865 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
870 /* Local static route. */
871 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
872 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
873 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
874 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
881 /* Now, check to see whether there is already an explicit route
882 for the destination prefix. If there is no such route, add
883 this route to the routing table, unless the metric is
884 infinity (there is no point in adding a route which
886 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
887 ripng_ecmp_add(ripng
, &newinfo
);
891 /* If there is an existing route, compare the next hop address
892 to the address of the router from which the datagram came.
893 If this datagram is from the same router as the existing
894 route, reinitialize the timeout. */
895 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
896 && (rinfo
->ifindex
== ifp
->ifindex
));
899 * RFC 2080 - Section 2.4.2:
900 * "If the new metric is the same as the old one, examine the
902 * for the existing route. If it is at least halfway to the
904 * point, switch to the new route. This heuristic is optional,
906 * highly recommended".
908 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
910 && (thread_timer_remain_second(rinfo
->t_timeout
)
911 < (ripng
->timeout_time
/ 2))) {
912 ripng_ecmp_replace(ripng
, &newinfo
);
914 /* Next, compare the metrics. If the datagram is from the same
915 router as the existing route, and the new metric is different
916 than the old one; or, if the new metric is lower than the old
917 one; do the following actions: */
918 else if ((same
&& rinfo
->metric
!= rte
->metric
)
919 || rte
->metric
< rinfo
->metric
) {
920 if (listcount(list
) == 1) {
921 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
922 ripng_ecmp_replace(ripng
, &newinfo
);
924 ripng_ecmp_delete(ripng
, rinfo
);
926 if (newinfo
.metric
< rinfo
->metric
)
927 ripng_ecmp_replace(ripng
, &newinfo
);
928 else /* newinfo.metric > rinfo->metric */
929 ripng_ecmp_delete(ripng
, rinfo
);
931 } else /* same & no change */
932 ripng_timeout_update(ripng
, rinfo
);
934 /* Unlock tempolary lock of the route. */
939 /* Add redistributed route to RIPng table. */
940 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
941 struct prefix_ipv6
*p
, ifindex_t ifindex
,
942 struct in6_addr
*nexthop
, route_tag_t tag
)
945 struct ripng_info
*rinfo
= NULL
, newinfo
;
946 struct list
*list
= NULL
;
948 /* Redistribute route */
949 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
951 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
954 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
956 memset(&newinfo
, 0, sizeof(struct ripng_info
));
958 newinfo
.sub_type
= sub_type
;
959 newinfo
.ifindex
= ifindex
;
961 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
964 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
965 newinfo
.nexthop
= *nexthop
;
967 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
968 rinfo
= listgetdata(listhead(list
));
970 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
971 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
972 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
977 /* Manually configured RIPng route check.
978 * They have the precedence on all the other entries.
980 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
981 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
982 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
983 if (type
!= ZEBRA_ROUTE_RIPNG
984 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
985 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
991 ripng_ecmp_replace(ripng
, &newinfo
);
994 ripng_ecmp_add(ripng
, &newinfo
);
996 if (IS_RIPNG_DEBUG_EVENT
) {
999 "Redistribute new prefix %s/%d on the interface %s",
1000 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1001 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1004 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
1005 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1006 inet6_ntoa(*nexthop
),
1007 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1010 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1013 /* Delete redistributed route to RIPng table. */
1014 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1015 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1017 struct agg_node
*rp
;
1018 struct ripng_info
*rinfo
;
1020 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1022 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1025 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1028 struct list
*list
= rp
->info
;
1030 if (list
!= NULL
&& listcount(list
) != 0) {
1031 rinfo
= listgetdata(listhead(list
));
1032 if (rinfo
!= NULL
&& rinfo
->type
== type
1033 && rinfo
->sub_type
== sub_type
1034 && rinfo
->ifindex
== ifindex
) {
1035 /* Perform poisoned reverse. */
1036 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1037 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1038 ripng_garbage_collect
,
1039 ripng
->garbage_time
);
1040 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1042 /* Aggregate count decrement. */
1043 ripng_aggregate_decrement(rp
, rinfo
);
1045 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1047 if (IS_RIPNG_DEBUG_EVENT
)
1049 "Poisone %s/%d on the interface %s with an "
1050 "infinity metric [delete]",
1051 inet6_ntoa(p
->prefix
),
1055 ripng
->vrf
->vrf_id
));
1057 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1060 agg_unlock_node(rp
);
1064 /* Withdraw redistributed route. */
1065 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1067 struct agg_node
*rp
;
1068 struct ripng_info
*rinfo
= NULL
;
1069 struct list
*list
= NULL
;
1071 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1072 if ((list
= rp
->info
) != NULL
) {
1073 rinfo
= listgetdata(listhead(list
));
1074 if ((rinfo
->type
== type
)
1075 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1076 /* Perform poisoned reverse. */
1077 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1078 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1079 ripng_garbage_collect
,
1080 ripng
->garbage_time
);
1081 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1083 /* Aggregate count decrement. */
1084 ripng_aggregate_decrement(rp
, rinfo
);
1086 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1088 if (IS_RIPNG_DEBUG_EVENT
) {
1089 struct prefix_ipv6
*p
=
1090 (struct prefix_ipv6
*)&rp
->p
;
1093 "Poisone %s/%d on the interface %s [withdraw]",
1094 inet6_ntoa(p
->prefix
),
1098 ripng
->vrf
->vrf_id
));
1101 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1106 /* RIP routing information. */
1107 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1108 struct sockaddr_in6
*from
,
1109 struct interface
*ifp
, int hoplimit
)
1111 struct ripng_interface
*ri
= ifp
->info
;
1112 struct ripng
*ripng
= ri
->ripng
;
1115 struct ripng_nexthop nexthop
;
1117 /* RFC2080 2.4.2 Response Messages:
1118 The Response must be ignored if it is not from the RIPng port. */
1119 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1120 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1121 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1122 ripng_peer_bad_packet(ripng
, from
);
1126 /* The datagram's IPv6 source address should be checked to see
1127 whether the datagram is from a valid neighbor; the source of the
1128 datagram must be a link-local address. */
1129 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1130 zlog_warn("RIPng packet comes from non link local address %s",
1131 inet6_ntoa(from
->sin6_addr
));
1132 ripng_peer_bad_packet(ripng
, from
);
1136 /* It is also worth checking to see whether the response is from one
1137 of the router's own addresses. Interfaces on broadcast networks
1138 may receive copies of their own multicasts immediately. If a
1139 router processes its own output as new input, confusion is likely,
1140 and such datagrams must be ignored. */
1141 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1143 "RIPng packet comes from my own link local address %s",
1144 inet6_ntoa(from
->sin6_addr
));
1145 ripng_peer_bad_packet(ripng
, from
);
1149 /* As an additional check, periodic advertisements must have their
1150 hop counts set to 255, and inbound, multicast packets sent from the
1151 RIPng port (i.e. periodic advertisement or triggered update
1152 packets) must be examined to ensure that the hop count is 255. */
1153 if (hoplimit
>= 0 && hoplimit
!= 255) {
1155 "RIPng packet comes with non 255 hop count %d from %s",
1156 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1157 ripng_peer_bad_packet(ripng
, from
);
1161 /* Update RIPng peer. */
1162 ripng_peer_update(ripng
, from
, packet
->version
);
1164 /* Reset nexthop. */
1165 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1166 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1168 /* Set RTE pointer. */
1171 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1172 /* First of all, we have to check this RTE is next hop RTE or
1173 not. Next hop RTE is completely different with normal RTE so
1174 we need special treatment. */
1175 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1176 ripng_nexthop_rte(rte
, from
, &nexthop
);
1180 /* RTE information validation. */
1182 /* - is the destination prefix valid (e.g., not a multicast
1183 prefix and not a link-local address) A link-local address
1184 should never be present in an RTE. */
1185 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1187 "Destination prefix is a multicast address %s/%d [%d]",
1188 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1190 ripng_peer_bad_route(ripng
, from
);
1193 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1195 "Destination prefix is a link-local address %s/%d [%d]",
1196 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1198 ripng_peer_bad_route(ripng
, from
);
1201 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1203 "Destination prefix is a loopback address %s/%d [%d]",
1204 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1206 ripng_peer_bad_route(ripng
, from
);
1210 /* - is the prefix length valid (i.e., between 0 and 128,
1212 if (rte
->prefixlen
> 128) {
1213 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1214 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1215 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1216 ripng_peer_bad_route(ripng
, from
);
1220 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1221 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1222 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1223 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1224 ripng_peer_bad_route(ripng
, from
);
1228 /* Vincent: XXX Should we compute the direclty reachable nexthop
1229 * for our RIPng network ?
1232 /* Routing table updates. */
1233 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1237 /* Response to request message. */
1238 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1239 struct sockaddr_in6
*from
,
1240 struct interface
*ifp
)
1242 struct ripng
*ripng
;
1245 struct prefix_ipv6 p
;
1246 struct agg_node
*rp
;
1247 struct ripng_info
*rinfo
;
1248 struct ripng_interface
*ri
;
1250 /* Does not reponse to the requests on the loopback interfaces */
1251 if (if_is_loopback(ifp
))
1254 /* Check RIPng process is enabled on this interface. */
1260 /* When passive interface is specified, suppress responses */
1264 /* RIPng peer update. */
1265 ripng_peer_update(ripng
, from
, packet
->version
);
1267 lim
= ((caddr_t
)packet
) + size
;
1270 /* The Request is processed entry by entry. If there are no
1271 entries, no response is given. */
1272 if (lim
== (caddr_t
)rte
)
1275 /* There is one special case. If there is exactly one entry in the
1276 request, and it has a destination prefix of zero, a prefix length
1277 of zero, and a metric of infinity (i.e., 16), then this is a
1278 request to send the entire routing table. In that case, a call
1279 is made to the output process to send the routing table to the
1280 requesting address/port. */
1281 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1282 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1283 /* All route with split horizon */
1284 ripng_output_process(ifp
, from
, ripng_all_route
);
1286 /* Except for this special case, processing is quite simple.
1287 Examine the list of RTEs in the Request one by one. For each
1288 entry, look up the destination in the router's routing
1289 database and, if there is a route, put that route's metric in
1290 the metric field of the RTE. If there is no explicit route
1291 to the specified destination, put infinity in the metric
1292 field. Once all the entries have been filled in, change the
1293 command from Request to Response and send the datagram back
1294 to the requestor. */
1295 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1296 p
.family
= AF_INET6
;
1298 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1299 p
.prefix
= rte
->addr
;
1300 p
.prefixlen
= rte
->prefixlen
;
1301 apply_mask_ipv6(&p
);
1303 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1306 rinfo
= listgetdata(
1307 listhead((struct list
*)rp
->info
));
1308 rte
->metric
= rinfo
->metric
;
1309 agg_unlock_node(rp
);
1311 rte
->metric
= RIPNG_METRIC_INFINITY
;
1313 packet
->command
= RIPNG_RESPONSE
;
1315 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1319 /* First entry point of reading RIPng packet. */
1320 static int ripng_read(struct thread
*thread
)
1322 struct ripng
*ripng
= THREAD_ARG(thread
);
1325 struct sockaddr_in6 from
;
1326 struct ripng_packet
*packet
;
1327 ifindex_t ifindex
= 0;
1328 struct interface
*ifp
;
1331 /* Check ripng is active and alive. */
1332 assert(ripng
!= NULL
);
1333 assert(ripng
->sock
>= 0);
1335 /* Fetch thread data and set read pointer to empty for event
1336 managing. `sock' sould be same as ripng->sock. */
1337 sock
= THREAD_FD(thread
);
1338 ripng
->t_read
= NULL
;
1340 /* Add myself to the next event. */
1341 ripng_event(ripng
, RIPNG_READ
, sock
);
1343 /* Read RIPng packet. */
1344 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1345 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1348 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1349 ripng
->vrf_name
, safe_strerror(errno
));
1353 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1354 (4)) must be multiple size of one RTE size (20). */
1355 if (((len
- 4) % 20) != 0) {
1356 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1357 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1358 ripng_peer_bad_packet(ripng
, &from
);
1362 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1363 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1365 /* RIPng packet received. */
1366 if (IS_RIPNG_DEBUG_EVENT
)
1368 "RIPng packet received from %s port %d on %s (VRF %s)",
1369 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1370 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1372 /* Logging before packet checking. */
1373 if (IS_RIPNG_DEBUG_RECV
)
1374 ripng_packet_dump(packet
, len
, "RECV");
1376 /* Packet comes from unknown interface. */
1379 "RIPng packet comes from unknown interface %d (VRF %s)",
1380 ifindex
, ripng
->vrf_name
);
1384 /* Packet version mismatch checking. */
1385 if (packet
->version
!= ripng
->version
) {
1387 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1388 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1389 ripng_peer_bad_packet(ripng
, &from
);
1393 /* Process RIPng packet. */
1394 switch (packet
->command
) {
1396 ripng_request_process(packet
, len
, &from
, ifp
);
1398 case RIPNG_RESPONSE
:
1399 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1402 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1404 ripng_peer_bad_packet(ripng
, &from
);
1410 /* Walk down the RIPng routing table then clear changed flag. */
1411 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1413 struct agg_node
*rp
;
1414 struct ripng_info
*rinfo
= NULL
;
1415 struct list
*list
= NULL
;
1416 struct listnode
*listnode
= NULL
;
1418 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1419 if ((list
= rp
->info
) != NULL
)
1420 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1421 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1422 /* This flag can be set only on the first entry.
1428 /* Regular update of RIPng route. Send all routing formation to RIPng
1429 enabled interface. */
1430 static int ripng_update(struct thread
*t
)
1432 struct ripng
*ripng
= THREAD_ARG(t
);
1433 struct interface
*ifp
;
1434 struct ripng_interface
*ri
;
1436 /* Clear update timer thread. */
1437 ripng
->t_update
= NULL
;
1439 /* Logging update event. */
1440 if (IS_RIPNG_DEBUG_EVENT
)
1441 zlog_debug("RIPng update timer expired!");
1443 /* Supply routes to each interface. */
1444 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1447 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1453 /* When passive interface is specified, suppress announce to the
1459 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1460 if (IS_RIPNG_DEBUG_EVENT
)
1462 "[Event] RIPng send to if %d is suppressed by config",
1466 #endif /* RIPNG_ADVANCED */
1468 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1471 /* Triggered updates may be suppressed if a regular update is due by
1472 the time the triggered update would be sent. */
1473 if (ripng
->t_triggered_interval
) {
1474 thread_cancel(ripng
->t_triggered_interval
);
1475 ripng
->t_triggered_interval
= NULL
;
1479 /* Reset flush event. */
1480 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1485 /* Triggered update interval timer. */
1486 static int ripng_triggered_interval(struct thread
*t
)
1488 struct ripng
*ripng
= THREAD_ARG(t
);
1490 ripng
->t_triggered_interval
= NULL
;
1492 if (ripng
->trigger
) {
1494 ripng_triggered_update(t
);
1499 /* Execute triggered update. */
1500 int ripng_triggered_update(struct thread
*t
)
1502 struct ripng
*ripng
= THREAD_ARG(t
);
1503 struct interface
*ifp
;
1504 struct ripng_interface
*ri
;
1507 ripng
->t_triggered_update
= NULL
;
1509 /* Cancel interval timer. */
1510 if (ripng
->t_triggered_interval
) {
1511 thread_cancel(ripng
->t_triggered_interval
);
1512 ripng
->t_triggered_interval
= NULL
;
1516 /* Logging triggered update. */
1517 if (IS_RIPNG_DEBUG_EVENT
)
1518 zlog_debug("RIPng triggered update!");
1520 /* Split Horizon processing is done when generating triggered
1521 updates as well as normal updates (see section 2.6). */
1522 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1525 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1531 /* When passive interface is specified, suppress announce to the
1536 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1539 /* Once all of the triggered updates have been generated, the route
1540 change flags should be cleared. */
1541 ripng_clear_changed_flag(ripng
);
1543 /* After a triggered update is sent, a timer should be set for a
1544 random interval between 1 and 5 seconds. If other changes that
1545 would trigger updates occur before the timer expires, a single
1546 update is triggered when the timer expires. */
1547 interval
= (random() % 5) + 1;
1549 ripng
->t_triggered_interval
= NULL
;
1550 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1551 &ripng
->t_triggered_interval
);
1556 /* Write routing table entry to the stream and return next index of
1557 the routing table entry in the stream. */
1558 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1559 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1561 /* RIPng packet header. */
1563 stream_putc(s
, RIPNG_RESPONSE
);
1564 stream_putc(s
, RIPNG_V1
);
1568 /* Write routing table entry. */
1571 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1573 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1574 stream_putw(s
, tag
);
1576 stream_putc(s
, p
->prefixlen
);
1579 stream_putc(s
, metric
);
1584 /* Send RESPONSE message to specified destination. */
1585 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1588 struct ripng
*ripng
;
1590 struct agg_node
*rp
;
1591 struct ripng_info
*rinfo
;
1592 struct ripng_interface
*ri
;
1593 struct ripng_aggregate
*aggregate
;
1594 struct prefix_ipv6
*p
;
1595 struct list
*ripng_rte_list
;
1596 struct list
*list
= NULL
;
1597 struct listnode
*listnode
= NULL
;
1599 if (IS_RIPNG_DEBUG_EVENT
) {
1601 zlog_debug("RIPng update routes to neighbor %s",
1602 inet6_ntoa(to
->sin6_addr
));
1604 zlog_debug("RIPng update routes on interface %s",
1608 /* Get RIPng interface and instance. */
1612 ripng_rte_list
= ripng_rte_new();
1614 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1615 if ((list
= rp
->info
) != NULL
1616 && (rinfo
= listgetdata(listhead(list
))) != NULL
1617 && rinfo
->suppress
== 0) {
1618 /* If no route-map are applied, the RTE will be these
1622 p
= (struct prefix_ipv6
*)&rp
->p
;
1623 rinfo
->metric_out
= rinfo
->metric
;
1624 rinfo
->tag_out
= rinfo
->tag
;
1625 memset(&rinfo
->nexthop_out
, 0,
1626 sizeof(rinfo
->nexthop_out
));
1627 /* In order to avoid some local loops,
1628 * if the RIPng route has a nexthop via this interface,
1630 * otherwise set it to 0. The nexthop should not be
1632 * beyond the local broadcast/multicast area in order
1633 * to avoid an IGP multi-level recursive look-up.
1635 if (rinfo
->ifindex
== ifp
->ifindex
)
1636 rinfo
->nexthop_out
= rinfo
->nexthop
;
1638 /* Apply output filters. */
1639 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1643 /* Changed route only output. */
1644 if (route_type
== ripng_changed_route
1645 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1648 /* Split horizon. */
1649 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1650 /* We perform split horizon for RIPng routes. */
1652 struct ripng_info
*tmp_rinfo
= NULL
;
1654 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1656 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1657 && tmp_rinfo
->ifindex
1666 /* Preparation for route-map. */
1667 rinfo
->metric_set
= 0;
1670 * and tag_out are already initialized.
1673 /* Interface route-map */
1674 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1675 ret
= route_map_apply(
1676 ri
->routemap
[RIPNG_FILTER_OUT
],
1677 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1679 if (ret
== RMAP_DENYMATCH
) {
1680 if (IS_RIPNG_DEBUG_PACKET
)
1682 "RIPng %s/%d is filtered by route-map out",
1683 inet6_ntoa(p
->prefix
),
1689 /* Redistribute route-map. */
1690 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1691 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1696 if (ret
== RMAP_DENYMATCH
) {
1697 if (IS_RIPNG_DEBUG_PACKET
)
1699 "RIPng %s/%d is filtered by route-map",
1700 inet6_ntoa(p
->prefix
),
1706 /* When the route-map does not set metric. */
1707 if (!rinfo
->metric_set
) {
1708 /* If the redistribute metric is set. */
1709 if (ripng
->redist
[rinfo
->type
].metric_config
1710 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1712 ripng
->redist
[rinfo
->type
]
1715 /* If the route is not connected or
1717 one, use default-metric value */
1718 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1720 != ZEBRA_ROUTE_CONNECT
1722 != RIPNG_METRIC_INFINITY
)
1724 ripng
->default_metric
;
1728 /* Apply offset-list */
1729 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1730 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1731 &rinfo
->metric_out
);
1733 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1734 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1736 /* Perform split-horizon with poisoned reverse
1739 if (ri
->split_horizon
1740 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1741 struct ripng_info
*tmp_rinfo
= NULL
;
1743 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1745 if ((tmp_rinfo
->type
1746 == ZEBRA_ROUTE_RIPNG
)
1747 && tmp_rinfo
->ifindex
1750 RIPNG_METRIC_INFINITY
;
1753 /* Add RTE to the list */
1754 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1757 /* Process the aggregated RTE entry */
1758 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1759 && aggregate
->suppress
== 0) {
1760 /* If no route-map are applied, the RTE will be these
1764 p
= (struct prefix_ipv6
*)&rp
->p
;
1765 aggregate
->metric_set
= 0;
1766 aggregate
->metric_out
= aggregate
->metric
;
1767 aggregate
->tag_out
= aggregate
->tag
;
1768 memset(&aggregate
->nexthop_out
, 0,
1769 sizeof(aggregate
->nexthop_out
));
1771 /* Apply output filters.*/
1772 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1776 /* Interface route-map */
1777 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1778 struct ripng_info newinfo
;
1780 /* let's cast the aggregate structure to
1782 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1783 /* the nexthop is :: */
1784 newinfo
.metric
= aggregate
->metric
;
1785 newinfo
.metric_out
= aggregate
->metric_out
;
1786 newinfo
.tag
= aggregate
->tag
;
1787 newinfo
.tag_out
= aggregate
->tag_out
;
1789 ret
= route_map_apply(
1790 ri
->routemap
[RIPNG_FILTER_OUT
],
1791 (struct prefix
*)p
, RMAP_RIPNG
,
1794 if (ret
== RMAP_DENYMATCH
) {
1795 if (IS_RIPNG_DEBUG_PACKET
)
1797 "RIPng %s/%d is filtered by route-map out",
1798 inet6_ntoa(p
->prefix
),
1803 aggregate
->metric_out
= newinfo
.metric_out
;
1804 aggregate
->tag_out
= newinfo
.tag_out
;
1805 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1806 aggregate
->nexthop_out
=
1807 newinfo
.nexthop_out
;
1810 /* There is no redistribute routemap for the aggregated
1813 /* Changed route only output. */
1814 /* XXX, vincent, in order to increase time convergence,
1815 * it should be announced if a child has changed.
1817 if (route_type
== ripng_changed_route
)
1820 /* Apply offset-list */
1821 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1822 ripng_offset_list_apply_out(
1823 ripng
, p
, ifp
, &aggregate
->metric_out
);
1825 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1826 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1828 /* Add RTE to the list */
1829 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1833 /* Flush the list */
1834 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1835 ripng_rte_free(ripng_rte_list
);
1838 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1842 vrf
= vrf_lookup_by_id(vrf_id
);
1849 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1853 ripng
.vrf_name
= (char *)vrf_name
;
1855 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1858 /* Create new RIPng instance and set it to global variable. */
1859 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1861 struct ripng
*ripng
;
1863 /* Allocaste RIPng instance. */
1864 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1865 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1867 /* Default version and timer values. */
1868 ripng
->version
= RIPNG_V1
;
1869 ripng
->update_time
= yang_get_default_uint32(
1870 "%s/timers/update-interval", RIPNG_INSTANCE
);
1871 ripng
->timeout_time
= yang_get_default_uint32(
1872 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1873 ripng
->garbage_time
= yang_get_default_uint32(
1874 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1875 ripng
->default_metric
=
1876 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1877 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1880 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1881 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1883 /* Initialize RIPng data structures. */
1884 ripng
->table
= agg_table_init();
1885 agg_set_table_info(ripng
->table
, ripng
);
1886 ripng
->peer_list
= list_new();
1887 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1888 ripng
->peer_list
->del
= ripng_peer_list_del
;
1889 ripng
->enable_if
= vector_init(1);
1890 ripng
->enable_network
= agg_table_init();
1891 ripng
->passive_interface
= vector_init(1);
1892 ripng
->offset_list_master
= list_new();
1893 ripng
->offset_list_master
->cmp
=
1894 (int (*)(void *, void *))offset_list_cmp
;
1895 ripng
->offset_list_master
->del
=
1896 (void (*)(void *))ripng_offset_list_free
;
1897 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1898 distribute_list_add_hook(ripng
->distribute_ctx
,
1899 ripng_distribute_update
);
1900 distribute_list_delete_hook(ripng
->distribute_ctx
,
1901 ripng_distribute_update
);
1903 /* if rmap install. */
1904 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1905 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1906 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1908 /* Enable the routing instance if possible. */
1909 if (vrf
&& vrf_is_enabled(vrf
))
1910 ripng_instance_enable(ripng
, vrf
, socket
);
1916 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1921 /* Send RIPng request to the interface. */
1922 int ripng_request(struct interface
*ifp
)
1925 struct ripng_packet ripng_packet
;
1927 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1929 if (if_is_loopback(ifp
))
1932 /* If interface is down, don't send RIP packet. */
1936 if (IS_RIPNG_DEBUG_EVENT
)
1937 zlog_debug("RIPng send request to %s", ifp
->name
);
1939 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1940 ripng_packet
.command
= RIPNG_REQUEST
;
1941 ripng_packet
.version
= RIPNG_V1
;
1942 rte
= ripng_packet
.rte
;
1943 rte
->metric
= RIPNG_METRIC_INFINITY
;
1945 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1950 static int ripng_update_jitter(int time
)
1952 return ((random() % (time
+ 1)) - (time
/ 2));
1955 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1961 thread_add_read(master
, ripng_read
, ripng
, sock
,
1964 case RIPNG_UPDATE_EVENT
:
1965 if (ripng
->t_update
) {
1966 thread_cancel(ripng
->t_update
);
1967 ripng
->t_update
= NULL
;
1969 /* Update timer jitter. */
1970 jitter
= ripng_update_jitter(ripng
->update_time
);
1972 ripng
->t_update
= NULL
;
1973 thread_add_timer(master
, ripng_update
, ripng
,
1974 sock
? 2 : ripng
->update_time
+ jitter
,
1977 case RIPNG_TRIGGERED_UPDATE
:
1978 if (ripng
->t_triggered_interval
)
1981 thread_add_event(master
, ripng_triggered_update
, ripng
,
1982 0, &ripng
->t_triggered_update
);
1990 /* Print out routes update time. */
1991 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1996 char timebuf
[TIME_BUF
];
1997 struct thread
*thread
;
1999 if ((thread
= rinfo
->t_timeout
) != NULL
) {
2000 clock
= thread_timer_remain_second(thread
);
2001 tm
= gmtime(&clock
);
2002 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
2003 vty_out(vty
, "%5s", timebuf
);
2004 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
2005 clock
= thread_timer_remain_second(thread
);
2006 tm
= gmtime(&clock
);
2007 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
2008 vty_out(vty
, "%5s", timebuf
);
2012 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
2017 if (rinfo
->suppress
)
2018 strlcat(str
, "S", sizeof(str
));
2020 switch (rinfo
->sub_type
) {
2021 case RIPNG_ROUTE_RTE
:
2022 strlcat(str
, "n", sizeof(str
));
2024 case RIPNG_ROUTE_STATIC
:
2025 strlcat(str
, "s", sizeof(str
));
2027 case RIPNG_ROUTE_DEFAULT
:
2028 strlcat(str
, "d", sizeof(str
));
2030 case RIPNG_ROUTE_REDISTRIBUTE
:
2031 strlcat(str
, "r", sizeof(str
));
2033 case RIPNG_ROUTE_INTERFACE
:
2034 strlcat(str
, "i", sizeof(str
));
2037 strlcat(str
, "?", sizeof(str
));
2044 DEFUN (show_ipv6_ripng
,
2045 show_ipv6_ripng_cmd
,
2046 "show ipv6 ripng [vrf NAME]",
2049 "Show RIPng routes\n"
2052 struct ripng
*ripng
;
2053 struct agg_node
*rp
;
2054 struct ripng_info
*rinfo
;
2055 struct ripng_aggregate
*aggregate
;
2056 struct prefix_ipv6
*p
;
2057 struct list
*list
= NULL
;
2058 struct listnode
*listnode
= NULL
;
2060 const char *vrf_name
;
2063 if (argv_find(argv
, argc
, "vrf", &idx
))
2064 vrf_name
= argv
[idx
+ 1]->arg
;
2066 vrf_name
= VRF_DEFAULT_NAME
;
2068 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2070 vty_out(vty
, "%% RIPng instance not found\n");
2073 if (!ripng
->enabled
) {
2074 vty_out(vty
, "%% RIPng instance is disabled\n");
2078 /* Header of display. */
2080 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2082 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2083 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2084 " Network Next Hop Via Metric Tag Time\n");
2086 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2087 if ((aggregate
= rp
->aggregate
) != NULL
) {
2088 p
= (struct prefix_ipv6
*)&rp
->p
;
2091 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
2092 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
2095 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
2099 vty_out(vty
, "%*s", 18, " ");
2101 vty_out(vty
, "%*s", 28, " ");
2102 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2103 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2106 if ((list
= rp
->info
) != NULL
)
2107 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2108 p
= (struct prefix_ipv6
*)&rp
->p
;
2111 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2112 zebra_route_char(rinfo
->type
),
2113 ripng_route_subtype_print(rinfo
),
2114 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2117 vty_out(vty
, "%c(%s) %s/%d ",
2118 zebra_route_char(rinfo
->type
),
2119 ripng_route_subtype_print(rinfo
),
2120 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2123 vty_out(vty
, "%*s", 18, " ");
2124 len
= vty_out(vty
, "%s",
2125 inet6_ntoa(rinfo
->nexthop
));
2129 vty_out(vty
, "%*s", len
, " ");
2132 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2133 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2138 ripng
->vrf
->vrf_id
));
2139 } else if (rinfo
->metric
2140 == RIPNG_METRIC_INFINITY
) {
2141 len
= vty_out(vty
, "kill");
2143 len
= vty_out(vty
, "self");
2147 vty_out(vty
, "%*s", len
, " ");
2149 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2150 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2153 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2154 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2155 /* RTE from remote RIP routers */
2156 ripng_vty_out_uptime(vty
, rinfo
);
2157 } else if (rinfo
->metric
2158 == RIPNG_METRIC_INFINITY
) {
2159 /* poisonous reversed routes (gc) */
2160 ripng_vty_out_uptime(vty
, rinfo
);
2170 DEFUN (show_ipv6_ripng_status
,
2171 show_ipv6_ripng_status_cmd
,
2172 "show ipv6 ripng [vrf NAME] status",
2175 "Show RIPng routes\n"
2177 "IPv6 routing protocol process parameters and statistics\n")
2179 struct ripng
*ripng
;
2180 struct interface
*ifp
;
2181 const char *vrf_name
;
2184 if (argv_find(argv
, argc
, "vrf", &idx
))
2185 vrf_name
= argv
[idx
+ 1]->arg
;
2187 vrf_name
= VRF_DEFAULT_NAME
;
2189 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2191 vty_out(vty
, "%% RIPng instance not found\n");
2194 if (!ripng
->enabled
) {
2195 vty_out(vty
, "%% RIPng instance is disabled\n");
2199 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2200 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2201 ripng
->update_time
);
2202 vty_out(vty
, " next due in %lu seconds\n",
2203 thread_timer_remain_second(ripng
->t_update
));
2204 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2205 vty_out(vty
, " garbage collect after %u seconds\n",
2206 ripng
->garbage_time
);
2208 /* Filtering status show. */
2209 config_show_distribute(vty
, ripng
->distribute_ctx
);
2211 /* Default metric information. */
2212 vty_out(vty
, " Default redistribution metric is %d\n",
2213 ripng
->default_metric
);
2215 /* Redistribute information. */
2216 vty_out(vty
, " Redistributing:");
2217 ripng_redistribute_write(vty
, ripng
);
2220 vty_out(vty
, " Default version control: send version %d,",
2222 vty_out(vty
, " receive version %d \n", ripng
->version
);
2224 vty_out(vty
, " Interface Send Recv\n");
2226 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2227 struct ripng_interface
*ri
;
2231 if (ri
->enable_network
|| ri
->enable_interface
) {
2233 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2234 ripng
->version
, ripng
->version
);
2238 vty_out(vty
, " Routing for Networks:\n");
2239 ripng_network_write(vty
, ripng
);
2241 vty_out(vty
, " Routing Information Sources:\n");
2243 " Gateway BadPackets BadRoutes Distance Last Update\n");
2244 ripng_peer_display(vty
, ripng
);
2250 /* RIPng update timer setup. */
2251 DEFUN (ripng_update_timer
,
2252 ripng_update_timer_cmd
,
2253 "update-timer SECOND",
2254 "Set RIPng update timer in seconds\n"
2257 unsigned long update
;
2258 char *endptr
= NULL
;
2260 update
= strtoul (argv
[0], &endptr
, 10);
2261 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2263 vty_out (vty
, "update timer value error\n");
2264 return CMD_WARNING_CONFIG_FAILED
;
2267 ripng
->update_time
= update
;
2269 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2273 DEFUN (no_ripng_update_timer
,
2274 no_ripng_update_timer_cmd
,
2275 "no update-timer SECOND",
2277 "Unset RIPng update timer in seconds\n"
2280 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2281 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2285 /* RIPng timeout timer setup. */
2286 DEFUN (ripng_timeout_timer
,
2287 ripng_timeout_timer_cmd
,
2288 "timeout-timer SECOND",
2289 "Set RIPng timeout timer in seconds\n"
2292 unsigned long timeout
;
2293 char *endptr
= NULL
;
2295 timeout
= strtoul (argv
[0], &endptr
, 10);
2296 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2298 vty_out (vty
, "timeout timer value error\n");
2299 return CMD_WARNING_CONFIG_FAILED
;
2302 ripng
->timeout_time
= timeout
;
2307 DEFUN (no_ripng_timeout_timer
,
2308 no_ripng_timeout_timer_cmd
,
2309 "no timeout-timer SECOND",
2311 "Unset RIPng timeout timer in seconds\n"
2314 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2318 /* RIPng garbage timer setup. */
2319 DEFUN (ripng_garbage_timer
,
2320 ripng_garbage_timer_cmd
,
2321 "garbage-timer SECOND",
2322 "Set RIPng garbage timer in seconds\n"
2325 unsigned long garbage
;
2326 char *endptr
= NULL
;
2328 garbage
= strtoul (argv
[0], &endptr
, 10);
2329 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2331 vty_out (vty
, "garbage timer value error\n");
2332 return CMD_WARNING_CONFIG_FAILED
;
2335 ripng
->garbage_time
= garbage
;
2340 DEFUN (no_ripng_garbage_timer
,
2341 no_ripng_garbage_timer_cmd
,
2342 "no garbage-timer SECOND",
2344 "Unset RIPng garbage timer in seconds\n"
2347 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2353 DEFUN (show_ipv6_protocols
,
2354 show_ipv6_protocols_cmd
,
2355 "show ipv6 protocols",
2358 "Routing protocol information\n")
2363 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2365 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2366 ripng
->update_time
, 0);
2368 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2369 ripng
->timeout_time
,
2370 ripng
->garbage_time
);
2372 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2373 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2379 /* Update ECMP routes to zebra when ECMP is disabled. */
2380 void ripng_ecmp_disable(struct ripng
*ripng
)
2382 struct agg_node
*rp
;
2383 struct ripng_info
*rinfo
, *tmp_rinfo
;
2385 struct listnode
*node
, *nextnode
;
2390 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2391 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2392 rinfo
= listgetdata(listhead(list
));
2393 if (!ripng_route_rte(rinfo
))
2396 /* Drop all other entries, except the first one. */
2397 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2398 if (tmp_rinfo
!= rinfo
) {
2399 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2401 tmp_rinfo
->t_garbage_collect
);
2402 list_delete_node(list
, node
);
2403 ripng_info_free(tmp_rinfo
);
2407 ripng_zebra_ipv6_add(ripng
, rp
);
2409 /* Set the route change flag. */
2410 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2412 /* Signal the output process to trigger an update. */
2413 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2417 /* RIPng configuration write function. */
2418 static int ripng_config_write(struct vty
*vty
)
2420 struct ripng
*ripng
;
2423 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2424 char xpath
[XPATH_MAXLEN
];
2425 struct lyd_node
*dnode
;
2427 snprintf(xpath
, sizeof(xpath
),
2428 "/frr-ripngd:ripngd/instance[vrf='%s']",
2431 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2434 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2436 config_write_distribute(vty
, ripng
->distribute_ctx
);
2437 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2445 /* RIPng node structure. */
2446 static struct cmd_node cmd_ripng_node
= {
2447 RIPNG_NODE
, "%s(config-router)# ", 1,
2450 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2451 struct distribute
*dist
)
2453 struct interface
*ifp
;
2454 struct ripng_interface
*ri
;
2455 struct access_list
*alist
;
2456 struct prefix_list
*plist
;
2458 if (!ctx
->vrf
|| !dist
->ifname
)
2461 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2467 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2468 alist
= access_list_lookup(AFI_IP6
,
2469 dist
->list
[DISTRIBUTE_V6_IN
]);
2471 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2473 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2475 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2477 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2478 alist
= access_list_lookup(AFI_IP6
,
2479 dist
->list
[DISTRIBUTE_V6_OUT
]);
2481 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2483 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2485 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2487 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2488 plist
= prefix_list_lookup(AFI_IP6
,
2489 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2491 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2493 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2495 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2497 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2498 plist
= prefix_list_lookup(AFI_IP6
,
2499 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2501 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2503 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2505 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2508 void ripng_distribute_update_interface(struct interface
*ifp
)
2510 struct ripng_interface
*ri
= ifp
->info
;
2511 struct ripng
*ripng
= ri
->ripng
;
2512 struct distribute
*dist
;
2516 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2518 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2521 /* Update all interface's distribute list. */
2522 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2524 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2525 struct interface
*ifp
;
2527 FOR_ALL_INTERFACES (vrf
, ifp
)
2528 ripng_distribute_update_interface(ifp
);
2531 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2533 ripng_distribute_update_all(NULL
);
2536 /* delete all the added ripng routes. */
2537 void ripng_clean(struct ripng
*ripng
)
2540 ripng_instance_disable(ripng
);
2542 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2543 if (ripng
->redist
[i
].route_map
.name
)
2544 free(ripng
->redist
[i
].route_map
.name
);
2546 agg_table_finish(ripng
->table
);
2547 list_delete(&ripng
->peer_list
);
2548 distribute_list_delete(&ripng
->distribute_ctx
);
2549 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2551 stream_free(ripng
->ibuf
);
2552 stream_free(ripng
->obuf
);
2554 ripng_clean_network(ripng
);
2555 ripng_passive_interface_clean(ripng
);
2556 vector_free(ripng
->enable_if
);
2557 agg_table_finish(ripng
->enable_network
);
2558 vector_free(ripng
->passive_interface
);
2559 list_delete(&ripng
->offset_list_master
);
2560 ripng_interface_clean(ripng
);
2562 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2563 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2564 XFREE(MTYPE_RIPNG
, ripng
);
2567 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2568 struct if_rmap
*if_rmap
)
2570 struct interface
*ifp
= NULL
;
2571 struct ripng_interface
*ri
;
2572 struct route_map
*rmap
;
2573 struct vrf
*vrf
= NULL
;
2576 vrf
= vrf_lookup_by_name(ctx
->name
);
2578 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2584 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2585 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2587 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2589 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2591 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2593 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2594 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2596 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2598 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2600 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2603 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2605 struct ripng_interface
*ri
= ifp
->info
;
2606 struct ripng
*ripng
= ri
->ripng
;
2607 struct if_rmap
*if_rmap
;
2608 struct if_rmap_ctx
*ctx
;
2612 ctx
= ripng
->if_rmap_ctx
;
2615 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2617 ripng_if_rmap_update(ctx
, if_rmap
);
2620 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2622 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2623 if (ripng
->redist
[i
].route_map
.name
) {
2624 ripng
->redist
[i
].route_map
.map
=
2625 route_map_lookup_by_name(
2626 ripng
->redist
[i
].route_map
.name
);
2627 route_map_counter_increment(
2628 ripng
->redist
[i
].route_map
.map
);
2633 static void ripng_routemap_update(const char *unused
)
2635 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2636 struct ripng
*ripng
;
2637 struct interface
*ifp
;
2639 FOR_ALL_INTERFACES (vrf
, ifp
)
2640 ripng_if_rmap_update_interface(ifp
);
2644 ripng_routemap_update_redistribute(ripng
);
2647 /* Link RIPng instance to VRF. */
2648 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2650 struct interface
*ifp
;
2653 ripng
->distribute_ctx
->vrf
= vrf
;
2656 FOR_ALL_INTERFACES (vrf
, ifp
)
2657 ripng_interface_sync(ifp
);
2660 /* Unlink RIPng instance from VRF. */
2661 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2663 struct interface
*ifp
;
2666 ripng
->distribute_ctx
->vrf
= NULL
;
2669 FOR_ALL_INTERFACES (vrf
, ifp
)
2670 ripng_interface_sync(ifp
);
2673 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2678 ripng_vrf_link(ripng
, vrf
);
2679 ripng
->enabled
= true;
2681 /* Resend all redistribute requests. */
2682 ripng_redistribute_enable(ripng
);
2684 /* Create read and timer thread. */
2685 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2686 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2688 ripng_zebra_vrf_register(vrf
);
2691 static void ripng_instance_disable(struct ripng
*ripng
)
2693 struct vrf
*vrf
= ripng
->vrf
;
2694 struct agg_node
*rp
;
2696 /* Clear RIPng routes */
2697 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2698 struct ripng_aggregate
*aggregate
;
2701 if ((list
= rp
->info
) != NULL
) {
2702 struct ripng_info
*rinfo
;
2703 struct listnode
*listnode
;
2705 rinfo
= listgetdata(listhead(list
));
2706 if (ripng_route_rte(rinfo
))
2707 ripng_zebra_ipv6_delete(ripng
, rp
);
2709 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2710 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2711 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2712 ripng_info_free(rinfo
);
2716 agg_unlock_node(rp
);
2719 if ((aggregate
= rp
->aggregate
) != NULL
) {
2720 ripng_aggregate_free(aggregate
);
2721 rp
->aggregate
= NULL
;
2722 agg_unlock_node(rp
);
2726 /* Flush all redistribute requests. */
2727 ripng_redistribute_disable(ripng
);
2729 /* Cancel the RIPng timers */
2730 RIPNG_TIMER_OFF(ripng
->t_update
);
2731 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2732 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2734 /* Cancel the read thread */
2735 if (ripng
->t_read
) {
2736 thread_cancel(ripng
->t_read
);
2737 ripng
->t_read
= NULL
;
2740 /* Close the RIPng socket */
2741 if (ripng
->sock
>= 0) {
2746 /* Clear existing peers. */
2747 list_delete_all_node(ripng
->peer_list
);
2749 ripng_zebra_vrf_deregister(vrf
);
2751 ripng_vrf_unlink(ripng
, vrf
);
2752 ripng
->enabled
= false;
2755 static int ripng_vrf_new(struct vrf
*vrf
)
2757 if (IS_RIPNG_DEBUG_EVENT
)
2758 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2764 static int ripng_vrf_delete(struct vrf
*vrf
)
2766 if (IS_RIPNG_DEBUG_EVENT
)
2767 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2773 static int ripng_vrf_enable(struct vrf
*vrf
)
2775 struct ripng
*ripng
;
2778 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2780 char *old_vrf_name
= NULL
;
2782 ripng
= (struct ripng
*)vrf
->info
;
2785 /* update vrf name */
2786 if (ripng
->vrf_name
)
2787 old_vrf_name
= ripng
->vrf_name
;
2788 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf
->name
);
2790 * HACK: Change the RIPng VRF in the running configuration directly,
2791 * bypassing the northbound layer. This is necessary to avoid deleting
2792 * the RIPng and readding it in the new VRF, which would have
2793 * several implications.
2795 if (yang_module_find("frr-ripngd") && old_vrf_name
) {
2796 struct lyd_node
*ripng_dnode
;
2798 ripng_dnode
= yang_dnode_get(
2799 running_config
->dnode
,
2800 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2803 yang_dnode_change_leaf(ripng_dnode
, vrf
->name
);
2804 running_config
->version
++;
2808 XFREE(MTYPE_RIPNG_VRF_NAME
, old_vrf_name
);
2814 if (IS_RIPNG_DEBUG_EVENT
)
2815 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2818 /* Activate the VRF RIPng instance. */
2819 socket
= ripng_make_socket(vrf
);
2823 ripng_instance_enable(ripng
, vrf
, socket
);
2828 static int ripng_vrf_disable(struct vrf
*vrf
)
2830 struct ripng
*ripng
;
2832 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2833 if (!ripng
|| !ripng
->enabled
)
2836 if (IS_RIPNG_DEBUG_EVENT
)
2837 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2840 /* Deactivate the VRF RIPng instance. */
2842 ripng_instance_disable(ripng
);
2847 void ripng_vrf_init(void)
2849 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2850 ripng_vrf_delete
, ripng_vrf_enable
);
2853 void ripng_vrf_terminate(void)
2858 /* Initialize ripng structure and set commands. */
2859 void ripng_init(void)
2861 /* Install RIPNG_NODE. */
2862 install_node(&cmd_ripng_node
, ripng_config_write
);
2864 /* Install ripng commands. */
2865 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2866 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2868 install_default(RIPNG_NODE
);
2871 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2872 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2873 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2874 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2875 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2876 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2877 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2883 /* Access list install. */
2885 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2886 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2888 /* Prefix list initialize.*/
2890 prefix_list_add_hook(ripng_distribute_update_all
);
2891 prefix_list_delete_hook(ripng_distribute_update_all
);
2893 /* Distribute list install. */
2894 distribute_list_init(RIPNG_NODE
);
2896 /* Route-map for interface. */
2897 ripng_route_map_init();
2899 route_map_add_hook(ripng_routemap_update
);
2900 route_map_delete_hook(ripng_routemap_update
);
2902 if_rmap_init(RIPNG_NODE
);