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
, &newinfo
);
753 if (ret
== RMAP_DENYMATCH
) {
754 if (IS_RIPNG_DEBUG_PACKET
)
756 "RIPng %s/%d is filtered by route-map in",
757 inet6_ntoa(p
.prefix
), p
.prefixlen
);
761 /* Get back the object */
762 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
763 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
764 &ripng_nexthop
->address
)) {
765 /* the nexthop get changed by the routemap */
766 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
767 ripng_nexthop
->address
=
770 ripng_nexthop
->address
= in6addr_any
;
773 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
775 /* the nexthop get changed by the routemap */
776 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
777 ripng_nexthop
->flag
=
778 RIPNG_NEXTHOP_ADDRESS
;
779 ripng_nexthop
->address
=
784 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
786 newinfo
.metric_out
; /* XXX: the routemap uses the
790 /* Once the entry has been validated, update the metric by
791 * adding the cost of the network on wich the message
792 * arrived. If the result is greater than infinity, use infinity
793 * (RFC2453 Sec. 3.9.2)
796 /* Zebra ripngd can handle offset-list in. */
797 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
799 /* If offset-list does not modify the metric use interface's
802 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
804 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
805 rte
->metric
= RIPNG_METRIC_INFINITY
;
807 /* Set nexthop pointer. */
808 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
809 nexthop
= &ripng_nexthop
->address
;
811 nexthop
= &from
->sin6_addr
;
813 /* Lookup RIPng routing table. */
814 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
817 newinfo
.nexthop
= *nexthop
;
818 newinfo
.metric
= rte
->metric
;
819 newinfo
.tag
= ntohs(rte
->tag
);
821 /* Check to see whether there is already RIPng route on the table. */
822 if ((list
= rp
->info
) != NULL
)
823 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
824 /* Need to compare with redistributed entry or local
826 if (!ripng_route_rte(rinfo
))
829 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
830 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
833 if (!listnextnode(node
)) {
834 /* Not found in the list */
836 if (rte
->metric
> rinfo
->metric
) {
837 /* New route has a greater metric.
843 if (rte
->metric
< rinfo
->metric
)
844 /* New route has a smaller metric.
845 * Replace the ECMP list
846 * with the new one in below. */
849 /* Metrics are same. Unless ECMP is disabled,
850 * keep "rinfo" null and
851 * the new route is added in the ECMP list in
859 /* Redistributed route check. */
860 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
861 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
866 /* Local static route. */
867 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
868 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
869 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
870 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
877 /* Now, check to see whether there is already an explicit route
878 for the destination prefix. If there is no such route, add
879 this route to the routing table, unless the metric is
880 infinity (there is no point in adding a route which
882 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
883 ripng_ecmp_add(ripng
, &newinfo
);
887 /* If there is an existing route, compare the next hop address
888 to the address of the router from which the datagram came.
889 If this datagram is from the same router as the existing
890 route, reinitialize the timeout. */
891 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
892 && (rinfo
->ifindex
== ifp
->ifindex
));
895 * RFC 2080 - Section 2.4.2:
896 * "If the new metric is the same as the old one, examine the
898 * for the existing route. If it is at least halfway to the
900 * point, switch to the new route. This heuristic is optional,
902 * highly recommended".
904 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
906 && (thread_timer_remain_second(rinfo
->t_timeout
)
907 < (ripng
->timeout_time
/ 2))) {
908 ripng_ecmp_replace(ripng
, &newinfo
);
910 /* Next, compare the metrics. If the datagram is from the same
911 router as the existing route, and the new metric is different
912 than the old one; or, if the new metric is lower than the old
913 one; do the following actions: */
914 else if ((same
&& rinfo
->metric
!= rte
->metric
)
915 || rte
->metric
< rinfo
->metric
) {
916 if (listcount(list
) == 1) {
917 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
918 ripng_ecmp_replace(ripng
, &newinfo
);
920 ripng_ecmp_delete(ripng
, rinfo
);
922 if (newinfo
.metric
< rinfo
->metric
)
923 ripng_ecmp_replace(ripng
, &newinfo
);
924 else /* newinfo.metric > rinfo->metric */
925 ripng_ecmp_delete(ripng
, rinfo
);
927 } else /* same & no change */
928 ripng_timeout_update(ripng
, rinfo
);
930 /* Unlock tempolary lock of the route. */
935 /* Add redistributed route to RIPng table. */
936 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
937 struct prefix_ipv6
*p
, ifindex_t ifindex
,
938 struct in6_addr
*nexthop
, route_tag_t tag
)
941 struct ripng_info
*rinfo
= NULL
, newinfo
;
942 struct list
*list
= NULL
;
944 /* Redistribute route */
945 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
947 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
950 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
952 memset(&newinfo
, 0, sizeof(struct ripng_info
));
954 newinfo
.sub_type
= sub_type
;
955 newinfo
.ifindex
= ifindex
;
957 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
960 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
961 newinfo
.nexthop
= *nexthop
;
963 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
964 rinfo
= listgetdata(listhead(list
));
966 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
967 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
968 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
973 /* Manually configured RIPng route check.
974 * They have the precedence on all the other entries.
976 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
977 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
978 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
979 if (type
!= ZEBRA_ROUTE_RIPNG
980 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
981 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
987 ripng_ecmp_replace(ripng
, &newinfo
);
990 ripng_ecmp_add(ripng
, &newinfo
);
992 if (IS_RIPNG_DEBUG_EVENT
) {
995 "Redistribute new prefix %pFX on the interface %s",
996 p
, ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
999 "Redistribute new prefix %pFX with nexthop %s on the interface %s",
1000 p
, inet6_ntoa(*nexthop
),
1001 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1004 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1007 /* Delete redistributed route to RIPng table. */
1008 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1009 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1011 struct agg_node
*rp
;
1012 struct ripng_info
*rinfo
;
1014 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1016 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1019 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1022 struct list
*list
= rp
->info
;
1024 if (list
!= NULL
&& listcount(list
) != 0) {
1025 rinfo
= listgetdata(listhead(list
));
1026 if (rinfo
!= NULL
&& rinfo
->type
== type
1027 && rinfo
->sub_type
== sub_type
1028 && rinfo
->ifindex
== ifindex
) {
1029 /* Perform poisoned reverse. */
1030 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1031 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1032 ripng_garbage_collect
,
1033 ripng
->garbage_time
);
1034 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1036 /* Aggregate count decrement. */
1037 ripng_aggregate_decrement(rp
, rinfo
);
1039 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1041 if (IS_RIPNG_DEBUG_EVENT
)
1043 "Poisone %pFX on the interface %s with an infinity metric [delete]",
1047 ripng
->vrf
->vrf_id
));
1049 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1052 agg_unlock_node(rp
);
1056 /* Withdraw redistributed route. */
1057 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1059 struct agg_node
*rp
;
1060 struct ripng_info
*rinfo
= NULL
;
1061 struct list
*list
= NULL
;
1063 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1064 if ((list
= rp
->info
) != NULL
) {
1065 rinfo
= listgetdata(listhead(list
));
1066 if ((rinfo
->type
== type
)
1067 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1068 /* Perform poisoned reverse. */
1069 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1070 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1071 ripng_garbage_collect
,
1072 ripng
->garbage_time
);
1073 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1075 /* Aggregate count decrement. */
1076 ripng_aggregate_decrement(rp
, rinfo
);
1078 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1080 if (IS_RIPNG_DEBUG_EVENT
) {
1081 struct prefix_ipv6
*p
=
1082 (struct prefix_ipv6
*)
1083 agg_node_get_prefix(rp
);
1086 "Poisone %pFX on the interface %s [withdraw]",
1090 ripng
->vrf
->vrf_id
));
1093 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1098 /* RIP routing information. */
1099 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1100 struct sockaddr_in6
*from
,
1101 struct interface
*ifp
, int hoplimit
)
1103 struct ripng_interface
*ri
= ifp
->info
;
1104 struct ripng
*ripng
= ri
->ripng
;
1107 struct ripng_nexthop nexthop
;
1109 /* RFC2080 2.4.2 Response Messages:
1110 The Response must be ignored if it is not from the RIPng port. */
1111 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1112 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1113 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1114 ripng_peer_bad_packet(ripng
, from
);
1118 /* The datagram's IPv6 source address should be checked to see
1119 whether the datagram is from a valid neighbor; the source of the
1120 datagram must be a link-local address. */
1121 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1122 zlog_warn("RIPng packet comes from non link local address %s",
1123 inet6_ntoa(from
->sin6_addr
));
1124 ripng_peer_bad_packet(ripng
, from
);
1128 /* It is also worth checking to see whether the response is from one
1129 of the router's own addresses. Interfaces on broadcast networks
1130 may receive copies of their own multicasts immediately. If a
1131 router processes its own output as new input, confusion is likely,
1132 and such datagrams must be ignored. */
1133 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1135 "RIPng packet comes from my own link local address %s",
1136 inet6_ntoa(from
->sin6_addr
));
1137 ripng_peer_bad_packet(ripng
, from
);
1141 /* As an additional check, periodic advertisements must have their
1142 hop counts set to 255, and inbound, multicast packets sent from the
1143 RIPng port (i.e. periodic advertisement or triggered update
1144 packets) must be examined to ensure that the hop count is 255. */
1145 if (hoplimit
>= 0 && hoplimit
!= 255) {
1147 "RIPng packet comes with non 255 hop count %d from %s",
1148 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1149 ripng_peer_bad_packet(ripng
, from
);
1153 /* Update RIPng peer. */
1154 ripng_peer_update(ripng
, from
, packet
->version
);
1156 /* Reset nexthop. */
1157 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1158 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1160 /* Set RTE pointer. */
1163 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1164 /* First of all, we have to check this RTE is next hop RTE or
1165 not. Next hop RTE is completely different with normal RTE so
1166 we need special treatment. */
1167 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1168 ripng_nexthop_rte(rte
, from
, &nexthop
);
1172 /* RTE information validation. */
1174 /* - is the destination prefix valid (e.g., not a multicast
1175 prefix and not a link-local address) A link-local address
1176 should never be present in an RTE. */
1177 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1179 "Destination prefix is a multicast address %s/%d [%d]",
1180 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1182 ripng_peer_bad_route(ripng
, from
);
1185 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1187 "Destination prefix is a link-local address %s/%d [%d]",
1188 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1190 ripng_peer_bad_route(ripng
, from
);
1193 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1195 "Destination prefix is a loopback address %s/%d [%d]",
1196 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1198 ripng_peer_bad_route(ripng
, from
);
1202 /* - is the prefix length valid (i.e., between 0 and 128,
1204 if (rte
->prefixlen
> 128) {
1205 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1206 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1207 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1208 ripng_peer_bad_route(ripng
, from
);
1212 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1213 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1214 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1215 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1216 ripng_peer_bad_route(ripng
, from
);
1220 /* Vincent: XXX Should we compute the direclty reachable nexthop
1221 * for our RIPng network ?
1224 /* Routing table updates. */
1225 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1229 /* Response to request message. */
1230 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1231 struct sockaddr_in6
*from
,
1232 struct interface
*ifp
)
1234 struct ripng
*ripng
;
1237 struct prefix_ipv6 p
;
1238 struct agg_node
*rp
;
1239 struct ripng_info
*rinfo
;
1240 struct ripng_interface
*ri
;
1242 /* Does not reponse to the requests on the loopback interfaces */
1243 if (if_is_loopback(ifp
))
1246 /* Check RIPng process is enabled on this interface. */
1252 /* When passive interface is specified, suppress responses */
1256 /* RIPng peer update. */
1257 ripng_peer_update(ripng
, from
, packet
->version
);
1259 lim
= ((caddr_t
)packet
) + size
;
1262 /* The Request is processed entry by entry. If there are no
1263 entries, no response is given. */
1264 if (lim
== (caddr_t
)rte
)
1267 /* There is one special case. If there is exactly one entry in the
1268 request, and it has a destination prefix of zero, a prefix length
1269 of zero, and a metric of infinity (i.e., 16), then this is a
1270 request to send the entire routing table. In that case, a call
1271 is made to the output process to send the routing table to the
1272 requesting address/port. */
1273 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1274 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1275 /* All route with split horizon */
1276 ripng_output_process(ifp
, from
, ripng_all_route
);
1278 /* Except for this special case, processing is quite simple.
1279 Examine the list of RTEs in the Request one by one. For each
1280 entry, look up the destination in the router's routing
1281 database and, if there is a route, put that route's metric in
1282 the metric field of the RTE. If there is no explicit route
1283 to the specified destination, put infinity in the metric
1284 field. Once all the entries have been filled in, change the
1285 command from Request to Response and send the datagram back
1286 to the requestor. */
1287 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1288 p
.family
= AF_INET6
;
1290 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1291 p
.prefix
= rte
->addr
;
1292 p
.prefixlen
= rte
->prefixlen
;
1293 apply_mask_ipv6(&p
);
1295 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1298 rinfo
= listgetdata(
1299 listhead((struct list
*)rp
->info
));
1300 rte
->metric
= rinfo
->metric
;
1301 agg_unlock_node(rp
);
1303 rte
->metric
= RIPNG_METRIC_INFINITY
;
1305 packet
->command
= RIPNG_RESPONSE
;
1307 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1311 /* First entry point of reading RIPng packet. */
1312 static int ripng_read(struct thread
*thread
)
1314 struct ripng
*ripng
= THREAD_ARG(thread
);
1317 struct sockaddr_in6 from
;
1318 struct ripng_packet
*packet
;
1319 ifindex_t ifindex
= 0;
1320 struct interface
*ifp
;
1323 /* Check ripng is active and alive. */
1324 assert(ripng
!= NULL
);
1325 assert(ripng
->sock
>= 0);
1327 /* Fetch thread data and set read pointer to empty for event
1328 managing. `sock' sould be same as ripng->sock. */
1329 sock
= THREAD_FD(thread
);
1330 ripng
->t_read
= NULL
;
1332 /* Add myself to the next event. */
1333 ripng_event(ripng
, RIPNG_READ
, sock
);
1335 /* Read RIPng packet. */
1336 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1337 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1340 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1341 ripng
->vrf_name
, safe_strerror(errno
));
1345 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1346 (4)) must be multiple size of one RTE size (20). */
1347 if (((len
- 4) % 20) != 0) {
1348 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1349 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1350 ripng_peer_bad_packet(ripng
, &from
);
1354 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1355 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1357 /* RIPng packet received. */
1358 if (IS_RIPNG_DEBUG_EVENT
)
1360 "RIPng packet received from %s port %d on %s (VRF %s)",
1361 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1362 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1364 /* Logging before packet checking. */
1365 if (IS_RIPNG_DEBUG_RECV
)
1366 ripng_packet_dump(packet
, len
, "RECV");
1368 /* Packet comes from unknown interface. */
1371 "RIPng packet comes from unknown interface %d (VRF %s)",
1372 ifindex
, ripng
->vrf_name
);
1376 /* Packet version mismatch checking. */
1377 if (packet
->version
!= ripng
->version
) {
1379 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1380 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1381 ripng_peer_bad_packet(ripng
, &from
);
1385 /* Process RIPng packet. */
1386 switch (packet
->command
) {
1388 ripng_request_process(packet
, len
, &from
, ifp
);
1390 case RIPNG_RESPONSE
:
1391 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1394 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1396 ripng_peer_bad_packet(ripng
, &from
);
1402 /* Walk down the RIPng routing table then clear changed flag. */
1403 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1405 struct agg_node
*rp
;
1406 struct ripng_info
*rinfo
= NULL
;
1407 struct list
*list
= NULL
;
1408 struct listnode
*listnode
= NULL
;
1410 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1411 if ((list
= rp
->info
) != NULL
)
1412 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1413 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1414 /* This flag can be set only on the first entry.
1420 /* Regular update of RIPng route. Send all routing formation to RIPng
1421 enabled interface. */
1422 static int ripng_update(struct thread
*t
)
1424 struct ripng
*ripng
= THREAD_ARG(t
);
1425 struct interface
*ifp
;
1426 struct ripng_interface
*ri
;
1428 /* Clear update timer thread. */
1429 ripng
->t_update
= NULL
;
1431 /* Logging update event. */
1432 if (IS_RIPNG_DEBUG_EVENT
)
1433 zlog_debug("RIPng update timer expired!");
1435 /* Supply routes to each interface. */
1436 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1439 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1445 /* When passive interface is specified, suppress announce to the
1450 #ifdef RIPNG_ADVANCED
1451 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1452 if (IS_RIPNG_DEBUG_EVENT
)
1454 "[Event] RIPng send to if %d is suppressed by config",
1458 #endif /* RIPNG_ADVANCED */
1460 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1463 /* Triggered updates may be suppressed if a regular update is due by
1464 the time the triggered update would be sent. */
1465 thread_cancel(&ripng
->t_triggered_interval
);
1468 /* Reset flush event. */
1469 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1474 /* Triggered update interval timer. */
1475 static int ripng_triggered_interval(struct thread
*t
)
1477 struct ripng
*ripng
= THREAD_ARG(t
);
1479 ripng
->t_triggered_interval
= NULL
;
1481 if (ripng
->trigger
) {
1483 ripng_triggered_update(t
);
1488 /* Execute triggered update. */
1489 int ripng_triggered_update(struct thread
*t
)
1491 struct ripng
*ripng
= THREAD_ARG(t
);
1492 struct interface
*ifp
;
1493 struct ripng_interface
*ri
;
1496 ripng
->t_triggered_update
= NULL
;
1498 /* Cancel interval timer. */
1499 thread_cancel(&ripng
->t_triggered_interval
);
1502 /* Logging triggered update. */
1503 if (IS_RIPNG_DEBUG_EVENT
)
1504 zlog_debug("RIPng triggered update!");
1506 /* Split Horizon processing is done when generating triggered
1507 updates as well as normal updates (see section 2.6). */
1508 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1511 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1517 /* When passive interface is specified, suppress announce to the
1522 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1525 /* Once all of the triggered updates have been generated, the route
1526 change flags should be cleared. */
1527 ripng_clear_changed_flag(ripng
);
1529 /* After a triggered update is sent, a timer should be set for a
1530 random interval between 1 and 5 seconds. If other changes that
1531 would trigger updates occur before the timer expires, a single
1532 update is triggered when the timer expires. */
1533 interval
= (frr_weak_random() % 5) + 1;
1535 ripng
->t_triggered_interval
= NULL
;
1536 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1537 &ripng
->t_triggered_interval
);
1542 /* Write routing table entry to the stream and return next index of
1543 the routing table entry in the stream. */
1544 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1545 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1547 /* RIPng packet header. */
1549 stream_putc(s
, RIPNG_RESPONSE
);
1550 stream_putc(s
, RIPNG_V1
);
1554 /* Write routing table entry. */
1557 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1559 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1560 stream_putw(s
, tag
);
1562 stream_putc(s
, p
->prefixlen
);
1565 stream_putc(s
, metric
);
1570 /* Send RESPONSE message to specified destination. */
1571 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1574 struct ripng
*ripng
;
1576 struct agg_node
*rp
;
1577 struct ripng_info
*rinfo
;
1578 struct ripng_interface
*ri
;
1579 struct ripng_aggregate
*aggregate
;
1580 struct prefix_ipv6
*p
;
1581 struct list
*ripng_rte_list
;
1582 struct list
*list
= NULL
;
1583 struct listnode
*listnode
= NULL
;
1585 if (IS_RIPNG_DEBUG_EVENT
) {
1587 zlog_debug("RIPng update routes to neighbor %s",
1588 inet6_ntoa(to
->sin6_addr
));
1590 zlog_debug("RIPng update routes on interface %s",
1594 /* Get RIPng interface and instance. */
1598 ripng_rte_list
= ripng_rte_new();
1600 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1601 if ((list
= rp
->info
) != NULL
1602 && (rinfo
= listgetdata(listhead(list
))) != NULL
1603 && rinfo
->suppress
== 0) {
1604 /* If no route-map are applied, the RTE will be these
1608 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1609 rinfo
->metric_out
= rinfo
->metric
;
1610 rinfo
->tag_out
= rinfo
->tag
;
1611 memset(&rinfo
->nexthop_out
, 0,
1612 sizeof(rinfo
->nexthop_out
));
1613 /* In order to avoid some local loops,
1614 * if the RIPng route has a nexthop via this interface,
1616 * otherwise set it to 0. The nexthop should not be
1618 * beyond the local broadcast/multicast area in order
1619 * to avoid an IGP multi-level recursive look-up.
1621 if (rinfo
->ifindex
== ifp
->ifindex
)
1622 rinfo
->nexthop_out
= rinfo
->nexthop
;
1624 /* Apply output filters. */
1625 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1629 /* Changed route only output. */
1630 if (route_type
== ripng_changed_route
1631 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1634 /* Split horizon. */
1635 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1636 /* We perform split horizon for RIPng routes. */
1638 struct ripng_info
*tmp_rinfo
= NULL
;
1640 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1642 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1643 && tmp_rinfo
->ifindex
1652 /* Preparation for route-map. */
1653 rinfo
->metric_set
= 0;
1656 * and tag_out are already initialized.
1659 /* Interface route-map */
1660 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1661 ret
= route_map_apply(
1662 ri
->routemap
[RIPNG_FILTER_OUT
],
1663 (struct prefix
*)p
, rinfo
);
1665 if (ret
== RMAP_DENYMATCH
) {
1666 if (IS_RIPNG_DEBUG_PACKET
)
1668 "RIPng %pFX is filtered by route-map out",
1674 /* Redistribute route-map. */
1675 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1676 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1681 if (ret
== RMAP_DENYMATCH
) {
1682 if (IS_RIPNG_DEBUG_PACKET
)
1684 "RIPng %pFX is filtered by route-map",
1690 /* When the route-map does not set metric. */
1691 if (!rinfo
->metric_set
) {
1692 /* If the redistribute metric is set. */
1693 if (ripng
->redist
[rinfo
->type
].metric_config
1694 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1696 ripng
->redist
[rinfo
->type
]
1699 /* If the route is not connected or
1701 one, use default-metric value */
1702 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1704 != ZEBRA_ROUTE_CONNECT
1706 != RIPNG_METRIC_INFINITY
)
1708 ripng
->default_metric
;
1712 /* Apply offset-list */
1713 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1714 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1715 &rinfo
->metric_out
);
1717 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1718 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1720 /* Perform split-horizon with poisoned reverse
1723 if (ri
->split_horizon
1724 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1725 struct ripng_info
*tmp_rinfo
= NULL
;
1727 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1729 if ((tmp_rinfo
->type
1730 == ZEBRA_ROUTE_RIPNG
)
1731 && tmp_rinfo
->ifindex
1734 RIPNG_METRIC_INFINITY
;
1737 /* Add RTE to the list */
1738 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1741 /* Process the aggregated RTE entry */
1742 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1743 && aggregate
->suppress
== 0) {
1744 /* If no route-map are applied, the RTE will be these
1748 p
= (struct prefix_ipv6
*)agg_node_get_prefix(rp
);
1749 aggregate
->metric_set
= 0;
1750 aggregate
->metric_out
= aggregate
->metric
;
1751 aggregate
->tag_out
= aggregate
->tag
;
1752 memset(&aggregate
->nexthop_out
, 0,
1753 sizeof(aggregate
->nexthop_out
));
1755 /* Apply output filters.*/
1756 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1760 /* Interface route-map */
1761 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1762 struct ripng_info newinfo
;
1764 /* let's cast the aggregate structure to
1766 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1767 /* the nexthop is :: */
1768 newinfo
.metric
= aggregate
->metric
;
1769 newinfo
.metric_out
= aggregate
->metric_out
;
1770 newinfo
.tag
= aggregate
->tag
;
1771 newinfo
.tag_out
= aggregate
->tag_out
;
1773 ret
= route_map_apply(
1774 ri
->routemap
[RIPNG_FILTER_OUT
],
1775 (struct prefix
*)p
, &newinfo
);
1777 if (ret
== RMAP_DENYMATCH
) {
1778 if (IS_RIPNG_DEBUG_PACKET
)
1780 "RIPng %pFX is filtered by route-map out",
1785 aggregate
->metric_out
= newinfo
.metric_out
;
1786 aggregate
->tag_out
= newinfo
.tag_out
;
1787 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1788 aggregate
->nexthop_out
=
1789 newinfo
.nexthop_out
;
1792 /* There is no redistribute routemap for the aggregated
1795 /* Changed route only output. */
1796 /* XXX, vincent, in order to increase time convergence,
1797 * it should be announced if a child has changed.
1799 if (route_type
== ripng_changed_route
)
1802 /* Apply offset-list */
1803 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1804 ripng_offset_list_apply_out(
1805 ripng
, p
, ifp
, &aggregate
->metric_out
);
1807 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1808 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1810 /* Add RTE to the list */
1811 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1815 /* Flush the list */
1816 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1817 ripng_rte_free(ripng_rte_list
);
1820 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1824 vrf
= vrf_lookup_by_id(vrf_id
);
1831 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1835 ripng
.vrf_name
= (char *)vrf_name
;
1837 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1840 /* Create new RIPng instance and set it to global variable. */
1841 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1843 struct ripng
*ripng
;
1845 /* Allocaste RIPng instance. */
1846 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1847 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1849 /* Default version and timer values. */
1850 ripng
->version
= RIPNG_V1
;
1851 ripng
->update_time
= yang_get_default_uint32(
1852 "%s/timers/update-interval", RIPNG_INSTANCE
);
1853 ripng
->timeout_time
= yang_get_default_uint32(
1854 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1855 ripng
->garbage_time
= yang_get_default_uint32(
1856 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1857 ripng
->default_metric
=
1858 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1859 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1862 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1863 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1865 /* Initialize RIPng data structures. */
1866 ripng
->table
= agg_table_init();
1867 agg_set_table_info(ripng
->table
, ripng
);
1868 ripng
->peer_list
= list_new();
1869 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1870 ripng
->peer_list
->del
= ripng_peer_list_del
;
1871 ripng
->enable_if
= vector_init(1);
1872 ripng
->enable_network
= agg_table_init();
1873 ripng
->passive_interface
= vector_init(1);
1874 ripng
->offset_list_master
= list_new();
1875 ripng
->offset_list_master
->cmp
=
1876 (int (*)(void *, void *))offset_list_cmp
;
1877 ripng
->offset_list_master
->del
=
1878 (void (*)(void *))ripng_offset_list_free
;
1879 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1880 distribute_list_add_hook(ripng
->distribute_ctx
,
1881 ripng_distribute_update
);
1882 distribute_list_delete_hook(ripng
->distribute_ctx
,
1883 ripng_distribute_update
);
1885 /* if rmap install. */
1886 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1887 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1888 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1890 /* Enable the routing instance if possible. */
1891 if (vrf
&& vrf_is_enabled(vrf
))
1892 ripng_instance_enable(ripng
, vrf
, socket
);
1898 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1903 /* Send RIPng request to the interface. */
1904 int ripng_request(struct interface
*ifp
)
1907 struct ripng_packet ripng_packet
;
1909 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1911 if (if_is_loopback(ifp
))
1914 /* If interface is down, don't send RIP packet. */
1918 if (IS_RIPNG_DEBUG_EVENT
)
1919 zlog_debug("RIPng send request to %s", ifp
->name
);
1921 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1922 ripng_packet
.command
= RIPNG_REQUEST
;
1923 ripng_packet
.version
= RIPNG_V1
;
1924 rte
= ripng_packet
.rte
;
1925 rte
->metric
= RIPNG_METRIC_INFINITY
;
1927 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1932 static int ripng_update_jitter(int time
)
1934 return ((frr_weak_random() % (time
+ 1)) - (time
/ 2));
1937 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1943 thread_add_read(master
, ripng_read
, ripng
, sock
,
1946 case RIPNG_UPDATE_EVENT
:
1947 thread_cancel(&ripng
->t_update
);
1949 /* Update timer jitter. */
1950 jitter
= ripng_update_jitter(ripng
->update_time
);
1952 ripng
->t_update
= NULL
;
1953 thread_add_timer(master
, ripng_update
, ripng
,
1954 sock
? 2 : ripng
->update_time
+ jitter
,
1957 case RIPNG_TRIGGERED_UPDATE
:
1958 if (ripng
->t_triggered_interval
)
1961 thread_add_event(master
, ripng_triggered_update
, ripng
,
1962 0, &ripng
->t_triggered_update
);
1970 /* Print out routes update time. */
1971 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1976 char timebuf
[TIME_BUF
];
1977 struct thread
*thread
;
1979 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1980 clock
= thread_timer_remain_second(thread
);
1981 gmtime_r(&clock
, &tm
);
1982 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1983 vty_out(vty
, "%5s", timebuf
);
1984 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1985 clock
= thread_timer_remain_second(thread
);
1986 gmtime_r(&clock
, &tm
);
1987 strftime(timebuf
, TIME_BUF
, "%M:%S", &tm
);
1988 vty_out(vty
, "%5s", timebuf
);
1992 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1997 if (rinfo
->suppress
)
1998 strlcat(str
, "S", sizeof(str
));
2000 switch (rinfo
->sub_type
) {
2001 case RIPNG_ROUTE_RTE
:
2002 strlcat(str
, "n", sizeof(str
));
2004 case RIPNG_ROUTE_STATIC
:
2005 strlcat(str
, "s", sizeof(str
));
2007 case RIPNG_ROUTE_DEFAULT
:
2008 strlcat(str
, "d", sizeof(str
));
2010 case RIPNG_ROUTE_REDISTRIBUTE
:
2011 strlcat(str
, "r", sizeof(str
));
2013 case RIPNG_ROUTE_INTERFACE
:
2014 strlcat(str
, "i", sizeof(str
));
2017 strlcat(str
, "?", sizeof(str
));
2024 DEFUN (show_ipv6_ripng
,
2025 show_ipv6_ripng_cmd
,
2026 "show ipv6 ripng [vrf NAME]",
2029 "Show RIPng routes\n"
2032 struct ripng
*ripng
;
2033 struct agg_node
*rp
;
2034 struct ripng_info
*rinfo
;
2035 struct ripng_aggregate
*aggregate
;
2036 struct list
*list
= NULL
;
2037 struct listnode
*listnode
= NULL
;
2039 const char *vrf_name
;
2042 if (argv_find(argv
, argc
, "vrf", &idx
))
2043 vrf_name
= argv
[idx
+ 1]->arg
;
2045 vrf_name
= VRF_DEFAULT_NAME
;
2047 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2049 vty_out(vty
, "%% RIPng instance not found\n");
2052 if (!ripng
->enabled
) {
2053 vty_out(vty
, "%% RIPng instance is disabled\n");
2057 /* Header of display. */
2059 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2061 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2062 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2063 " Network Next Hop Via Metric Tag Time\n");
2065 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2066 if ((aggregate
= rp
->aggregate
) != NULL
) {
2068 vty_out(vty
, "R(a) %d/%d %pRN ", aggregate
->count
,
2069 aggregate
->suppress
, rp
);
2071 vty_out(vty
, "R(a) %pRN ", rp
);
2074 vty_out(vty
, "%*s", 18, " ");
2076 vty_out(vty
, "%*s", 28, " ");
2077 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2078 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2081 if ((list
= rp
->info
) != NULL
)
2082 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2084 vty_out(vty
, "%c(%s) 0/%d %pRN ",
2085 zebra_route_char(rinfo
->type
),
2086 ripng_route_subtype_print(rinfo
),
2087 rinfo
->suppress
, rp
);
2089 vty_out(vty
, "%c(%s) %pRN ",
2090 zebra_route_char(rinfo
->type
),
2091 ripng_route_subtype_print(rinfo
), rp
);
2094 vty_out(vty
, "%*s", 18, " ");
2095 len
= vty_out(vty
, "%s",
2096 inet6_ntoa(rinfo
->nexthop
));
2100 vty_out(vty
, "%*s", len
, " ");
2103 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2104 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2109 ripng
->vrf
->vrf_id
));
2110 } else if (rinfo
->metric
2111 == RIPNG_METRIC_INFINITY
) {
2112 len
= vty_out(vty
, "kill");
2114 len
= vty_out(vty
, "self");
2118 vty_out(vty
, "%*s", len
, " ");
2120 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2121 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2124 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2125 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2126 /* RTE from remote RIP routers */
2127 ripng_vty_out_uptime(vty
, rinfo
);
2128 } else if (rinfo
->metric
2129 == RIPNG_METRIC_INFINITY
) {
2130 /* poisonous reversed routes (gc) */
2131 ripng_vty_out_uptime(vty
, rinfo
);
2141 DEFUN (show_ipv6_ripng_status
,
2142 show_ipv6_ripng_status_cmd
,
2143 "show ipv6 ripng [vrf NAME] status",
2146 "Show RIPng routes\n"
2148 "IPv6 routing protocol process parameters and statistics\n")
2150 struct ripng
*ripng
;
2151 struct interface
*ifp
;
2152 const char *vrf_name
;
2155 if (argv_find(argv
, argc
, "vrf", &idx
))
2156 vrf_name
= argv
[idx
+ 1]->arg
;
2158 vrf_name
= VRF_DEFAULT_NAME
;
2160 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2162 vty_out(vty
, "%% RIPng instance not found\n");
2165 if (!ripng
->enabled
) {
2166 vty_out(vty
, "%% RIPng instance is disabled\n");
2170 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2171 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2172 ripng
->update_time
);
2173 vty_out(vty
, " next due in %lu seconds\n",
2174 thread_timer_remain_second(ripng
->t_update
));
2175 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2176 vty_out(vty
, " garbage collect after %u seconds\n",
2177 ripng
->garbage_time
);
2179 /* Filtering status show. */
2180 config_show_distribute(vty
, ripng
->distribute_ctx
);
2182 /* Default metric information. */
2183 vty_out(vty
, " Default redistribution metric is %d\n",
2184 ripng
->default_metric
);
2186 /* Redistribute information. */
2187 vty_out(vty
, " Redistributing:");
2188 ripng_redistribute_write(vty
, ripng
);
2191 vty_out(vty
, " Default version control: send version %d,",
2193 vty_out(vty
, " receive version %d \n", ripng
->version
);
2195 vty_out(vty
, " Interface Send Recv\n");
2197 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2198 struct ripng_interface
*ri
;
2202 if (ri
->enable_network
|| ri
->enable_interface
) {
2204 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2205 ripng
->version
, ripng
->version
);
2209 vty_out(vty
, " Routing for Networks:\n");
2210 ripng_network_write(vty
, ripng
);
2212 vty_out(vty
, " Routing Information Sources:\n");
2214 " Gateway BadPackets BadRoutes Distance Last Update\n");
2215 ripng_peer_display(vty
, ripng
);
2220 /* Update ECMP routes to zebra when ECMP is disabled. */
2221 void ripng_ecmp_disable(struct ripng
*ripng
)
2223 struct agg_node
*rp
;
2224 struct ripng_info
*rinfo
, *tmp_rinfo
;
2226 struct listnode
*node
, *nextnode
;
2231 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2232 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2233 rinfo
= listgetdata(listhead(list
));
2234 if (!ripng_route_rte(rinfo
))
2237 /* Drop all other entries, except the first one. */
2238 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2239 if (tmp_rinfo
!= rinfo
) {
2240 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2242 tmp_rinfo
->t_garbage_collect
);
2243 list_delete_node(list
, node
);
2244 ripng_info_free(tmp_rinfo
);
2248 ripng_zebra_ipv6_add(ripng
, rp
);
2250 /* Set the route change flag. */
2251 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2253 /* Signal the output process to trigger an update. */
2254 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2258 /* RIPng configuration write function. */
2259 static int ripng_config_write(struct vty
*vty
)
2261 struct ripng
*ripng
;
2264 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2265 char xpath
[XPATH_MAXLEN
];
2266 struct lyd_node
*dnode
;
2268 snprintf(xpath
, sizeof(xpath
),
2269 "/frr-ripngd:ripngd/instance[vrf='%s']",
2272 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2275 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2277 config_write_distribute(vty
, ripng
->distribute_ctx
);
2278 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2286 static int ripng_config_write(struct vty
*vty
);
2287 /* RIPng node structure. */
2288 static struct cmd_node cmd_ripng_node
= {
2291 .parent_node
= CONFIG_NODE
,
2292 .prompt
= "%s(config-router)# ",
2293 .config_write
= ripng_config_write
,
2296 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2297 struct distribute
*dist
)
2299 struct interface
*ifp
;
2300 struct ripng_interface
*ri
;
2301 struct access_list
*alist
;
2302 struct prefix_list
*plist
;
2304 if (!ctx
->vrf
|| !dist
->ifname
)
2307 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2313 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2314 alist
= access_list_lookup(AFI_IP6
,
2315 dist
->list
[DISTRIBUTE_V6_IN
]);
2317 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2319 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2321 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2323 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2324 alist
= access_list_lookup(AFI_IP6
,
2325 dist
->list
[DISTRIBUTE_V6_OUT
]);
2327 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2329 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2331 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2333 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2334 plist
= prefix_list_lookup(AFI_IP6
,
2335 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2337 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2339 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2341 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2343 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2344 plist
= prefix_list_lookup(AFI_IP6
,
2345 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2347 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2349 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2351 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2354 void ripng_distribute_update_interface(struct interface
*ifp
)
2356 struct ripng_interface
*ri
= ifp
->info
;
2357 struct ripng
*ripng
= ri
->ripng
;
2358 struct distribute
*dist
;
2362 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2364 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2367 /* Update all interface's distribute list. */
2368 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2370 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2371 struct interface
*ifp
;
2373 FOR_ALL_INTERFACES (vrf
, ifp
)
2374 ripng_distribute_update_interface(ifp
);
2377 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2379 ripng_distribute_update_all(NULL
);
2382 /* delete all the added ripng routes. */
2383 void ripng_clean(struct ripng
*ripng
)
2385 ripng_interface_clean(ripng
);
2388 ripng_instance_disable(ripng
);
2390 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2391 if (ripng
->redist
[i
].route_map
.name
)
2392 free(ripng
->redist
[i
].route_map
.name
);
2394 agg_table_finish(ripng
->table
);
2395 list_delete(&ripng
->peer_list
);
2396 distribute_list_delete(&ripng
->distribute_ctx
);
2397 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2399 stream_free(ripng
->ibuf
);
2400 stream_free(ripng
->obuf
);
2402 ripng_clean_network(ripng
);
2403 ripng_passive_interface_clean(ripng
);
2404 vector_free(ripng
->enable_if
);
2405 agg_table_finish(ripng
->enable_network
);
2406 vector_free(ripng
->passive_interface
);
2407 list_delete(&ripng
->offset_list_master
);
2409 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2410 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2411 XFREE(MTYPE_RIPNG
, ripng
);
2414 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2415 struct if_rmap
*if_rmap
)
2417 struct interface
*ifp
= NULL
;
2418 struct ripng_interface
*ri
;
2419 struct route_map
*rmap
;
2420 struct vrf
*vrf
= NULL
;
2423 vrf
= vrf_lookup_by_name(ctx
->name
);
2425 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2431 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2432 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2434 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2436 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2438 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2440 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2441 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2443 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2445 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2447 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2450 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2452 struct ripng_interface
*ri
= ifp
->info
;
2453 struct ripng
*ripng
= ri
->ripng
;
2454 struct if_rmap
*if_rmap
;
2455 struct if_rmap_ctx
*ctx
;
2459 ctx
= ripng
->if_rmap_ctx
;
2462 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2464 ripng_if_rmap_update(ctx
, if_rmap
);
2467 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2469 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2470 if (ripng
->redist
[i
].route_map
.name
) {
2471 ripng
->redist
[i
].route_map
.map
=
2472 route_map_lookup_by_name(
2473 ripng
->redist
[i
].route_map
.name
);
2474 route_map_counter_increment(
2475 ripng
->redist
[i
].route_map
.map
);
2480 static void ripng_routemap_update(const char *unused
)
2482 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2483 struct ripng
*ripng
;
2484 struct interface
*ifp
;
2486 FOR_ALL_INTERFACES (vrf
, ifp
)
2487 ripng_if_rmap_update_interface(ifp
);
2491 ripng_routemap_update_redistribute(ripng
);
2494 /* Link RIPng instance to VRF. */
2495 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2497 struct interface
*ifp
;
2500 ripng
->distribute_ctx
->vrf
= vrf
;
2503 FOR_ALL_INTERFACES (vrf
, ifp
)
2504 ripng_interface_sync(ifp
);
2507 /* Unlink RIPng instance from VRF. */
2508 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2510 struct interface
*ifp
;
2513 ripng
->distribute_ctx
->vrf
= NULL
;
2516 FOR_ALL_INTERFACES (vrf
, ifp
)
2517 ripng_interface_sync(ifp
);
2520 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2525 ripng_vrf_link(ripng
, vrf
);
2526 ripng
->enabled
= true;
2528 /* Resend all redistribute requests. */
2529 ripng_redistribute_enable(ripng
);
2531 /* Create read and timer thread. */
2532 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2533 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2535 ripng_zebra_vrf_register(vrf
);
2538 static void ripng_instance_disable(struct ripng
*ripng
)
2540 struct vrf
*vrf
= ripng
->vrf
;
2541 struct agg_node
*rp
;
2543 /* Clear RIPng routes */
2544 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2545 struct ripng_aggregate
*aggregate
;
2548 if ((list
= rp
->info
) != NULL
) {
2549 struct ripng_info
*rinfo
;
2550 struct listnode
*listnode
;
2552 rinfo
= listgetdata(listhead(list
));
2553 if (ripng_route_rte(rinfo
))
2554 ripng_zebra_ipv6_delete(ripng
, rp
);
2556 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2557 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2558 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2559 ripng_info_free(rinfo
);
2563 agg_unlock_node(rp
);
2566 if ((aggregate
= rp
->aggregate
) != NULL
) {
2567 ripng_aggregate_free(aggregate
);
2568 rp
->aggregate
= NULL
;
2569 agg_unlock_node(rp
);
2573 /* Flush all redistribute requests. */
2574 ripng_redistribute_disable(ripng
);
2576 /* Cancel the RIPng timers */
2577 RIPNG_TIMER_OFF(ripng
->t_update
);
2578 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2579 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2581 /* Cancel the read thread */
2582 thread_cancel(&ripng
->t_read
);
2584 /* Close the RIPng socket */
2585 if (ripng
->sock
>= 0) {
2590 /* Clear existing peers. */
2591 list_delete_all_node(ripng
->peer_list
);
2593 ripng_zebra_vrf_deregister(vrf
);
2595 ripng_vrf_unlink(ripng
, vrf
);
2596 ripng
->enabled
= false;
2599 static int ripng_vrf_new(struct vrf
*vrf
)
2601 if (IS_RIPNG_DEBUG_EVENT
)
2602 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2608 static int ripng_vrf_delete(struct vrf
*vrf
)
2610 if (IS_RIPNG_DEBUG_EVENT
)
2611 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2617 static int ripng_vrf_enable(struct vrf
*vrf
)
2619 struct ripng
*ripng
;
2622 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2624 char *old_vrf_name
= NULL
;
2626 ripng
= (struct ripng
*)vrf
->info
;
2629 /* update vrf name */
2630 if (ripng
->vrf_name
)
2631 old_vrf_name
= ripng
->vrf_name
;
2632 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf
->name
);
2634 * HACK: Change the RIPng VRF in the running configuration directly,
2635 * bypassing the northbound layer. This is necessary to avoid deleting
2636 * the RIPng and readding it in the new VRF, which would have
2637 * several implications.
2639 if (yang_module_find("frr-ripngd") && old_vrf_name
) {
2640 struct lyd_node
*ripng_dnode
;
2641 char oldpath
[XPATH_MAXLEN
];
2642 char newpath
[XPATH_MAXLEN
];
2644 ripng_dnode
= yang_dnode_get(
2645 running_config
->dnode
,
2646 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2649 yang_dnode_get_path(ripng_dnode
->parent
, oldpath
,
2651 yang_dnode_change_leaf(ripng_dnode
, vrf
->name
);
2652 yang_dnode_get_path(ripng_dnode
->parent
, newpath
,
2654 nb_running_move_tree(oldpath
, newpath
);
2655 running_config
->version
++;
2658 XFREE(MTYPE_RIPNG_VRF_NAME
, old_vrf_name
);
2664 if (IS_RIPNG_DEBUG_EVENT
)
2665 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2668 /* Activate the VRF RIPng instance. */
2669 socket
= ripng_make_socket(vrf
);
2673 ripng_instance_enable(ripng
, vrf
, socket
);
2678 static int ripng_vrf_disable(struct vrf
*vrf
)
2680 struct ripng
*ripng
;
2682 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2683 if (!ripng
|| !ripng
->enabled
)
2686 if (IS_RIPNG_DEBUG_EVENT
)
2687 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2690 /* Deactivate the VRF RIPng instance. */
2692 ripng_instance_disable(ripng
);
2697 void ripng_vrf_init(void)
2699 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2700 ripng_vrf_delete
, ripng_vrf_enable
);
2703 void ripng_vrf_terminate(void)
2708 /* Initialize ripng structure and set commands. */
2709 void ripng_init(void)
2711 /* Install RIPNG_NODE. */
2712 install_node(&cmd_ripng_node
);
2714 /* Install ripng commands. */
2715 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2716 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2718 install_default(RIPNG_NODE
);
2723 /* Access list install. */
2725 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2726 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2728 /* Prefix list initialize.*/
2730 prefix_list_add_hook(ripng_distribute_update_all
);
2731 prefix_list_delete_hook(ripng_distribute_update_all
);
2733 /* Distribute list install. */
2734 distribute_list_init(RIPNG_NODE
);
2736 /* Route-map for interface. */
2737 ripng_route_map_init();
2739 route_map_add_hook(ripng_routemap_update
);
2740 route_map_delete_hook(ripng_routemap_update
);
2742 if_rmap_init(RIPNG_NODE
);