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 char buf
[INET6_BUFSIZ
];
356 /* Logging before checking RTE. */
357 if (IS_RIPNG_DEBUG_RECV
)
358 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
360 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
363 /* RFC2080 2.1.1 Next Hop:
364 The route tag and prefix length in the next hop RTE must be
365 set to zero on sending and ignored on receiption. */
366 if (ntohs(rte
->tag
) != 0)
368 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
370 (route_tag_t
)ntohs(rte
->tag
),
371 inet6_ntoa(from
->sin6_addr
));
373 if (rte
->prefixlen
!= 0)
375 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
376 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
378 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
379 next hop RTE indicates that the next hop address should be the
380 originator of the RIPng advertisement. An address specified as a
381 next hop must be a link-local address. */
382 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
383 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
384 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
388 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
389 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
390 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
394 /* The purpose of the next hop RTE is to eliminate packets being
395 routed through extra hops in the system. It is particularly useful
396 when RIPng is not being run on all of the routers on a network.
397 Note that next hop RTE is "advisory". That is, if the provided
398 information is ignored, a possibly sub-optimal, but absolutely
399 valid, route may be taken. If the received next hop address is not
400 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
401 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
402 inet6_ntoa(rte
->addr
),
403 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
405 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
406 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
411 /* If ifp has same link-local address then return 1. */
412 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
414 struct listnode
*node
;
415 struct connected
*connected
;
418 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
419 p
= connected
->address
;
421 if (p
->family
== AF_INET6
422 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
423 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
429 /* RIPng route garbage collect timer. */
430 static int ripng_garbage_collect(struct thread
*t
)
432 struct ripng_info
*rinfo
;
435 rinfo
= THREAD_ARG(t
);
436 rinfo
->t_garbage_collect
= NULL
;
438 /* Off timeout timer. */
439 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
441 /* Get route_node pointer. */
444 /* Unlock route_node. */
445 listnode_delete(rp
->info
, rinfo
);
446 if (list_isempty((struct list
*)rp
->info
)) {
447 list_delete((struct list
**)&rp
->info
);
451 /* Free RIPng routing information. */
452 ripng_info_free(rinfo
);
457 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
459 /* Add new route to the ECMP list.
460 * RETURN: the new entry added in the list, or NULL if it is not the first
461 * entry and ECMP is not allowed.
463 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
464 struct ripng_info
*rinfo_new
)
466 struct agg_node
*rp
= rinfo_new
->rp
;
467 struct ripng_info
*rinfo
= NULL
;
468 struct list
*list
= NULL
;
470 if (rp
->info
== NULL
)
471 rp
->info
= list_new();
472 list
= (struct list
*)rp
->info
;
474 /* If ECMP is not allowed and some entry already exists in the list,
476 if (listcount(list
) && !ripng
->ecmp
)
479 rinfo
= ripng_info_new();
480 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
481 listnode_add(list
, rinfo
);
483 if (ripng_route_rte(rinfo
)) {
484 ripng_timeout_update(ripng
, rinfo
);
485 ripng_zebra_ipv6_add(ripng
, rp
);
488 ripng_aggregate_increment(rp
, rinfo
);
490 /* Set the route change flag on the first entry. */
491 rinfo
= listgetdata(listhead(list
));
492 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
494 /* Signal the output process to trigger an update. */
495 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
500 /* Replace the ECMP list with the new route.
501 * RETURN: the new entry added in the list
503 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
504 struct ripng_info
*rinfo_new
)
506 struct agg_node
*rp
= rinfo_new
->rp
;
507 struct list
*list
= (struct list
*)rp
->info
;
508 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
509 struct listnode
*node
= NULL
, *nextnode
= NULL
;
511 if (list
== NULL
|| listcount(list
) == 0)
512 return ripng_ecmp_add(ripng
, rinfo_new
);
514 /* Get the first entry */
515 rinfo
= listgetdata(listhead(list
));
517 /* Learnt route replaced by a local one. Delete it from zebra. */
518 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
519 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
520 ripng_zebra_ipv6_delete(ripng
, rp
);
522 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
523 ripng_aggregate_decrement_list(rp
, list
);
525 /* Re-use the first entry, and delete the others. */
526 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
527 if (tmp_rinfo
!= rinfo
) {
528 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
529 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
530 list_delete_node(list
, node
);
531 ripng_info_free(tmp_rinfo
);
534 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
535 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
536 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
538 if (ripng_route_rte(rinfo
)) {
539 ripng_timeout_update(ripng
, rinfo
);
540 /* The ADD message implies an update. */
541 ripng_zebra_ipv6_add(ripng
, rp
);
544 ripng_aggregate_increment(rp
, rinfo
);
546 /* Set the route change flag. */
547 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
549 /* Signal the output process to trigger an update. */
550 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
555 /* Delete one route from the ECMP list.
557 * null - the entry is freed, and other entries exist in the list
558 * the entry - the entry is the last one in the list; its metric is set
559 * to INFINITY, and the garbage collector is started for it
561 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
562 struct ripng_info
*rinfo
)
564 struct agg_node
*rp
= rinfo
->rp
;
565 struct list
*list
= (struct list
*)rp
->info
;
567 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
569 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
570 ripng_aggregate_decrement(rp
, rinfo
);
572 if (listcount(list
) > 1) {
573 /* Some other ECMP entries still exist. Just delete this entry.
575 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
576 listnode_delete(list
, rinfo
);
577 if (ripng_route_rte(rinfo
)
578 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
579 /* The ADD message implies the update. */
580 ripng_zebra_ipv6_add(ripng
, rp
);
581 ripng_info_free(rinfo
);
584 assert(rinfo
== listgetdata(listhead(list
)));
586 /* This is the only entry left in the list. We must keep it in
587 * the list for garbage collection time, with INFINITY metric.
590 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
591 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
592 ripng
->garbage_time
);
594 if (ripng_route_rte(rinfo
)
595 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
596 ripng_zebra_ipv6_delete(ripng
, rp
);
599 /* Set the route change flag on the first entry. */
600 rinfo
= listgetdata(listhead(list
));
601 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
603 /* Signal the output process to trigger an update. */
604 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
609 /* Timeout RIPng routes. */
610 static int ripng_timeout(struct thread
*t
)
612 struct ripng_info
*rinfo
= THREAD_ARG(t
);
613 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
615 ripng_ecmp_delete(ripng
, rinfo
);
620 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
622 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
623 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
624 thread_add_timer(master
, ripng_timeout
, rinfo
,
625 ripng
->timeout_time
, &rinfo
->t_timeout
);
629 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
630 struct ripng_interface
*ri
)
632 struct distribute
*dist
;
633 struct access_list
*alist
;
634 struct prefix_list
*plist
;
635 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
638 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
640 /* Input distribute-list filtering. */
641 if (ri
->list
[ripng_distribute
]) {
642 if (access_list_apply(ri
->list
[ripng_distribute
],
645 if (IS_RIPNG_DEBUG_PACKET
)
646 zlog_debug("%pFX filtered by distribute %s", p
,
651 if (ri
->prefix
[ripng_distribute
]) {
652 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
655 if (IS_RIPNG_DEBUG_PACKET
)
656 zlog_debug("%pFX filtered by prefix-list %s", p
,
662 /* All interface filter check. */
663 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
665 if (dist
->list
[distribute
]) {
666 alist
= access_list_lookup(AFI_IP6
,
667 dist
->list
[distribute
]);
670 if (access_list_apply(alist
, (struct prefix
*)p
)
672 if (IS_RIPNG_DEBUG_PACKET
)
674 "%pFX filtered by distribute %s",
680 if (dist
->prefix
[distribute
]) {
681 plist
= prefix_list_lookup(AFI_IP6
,
682 dist
->prefix
[distribute
]);
685 if (prefix_list_apply(plist
, (struct prefix
*)p
)
687 if (IS_RIPNG_DEBUG_PACKET
)
689 "%pFX filtered by prefix-list %s",
699 /* Process RIPng route according to RFC2080. */
700 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
701 struct ripng_nexthop
*ripng_nexthop
,
702 struct interface
*ifp
)
705 struct prefix_ipv6 p
;
707 struct ripng_info
*rinfo
= NULL
, newinfo
;
708 struct ripng_interface
*ri
;
710 struct in6_addr
*nexthop
;
712 struct list
*list
= NULL
;
713 struct listnode
*node
= NULL
;
715 /* Make prefix structure. */
716 memset(&p
, 0, sizeof(struct prefix_ipv6
));
718 /* p.prefix = rte->addr; */
719 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
720 p
.prefixlen
= rte
->prefixlen
;
722 /* Make sure mask is applied. */
723 /* XXX We have to check the prefix is valid or not before call
730 /* Apply input filters. */
731 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
735 memset(&newinfo
, 0, sizeof(newinfo
));
736 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
737 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
738 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
739 newinfo
.nexthop
= ripng_nexthop
->address
;
741 newinfo
.nexthop
= from
->sin6_addr
;
742 newinfo
.from
= from
->sin6_addr
;
743 newinfo
.ifindex
= ifp
->ifindex
;
744 newinfo
.metric
= rte
->metric
;
745 newinfo
.metric_out
= rte
->metric
; /* XXX */
746 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
749 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
750 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
751 (struct prefix
*)&p
, RMAP_RIPNG
,
754 if (ret
== RMAP_DENYMATCH
) {
755 if (IS_RIPNG_DEBUG_PACKET
)
757 "RIPng %s/%d is filtered by route-map in",
758 inet6_ntoa(p
.prefix
), p
.prefixlen
);
762 /* Get back the object */
763 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
764 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
765 &ripng_nexthop
->address
)) {
766 /* the nexthop get changed by the routemap */
767 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
768 ripng_nexthop
->address
=
771 ripng_nexthop
->address
= in6addr_any
;
774 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
776 /* the nexthop get changed by the routemap */
777 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
778 ripng_nexthop
->flag
=
779 RIPNG_NEXTHOP_ADDRESS
;
780 ripng_nexthop
->address
=
785 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
787 newinfo
.metric_out
; /* XXX: the routemap uses the
791 /* Once the entry has been validated, update the metric by
792 * adding the cost of the network on wich the message
793 * arrived. If the result is greater than infinity, use infinity
794 * (RFC2453 Sec. 3.9.2)
797 /* Zebra ripngd can handle offset-list in. */
798 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
800 /* If offset-list does not modify the metric use interface's
803 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
805 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
806 rte
->metric
= RIPNG_METRIC_INFINITY
;
808 /* Set nexthop pointer. */
809 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
810 nexthop
= &ripng_nexthop
->address
;
812 nexthop
= &from
->sin6_addr
;
814 /* Lookup RIPng routing table. */
815 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
818 newinfo
.nexthop
= *nexthop
;
819 newinfo
.metric
= rte
->metric
;
820 newinfo
.tag
= ntohs(rte
->tag
);
822 /* Check to see whether there is already RIPng route on the table. */
823 if ((list
= rp
->info
) != NULL
)
824 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
825 /* Need to compare with redistributed entry or local
827 if (!ripng_route_rte(rinfo
))
830 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
831 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
834 if (!listnextnode(node
)) {
835 /* Not found in the list */
837 if (rte
->metric
> rinfo
->metric
) {
838 /* New route has a greater metric.
844 if (rte
->metric
< rinfo
->metric
)
845 /* New route has a smaller metric.
846 * Replace the ECMP list
847 * with the new one in below. */
850 /* Metrics are same. Unless ECMP is disabled,
851 * keep "rinfo" null and
852 * the new route is added in the ECMP list in
860 /* Redistributed route check. */
861 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
862 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
867 /* Local static route. */
868 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
869 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
870 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
871 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
878 /* Now, check to see whether there is already an explicit route
879 for the destination prefix. If there is no such route, add
880 this route to the routing table, unless the metric is
881 infinity (there is no point in adding a route which
883 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
884 ripng_ecmp_add(ripng
, &newinfo
);
888 /* If there is an existing route, compare the next hop address
889 to the address of the router from which the datagram came.
890 If this datagram is from the same router as the existing
891 route, reinitialize the timeout. */
892 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
893 && (rinfo
->ifindex
== ifp
->ifindex
));
896 * RFC 2080 - Section 2.4.2:
897 * "If the new metric is the same as the old one, examine the
899 * for the existing route. If it is at least halfway to the
901 * point, switch to the new route. This heuristic is optional,
903 * highly recommended".
905 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
907 && (thread_timer_remain_second(rinfo
->t_timeout
)
908 < (ripng
->timeout_time
/ 2))) {
909 ripng_ecmp_replace(ripng
, &newinfo
);
911 /* Next, compare the metrics. If the datagram is from the same
912 router as the existing route, and the new metric is different
913 than the old one; or, if the new metric is lower than the old
914 one; do the following actions: */
915 else if ((same
&& rinfo
->metric
!= rte
->metric
)
916 || rte
->metric
< rinfo
->metric
) {
917 if (listcount(list
) == 1) {
918 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
919 ripng_ecmp_replace(ripng
, &newinfo
);
921 ripng_ecmp_delete(ripng
, rinfo
);
923 if (newinfo
.metric
< rinfo
->metric
)
924 ripng_ecmp_replace(ripng
, &newinfo
);
925 else /* newinfo.metric > rinfo->metric */
926 ripng_ecmp_delete(ripng
, rinfo
);
928 } else /* same & no change */
929 ripng_timeout_update(ripng
, rinfo
);
931 /* Unlock tempolary lock of the route. */
936 /* Add redistributed route to RIPng table. */
937 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
938 struct prefix_ipv6
*p
, ifindex_t ifindex
,
939 struct in6_addr
*nexthop
, route_tag_t tag
)
942 struct ripng_info
*rinfo
= NULL
, newinfo
;
943 struct list
*list
= NULL
;
945 /* Redistribute route */
946 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
948 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
951 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
953 memset(&newinfo
, 0, sizeof(struct ripng_info
));
955 newinfo
.sub_type
= sub_type
;
956 newinfo
.ifindex
= ifindex
;
958 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
961 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
962 newinfo
.nexthop
= *nexthop
;
964 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
965 rinfo
= listgetdata(listhead(list
));
967 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
968 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
969 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
974 /* Manually configured RIPng route check.
975 * They have the precedence on all the other entries.
977 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
978 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
979 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
980 if (type
!= ZEBRA_ROUTE_RIPNG
981 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
982 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
988 ripng_ecmp_replace(ripng
, &newinfo
);
991 ripng_ecmp_add(ripng
, &newinfo
);
993 if (IS_RIPNG_DEBUG_EVENT
) {
996 "Redistribute new prefix %pFX on the interface %s",
997 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1000 "Redistribute new prefix %pFX with nexthop %s on the interface %s",
1001 p
, inet6_ntoa(*nexthop
),
1002 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1005 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1008 /* Delete redistributed route to RIPng table. */
1009 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1010 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1012 struct agg_node
*rp
;
1013 struct ripng_info
*rinfo
;
1015 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1017 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1020 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1023 struct list
*list
= rp
->info
;
1025 if (list
!= NULL
&& listcount(list
) != 0) {
1026 rinfo
= listgetdata(listhead(list
));
1027 if (rinfo
!= NULL
&& rinfo
->type
== type
1028 && rinfo
->sub_type
== sub_type
1029 && rinfo
->ifindex
== ifindex
) {
1030 /* Perform poisoned reverse. */
1031 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1032 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1033 ripng_garbage_collect
,
1034 ripng
->garbage_time
);
1035 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1037 /* Aggregate count decrement. */
1038 ripng_aggregate_decrement(rp
, rinfo
);
1040 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1042 if (IS_RIPNG_DEBUG_EVENT
)
1044 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1048 ripng
->vrf
->vrf_id
));
1050 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1053 agg_unlock_node(rp
);
1057 /* Withdraw redistributed route. */
1058 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1060 struct agg_node
*rp
;
1061 struct ripng_info
*rinfo
= NULL
;
1062 struct list
*list
= NULL
;
1064 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1065 if ((list
= rp
->info
) != NULL
) {
1066 rinfo
= listgetdata(listhead(list
));
1067 if ((rinfo
->type
== type
)
1068 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1069 /* Perform poisoned reverse. */
1070 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1071 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1072 ripng_garbage_collect
,
1073 ripng
->garbage_time
);
1074 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1076 /* Aggregate count decrement. */
1077 ripng_aggregate_decrement(rp
, rinfo
);
1079 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1081 if (IS_RIPNG_DEBUG_EVENT
) {
1082 struct prefix_ipv6
*p
=
1083 (struct prefix_ipv6
*)
1084 agg_node_get_prefix(rp
);
1087 "Poisone %pFX on the interface %s [withdraw]",
1091 ripng
->vrf
->vrf_id
));
1094 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1099 /* RIP routing information. */
1100 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1101 struct sockaddr_in6
*from
,
1102 struct interface
*ifp
, int hoplimit
)
1104 struct ripng_interface
*ri
= ifp
->info
;
1105 struct ripng
*ripng
= ri
->ripng
;
1108 struct ripng_nexthop nexthop
;
1110 /* RFC2080 2.4.2 Response Messages:
1111 The Response must be ignored if it is not from the RIPng port. */
1112 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1113 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1114 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1115 ripng_peer_bad_packet(ripng
, from
);
1119 /* The datagram's IPv6 source address should be checked to see
1120 whether the datagram is from a valid neighbor; the source of the
1121 datagram must be a link-local address. */
1122 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1123 zlog_warn("RIPng packet comes from non link local address %s",
1124 inet6_ntoa(from
->sin6_addr
));
1125 ripng_peer_bad_packet(ripng
, from
);
1129 /* It is also worth checking to see whether the response is from one
1130 of the router's own addresses. Interfaces on broadcast networks
1131 may receive copies of their own multicasts immediately. If a
1132 router processes its own output as new input, confusion is likely,
1133 and such datagrams must be ignored. */
1134 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1136 "RIPng packet comes from my own link local address %s",
1137 inet6_ntoa(from
->sin6_addr
));
1138 ripng_peer_bad_packet(ripng
, from
);
1142 /* As an additional check, periodic advertisements must have their
1143 hop counts set to 255, and inbound, multicast packets sent from the
1144 RIPng port (i.e. periodic advertisement or triggered update
1145 packets) must be examined to ensure that the hop count is 255. */
1146 if (hoplimit
>= 0 && hoplimit
!= 255) {
1148 "RIPng packet comes with non 255 hop count %d from %s",
1149 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1150 ripng_peer_bad_packet(ripng
, from
);
1154 /* Update RIPng peer. */
1155 ripng_peer_update(ripng
, from
, packet
->version
);
1157 /* Reset nexthop. */
1158 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1159 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1161 /* Set RTE pointer. */
1164 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1165 /* First of all, we have to check this RTE is next hop RTE or
1166 not. Next hop RTE is completely different with normal RTE so
1167 we need special treatment. */
1168 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1169 ripng_nexthop_rte(rte
, from
, &nexthop
);
1173 /* RTE information validation. */
1175 /* - is the destination prefix valid (e.g., not a multicast
1176 prefix and not a link-local address) A link-local address
1177 should never be present in an RTE. */
1178 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1180 "Destination prefix is a multicast address %s/%d [%d]",
1181 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1183 ripng_peer_bad_route(ripng
, from
);
1186 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1188 "Destination prefix is a link-local address %s/%d [%d]",
1189 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1191 ripng_peer_bad_route(ripng
, from
);
1194 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1196 "Destination prefix is a loopback address %s/%d [%d]",
1197 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1199 ripng_peer_bad_route(ripng
, from
);
1203 /* - is the prefix length valid (i.e., between 0 and 128,
1205 if (rte
->prefixlen
> 128) {
1206 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1207 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1208 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1209 ripng_peer_bad_route(ripng
, from
);
1213 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1214 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1215 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1216 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1217 ripng_peer_bad_route(ripng
, from
);
1221 /* Vincent: XXX Should we compute the direclty reachable nexthop
1222 * for our RIPng network ?
1225 /* Routing table updates. */
1226 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1230 /* Response to request message. */
1231 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1232 struct sockaddr_in6
*from
,
1233 struct interface
*ifp
)
1235 struct ripng
*ripng
;
1238 struct prefix_ipv6 p
;
1239 struct agg_node
*rp
;
1240 struct ripng_info
*rinfo
;
1241 struct ripng_interface
*ri
;
1243 /* Does not reponse to the requests on the loopback interfaces */
1244 if (if_is_loopback(ifp
))
1247 /* Check RIPng process is enabled on this interface. */
1253 /* When passive interface is specified, suppress responses */
1257 /* RIPng peer update. */
1258 ripng_peer_update(ripng
, from
, packet
->version
);
1260 lim
= ((caddr_t
)packet
) + size
;
1263 /* The Request is processed entry by entry. If there are no
1264 entries, no response is given. */
1265 if (lim
== (caddr_t
)rte
)
1268 /* There is one special case. If there is exactly one entry in the
1269 request, and it has a destination prefix of zero, a prefix length
1270 of zero, and a metric of infinity (i.e., 16), then this is a
1271 request to send the entire routing table. In that case, a call
1272 is made to the output process to send the routing table to the
1273 requesting address/port. */
1274 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1275 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1276 /* All route with split horizon */
1277 ripng_output_process(ifp
, from
, ripng_all_route
);
1279 /* Except for this special case, processing is quite simple.
1280 Examine the list of RTEs in the Request one by one. For each
1281 entry, look up the destination in the router's routing
1282 database and, if there is a route, put that route's metric in
1283 the metric field of the RTE. If there is no explicit route
1284 to the specified destination, put infinity in the metric
1285 field. Once all the entries have been filled in, change the
1286 command from Request to Response and send the datagram back
1287 to the requestor. */
1288 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1289 p
.family
= AF_INET6
;
1291 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1292 p
.prefix
= rte
->addr
;
1293 p
.prefixlen
= rte
->prefixlen
;
1294 apply_mask_ipv6(&p
);
1296 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1299 rinfo
= listgetdata(
1300 listhead((struct list
*)rp
->info
));
1301 rte
->metric
= rinfo
->metric
;
1302 agg_unlock_node(rp
);
1304 rte
->metric
= RIPNG_METRIC_INFINITY
;
1306 packet
->command
= RIPNG_RESPONSE
;
1308 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1312 /* First entry point of reading RIPng packet. */
1313 static int ripng_read(struct thread
*thread
)
1315 struct ripng
*ripng
= THREAD_ARG(thread
);
1318 struct sockaddr_in6 from
;
1319 struct ripng_packet
*packet
;
1320 ifindex_t ifindex
= 0;
1321 struct interface
*ifp
;
1324 /* Check ripng is active and alive. */
1325 assert(ripng
!= NULL
);
1326 assert(ripng
->sock
>= 0);
1328 /* Fetch thread data and set read pointer to empty for event
1329 managing. `sock' sould be same as ripng->sock. */
1330 sock
= THREAD_FD(thread
);
1331 ripng
->t_read
= NULL
;
1333 /* Add myself to the next event. */
1334 ripng_event(ripng
, RIPNG_READ
, sock
);
1336 /* Read RIPng packet. */
1337 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1338 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1341 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1342 ripng
->vrf_name
, safe_strerror(errno
));
1346 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1347 (4)) must be multiple size of one RTE size (20). */
1348 if (((len
- 4) % 20) != 0) {
1349 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1350 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1351 ripng_peer_bad_packet(ripng
, &from
);
1355 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1356 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1358 /* RIPng packet received. */
1359 if (IS_RIPNG_DEBUG_EVENT
)
1361 "RIPng packet received from %s port %d on %s (VRF %s)",
1362 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1363 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1365 /* Logging before packet checking. */
1366 if (IS_RIPNG_DEBUG_RECV
)
1367 ripng_packet_dump(packet
, len
, "RECV");
1369 /* Packet comes from unknown interface. */
1372 "RIPng packet comes from unknown interface %d (VRF %s)",
1373 ifindex
, ripng
->vrf_name
);
1377 /* Packet version mismatch checking. */
1378 if (packet
->version
!= ripng
->version
) {
1380 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1381 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1382 ripng_peer_bad_packet(ripng
, &from
);
1386 /* Process RIPng packet. */
1387 switch (packet
->command
) {
1389 ripng_request_process(packet
, len
, &from
, ifp
);
1391 case RIPNG_RESPONSE
:
1392 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1395 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1397 ripng_peer_bad_packet(ripng
, &from
);
1403 /* Walk down the RIPng routing table then clear changed flag. */
1404 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1406 struct agg_node
*rp
;
1407 struct ripng_info
*rinfo
= NULL
;
1408 struct list
*list
= NULL
;
1409 struct listnode
*listnode
= NULL
;
1411 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1412 if ((list
= rp
->info
) != NULL
)
1413 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1414 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1415 /* This flag can be set only on the first entry.
1421 /* Regular update of RIPng route. Send all routing formation to RIPng
1422 enabled interface. */
1423 static int ripng_update(struct thread
*t
)
1425 struct ripng
*ripng
= THREAD_ARG(t
);
1426 struct interface
*ifp
;
1427 struct ripng_interface
*ri
;
1429 /* Clear update timer thread. */
1430 ripng
->t_update
= NULL
;
1432 /* Logging update event. */
1433 if (IS_RIPNG_DEBUG_EVENT
)
1434 zlog_debug("RIPng update timer expired!");
1436 /* Supply routes to each interface. */
1437 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1440 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1446 /* When passive interface is specified, suppress announce to the
1451 #ifdef RIPNG_ADVANCED
1452 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1453 if (IS_RIPNG_DEBUG_EVENT
)
1455 "[Event] RIPng send to if %d is suppressed by config",
1459 #endif /* RIPNG_ADVANCED */
1461 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1464 /* Triggered updates may be suppressed if a regular update is due by
1465 the time the triggered update would be sent. */
1466 if (ripng
->t_triggered_interval
) {
1467 thread_cancel(ripng
->t_triggered_interval
);
1468 ripng
->t_triggered_interval
= NULL
;
1472 /* Reset flush event. */
1473 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1478 /* Triggered update interval timer. */
1479 static int ripng_triggered_interval(struct thread
*t
)
1481 struct ripng
*ripng
= THREAD_ARG(t
);
1483 ripng
->t_triggered_interval
= NULL
;
1485 if (ripng
->trigger
) {
1487 ripng_triggered_update(t
);
1492 /* Execute triggered update. */
1493 int ripng_triggered_update(struct thread
*t
)
1495 struct ripng
*ripng
= THREAD_ARG(t
);
1496 struct interface
*ifp
;
1497 struct ripng_interface
*ri
;
1500 ripng
->t_triggered_update
= NULL
;
1502 /* Cancel interval timer. */
1503 if (ripng
->t_triggered_interval
) {
1504 thread_cancel(ripng
->t_triggered_interval
);
1505 ripng
->t_triggered_interval
= NULL
;
1509 /* Logging triggered update. */
1510 if (IS_RIPNG_DEBUG_EVENT
)
1511 zlog_debug("RIPng triggered update!");
1513 /* Split Horizon processing is done when generating triggered
1514 updates as well as normal updates (see section 2.6). */
1515 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1518 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1524 /* When passive interface is specified, suppress announce to the
1529 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1532 /* Once all of the triggered updates have been generated, the route
1533 change flags should be cleared. */
1534 ripng_clear_changed_flag(ripng
);
1536 /* After a triggered update is sent, a timer should be set for a
1537 random interval between 1 and 5 seconds. If other changes that
1538 would trigger updates occur before the timer expires, a single
1539 update is triggered when the timer expires. */
1540 interval
= (frr_weak_random() % 5) + 1;
1542 ripng
->t_triggered_interval
= NULL
;
1543 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1544 &ripng
->t_triggered_interval
);
1549 /* Write routing table entry to the stream and return next index of
1550 the routing table entry in the stream. */
1551 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1552 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1554 /* RIPng packet header. */
1556 stream_putc(s
, RIPNG_RESPONSE
);
1557 stream_putc(s
, RIPNG_V1
);
1561 /* Write routing table entry. */
1564 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1566 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1567 stream_putw(s
, tag
);
1569 stream_putc(s
, p
->prefixlen
);
1572 stream_putc(s
, metric
);
1577 /* Send RESPONSE message to specified destination. */
1578 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1581 struct ripng
*ripng
;
1583 struct agg_node
*rp
;
1584 struct ripng_info
*rinfo
;
1585 struct ripng_interface
*ri
;
1586 struct ripng_aggregate
*aggregate
;
1587 struct prefix_ipv6
*p
;
1588 struct list
*ripng_rte_list
;
1589 struct list
*list
= NULL
;
1590 struct listnode
*listnode
= NULL
;
1592 if (IS_RIPNG_DEBUG_EVENT
) {
1594 zlog_debug("RIPng update routes to neighbor %s",
1595 inet6_ntoa(to
->sin6_addr
));
1597 zlog_debug("RIPng update routes on interface %s",
1601 /* Get RIPng interface and instance. */
1605 ripng_rte_list
= ripng_rte_new();
1607 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1608 if ((list
= rp
->info
) != NULL
1609 && (rinfo
= listgetdata(listhead(list
))) != NULL
1610 && rinfo
->suppress
== 0) {
1611 /* If no route-map are applied, the RTE will be these
1615 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1616 rinfo
->metric_out
= rinfo
->metric
;
1617 rinfo
->tag_out
= rinfo
->tag
;
1618 memset(&rinfo
->nexthop_out
, 0,
1619 sizeof(rinfo
->nexthop_out
));
1620 /* In order to avoid some local loops,
1621 * if the RIPng route has a nexthop via this interface,
1623 * otherwise set it to 0. The nexthop should not be
1625 * beyond the local broadcast/multicast area in order
1626 * to avoid an IGP multi-level recursive look-up.
1628 if (rinfo
->ifindex
== ifp
->ifindex
)
1629 rinfo
->nexthop_out
= rinfo
->nexthop
;
1631 /* Apply output filters. */
1632 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1636 /* Changed route only output. */
1637 if (route_type
== ripng_changed_route
1638 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1641 /* Split horizon. */
1642 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1643 /* We perform split horizon for RIPng routes. */
1645 struct ripng_info
*tmp_rinfo
= NULL
;
1647 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1649 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1650 && tmp_rinfo
->ifindex
1659 /* Preparation for route-map. */
1660 rinfo
->metric_set
= 0;
1663 * and tag_out are already initialized.
1666 /* Interface route-map */
1667 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1668 ret
= route_map_apply(
1669 ri
->routemap
[RIPNG_FILTER_OUT
],
1670 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1672 if (ret
== RMAP_DENYMATCH
) {
1673 if (IS_RIPNG_DEBUG_PACKET
)
1675 "RIPng %pFX is filtered by route-map out",
1681 /* Redistribute route-map. */
1682 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1683 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1688 if (ret
== RMAP_DENYMATCH
) {
1689 if (IS_RIPNG_DEBUG_PACKET
)
1691 "RIPng %pFX is filtered by route-map",
1697 /* When the route-map does not set metric. */
1698 if (!rinfo
->metric_set
) {
1699 /* If the redistribute metric is set. */
1700 if (ripng
->redist
[rinfo
->type
].metric_config
1701 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1703 ripng
->redist
[rinfo
->type
]
1706 /* If the route is not connected or
1708 one, use default-metric value */
1709 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1711 != ZEBRA_ROUTE_CONNECT
1713 != RIPNG_METRIC_INFINITY
)
1715 ripng
->default_metric
;
1719 /* Apply offset-list */
1720 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1721 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1722 &rinfo
->metric_out
);
1724 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1725 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1727 /* Perform split-horizon with poisoned reverse
1730 if (ri
->split_horizon
1731 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1732 struct ripng_info
*tmp_rinfo
= NULL
;
1734 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1736 if ((tmp_rinfo
->type
1737 == ZEBRA_ROUTE_RIPNG
)
1738 && tmp_rinfo
->ifindex
1741 RIPNG_METRIC_INFINITY
;
1744 /* Add RTE to the list */
1745 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1748 /* Process the aggregated RTE entry */
1749 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1750 && aggregate
->suppress
== 0) {
1751 /* If no route-map are applied, the RTE will be these
1755 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1756 aggregate
->metric_set
= 0;
1757 aggregate
->metric_out
= aggregate
->metric
;
1758 aggregate
->tag_out
= aggregate
->tag
;
1759 memset(&aggregate
->nexthop_out
, 0,
1760 sizeof(aggregate
->nexthop_out
));
1762 /* Apply output filters.*/
1763 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1767 /* Interface route-map */
1768 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1769 struct ripng_info newinfo
;
1771 /* let's cast the aggregate structure to
1773 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1774 /* the nexthop is :: */
1775 newinfo
.metric
= aggregate
->metric
;
1776 newinfo
.metric_out
= aggregate
->metric_out
;
1777 newinfo
.tag
= aggregate
->tag
;
1778 newinfo
.tag_out
= aggregate
->tag_out
;
1780 ret
= route_map_apply(
1781 ri
->routemap
[RIPNG_FILTER_OUT
],
1782 (struct prefix
*)p
, RMAP_RIPNG
,
1785 if (ret
== RMAP_DENYMATCH
) {
1786 if (IS_RIPNG_DEBUG_PACKET
)
1788 "RIPng %pFX is filtered by route-map out",
1793 aggregate
->metric_out
= newinfo
.metric_out
;
1794 aggregate
->tag_out
= newinfo
.tag_out
;
1795 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1796 aggregate
->nexthop_out
=
1797 newinfo
.nexthop_out
;
1800 /* There is no redistribute routemap for the aggregated
1803 /* Changed route only output. */
1804 /* XXX, vincent, in order to increase time convergence,
1805 * it should be announced if a child has changed.
1807 if (route_type
== ripng_changed_route
)
1810 /* Apply offset-list */
1811 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1812 ripng_offset_list_apply_out(
1813 ripng
, p
, ifp
, &aggregate
->metric_out
);
1815 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1816 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1818 /* Add RTE to the list */
1819 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1823 /* Flush the list */
1824 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1825 ripng_rte_free(ripng_rte_list
);
1828 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1832 vrf
= vrf_lookup_by_id(vrf_id
);
1839 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1843 ripng
.vrf_name
= (char *)vrf_name
;
1845 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1848 /* Create new RIPng instance and set it to global variable. */
1849 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1851 struct ripng
*ripng
;
1853 /* Allocaste RIPng instance. */
1854 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1855 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1857 /* Default version and timer values. */
1858 ripng
->version
= RIPNG_V1
;
1859 ripng
->update_time
= yang_get_default_uint32(
1860 "%s/timers/update-interval", RIPNG_INSTANCE
);
1861 ripng
->timeout_time
= yang_get_default_uint32(
1862 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1863 ripng
->garbage_time
= yang_get_default_uint32(
1864 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1865 ripng
->default_metric
=
1866 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1867 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1870 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1871 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1873 /* Initialize RIPng data structures. */
1874 ripng
->table
= agg_table_init();
1875 agg_set_table_info(ripng
->table
, ripng
);
1876 ripng
->peer_list
= list_new();
1877 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1878 ripng
->peer_list
->del
= ripng_peer_list_del
;
1879 ripng
->enable_if
= vector_init(1);
1880 ripng
->enable_network
= agg_table_init();
1881 ripng
->passive_interface
= vector_init(1);
1882 ripng
->offset_list_master
= list_new();
1883 ripng
->offset_list_master
->cmp
=
1884 (int (*)(void *, void *))offset_list_cmp
;
1885 ripng
->offset_list_master
->del
=
1886 (void (*)(void *))ripng_offset_list_free
;
1887 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1888 distribute_list_add_hook(ripng
->distribute_ctx
,
1889 ripng_distribute_update
);
1890 distribute_list_delete_hook(ripng
->distribute_ctx
,
1891 ripng_distribute_update
);
1893 /* if rmap install. */
1894 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1895 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1896 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1898 /* Enable the routing instance if possible. */
1899 if (vrf
&& vrf_is_enabled(vrf
))
1900 ripng_instance_enable(ripng
, vrf
, socket
);
1906 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1911 /* Send RIPng request to the interface. */
1912 int ripng_request(struct interface
*ifp
)
1915 struct ripng_packet ripng_packet
;
1917 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1919 if (if_is_loopback(ifp
))
1922 /* If interface is down, don't send RIP packet. */
1926 if (IS_RIPNG_DEBUG_EVENT
)
1927 zlog_debug("RIPng send request to %s", ifp
->name
);
1929 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1930 ripng_packet
.command
= RIPNG_REQUEST
;
1931 ripng_packet
.version
= RIPNG_V1
;
1932 rte
= ripng_packet
.rte
;
1933 rte
->metric
= RIPNG_METRIC_INFINITY
;
1935 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1940 static int ripng_update_jitter(int time
)
1942 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1945 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1951 thread_add_read(master
, ripng_read
, ripng
, sock
,
1954 case RIPNG_UPDATE_EVENT
:
1955 if (ripng
->t_update
) {
1956 thread_cancel(ripng
->t_update
);
1957 ripng
->t_update
= NULL
;
1959 /* Update timer jitter. */
1960 jitter
= ripng_update_jitter(ripng
->update_time
);
1962 ripng
->t_update
= NULL
;
1963 thread_add_timer(master
, ripng_update
, ripng
,
1964 sock
? 2 : ripng
->update_time
+ jitter
,
1967 case RIPNG_TRIGGERED_UPDATE
:
1968 if (ripng
->t_triggered_interval
)
1971 thread_add_event(master
, ripng_triggered_update
, ripng
,
1972 0, &ripng
->t_triggered_update
);
1980 /* Print out routes update time. */
1981 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1986 char timebuf
[TIME_BUF
];
1987 struct thread
*thread
;
1989 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1990 clock
= thread_timer_remain_second(thread
);
1991 gmtime_r(&clock
, &tm
);
1992 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1993 vty_out(vty
, "%5s", timebuf
);
1994 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1995 clock
= thread_timer_remain_second(thread
);
1996 gmtime_r(&clock
, &tm
);
1997 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1998 vty_out(vty
, "%5s", timebuf
);
2002 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
2007 if (rinfo
->suppress
)
2008 strlcat(str
, "S", sizeof(str
));
2010 switch (rinfo
->sub_type
) {
2011 case RIPNG_ROUTE_RTE
:
2012 strlcat(str
, "n", sizeof(str
));
2014 case RIPNG_ROUTE_STATIC
:
2015 strlcat(str
, "s", sizeof(str
));
2017 case RIPNG_ROUTE_DEFAULT
:
2018 strlcat(str
, "d", sizeof(str
));
2020 case RIPNG_ROUTE_REDISTRIBUTE
:
2021 strlcat(str
, "r", sizeof(str
));
2023 case RIPNG_ROUTE_INTERFACE
:
2024 strlcat(str
, "i", sizeof(str
));
2027 strlcat(str
, "?", sizeof(str
));
2034 DEFUN (show_ipv6_ripng
,
2035 show_ipv6_ripng_cmd
,
2036 "show ipv6 ripng [vrf NAME]",
2039 "Show RIPng routes\n"
2042 struct ripng
*ripng
;
2043 struct agg_node
*rp
;
2044 struct ripng_info
*rinfo
;
2045 struct ripng_aggregate
*aggregate
;
2046 struct list
*list
= NULL
;
2047 struct listnode
*listnode
= NULL
;
2049 const char *vrf_name
;
2052 if (argv_find(argv
, argc
, "vrf", &idx
))
2053 vrf_name
= argv
[idx
+ 1]->arg
;
2055 vrf_name
= VRF_DEFAULT_NAME
;
2057 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2059 vty_out(vty
, "%% RIPng instance not found\n");
2062 if (!ripng
->enabled
) {
2063 vty_out(vty
, "%% RIPng instance is disabled\n");
2067 /* Header of display. */
2069 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2071 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2072 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2073 " Network Next Hop Via Metric Tag Time\n");
2075 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2076 if ((aggregate
= rp
->aggregate
) != NULL
) {
2078 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2079 aggregate
->suppress
, rp
);
2081 vty_out(vty
, "R(a) %pRN ", rp
);
2084 vty_out(vty
, "%*s", 18, " ");
2086 vty_out(vty
, "%*s", 28, " ");
2087 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2088 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2091 if ((list
= rp
->info
) != NULL
)
2092 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2094 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2095 zebra_route_char(rinfo
->type
),
2096 ripng_route_subtype_print(rinfo
),
2097 rinfo
->suppress
, rp
);
2099 vty_out(vty
, "%c(%s) %pRN ",
2100 zebra_route_char(rinfo
->type
),
2101 ripng_route_subtype_print(rinfo
), rp
);
2104 vty_out(vty
, "%*s", 18, " ");
2105 len
= vty_out(vty
, "%s",
2106 inet6_ntoa(rinfo
->nexthop
));
2110 vty_out(vty
, "%*s", len
, " ");
2113 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2114 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2119 ripng
->vrf
->vrf_id
));
2120 } else if (rinfo
->metric
2121 == RIPNG_METRIC_INFINITY
) {
2122 len
= vty_out(vty
, "kill");
2124 len
= vty_out(vty
, "self");
2128 vty_out(vty
, "%*s", len
, " ");
2130 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2131 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2134 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2135 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2136 /* RTE from remote RIP routers */
2137 ripng_vty_out_uptime(vty
, rinfo
);
2138 } else if (rinfo
->metric
2139 == RIPNG_METRIC_INFINITY
) {
2140 /* poisonous reversed routes (gc) */
2141 ripng_vty_out_uptime(vty
, rinfo
);
2151 DEFUN (show_ipv6_ripng_status
,
2152 show_ipv6_ripng_status_cmd
,
2153 "show ipv6 ripng [vrf NAME] status",
2156 "Show RIPng routes\n"
2158 "IPv6 routing protocol process parameters and statistics\n")
2160 struct ripng
*ripng
;
2161 struct interface
*ifp
;
2162 const char *vrf_name
;
2165 if (argv_find(argv
, argc
, "vrf", &idx
))
2166 vrf_name
= argv
[idx
+ 1]->arg
;
2168 vrf_name
= VRF_DEFAULT_NAME
;
2170 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2172 vty_out(vty
, "%% RIPng instance not found\n");
2175 if (!ripng
->enabled
) {
2176 vty_out(vty
, "%% RIPng instance is disabled\n");
2180 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2181 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2182 ripng
->update_time
);
2183 vty_out(vty
, " next due in %lu seconds\n",
2184 thread_timer_remain_second(ripng
->t_update
));
2185 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2186 vty_out(vty
, " garbage collect after %u seconds\n",
2187 ripng
->garbage_time
);
2189 /* Filtering status show. */
2190 config_show_distribute(vty
, ripng
->distribute_ctx
);
2192 /* Default metric information. */
2193 vty_out(vty
, " Default redistribution metric is %d\n",
2194 ripng
->default_metric
);
2196 /* Redistribute information. */
2197 vty_out(vty
, " Redistributing:");
2198 ripng_redistribute_write(vty
, ripng
);
2201 vty_out(vty
, " Default version control: send version %d,",
2203 vty_out(vty
, " receive version %d \n", ripng
->version
);
2205 vty_out(vty
, " Interface Send Recv\n");
2207 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2208 struct ripng_interface
*ri
;
2212 if (ri
->enable_network
|| ri
->enable_interface
) {
2214 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2215 ripng
->version
, ripng
->version
);
2219 vty_out(vty
, " Routing for Networks:\n");
2220 ripng_network_write(vty
, ripng
);
2222 vty_out(vty
, " Routing Information Sources:\n");
2224 " Gateway BadPackets BadRoutes Distance Last Update\n");
2225 ripng_peer_display(vty
, ripng
);
2231 /* RIPng update timer setup. */
2232 DEFUN (ripng_update_timer
,
2233 ripng_update_timer_cmd
,
2234 "update-timer SECOND",
2235 "Set RIPng update timer in seconds\n"
2238 unsigned long update
;
2239 char *endptr
= NULL
;
2241 update
= strtoul (argv
[0], &endptr
, 10);
2242 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2244 vty_out (vty
, "update timer value error\n");
2245 return CMD_WARNING_CONFIG_FAILED
;
2248 ripng
->update_time
= update
;
2250 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2254 DEFUN (no_ripng_update_timer
,
2255 no_ripng_update_timer_cmd
,
2256 "no update-timer SECOND",
2258 "Unset RIPng update timer in seconds\n"
2261 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2262 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2266 /* RIPng timeout timer setup. */
2267 DEFUN (ripng_timeout_timer
,
2268 ripng_timeout_timer_cmd
,
2269 "timeout-timer SECOND",
2270 "Set RIPng timeout timer in seconds\n"
2273 unsigned long timeout
;
2274 char *endptr
= NULL
;
2276 timeout
= strtoul (argv
[0], &endptr
, 10);
2277 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2279 vty_out (vty
, "timeout timer value error\n");
2280 return CMD_WARNING_CONFIG_FAILED
;
2283 ripng
->timeout_time
= timeout
;
2288 DEFUN (no_ripng_timeout_timer
,
2289 no_ripng_timeout_timer_cmd
,
2290 "no timeout-timer SECOND",
2292 "Unset RIPng timeout timer in seconds\n"
2295 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2299 /* RIPng garbage timer setup. */
2300 DEFUN (ripng_garbage_timer
,
2301 ripng_garbage_timer_cmd
,
2302 "garbage-timer SECOND",
2303 "Set RIPng garbage timer in seconds\n"
2306 unsigned long garbage
;
2307 char *endptr
= NULL
;
2309 garbage
= strtoul (argv
[0], &endptr
, 10);
2310 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2312 vty_out (vty
, "garbage timer value error\n");
2313 return CMD_WARNING_CONFIG_FAILED
;
2316 ripng
->garbage_time
= garbage
;
2321 DEFUN (no_ripng_garbage_timer
,
2322 no_ripng_garbage_timer_cmd
,
2323 "no garbage-timer SECOND",
2325 "Unset RIPng garbage timer in seconds\n"
2328 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2334 DEFUN (show_ipv6_protocols
,
2335 show_ipv6_protocols_cmd
,
2336 "show ipv6 protocols",
2339 "Routing protocol information\n")
2344 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2346 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2347 ripng
->update_time
, 0);
2349 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2350 ripng
->timeout_time
,
2351 ripng
->garbage_time
);
2353 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2354 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2360 /* Update ECMP routes to zebra when ECMP is disabled. */
2361 void ripng_ecmp_disable(struct ripng
*ripng
)
2363 struct agg_node
*rp
;
2364 struct ripng_info
*rinfo
, *tmp_rinfo
;
2366 struct listnode
*node
, *nextnode
;
2371 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2372 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2373 rinfo
= listgetdata(listhead(list
));
2374 if (!ripng_route_rte(rinfo
))
2377 /* Drop all other entries, except the first one. */
2378 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2379 if (tmp_rinfo
!= rinfo
) {
2380 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2382 tmp_rinfo
->t_garbage_collect
);
2383 list_delete_node(list
, node
);
2384 ripng_info_free(tmp_rinfo
);
2388 ripng_zebra_ipv6_add(ripng
, rp
);
2390 /* Set the route change flag. */
2391 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2393 /* Signal the output process to trigger an update. */
2394 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2398 /* RIPng configuration write function. */
2399 static int ripng_config_write(struct vty
*vty
)
2401 struct ripng
*ripng
;
2404 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2405 char xpath
[XPATH_MAXLEN
];
2406 struct lyd_node
*dnode
;
2408 snprintf(xpath
, sizeof(xpath
),
2409 "/frr-ripngd:ripngd/instance[vrf='%s']",
2412 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2415 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2417 config_write_distribute(vty
, ripng
->distribute_ctx
);
2418 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2426 static int ripng_config_write(struct vty
*vty
);
2427 /* RIPng node structure. */
2428 static struct cmd_node cmd_ripng_node
= {
2431 .parent_node
= CONFIG_NODE
,
2432 .prompt
= "%s(config-router)# ",
2433 .config_write
= ripng_config_write
,
2436 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2437 struct distribute
*dist
)
2439 struct interface
*ifp
;
2440 struct ripng_interface
*ri
;
2441 struct access_list
*alist
;
2442 struct prefix_list
*plist
;
2444 if (!ctx
->vrf
|| !dist
->ifname
)
2447 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2453 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2454 alist
= access_list_lookup(AFI_IP6
,
2455 dist
->list
[DISTRIBUTE_V6_IN
]);
2457 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2459 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2461 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2463 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2464 alist
= access_list_lookup(AFI_IP6
,
2465 dist
->list
[DISTRIBUTE_V6_OUT
]);
2467 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2469 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2471 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2473 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2474 plist
= prefix_list_lookup(AFI_IP6
,
2475 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2477 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2479 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2481 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2483 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2484 plist
= prefix_list_lookup(AFI_IP6
,
2485 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2487 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2489 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2491 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2494 void ripng_distribute_update_interface(struct interface
*ifp
)
2496 struct ripng_interface
*ri
= ifp
->info
;
2497 struct ripng
*ripng
= ri
->ripng
;
2498 struct distribute
*dist
;
2502 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2504 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2507 /* Update all interface's distribute list. */
2508 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2510 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2511 struct interface
*ifp
;
2513 FOR_ALL_INTERFACES (vrf
, ifp
)
2514 ripng_distribute_update_interface(ifp
);
2517 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2519 ripng_distribute_update_all(NULL
);
2522 /* delete all the added ripng routes. */
2523 void ripng_clean(struct ripng
*ripng
)
2525 ripng_interface_clean(ripng
);
2528 ripng_instance_disable(ripng
);
2530 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2531 if (ripng
->redist
[i
].route_map
.name
)
2532 free(ripng
->redist
[i
].route_map
.name
);
2534 agg_table_finish(ripng
->table
);
2535 list_delete(&ripng
->peer_list
);
2536 distribute_list_delete(&ripng
->distribute_ctx
);
2537 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2539 stream_free(ripng
->ibuf
);
2540 stream_free(ripng
->obuf
);
2542 ripng_clean_network(ripng
);
2543 ripng_passive_interface_clean(ripng
);
2544 vector_free(ripng
->enable_if
);
2545 agg_table_finish(ripng
->enable_network
);
2546 vector_free(ripng
->passive_interface
);
2547 list_delete(&ripng
->offset_list_master
);
2549 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2550 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2551 XFREE(MTYPE_RIPNG
, ripng
);
2554 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2555 struct if_rmap
*if_rmap
)
2557 struct interface
*ifp
= NULL
;
2558 struct ripng_interface
*ri
;
2559 struct route_map
*rmap
;
2560 struct vrf
*vrf
= NULL
;
2563 vrf
= vrf_lookup_by_name(ctx
->name
);
2565 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2571 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2572 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2574 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2576 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2578 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2580 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2581 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2583 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2585 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2587 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2590 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2592 struct ripng_interface
*ri
= ifp
->info
;
2593 struct ripng
*ripng
= ri
->ripng
;
2594 struct if_rmap
*if_rmap
;
2595 struct if_rmap_ctx
*ctx
;
2599 ctx
= ripng
->if_rmap_ctx
;
2602 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2604 ripng_if_rmap_update(ctx
, if_rmap
);
2607 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2609 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2610 if (ripng
->redist
[i
].route_map
.name
) {
2611 ripng
->redist
[i
].route_map
.map
=
2612 route_map_lookup_by_name(
2613 ripng
->redist
[i
].route_map
.name
);
2614 route_map_counter_increment(
2615 ripng
->redist
[i
].route_map
.map
);
2620 static void ripng_routemap_update(const char *unused
)
2622 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2623 struct ripng
*ripng
;
2624 struct interface
*ifp
;
2626 FOR_ALL_INTERFACES (vrf
, ifp
)
2627 ripng_if_rmap_update_interface(ifp
);
2631 ripng_routemap_update_redistribute(ripng
);
2634 /* Link RIPng instance to VRF. */
2635 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2637 struct interface
*ifp
;
2640 ripng
->distribute_ctx
->vrf
= vrf
;
2643 FOR_ALL_INTERFACES (vrf
, ifp
)
2644 ripng_interface_sync(ifp
);
2647 /* Unlink RIPng instance from VRF. */
2648 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2650 struct interface
*ifp
;
2653 ripng
->distribute_ctx
->vrf
= NULL
;
2656 FOR_ALL_INTERFACES (vrf
, ifp
)
2657 ripng_interface_sync(ifp
);
2660 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2665 ripng_vrf_link(ripng
, vrf
);
2666 ripng
->enabled
= true;
2668 /* Resend all redistribute requests. */
2669 ripng_redistribute_enable(ripng
);
2671 /* Create read and timer thread. */
2672 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2673 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2675 ripng_zebra_vrf_register(vrf
);
2678 static void ripng_instance_disable(struct ripng
*ripng
)
2680 struct vrf
*vrf
= ripng
->vrf
;
2681 struct agg_node
*rp
;
2683 /* Clear RIPng routes */
2684 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2685 struct ripng_aggregate
*aggregate
;
2688 if ((list
= rp
->info
) != NULL
) {
2689 struct ripng_info
*rinfo
;
2690 struct listnode
*listnode
;
2692 rinfo
= listgetdata(listhead(list
));
2693 if (ripng_route_rte(rinfo
))
2694 ripng_zebra_ipv6_delete(ripng
, rp
);
2696 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2697 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2698 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2699 ripng_info_free(rinfo
);
2703 agg_unlock_node(rp
);
2706 if ((aggregate
= rp
->aggregate
) != NULL
) {
2707 ripng_aggregate_free(aggregate
);
2708 rp
->aggregate
= NULL
;
2709 agg_unlock_node(rp
);
2713 /* Flush all redistribute requests. */
2714 ripng_redistribute_disable(ripng
);
2716 /* Cancel the RIPng timers */
2717 RIPNG_TIMER_OFF(ripng
->t_update
);
2718 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2719 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2721 /* Cancel the read thread */
2722 if (ripng
->t_read
) {
2723 thread_cancel(ripng
->t_read
);
2724 ripng
->t_read
= NULL
;
2727 /* Close the RIPng socket */
2728 if (ripng
->sock
>= 0) {
2733 /* Clear existing peers. */
2734 list_delete_all_node(ripng
->peer_list
);
2736 ripng_zebra_vrf_deregister(vrf
);
2738 ripng_vrf_unlink(ripng
, vrf
);
2739 ripng
->enabled
= false;
2742 static int ripng_vrf_new(struct vrf
*vrf
)
2744 if (IS_RIPNG_DEBUG_EVENT
)
2745 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2751 static int ripng_vrf_delete(struct vrf
*vrf
)
2753 if (IS_RIPNG_DEBUG_EVENT
)
2754 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2760 static int ripng_vrf_enable(struct vrf
*vrf
)
2762 struct ripng
*ripng
;
2765 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2767 char *old_vrf_name
= NULL
;
2769 ripng
= (struct ripng
*)vrf
->info
;
2772 /* update vrf name */
2773 if (ripng
->vrf_name
)
2774 old_vrf_name
= ripng
->vrf_name
;
2775 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf
->name
);
2777 * HACK: Change the RIPng VRF in the running configuration directly,
2778 * bypassing the northbound layer. This is necessary to avoid deleting
2779 * the RIPng and readding it in the new VRF, which would have
2780 * several implications.
2782 if (yang_module_find("frr-ripngd") && old_vrf_name
) {
2783 struct lyd_node
*ripng_dnode
;
2784 char oldpath
[XPATH_MAXLEN
];
2785 char newpath
[XPATH_MAXLEN
];
2787 ripng_dnode
= yang_dnode_get(
2788 running_config
->dnode
,
2789 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2792 yang_dnode_get_path(ripng_dnode
->parent
, oldpath
,
2794 yang_dnode_change_leaf(ripng_dnode
, vrf
->name
);
2795 yang_dnode_get_path(ripng_dnode
->parent
, newpath
,
2797 nb_running_move_tree(oldpath
, newpath
);
2798 running_config
->version
++;
2801 XFREE(MTYPE_RIPNG_VRF_NAME
, old_vrf_name
);
2807 if (IS_RIPNG_DEBUG_EVENT
)
2808 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2811 /* Activate the VRF RIPng instance. */
2812 socket
= ripng_make_socket(vrf
);
2816 ripng_instance_enable(ripng
, vrf
, socket
);
2821 static int ripng_vrf_disable(struct vrf
*vrf
)
2823 struct ripng
*ripng
;
2825 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2826 if (!ripng
|| !ripng
->enabled
)
2829 if (IS_RIPNG_DEBUG_EVENT
)
2830 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2833 /* Deactivate the VRF RIPng instance. */
2835 ripng_instance_disable(ripng
);
2840 void ripng_vrf_init(void)
2842 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2843 ripng_vrf_delete
, ripng_vrf_enable
);
2846 void ripng_vrf_terminate(void)
2851 /* Initialize ripng structure and set commands. */
2852 void ripng_init(void)
2854 /* Install RIPNG_NODE. */
2855 install_node(&cmd_ripng_node
);
2857 /* Install ripng commands. */
2858 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2859 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2861 install_default(RIPNG_NODE
);
2864 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2865 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2866 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2867 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2868 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2869 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2870 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2876 /* Access list install. */
2878 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2879 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2881 /* Prefix list initialize.*/
2883 prefix_list_add_hook(ripng_distribute_update_all
);
2884 prefix_list_delete_hook(ripng_distribute_update_all
);
2886 /* Distribute list install. */
2887 distribute_list_init(RIPNG_NODE
);
2889 /* Route-map for interface. */
2890 ripng_route_map_init();
2892 route_map_add_hook(ripng_routemap_update
);
2893 route_map_delete_hook(ripng_routemap_update
);
2895 if_rmap_init(RIPNG_NODE
);