2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "agg_table.h"
33 #include "distribute.h"
38 #include "lib_errors.h"
39 #include "northbound_cli.h"
41 #include "ripngd/ripngd.h"
42 #include "ripngd/ripng_route.h"
43 #include "ripngd/ripng_debug.h"
44 #include "ripngd/ripng_nexthop.h"
46 enum { ripng_all_route
,
50 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
51 struct distribute
*dist
);
54 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
55 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
57 static void ripng_instance_disable(struct ripng
*ripng
);
58 int ripng_triggered_update(struct thread
*);
59 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
60 struct if_rmap
*if_rmap
);
62 /* Generate rb-tree of RIPng instances. */
63 static inline int ripng_instance_compare(const struct ripng
*a
,
64 const struct ripng
*b
)
66 return strcmp(a
->vrf_name
, b
->vrf_name
);
68 RB_GENERATE(ripng_instance_head
, ripng
, entry
, ripng_instance_compare
)
70 struct ripng_instance_head ripng_instances
= RB_INITIALIZER(&ripng_instances
);
72 /* RIPng next hop specification. */
73 struct ripng_nexthop
{
74 enum ripng_nexthop_type
{
78 struct in6_addr address
;
81 int ripng_route_rte(struct ripng_info
*rinfo
)
83 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
84 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
87 /* Allocate new ripng information. */
88 struct ripng_info
*ripng_info_new(void)
90 struct ripng_info
*new;
92 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
96 /* Free ripng information. */
97 void ripng_info_free(struct ripng_info
*rinfo
)
99 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
102 struct ripng
*ripng_info_get_instance(const struct ripng_info
*rinfo
)
104 return agg_get_table_info(agg_get_table(rinfo
->rp
));
107 /* Create ripng socket. */
108 int ripng_make_socket(struct vrf
*vrf
)
112 struct sockaddr_in6 ripaddr
;
113 const char *vrf_dev
= NULL
;
115 /* Make datagram socket. */
116 if (vrf
->vrf_id
!= VRF_DEFAULT
)
118 frr_elevate_privs(&ripngd_privs
)
120 sock
= vrf_socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
,
121 vrf
->vrf_id
, vrf_dev
);
123 flog_err_sys(EC_LIB_SOCKET
,
124 "Cannot create UDP socket: %s",
125 safe_strerror(errno
));
130 sockopt_reuseaddr(sock
);
131 sockopt_reuseport(sock
);
132 setsockopt_so_recvbuf(sock
, 8096);
133 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
136 #ifdef IPTOS_PREC_INTERNETCONTROL
137 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
141 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
144 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
147 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
151 memset(&ripaddr
, 0, sizeof(ripaddr
));
152 ripaddr
.sin6_family
= AF_INET6
;
154 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
155 #endif /* SIN6_LEN */
156 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
158 frr_elevate_privs(&ripngd_privs
) {
159 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
161 zlog_err("Can't bind ripng socket: %s.",
162 safe_strerror(errno
));
173 /* Send RIPng packet. */
174 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
175 struct interface
*ifp
)
177 struct ripng_interface
*ri
= ifp
->info
;
178 struct ripng
*ripng
= ri
->ripng
;
182 struct cmsghdr
*cmsgptr
;
183 char adata
[256] = {};
184 struct in6_pktinfo
*pkt
;
185 struct sockaddr_in6 addr
;
187 if (IS_RIPNG_DEBUG_SEND
) {
189 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
190 zlog_debug(" send interface %s", ifp
->name
);
191 zlog_debug(" send packet size %d", bufsize
);
194 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
195 addr
.sin6_family
= AF_INET6
;
197 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
198 #endif /* SIN6_LEN */
199 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
201 /* When destination is specified. */
203 addr
.sin6_addr
= to
->sin6_addr
;
204 addr
.sin6_port
= to
->sin6_port
;
206 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
207 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
210 memset(&msg
, 0, sizeof(msg
));
211 msg
.msg_name
= (void *)&addr
;
212 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
215 msg
.msg_control
= (void *)adata
;
216 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
219 iov
.iov_len
= bufsize
;
221 cmsgptr
= (struct cmsghdr
*)adata
;
222 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
223 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
224 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
226 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
227 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
228 pkt
->ipi6_ifindex
= ifp
->ifindex
;
230 ret
= sendmsg(ripng
->sock
, &msg
, 0);
234 flog_err_sys(EC_LIB_SOCKET
,
235 "RIPng send fail on %s to %s: %s",
236 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
237 safe_strerror(errno
));
239 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
240 ifp
->name
, safe_strerror(errno
));
246 /* Receive UDP RIPng packet from socket. */
247 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
248 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
254 struct cmsghdr
*cmsgptr
;
255 struct in6_addr dst
= {.s6_addr
= {0}};
257 memset(&dst
, 0, sizeof(struct in6_addr
));
259 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
260 point I can't determine size of cmsghdr */
263 /* Fill in message and iovec. */
264 memset(&msg
, 0, sizeof(msg
));
265 msg
.msg_name
= (void *)from
;
266 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
269 msg
.msg_control
= (void *)adata
;
270 msg
.msg_controllen
= sizeof adata
;
272 iov
.iov_len
= bufsize
;
274 /* If recvmsg fail return minus value. */
275 ret
= recvmsg(sock
, &msg
, 0);
279 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
280 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
281 /* I want interface index which this packet comes from. */
282 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
283 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
284 struct in6_pktinfo
*ptr
;
286 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
287 *ifindex
= ptr
->ipi6_ifindex
;
288 dst
= ptr
->ipi6_addr
;
292 "Interface index returned by IPV6_PKTINFO is zero");
295 /* Incoming packet's multicast hop limit. */
296 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
297 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
298 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
299 *hoplimit
= *phoplimit
;
303 /* Hoplimit check shold be done when destination address is
304 multicast address. */
305 if (!IN6_IS_ADDR_MULTICAST(&dst
))
311 /* Dump rip packet */
312 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
317 const char *command_str
;
319 /* Set command string. */
320 if (packet
->command
== RIPNG_REQUEST
)
321 command_str
= "request";
322 else if (packet
->command
== RIPNG_RESPONSE
)
323 command_str
= "response";
325 command_str
= "unknown";
327 /* Dump packet header. */
328 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
329 packet
->version
, size
);
331 /* Dump each routing table entry. */
334 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
335 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
336 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
339 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
340 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
341 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
345 /* RIPng next hop address RTE (Route Table Entry). */
346 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
347 struct ripng_nexthop
*nexthop
)
349 char buf
[INET6_BUFSIZ
];
351 /* Logging before checking RTE. */
352 if (IS_RIPNG_DEBUG_RECV
)
353 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
355 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
358 /* RFC2080 2.1.1 Next Hop:
359 The route tag and prefix length in the next hop RTE must be
360 set to zero on sending and ignored on receiption. */
361 if (ntohs(rte
->tag
) != 0)
363 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
365 (route_tag_t
)ntohs(rte
->tag
),
366 inet6_ntoa(from
->sin6_addr
));
368 if (rte
->prefixlen
!= 0)
370 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
371 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
373 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
374 next hop RTE indicates that the next hop address should be the
375 originator of the RIPng advertisement. An address specified as a
376 next hop must be a link-local address. */
377 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
378 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
379 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
383 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
384 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
385 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
389 /* The purpose of the next hop RTE is to eliminate packets being
390 routed through extra hops in the system. It is particularly useful
391 when RIPng is not being run on all of the routers on a network.
392 Note that next hop RTE is "advisory". That is, if the provided
393 information is ignored, a possibly sub-optimal, but absolutely
394 valid, route may be taken. If the received next hop address is not
395 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
396 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
397 inet6_ntoa(rte
->addr
),
398 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
400 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
401 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
406 /* If ifp has same link-local address then return 1. */
407 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
409 struct listnode
*node
;
410 struct connected
*connected
;
413 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
414 p
= connected
->address
;
416 if (p
->family
== AF_INET6
417 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
418 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
424 /* RIPng route garbage collect timer. */
425 static int ripng_garbage_collect(struct thread
*t
)
427 struct ripng_info
*rinfo
;
430 rinfo
= THREAD_ARG(t
);
431 rinfo
->t_garbage_collect
= NULL
;
433 /* Off timeout timer. */
434 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
436 /* Get route_node pointer. */
439 /* Unlock route_node. */
440 listnode_delete(rp
->info
, rinfo
);
441 if (list_isempty((struct list
*)rp
->info
)) {
442 list_delete((struct list
**)&rp
->info
);
446 /* Free RIPng routing information. */
447 ripng_info_free(rinfo
);
452 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
454 /* Add new route to the ECMP list.
455 * RETURN: the new entry added in the list, or NULL if it is not the first
456 * entry and ECMP is not allowed.
458 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
459 struct ripng_info
*rinfo_new
)
461 struct agg_node
*rp
= rinfo_new
->rp
;
462 struct ripng_info
*rinfo
= NULL
;
463 struct list
*list
= NULL
;
465 if (rp
->info
== NULL
)
466 rp
->info
= list_new();
467 list
= (struct list
*)rp
->info
;
469 /* If ECMP is not allowed and some entry already exists in the list,
471 if (listcount(list
) && !ripng
->ecmp
)
474 rinfo
= ripng_info_new();
475 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
476 listnode_add(list
, rinfo
);
478 if (ripng_route_rte(rinfo
)) {
479 ripng_timeout_update(ripng
, rinfo
);
480 ripng_zebra_ipv6_add(ripng
, rp
);
483 ripng_aggregate_increment(rp
, rinfo
);
485 /* Set the route change flag on the first entry. */
486 rinfo
= listgetdata(listhead(list
));
487 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
489 /* Signal the output process to trigger an update. */
490 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
495 /* Replace the ECMP list with the new route.
496 * RETURN: the new entry added in the list
498 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
499 struct ripng_info
*rinfo_new
)
501 struct agg_node
*rp
= rinfo_new
->rp
;
502 struct list
*list
= (struct list
*)rp
->info
;
503 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
504 struct listnode
*node
= NULL
, *nextnode
= NULL
;
506 if (list
== NULL
|| listcount(list
) == 0)
507 return ripng_ecmp_add(ripng
, rinfo_new
);
509 /* Get the first entry */
510 rinfo
= listgetdata(listhead(list
));
512 /* Learnt route replaced by a local one. Delete it from zebra. */
513 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
514 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
515 ripng_zebra_ipv6_delete(ripng
, rp
);
517 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
518 ripng_aggregate_decrement_list(rp
, list
);
520 /* Re-use the first entry, and delete the others. */
521 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
522 if (tmp_rinfo
!= rinfo
) {
523 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
524 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
525 list_delete_node(list
, node
);
526 ripng_info_free(tmp_rinfo
);
529 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
530 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
531 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
533 if (ripng_route_rte(rinfo
)) {
534 ripng_timeout_update(ripng
, rinfo
);
535 /* The ADD message implies an update. */
536 ripng_zebra_ipv6_add(ripng
, rp
);
539 ripng_aggregate_increment(rp
, rinfo
);
541 /* Set the route change flag. */
542 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
544 /* Signal the output process to trigger an update. */
545 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
550 /* Delete one route from the ECMP list.
552 * null - the entry is freed, and other entries exist in the list
553 * the entry - the entry is the last one in the list; its metric is set
554 * to INFINITY, and the garbage collector is started for it
556 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
557 struct ripng_info
*rinfo
)
559 struct agg_node
*rp
= rinfo
->rp
;
560 struct list
*list
= (struct list
*)rp
->info
;
562 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
564 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
565 ripng_aggregate_decrement(rp
, rinfo
);
567 if (listcount(list
) > 1) {
568 /* Some other ECMP entries still exist. Just delete this entry.
570 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
571 listnode_delete(list
, rinfo
);
572 if (ripng_route_rte(rinfo
)
573 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
574 /* The ADD message implies the update. */
575 ripng_zebra_ipv6_add(ripng
, rp
);
576 ripng_info_free(rinfo
);
579 assert(rinfo
== listgetdata(listhead(list
)));
581 /* This is the only entry left in the list. We must keep it in
582 * the list for garbage collection time, with INFINITY metric.
585 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
586 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
587 ripng
->garbage_time
);
589 if (ripng_route_rte(rinfo
)
590 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
591 ripng_zebra_ipv6_delete(ripng
, rp
);
594 /* Set the route change flag on the first entry. */
595 rinfo
= listgetdata(listhead(list
));
596 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
598 /* Signal the output process to trigger an update. */
599 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
604 /* Timeout RIPng routes. */
605 static int ripng_timeout(struct thread
*t
)
607 struct ripng_info
*rinfo
= THREAD_ARG(t
);
608 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
610 ripng_ecmp_delete(ripng
, rinfo
);
615 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
617 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
618 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
619 thread_add_timer(master
, ripng_timeout
, rinfo
,
620 ripng
->timeout_time
, &rinfo
->t_timeout
);
624 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
625 struct ripng_interface
*ri
)
627 struct distribute
*dist
;
628 struct access_list
*alist
;
629 struct prefix_list
*plist
;
630 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
633 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
635 /* Input distribute-list filtering. */
636 if (ri
->list
[ripng_distribute
]) {
637 if (access_list_apply(ri
->list
[ripng_distribute
],
640 if (IS_RIPNG_DEBUG_PACKET
)
641 zlog_debug("%s/%d filtered by distribute %s",
642 inet6_ntoa(p
->prefix
), p
->prefixlen
,
647 if (ri
->prefix
[ripng_distribute
]) {
648 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
651 if (IS_RIPNG_DEBUG_PACKET
)
652 zlog_debug("%s/%d filtered by prefix-list %s",
653 inet6_ntoa(p
->prefix
), p
->prefixlen
,
659 /* All interface filter check. */
660 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
662 if (dist
->list
[distribute
]) {
663 alist
= access_list_lookup(AFI_IP6
,
664 dist
->list
[distribute
]);
667 if (access_list_apply(alist
, (struct prefix
*)p
)
669 if (IS_RIPNG_DEBUG_PACKET
)
671 "%s/%d filtered by distribute %s",
672 inet6_ntoa(p
->prefix
),
673 p
->prefixlen
, inout
);
678 if (dist
->prefix
[distribute
]) {
679 plist
= prefix_list_lookup(AFI_IP6
,
680 dist
->prefix
[distribute
]);
683 if (prefix_list_apply(plist
, (struct prefix
*)p
)
685 if (IS_RIPNG_DEBUG_PACKET
)
687 "%s/%d filtered by prefix-list %s",
688 inet6_ntoa(p
->prefix
),
689 p
->prefixlen
, inout
);
698 /* Process RIPng route according to RFC2080. */
699 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
700 struct ripng_nexthop
*ripng_nexthop
,
701 struct interface
*ifp
)
704 struct prefix_ipv6 p
;
706 struct ripng_info
*rinfo
= NULL
, newinfo
;
707 struct ripng_interface
*ri
;
709 struct in6_addr
*nexthop
;
711 struct list
*list
= NULL
;
712 struct listnode
*node
= NULL
;
714 /* Make prefix structure. */
715 memset(&p
, 0, sizeof(struct prefix_ipv6
));
717 /* p.prefix = rte->addr; */
718 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
719 p
.prefixlen
= rte
->prefixlen
;
721 /* Make sure mask is applied. */
722 /* XXX We have to check the prefix is valid or not before call
729 /* Apply input filters. */
730 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
734 memset(&newinfo
, 0, sizeof(newinfo
));
735 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
736 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
737 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
738 newinfo
.nexthop
= ripng_nexthop
->address
;
740 newinfo
.nexthop
= from
->sin6_addr
;
741 newinfo
.from
= from
->sin6_addr
;
742 newinfo
.ifindex
= ifp
->ifindex
;
743 newinfo
.metric
= rte
->metric
;
744 newinfo
.metric_out
= rte
->metric
; /* XXX */
745 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
748 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
749 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
750 (struct prefix
*)&p
, RMAP_RIPNG
,
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 %s/%d on the interface %s",
996 inet6_ntoa(p
->prefix
), p
->prefixlen
,
997 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1000 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
1001 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1002 inet6_ntoa(*nexthop
),
1003 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1006 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1009 /* Delete redistributed route to RIPng table. */
1010 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1011 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1013 struct agg_node
*rp
;
1014 struct ripng_info
*rinfo
;
1016 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1018 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1021 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1024 struct list
*list
= rp
->info
;
1026 if (list
!= NULL
&& listcount(list
) != 0) {
1027 rinfo
= listgetdata(listhead(list
));
1028 if (rinfo
!= NULL
&& rinfo
->type
== type
1029 && rinfo
->sub_type
== sub_type
1030 && rinfo
->ifindex
== ifindex
) {
1031 /* Perform poisoned reverse. */
1032 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1033 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1034 ripng_garbage_collect
,
1035 ripng
->garbage_time
);
1036 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1038 /* Aggregate count decrement. */
1039 ripng_aggregate_decrement(rp
, rinfo
);
1041 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1043 if (IS_RIPNG_DEBUG_EVENT
)
1045 "Poisone %s/%d on the interface %s with an "
1046 "infinity metric [delete]",
1047 inet6_ntoa(p
->prefix
),
1051 ripng
->vrf
->vrf_id
));
1053 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1056 agg_unlock_node(rp
);
1060 /* Withdraw redistributed route. */
1061 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1063 struct agg_node
*rp
;
1064 struct ripng_info
*rinfo
= NULL
;
1065 struct list
*list
= NULL
;
1067 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1068 if ((list
= rp
->info
) != NULL
) {
1069 rinfo
= listgetdata(listhead(list
));
1070 if ((rinfo
->type
== type
)
1071 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1072 /* Perform poisoned reverse. */
1073 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1074 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1075 ripng_garbage_collect
,
1076 ripng
->garbage_time
);
1077 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1079 /* Aggregate count decrement. */
1080 ripng_aggregate_decrement(rp
, rinfo
);
1082 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1084 if (IS_RIPNG_DEBUG_EVENT
) {
1085 struct prefix_ipv6
*p
=
1086 (struct prefix_ipv6
*)&rp
->p
;
1089 "Poisone %s/%d on the interface %s [withdraw]",
1090 inet6_ntoa(p
->prefix
),
1094 ripng
->vrf
->vrf_id
));
1097 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1102 /* RIP routing information. */
1103 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1104 struct sockaddr_in6
*from
,
1105 struct interface
*ifp
, int hoplimit
)
1107 struct ripng_interface
*ri
= ifp
->info
;
1108 struct ripng
*ripng
= ri
->ripng
;
1111 struct ripng_nexthop nexthop
;
1113 /* RFC2080 2.4.2 Response Messages:
1114 The Response must be ignored if it is not from the RIPng port. */
1115 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1116 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1117 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1118 ripng_peer_bad_packet(ripng
, from
);
1122 /* The datagram's IPv6 source address should be checked to see
1123 whether the datagram is from a valid neighbor; the source of the
1124 datagram must be a link-local address. */
1125 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1126 zlog_warn("RIPng packet comes from non link local address %s",
1127 inet6_ntoa(from
->sin6_addr
));
1128 ripng_peer_bad_packet(ripng
, from
);
1132 /* It is also worth checking to see whether the response is from one
1133 of the router's own addresses. Interfaces on broadcast networks
1134 may receive copies of their own multicasts immediately. If a
1135 router processes its own output as new input, confusion is likely,
1136 and such datagrams must be ignored. */
1137 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1139 "RIPng packet comes from my own link local address %s",
1140 inet6_ntoa(from
->sin6_addr
));
1141 ripng_peer_bad_packet(ripng
, from
);
1145 /* As an additional check, periodic advertisements must have their
1146 hop counts set to 255, and inbound, multicast packets sent from the
1147 RIPng port (i.e. periodic advertisement or triggered update
1148 packets) must be examined to ensure that the hop count is 255. */
1149 if (hoplimit
>= 0 && hoplimit
!= 255) {
1151 "RIPng packet comes with non 255 hop count %d from %s",
1152 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1153 ripng_peer_bad_packet(ripng
, from
);
1157 /* Update RIPng peer. */
1158 ripng_peer_update(ripng
, from
, packet
->version
);
1160 /* Reset nexthop. */
1161 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1162 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1164 /* Set RTE pointer. */
1167 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1168 /* First of all, we have to check this RTE is next hop RTE or
1169 not. Next hop RTE is completely different with normal RTE so
1170 we need special treatment. */
1171 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1172 ripng_nexthop_rte(rte
, from
, &nexthop
);
1176 /* RTE information validation. */
1178 /* - is the destination prefix valid (e.g., not a multicast
1179 prefix and not a link-local address) A link-local address
1180 should never be present in an RTE. */
1181 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1183 "Destination prefix is a multicast address %s/%d [%d]",
1184 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1186 ripng_peer_bad_route(ripng
, from
);
1189 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1191 "Destination prefix is a link-local address %s/%d [%d]",
1192 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1194 ripng_peer_bad_route(ripng
, from
);
1197 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1199 "Destination prefix is a loopback address %s/%d [%d]",
1200 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1202 ripng_peer_bad_route(ripng
, from
);
1206 /* - is the prefix length valid (i.e., between 0 and 128,
1208 if (rte
->prefixlen
> 128) {
1209 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1210 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1211 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1212 ripng_peer_bad_route(ripng
, from
);
1216 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1217 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1218 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1219 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1220 ripng_peer_bad_route(ripng
, from
);
1224 /* Vincent: XXX Should we compute the direclty reachable nexthop
1225 * for our RIPng network ?
1228 /* Routing table updates. */
1229 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1233 /* Response to request message. */
1234 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1235 struct sockaddr_in6
*from
,
1236 struct interface
*ifp
)
1238 struct ripng
*ripng
;
1241 struct prefix_ipv6 p
;
1242 struct agg_node
*rp
;
1243 struct ripng_info
*rinfo
;
1244 struct ripng_interface
*ri
;
1246 /* Does not reponse to the requests on the loopback interfaces */
1247 if (if_is_loopback(ifp
))
1250 /* Check RIPng process is enabled on this interface. */
1256 /* When passive interface is specified, suppress responses */
1260 /* RIPng peer update. */
1261 ripng_peer_update(ripng
, from
, packet
->version
);
1263 lim
= ((caddr_t
)packet
) + size
;
1266 /* The Request is processed entry by entry. If there are no
1267 entries, no response is given. */
1268 if (lim
== (caddr_t
)rte
)
1271 /* There is one special case. If there is exactly one entry in the
1272 request, and it has a destination prefix of zero, a prefix length
1273 of zero, and a metric of infinity (i.e., 16), then this is a
1274 request to send the entire routing table. In that case, a call
1275 is made to the output process to send the routing table to the
1276 requesting address/port. */
1277 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1278 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1279 /* All route with split horizon */
1280 ripng_output_process(ifp
, from
, ripng_all_route
);
1282 /* Except for this special case, processing is quite simple.
1283 Examine the list of RTEs in the Request one by one. For each
1284 entry, look up the destination in the router's routing
1285 database and, if there is a route, put that route's metric in
1286 the metric field of the RTE. If there is no explicit route
1287 to the specified destination, put infinity in the metric
1288 field. Once all the entries have been filled in, change the
1289 command from Request to Response and send the datagram back
1290 to the requestor. */
1291 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1292 p
.family
= AF_INET6
;
1294 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1295 p
.prefix
= rte
->addr
;
1296 p
.prefixlen
= rte
->prefixlen
;
1297 apply_mask_ipv6(&p
);
1299 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1302 rinfo
= listgetdata(
1303 listhead((struct list
*)rp
->info
));
1304 rte
->metric
= rinfo
->metric
;
1305 agg_unlock_node(rp
);
1307 rte
->metric
= RIPNG_METRIC_INFINITY
;
1309 packet
->command
= RIPNG_RESPONSE
;
1311 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1315 /* First entry point of reading RIPng packet. */
1316 static int ripng_read(struct thread
*thread
)
1318 struct ripng
*ripng
= THREAD_ARG(thread
);
1321 struct sockaddr_in6 from
;
1322 struct ripng_packet
*packet
;
1323 ifindex_t ifindex
= 0;
1324 struct interface
*ifp
;
1327 /* Check ripng is active and alive. */
1328 assert(ripng
!= NULL
);
1329 assert(ripng
->sock
>= 0);
1331 /* Fetch thread data and set read pointer to empty for event
1332 managing. `sock' sould be same as ripng->sock. */
1333 sock
= THREAD_FD(thread
);
1334 ripng
->t_read
= NULL
;
1336 /* Add myself to the next event. */
1337 ripng_event(ripng
, RIPNG_READ
, sock
);
1339 /* Read RIPng packet. */
1340 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1341 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1344 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1345 ripng
->vrf_name
, safe_strerror(errno
));
1349 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1350 (4)) must be multiple size of one RTE size (20). */
1351 if (((len
- 4) % 20) != 0) {
1352 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1353 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1354 ripng_peer_bad_packet(ripng
, &from
);
1358 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1359 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1361 /* RIPng packet received. */
1362 if (IS_RIPNG_DEBUG_EVENT
)
1364 "RIPng packet received from %s port %d on %s (VRF %s)",
1365 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1366 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1368 /* Logging before packet checking. */
1369 if (IS_RIPNG_DEBUG_RECV
)
1370 ripng_packet_dump(packet
, len
, "RECV");
1372 /* Packet comes from unknown interface. */
1375 "RIPng packet comes from unknown interface %d (VRF %s)",
1376 ifindex
, ripng
->vrf_name
);
1380 /* Packet version mismatch checking. */
1381 if (packet
->version
!= ripng
->version
) {
1383 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1384 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1385 ripng_peer_bad_packet(ripng
, &from
);
1389 /* Process RIPng packet. */
1390 switch (packet
->command
) {
1392 ripng_request_process(packet
, len
, &from
, ifp
);
1394 case RIPNG_RESPONSE
:
1395 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1398 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1400 ripng_peer_bad_packet(ripng
, &from
);
1406 /* Walk down the RIPng routing table then clear changed flag. */
1407 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1409 struct agg_node
*rp
;
1410 struct ripng_info
*rinfo
= NULL
;
1411 struct list
*list
= NULL
;
1412 struct listnode
*listnode
= NULL
;
1414 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1415 if ((list
= rp
->info
) != NULL
)
1416 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1417 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1418 /* This flag can be set only on the first entry.
1424 /* Regular update of RIPng route. Send all routing formation to RIPng
1425 enabled interface. */
1426 static int ripng_update(struct thread
*t
)
1428 struct ripng
*ripng
= THREAD_ARG(t
);
1429 struct interface
*ifp
;
1430 struct ripng_interface
*ri
;
1432 /* Clear update timer thread. */
1433 ripng
->t_update
= NULL
;
1435 /* Logging update event. */
1436 if (IS_RIPNG_DEBUG_EVENT
)
1437 zlog_debug("RIPng update timer expired!");
1439 /* Supply routes to each interface. */
1440 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1443 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1449 /* When passive interface is specified, suppress announce to the
1455 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1456 if (IS_RIPNG_DEBUG_EVENT
)
1458 "[Event] RIPng send to if %d is suppressed by config",
1462 #endif /* RIPNG_ADVANCED */
1464 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1467 /* Triggered updates may be suppressed if a regular update is due by
1468 the time the triggered update would be sent. */
1469 if (ripng
->t_triggered_interval
) {
1470 thread_cancel(ripng
->t_triggered_interval
);
1471 ripng
->t_triggered_interval
= NULL
;
1475 /* Reset flush event. */
1476 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1481 /* Triggered update interval timer. */
1482 static int ripng_triggered_interval(struct thread
*t
)
1484 struct ripng
*ripng
= THREAD_ARG(t
);
1486 ripng
->t_triggered_interval
= NULL
;
1488 if (ripng
->trigger
) {
1490 ripng_triggered_update(t
);
1495 /* Execute triggered update. */
1496 int ripng_triggered_update(struct thread
*t
)
1498 struct ripng
*ripng
= THREAD_ARG(t
);
1499 struct interface
*ifp
;
1500 struct ripng_interface
*ri
;
1503 ripng
->t_triggered_update
= NULL
;
1505 /* Cancel interval timer. */
1506 if (ripng
->t_triggered_interval
) {
1507 thread_cancel(ripng
->t_triggered_interval
);
1508 ripng
->t_triggered_interval
= NULL
;
1512 /* Logging triggered update. */
1513 if (IS_RIPNG_DEBUG_EVENT
)
1514 zlog_debug("RIPng triggered update!");
1516 /* Split Horizon processing is done when generating triggered
1517 updates as well as normal updates (see section 2.6). */
1518 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1521 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1527 /* When passive interface is specified, suppress announce to the
1532 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1535 /* Once all of the triggered updates have been generated, the route
1536 change flags should be cleared. */
1537 ripng_clear_changed_flag(ripng
);
1539 /* After a triggered update is sent, a timer should be set for a
1540 random interval between 1 and 5 seconds. If other changes that
1541 would trigger updates occur before the timer expires, a single
1542 update is triggered when the timer expires. */
1543 interval
= (random() % 5) + 1;
1545 ripng
->t_triggered_interval
= NULL
;
1546 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1547 &ripng
->t_triggered_interval
);
1552 /* Write routing table entry to the stream and return next index of
1553 the routing table entry in the stream. */
1554 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1555 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1557 /* RIPng packet header. */
1559 stream_putc(s
, RIPNG_RESPONSE
);
1560 stream_putc(s
, RIPNG_V1
);
1564 /* Write routing table entry. */
1567 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1569 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1570 stream_putw(s
, tag
);
1572 stream_putc(s
, p
->prefixlen
);
1575 stream_putc(s
, metric
);
1580 /* Send RESPONSE message to specified destination. */
1581 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1584 struct ripng
*ripng
;
1586 struct agg_node
*rp
;
1587 struct ripng_info
*rinfo
;
1588 struct ripng_interface
*ri
;
1589 struct ripng_aggregate
*aggregate
;
1590 struct prefix_ipv6
*p
;
1591 struct list
*ripng_rte_list
;
1592 struct list
*list
= NULL
;
1593 struct listnode
*listnode
= NULL
;
1595 if (IS_RIPNG_DEBUG_EVENT
) {
1597 zlog_debug("RIPng update routes to neighbor %s",
1598 inet6_ntoa(to
->sin6_addr
));
1600 zlog_debug("RIPng update routes on interface %s",
1604 /* Get RIPng interface and instance. */
1608 ripng_rte_list
= ripng_rte_new();
1610 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1611 if ((list
= rp
->info
) != NULL
1612 && (rinfo
= listgetdata(listhead(list
))) != NULL
1613 && rinfo
->suppress
== 0) {
1614 /* If no route-map are applied, the RTE will be these
1618 p
= (struct prefix_ipv6
*)&rp
->p
;
1619 rinfo
->metric_out
= rinfo
->metric
;
1620 rinfo
->tag_out
= rinfo
->tag
;
1621 memset(&rinfo
->nexthop_out
, 0,
1622 sizeof(rinfo
->nexthop_out
));
1623 /* In order to avoid some local loops,
1624 * if the RIPng route has a nexthop via this interface,
1626 * otherwise set it to 0. The nexthop should not be
1628 * beyond the local broadcast/multicast area in order
1629 * to avoid an IGP multi-level recursive look-up.
1631 if (rinfo
->ifindex
== ifp
->ifindex
)
1632 rinfo
->nexthop_out
= rinfo
->nexthop
;
1634 /* Apply output filters. */
1635 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1639 /* Changed route only output. */
1640 if (route_type
== ripng_changed_route
1641 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1644 /* Split horizon. */
1645 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1646 /* We perform split horizon for RIPng routes. */
1648 struct ripng_info
*tmp_rinfo
= NULL
;
1650 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1652 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1653 && tmp_rinfo
->ifindex
1662 /* Preparation for route-map. */
1663 rinfo
->metric_set
= 0;
1666 * and tag_out are already initialized.
1669 /* Interface route-map */
1670 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1671 ret
= route_map_apply(
1672 ri
->routemap
[RIPNG_FILTER_OUT
],
1673 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1675 if (ret
== RMAP_DENYMATCH
) {
1676 if (IS_RIPNG_DEBUG_PACKET
)
1678 "RIPng %s/%d is filtered by route-map out",
1679 inet6_ntoa(p
->prefix
),
1685 /* Redistribute route-map. */
1686 if (ripng
->redist
[rinfo
->type
].route_map
.name
) {
1687 ret
= route_map_apply(ripng
->redist
[rinfo
->type
]
1692 if (ret
== RMAP_DENYMATCH
) {
1693 if (IS_RIPNG_DEBUG_PACKET
)
1695 "RIPng %s/%d is filtered by route-map",
1696 inet6_ntoa(p
->prefix
),
1702 /* When the route-map does not set metric. */
1703 if (!rinfo
->metric_set
) {
1704 /* If the redistribute metric is set. */
1705 if (ripng
->redist
[rinfo
->type
].metric_config
1706 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1708 ripng
->redist
[rinfo
->type
]
1711 /* If the route is not connected or
1713 one, use default-metric value */
1714 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1716 != ZEBRA_ROUTE_CONNECT
1718 != RIPNG_METRIC_INFINITY
)
1720 ripng
->default_metric
;
1724 /* Apply offset-list */
1725 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1726 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1727 &rinfo
->metric_out
);
1729 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1730 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1732 /* Perform split-horizon with poisoned reverse
1735 if (ri
->split_horizon
1736 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1737 struct ripng_info
*tmp_rinfo
= NULL
;
1739 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1741 if ((tmp_rinfo
->type
1742 == ZEBRA_ROUTE_RIPNG
)
1743 && tmp_rinfo
->ifindex
1746 RIPNG_METRIC_INFINITY
;
1749 /* Add RTE to the list */
1750 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1753 /* Process the aggregated RTE entry */
1754 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1755 && aggregate
->suppress
== 0) {
1756 /* If no route-map are applied, the RTE will be these
1760 p
= (struct prefix_ipv6
*)&rp
->p
;
1761 aggregate
->metric_set
= 0;
1762 aggregate
->metric_out
= aggregate
->metric
;
1763 aggregate
->tag_out
= aggregate
->tag
;
1764 memset(&aggregate
->nexthop_out
, 0,
1765 sizeof(aggregate
->nexthop_out
));
1767 /* Apply output filters.*/
1768 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1772 /* Interface route-map */
1773 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1774 struct ripng_info newinfo
;
1776 /* let's cast the aggregate structure to
1778 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1779 /* the nexthop is :: */
1780 newinfo
.metric
= aggregate
->metric
;
1781 newinfo
.metric_out
= aggregate
->metric_out
;
1782 newinfo
.tag
= aggregate
->tag
;
1783 newinfo
.tag_out
= aggregate
->tag_out
;
1785 ret
= route_map_apply(
1786 ri
->routemap
[RIPNG_FILTER_OUT
],
1787 (struct prefix
*)p
, RMAP_RIPNG
,
1790 if (ret
== RMAP_DENYMATCH
) {
1791 if (IS_RIPNG_DEBUG_PACKET
)
1793 "RIPng %s/%d is filtered by route-map out",
1794 inet6_ntoa(p
->prefix
),
1799 aggregate
->metric_out
= newinfo
.metric_out
;
1800 aggregate
->tag_out
= newinfo
.tag_out
;
1801 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1802 aggregate
->nexthop_out
=
1803 newinfo
.nexthop_out
;
1806 /* There is no redistribute routemap for the aggregated
1809 /* Changed route only output. */
1810 /* XXX, vincent, in order to increase time convergence,
1811 * it should be announced if a child has changed.
1813 if (route_type
== ripng_changed_route
)
1816 /* Apply offset-list */
1817 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1818 ripng_offset_list_apply_out(
1819 ripng
, p
, ifp
, &aggregate
->metric_out
);
1821 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1822 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1824 /* Add RTE to the list */
1825 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1829 /* Flush the list */
1830 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1831 ripng_rte_free(ripng_rte_list
);
1834 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1838 vrf
= vrf_lookup_by_id(vrf_id
);
1845 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1849 ripng
.vrf_name
= (char *)vrf_name
;
1851 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1854 /* Create new RIPng instance and set it to global variable. */
1855 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1857 struct ripng
*ripng
;
1859 /* Allocaste RIPng instance. */
1860 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1861 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1863 /* Default version and timer values. */
1864 ripng
->version
= RIPNG_V1
;
1865 ripng
->update_time
= yang_get_default_uint32(
1866 "%s/timers/update-interval", RIPNG_INSTANCE
);
1867 ripng
->timeout_time
= yang_get_default_uint32(
1868 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1869 ripng
->garbage_time
= yang_get_default_uint32(
1870 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1871 ripng
->default_metric
=
1872 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1873 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1876 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1877 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1879 /* Initialize RIPng data structures. */
1880 ripng
->table
= agg_table_init();
1881 agg_set_table_info(ripng
->table
, ripng
);
1882 ripng
->peer_list
= list_new();
1883 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1884 ripng
->peer_list
->del
= ripng_peer_list_del
;
1885 ripng
->enable_if
= vector_init(1);
1886 ripng
->enable_network
= agg_table_init();
1887 ripng
->passive_interface
= vector_init(1);
1888 ripng
->offset_list_master
= list_new();
1889 ripng
->offset_list_master
->cmp
=
1890 (int (*)(void *, void *))offset_list_cmp
;
1891 ripng
->offset_list_master
->del
=
1892 (void (*)(void *))ripng_offset_list_free
;
1893 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1894 distribute_list_add_hook(ripng
->distribute_ctx
,
1895 ripng_distribute_update
);
1896 distribute_list_delete_hook(ripng
->distribute_ctx
,
1897 ripng_distribute_update
);
1899 /* if rmap install. */
1900 ripng
->if_rmap_ctx
= if_rmap_ctx_create(vrf_name
);
1901 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1902 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1904 /* Enable the routing instance if possible. */
1905 if (vrf
&& vrf_is_enabled(vrf
))
1906 ripng_instance_enable(ripng
, vrf
, socket
);
1912 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1917 /* Send RIPng request to the interface. */
1918 int ripng_request(struct interface
*ifp
)
1921 struct ripng_packet ripng_packet
;
1923 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1925 if (if_is_loopback(ifp
))
1928 /* If interface is down, don't send RIP packet. */
1932 if (IS_RIPNG_DEBUG_EVENT
)
1933 zlog_debug("RIPng send request to %s", ifp
->name
);
1935 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1936 ripng_packet
.command
= RIPNG_REQUEST
;
1937 ripng_packet
.version
= RIPNG_V1
;
1938 rte
= ripng_packet
.rte
;
1939 rte
->metric
= RIPNG_METRIC_INFINITY
;
1941 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1946 static int ripng_update_jitter(int time
)
1948 return ((random() % (time
+ 1)) - (time
/ 2));
1951 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1957 thread_add_read(master
, ripng_read
, ripng
, sock
,
1960 case RIPNG_UPDATE_EVENT
:
1961 if (ripng
->t_update
) {
1962 thread_cancel(ripng
->t_update
);
1963 ripng
->t_update
= NULL
;
1965 /* Update timer jitter. */
1966 jitter
= ripng_update_jitter(ripng
->update_time
);
1968 ripng
->t_update
= NULL
;
1969 thread_add_timer(master
, ripng_update
, ripng
,
1970 sock
? 2 : ripng
->update_time
+ jitter
,
1973 case RIPNG_TRIGGERED_UPDATE
:
1974 if (ripng
->t_triggered_interval
)
1977 thread_add_event(master
, ripng_triggered_update
, ripng
,
1978 0, &ripng
->t_triggered_update
);
1986 /* Print out routes update time. */
1987 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1992 char timebuf
[TIME_BUF
];
1993 struct thread
*thread
;
1995 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1996 clock
= thread_timer_remain_second(thread
);
1997 tm
= gmtime(&clock
);
1998 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1999 vty_out(vty
, "%5s", timebuf
);
2000 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
2001 clock
= thread_timer_remain_second(thread
);
2002 tm
= gmtime(&clock
);
2003 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
2004 vty_out(vty
, "%5s", timebuf
);
2008 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
2013 if (rinfo
->suppress
)
2014 strlcat(str
, "S", sizeof(str
));
2016 switch (rinfo
->sub_type
) {
2017 case RIPNG_ROUTE_RTE
:
2018 strlcat(str
, "n", sizeof(str
));
2020 case RIPNG_ROUTE_STATIC
:
2021 strlcat(str
, "s", sizeof(str
));
2023 case RIPNG_ROUTE_DEFAULT
:
2024 strlcat(str
, "d", sizeof(str
));
2026 case RIPNG_ROUTE_REDISTRIBUTE
:
2027 strlcat(str
, "r", sizeof(str
));
2029 case RIPNG_ROUTE_INTERFACE
:
2030 strlcat(str
, "i", sizeof(str
));
2033 strlcat(str
, "?", sizeof(str
));
2040 DEFUN (show_ipv6_ripng
,
2041 show_ipv6_ripng_cmd
,
2042 "show ipv6 ripng [vrf NAME]",
2045 "Show RIPng routes\n"
2048 struct ripng
*ripng
;
2049 struct agg_node
*rp
;
2050 struct ripng_info
*rinfo
;
2051 struct ripng_aggregate
*aggregate
;
2052 struct prefix_ipv6
*p
;
2053 struct list
*list
= NULL
;
2054 struct listnode
*listnode
= NULL
;
2056 const char *vrf_name
;
2059 if (argv_find(argv
, argc
, "vrf", &idx
))
2060 vrf_name
= argv
[idx
+ 1]->arg
;
2062 vrf_name
= VRF_DEFAULT_NAME
;
2064 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2066 vty_out(vty
, "%% RIPng instance not found\n");
2069 if (!ripng
->enabled
) {
2070 vty_out(vty
, "%% RIPng instance is disabled\n");
2074 /* Header of display. */
2076 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2078 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2079 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2080 " Network Next Hop Via Metric Tag Time\n");
2082 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2083 if ((aggregate
= rp
->aggregate
) != NULL
) {
2084 p
= (struct prefix_ipv6
*)&rp
->p
;
2087 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
2088 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
2091 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
2095 vty_out(vty
, "%*s", 18, " ");
2097 vty_out(vty
, "%*s", 28, " ");
2098 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2099 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2102 if ((list
= rp
->info
) != NULL
)
2103 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2104 p
= (struct prefix_ipv6
*)&rp
->p
;
2107 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2108 zebra_route_char(rinfo
->type
),
2109 ripng_route_subtype_print(rinfo
),
2110 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2113 vty_out(vty
, "%c(%s) %s/%d ",
2114 zebra_route_char(rinfo
->type
),
2115 ripng_route_subtype_print(rinfo
),
2116 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2119 vty_out(vty
, "%*s", 18, " ");
2120 len
= vty_out(vty
, "%s",
2121 inet6_ntoa(rinfo
->nexthop
));
2125 vty_out(vty
, "%*s", len
, " ");
2128 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2129 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2134 ripng
->vrf
->vrf_id
));
2135 } else if (rinfo
->metric
2136 == RIPNG_METRIC_INFINITY
) {
2137 len
= vty_out(vty
, "kill");
2139 len
= vty_out(vty
, "self");
2143 vty_out(vty
, "%*s", len
, " ");
2145 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2146 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2149 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2150 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2151 /* RTE from remote RIP routers */
2152 ripng_vty_out_uptime(vty
, rinfo
);
2153 } else if (rinfo
->metric
2154 == RIPNG_METRIC_INFINITY
) {
2155 /* poisonous reversed routes (gc) */
2156 ripng_vty_out_uptime(vty
, rinfo
);
2166 DEFUN (show_ipv6_ripng_status
,
2167 show_ipv6_ripng_status_cmd
,
2168 "show ipv6 ripng [vrf NAME] status",
2171 "Show RIPng routes\n"
2173 "IPv6 routing protocol process parameters and statistics\n")
2175 struct ripng
*ripng
;
2176 struct interface
*ifp
;
2177 const char *vrf_name
;
2180 if (argv_find(argv
, argc
, "vrf", &idx
))
2181 vrf_name
= argv
[idx
+ 1]->arg
;
2183 vrf_name
= VRF_DEFAULT_NAME
;
2185 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2187 vty_out(vty
, "%% RIPng instance not found\n");
2190 if (!ripng
->enabled
) {
2191 vty_out(vty
, "%% RIPng instance is disabled\n");
2195 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2196 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2197 ripng
->update_time
);
2198 vty_out(vty
, " next due in %lu seconds\n",
2199 thread_timer_remain_second(ripng
->t_update
));
2200 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2201 vty_out(vty
, " garbage collect after %u seconds\n",
2202 ripng
->garbage_time
);
2204 /* Filtering status show. */
2205 config_show_distribute(vty
, ripng
->distribute_ctx
);
2207 /* Default metric information. */
2208 vty_out(vty
, " Default redistribution metric is %d\n",
2209 ripng
->default_metric
);
2211 /* Redistribute information. */
2212 vty_out(vty
, " Redistributing:");
2213 ripng_redistribute_write(vty
, ripng
);
2216 vty_out(vty
, " Default version control: send version %d,",
2218 vty_out(vty
, " receive version %d \n", ripng
->version
);
2220 vty_out(vty
, " Interface Send Recv\n");
2222 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2223 struct ripng_interface
*ri
;
2227 if (ri
->enable_network
|| ri
->enable_interface
) {
2229 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2230 ripng
->version
, ripng
->version
);
2234 vty_out(vty
, " Routing for Networks:\n");
2235 ripng_network_write(vty
, ripng
);
2237 vty_out(vty
, " Routing Information Sources:\n");
2239 " Gateway BadPackets BadRoutes Distance Last Update\n");
2240 ripng_peer_display(vty
, ripng
);
2246 /* RIPng update timer setup. */
2247 DEFUN (ripng_update_timer
,
2248 ripng_update_timer_cmd
,
2249 "update-timer SECOND",
2250 "Set RIPng update timer in seconds\n"
2253 unsigned long update
;
2254 char *endptr
= NULL
;
2256 update
= strtoul (argv
[0], &endptr
, 10);
2257 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2259 vty_out (vty
, "update timer value error\n");
2260 return CMD_WARNING_CONFIG_FAILED
;
2263 ripng
->update_time
= update
;
2265 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2269 DEFUN (no_ripng_update_timer
,
2270 no_ripng_update_timer_cmd
,
2271 "no update-timer SECOND",
2273 "Unset RIPng update timer in seconds\n"
2276 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2277 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2281 /* RIPng timeout timer setup. */
2282 DEFUN (ripng_timeout_timer
,
2283 ripng_timeout_timer_cmd
,
2284 "timeout-timer SECOND",
2285 "Set RIPng timeout timer in seconds\n"
2288 unsigned long timeout
;
2289 char *endptr
= NULL
;
2291 timeout
= strtoul (argv
[0], &endptr
, 10);
2292 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2294 vty_out (vty
, "timeout timer value error\n");
2295 return CMD_WARNING_CONFIG_FAILED
;
2298 ripng
->timeout_time
= timeout
;
2303 DEFUN (no_ripng_timeout_timer
,
2304 no_ripng_timeout_timer_cmd
,
2305 "no timeout-timer SECOND",
2307 "Unset RIPng timeout timer in seconds\n"
2310 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2314 /* RIPng garbage timer setup. */
2315 DEFUN (ripng_garbage_timer
,
2316 ripng_garbage_timer_cmd
,
2317 "garbage-timer SECOND",
2318 "Set RIPng garbage timer in seconds\n"
2321 unsigned long garbage
;
2322 char *endptr
= NULL
;
2324 garbage
= strtoul (argv
[0], &endptr
, 10);
2325 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2327 vty_out (vty
, "garbage timer value error\n");
2328 return CMD_WARNING_CONFIG_FAILED
;
2331 ripng
->garbage_time
= garbage
;
2336 DEFUN (no_ripng_garbage_timer
,
2337 no_ripng_garbage_timer_cmd
,
2338 "no garbage-timer SECOND",
2340 "Unset RIPng garbage timer in seconds\n"
2343 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2349 DEFUN (show_ipv6_protocols
,
2350 show_ipv6_protocols_cmd
,
2351 "show ipv6 protocols",
2354 "Routing protocol information\n")
2359 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2361 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2362 ripng
->update_time
, 0);
2364 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2365 ripng
->timeout_time
,
2366 ripng
->garbage_time
);
2368 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2369 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2375 /* Update ECMP routes to zebra when ECMP is disabled. */
2376 void ripng_ecmp_disable(struct ripng
*ripng
)
2378 struct agg_node
*rp
;
2379 struct ripng_info
*rinfo
, *tmp_rinfo
;
2381 struct listnode
*node
, *nextnode
;
2386 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2387 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2388 rinfo
= listgetdata(listhead(list
));
2389 if (!ripng_route_rte(rinfo
))
2392 /* Drop all other entries, except the first one. */
2393 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2394 if (tmp_rinfo
!= rinfo
) {
2395 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2397 tmp_rinfo
->t_garbage_collect
);
2398 list_delete_node(list
, node
);
2399 ripng_info_free(tmp_rinfo
);
2403 ripng_zebra_ipv6_add(ripng
, rp
);
2405 /* Set the route change flag. */
2406 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2408 /* Signal the output process to trigger an update. */
2409 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2413 /* RIPng configuration write function. */
2414 static int ripng_config_write(struct vty
*vty
)
2416 struct ripng
*ripng
;
2419 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2420 char xpath
[XPATH_MAXLEN
];
2421 struct lyd_node
*dnode
;
2423 snprintf(xpath
, sizeof(xpath
),
2424 "/frr-ripngd:ripngd/instance[vrf='%s']",
2427 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2430 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2432 config_write_distribute(vty
, ripng
->distribute_ctx
);
2433 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2441 /* RIPng node structure. */
2442 static struct cmd_node cmd_ripng_node
= {
2443 RIPNG_NODE
, "%s(config-router)# ", 1,
2446 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2447 struct distribute
*dist
)
2449 struct interface
*ifp
;
2450 struct ripng_interface
*ri
;
2451 struct access_list
*alist
;
2452 struct prefix_list
*plist
;
2454 if (!ctx
->vrf
|| !dist
->ifname
)
2457 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
);
2463 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2464 alist
= access_list_lookup(AFI_IP6
,
2465 dist
->list
[DISTRIBUTE_V6_IN
]);
2467 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2469 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2471 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2473 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2474 alist
= access_list_lookup(AFI_IP6
,
2475 dist
->list
[DISTRIBUTE_V6_OUT
]);
2477 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2479 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2481 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2483 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2484 plist
= prefix_list_lookup(AFI_IP6
,
2485 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2487 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2489 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2491 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2493 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2494 plist
= prefix_list_lookup(AFI_IP6
,
2495 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2497 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2499 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2501 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2504 void ripng_distribute_update_interface(struct interface
*ifp
)
2506 struct ripng_interface
*ri
= ifp
->info
;
2507 struct ripng
*ripng
= ri
->ripng
;
2508 struct distribute
*dist
;
2512 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2514 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2517 /* Update all interface's distribute list. */
2518 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2520 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2521 struct interface
*ifp
;
2523 FOR_ALL_INTERFACES (vrf
, ifp
)
2524 ripng_distribute_update_interface(ifp
);
2527 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2529 ripng_distribute_update_all(NULL
);
2532 /* delete all the added ripng routes. */
2533 void ripng_clean(struct ripng
*ripng
)
2536 ripng_instance_disable(ripng
);
2538 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2539 if (ripng
->redist
[i
].route_map
.name
)
2540 free(ripng
->redist
[i
].route_map
.name
);
2542 agg_table_finish(ripng
->table
);
2543 list_delete(&ripng
->peer_list
);
2544 distribute_list_delete(&ripng
->distribute_ctx
);
2545 if_rmap_ctx_delete(ripng
->if_rmap_ctx
);
2547 stream_free(ripng
->ibuf
);
2548 stream_free(ripng
->obuf
);
2550 ripng_clean_network(ripng
);
2551 ripng_passive_interface_clean(ripng
);
2552 vector_free(ripng
->enable_if
);
2553 agg_table_finish(ripng
->enable_network
);
2554 vector_free(ripng
->passive_interface
);
2555 list_delete(&ripng
->offset_list_master
);
2556 ripng_interface_clean(ripng
);
2558 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2559 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2560 XFREE(MTYPE_RIPNG
, ripng
);
2563 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2564 struct if_rmap
*if_rmap
)
2566 struct interface
*ifp
= NULL
;
2567 struct ripng_interface
*ri
;
2568 struct route_map
*rmap
;
2569 struct vrf
*vrf
= NULL
;
2572 vrf
= vrf_lookup_by_name(ctx
->name
);
2574 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
);
2580 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2581 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2583 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2585 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2587 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2589 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2590 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2592 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2594 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2596 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2599 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2601 struct ripng_interface
*ri
= ifp
->info
;
2602 struct ripng
*ripng
= ri
->ripng
;
2603 struct if_rmap
*if_rmap
;
2604 struct if_rmap_ctx
*ctx
;
2606 if (ifp
->vrf
&& ifp
->vrf
->vrf_id
== VRF_UNKNOWN
)
2610 ctx
= ripng
->if_rmap_ctx
;
2613 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2615 ripng_if_rmap_update(ctx
, if_rmap
);
2618 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2620 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2621 if (ripng
->redist
[i
].route_map
.name
) {
2622 ripng
->redist
[i
].route_map
.map
=
2623 route_map_lookup_by_name(
2624 ripng
->redist
[i
].route_map
.name
);
2625 route_map_counter_increment(
2626 ripng
->redist
[i
].route_map
.map
);
2631 static void ripng_routemap_update(const char *unused
)
2633 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2634 struct ripng
*ripng
;
2635 struct interface
*ifp
;
2637 FOR_ALL_INTERFACES (vrf
, ifp
)
2638 ripng_if_rmap_update_interface(ifp
);
2642 ripng_routemap_update_redistribute(ripng
);
2645 /* Link RIPng instance to VRF. */
2646 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2648 struct interface
*ifp
;
2651 ripng
->distribute_ctx
->vrf
= vrf
;
2654 FOR_ALL_INTERFACES (vrf
, ifp
)
2655 ripng_interface_sync(ifp
);
2658 /* Unlink RIPng instance from VRF. */
2659 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2661 struct interface
*ifp
;
2664 ripng
->distribute_ctx
->vrf
= NULL
;
2667 FOR_ALL_INTERFACES (vrf
, ifp
)
2668 ripng_interface_sync(ifp
);
2671 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2676 ripng_vrf_link(ripng
, vrf
);
2677 ripng
->enabled
= true;
2679 /* Resend all redistribute requests. */
2680 ripng_redistribute_enable(ripng
);
2682 /* Create read and timer thread. */
2683 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2684 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2686 ripng_zebra_vrf_register(vrf
);
2689 static void ripng_instance_disable(struct ripng
*ripng
)
2691 struct vrf
*vrf
= ripng
->vrf
;
2692 struct agg_node
*rp
;
2694 /* Clear RIPng routes */
2695 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2696 struct ripng_aggregate
*aggregate
;
2699 if ((list
= rp
->info
) != NULL
) {
2700 struct ripng_info
*rinfo
;
2701 struct listnode
*listnode
;
2703 rinfo
= listgetdata(listhead(list
));
2704 if (ripng_route_rte(rinfo
))
2705 ripng_zebra_ipv6_delete(ripng
, rp
);
2707 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2708 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2709 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2710 ripng_info_free(rinfo
);
2714 agg_unlock_node(rp
);
2717 if ((aggregate
= rp
->aggregate
) != NULL
) {
2718 ripng_aggregate_free(aggregate
);
2719 rp
->aggregate
= NULL
;
2720 agg_unlock_node(rp
);
2724 /* Flush all redistribute requests. */
2725 ripng_redistribute_disable(ripng
);
2727 /* Cancel the RIPng timers */
2728 RIPNG_TIMER_OFF(ripng
->t_update
);
2729 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2730 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2732 /* Cancel the read thread */
2733 if (ripng
->t_read
) {
2734 thread_cancel(ripng
->t_read
);
2735 ripng
->t_read
= NULL
;
2738 /* Close the RIPng socket */
2739 if (ripng
->sock
>= 0) {
2744 /* Clear existing peers. */
2745 list_delete_all_node(ripng
->peer_list
);
2747 ripng_zebra_vrf_deregister(vrf
);
2749 ripng_vrf_unlink(ripng
, vrf
);
2750 ripng
->enabled
= false;
2753 static int ripng_vrf_new(struct vrf
*vrf
)
2755 if (IS_RIPNG_DEBUG_EVENT
)
2756 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2762 static int ripng_vrf_delete(struct vrf
*vrf
)
2764 if (IS_RIPNG_DEBUG_EVENT
)
2765 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2771 static int ripng_vrf_enable(struct vrf
*vrf
)
2773 struct ripng
*ripng
;
2776 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2777 if (!ripng
|| ripng
->enabled
)
2780 if (IS_RIPNG_DEBUG_EVENT
)
2781 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2784 /* Activate the VRF RIPng instance. */
2785 if (!ripng
->enabled
) {
2786 socket
= ripng_make_socket(vrf
);
2790 ripng_instance_enable(ripng
, vrf
, socket
);
2796 static int ripng_vrf_disable(struct vrf
*vrf
)
2798 struct ripng
*ripng
;
2800 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2801 if (!ripng
|| !ripng
->enabled
)
2804 if (IS_RIPNG_DEBUG_EVENT
)
2805 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2808 /* Deactivate the VRF RIPng instance. */
2810 ripng_instance_disable(ripng
);
2815 void ripng_vrf_init(void)
2817 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2818 ripng_vrf_delete
, NULL
);
2821 void ripng_vrf_terminate(void)
2826 /* Initialize ripng structure and set commands. */
2827 void ripng_init(void)
2829 /* Install RIPNG_NODE. */
2830 install_node(&cmd_ripng_node
, ripng_config_write
);
2832 /* Install ripng commands. */
2833 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2834 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2836 install_default(RIPNG_NODE
);
2839 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2840 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2841 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2842 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2843 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2844 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2845 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2851 /* Access list install. */
2853 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2854 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2856 /* Prefix list initialize.*/
2858 prefix_list_add_hook(ripng_distribute_update_all
);
2859 prefix_list_delete_hook(ripng_distribute_update_all
);
2861 /* Distribute list install. */
2862 distribute_list_init(RIPNG_NODE
);
2864 /* Route-map for interface. */
2865 ripng_route_map_init();
2867 route_map_add_hook(ripng_routemap_update
);
2868 route_map_delete_hook(ripng_routemap_update
);
2870 if_rmap_init(RIPNG_NODE
);