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 /* RIPng structure which includes many parameters related to RIPng
47 protocol. If ripng couldn't active or ripng doesn't configured,
48 ripng->fd must be negative value. */
49 struct ripng
*ripng
= NULL
;
51 enum { ripng_all_route
,
56 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
58 int ripng_triggered_update(struct thread
*);
60 /* RIPng next hop specification. */
61 struct ripng_nexthop
{
62 enum ripng_nexthop_type
{
66 struct in6_addr address
;
69 static int ripng_route_rte(struct ripng_info
*rinfo
)
71 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
72 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
75 /* Allocate new ripng information. */
76 struct ripng_info
*ripng_info_new()
78 struct ripng_info
*new;
80 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
84 /* Free ripng information. */
85 void ripng_info_free(struct ripng_info
*rinfo
)
87 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
90 /* Create ripng socket. */
91 int ripng_make_socket(void)
95 struct sockaddr_in6 ripaddr
;
97 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
99 flog_err_sys(EC_LIB_SOCKET
, "Can't make ripng socket");
103 setsockopt_so_recvbuf(sock
, 8096);
104 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
107 #ifdef IPTOS_PREC_INTERNETCONTROL
108 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
112 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
115 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
118 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
122 memset(&ripaddr
, 0, sizeof(ripaddr
));
123 ripaddr
.sin6_family
= AF_INET6
;
125 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
126 #endif /* SIN6_LEN */
127 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
129 frr_elevate_privs(&ripngd_privs
) {
130 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
132 zlog_err("Can't bind ripng socket: %s.",
133 safe_strerror(errno
));
144 /* Send RIPng packet. */
145 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
146 struct interface
*ifp
)
151 struct cmsghdr
*cmsgptr
;
153 struct in6_pktinfo
*pkt
;
154 struct sockaddr_in6 addr
;
156 if (IS_RIPNG_DEBUG_SEND
) {
158 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
159 zlog_debug(" send interface %s", ifp
->name
);
160 zlog_debug(" send packet size %d", bufsize
);
163 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
164 addr
.sin6_family
= AF_INET6
;
166 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
167 #endif /* SIN6_LEN */
168 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
170 /* When destination is specified. */
172 addr
.sin6_addr
= to
->sin6_addr
;
173 addr
.sin6_port
= to
->sin6_port
;
175 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
176 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
179 memset(&msg
, 0, sizeof(msg
));
180 msg
.msg_name
= (void *)&addr
;
181 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
184 msg
.msg_control
= (void *)adata
;
185 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
188 iov
.iov_len
= bufsize
;
190 cmsgptr
= (struct cmsghdr
*)adata
;
191 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
192 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
193 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
195 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
196 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
197 pkt
->ipi6_ifindex
= ifp
->ifindex
;
199 ret
= sendmsg(ripng
->sock
, &msg
, 0);
203 flog_err_sys(EC_LIB_SOCKET
,
204 "RIPng send fail on %s to %s: %s",
205 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
206 safe_strerror(errno
));
208 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
209 ifp
->name
, safe_strerror(errno
));
215 /* Receive UDP RIPng packet from socket. */
216 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
217 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
223 struct cmsghdr
*cmsgptr
;
224 struct in6_addr dst
= {.s6_addr
= {0}};
226 memset(&dst
, 0, sizeof(struct in6_addr
));
228 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
229 point I can't determine size of cmsghdr */
232 /* Fill in message and iovec. */
233 memset(&msg
, 0, sizeof(msg
));
234 msg
.msg_name
= (void *)from
;
235 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
238 msg
.msg_control
= (void *)adata
;
239 msg
.msg_controllen
= sizeof adata
;
241 iov
.iov_len
= bufsize
;
243 /* If recvmsg fail return minus value. */
244 ret
= recvmsg(sock
, &msg
, 0);
248 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
249 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
250 /* I want interface index which this packet comes from. */
251 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
252 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
253 struct in6_pktinfo
*ptr
;
255 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
256 *ifindex
= ptr
->ipi6_ifindex
;
257 dst
= ptr
->ipi6_addr
;
261 "Interface index returned by IPV6_PKTINFO is zero");
264 /* Incoming packet's multicast hop limit. */
265 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
266 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
267 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
268 *hoplimit
= *phoplimit
;
272 /* Hoplimit check shold be done when destination address is
273 multicast address. */
274 if (!IN6_IS_ADDR_MULTICAST(&dst
))
280 /* Dump rip packet */
281 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
286 const char *command_str
;
288 /* Set command string. */
289 if (packet
->command
== RIPNG_REQUEST
)
290 command_str
= "request";
291 else if (packet
->command
== RIPNG_RESPONSE
)
292 command_str
= "response";
294 command_str
= "unknown";
296 /* Dump packet header. */
297 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
298 packet
->version
, size
);
300 /* Dump each routing table entry. */
303 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
304 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
305 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
308 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
309 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
310 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
314 /* RIPng next hop address RTE (Route Table Entry). */
315 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
316 struct ripng_nexthop
*nexthop
)
318 char buf
[INET6_BUFSIZ
];
320 /* Logging before checking RTE. */
321 if (IS_RIPNG_DEBUG_RECV
)
322 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
324 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
327 /* RFC2080 2.1.1 Next Hop:
328 The route tag and prefix length in the next hop RTE must be
329 set to zero on sending and ignored on receiption. */
330 if (ntohs(rte
->tag
) != 0)
332 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
334 (route_tag_t
)ntohs(rte
->tag
),
335 inet6_ntoa(from
->sin6_addr
));
337 if (rte
->prefixlen
!= 0)
339 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
340 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
342 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
343 next hop RTE indicates that the next hop address should be the
344 originator of the RIPng advertisement. An address specified as a
345 next hop must be a link-local address. */
346 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
347 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
348 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
352 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
353 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
354 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
358 /* The purpose of the next hop RTE is to eliminate packets being
359 routed through extra hops in the system. It is particularly useful
360 when RIPng is not being run on all of the routers on a network.
361 Note that next hop RTE is "advisory". That is, if the provided
362 information is ignored, a possibly sub-optimal, but absolutely
363 valid, route may be taken. If the received next hop address is not
364 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
365 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
366 inet6_ntoa(rte
->addr
),
367 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
369 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
370 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
375 /* If ifp has same link-local address then return 1. */
376 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
378 struct listnode
*node
;
379 struct connected
*connected
;
382 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
383 p
= connected
->address
;
385 if (p
->family
== AF_INET6
386 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
387 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
393 /* RIPng route garbage collect timer. */
394 static int ripng_garbage_collect(struct thread
*t
)
396 struct ripng_info
*rinfo
;
399 rinfo
= THREAD_ARG(t
);
400 rinfo
->t_garbage_collect
= NULL
;
402 /* Off timeout timer. */
403 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
405 /* Get route_node pointer. */
408 /* Unlock route_node. */
409 listnode_delete(rp
->info
, rinfo
);
410 if (list_isempty((struct list
*)rp
->info
)) {
411 list_delete((struct list
**)&rp
->info
);
415 /* Free RIPng routing information. */
416 ripng_info_free(rinfo
);
421 static void ripng_timeout_update(struct ripng_info
*rinfo
);
423 /* Add new route to the ECMP list.
424 * RETURN: the new entry added in the list, or NULL if it is not the first
425 * entry and ECMP is not allowed.
427 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
429 struct agg_node
*rp
= rinfo_new
->rp
;
430 struct ripng_info
*rinfo
= NULL
;
431 struct list
*list
= NULL
;
433 if (rp
->info
== NULL
)
434 rp
->info
= list_new();
435 list
= (struct list
*)rp
->info
;
437 /* If ECMP is not allowed and some entry already exists in the list,
439 if (listcount(list
) && !ripng
->ecmp
)
442 rinfo
= ripng_info_new();
443 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
444 listnode_add(list
, rinfo
);
446 if (ripng_route_rte(rinfo
)) {
447 ripng_timeout_update(rinfo
);
448 ripng_zebra_ipv6_add(rp
);
451 ripng_aggregate_increment(rp
, rinfo
);
453 /* Set the route change flag on the first entry. */
454 rinfo
= listgetdata(listhead(list
));
455 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
457 /* Signal the output process to trigger an update. */
458 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
463 /* Replace the ECMP list with the new route.
464 * RETURN: the new entry added in the list
466 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
468 struct agg_node
*rp
= rinfo_new
->rp
;
469 struct list
*list
= (struct list
*)rp
->info
;
470 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
471 struct listnode
*node
= NULL
, *nextnode
= NULL
;
473 if (list
== NULL
|| listcount(list
) == 0)
474 return ripng_ecmp_add(rinfo_new
);
476 /* Get the first entry */
477 rinfo
= listgetdata(listhead(list
));
479 /* Learnt route replaced by a local one. Delete it from zebra. */
480 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
481 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
482 ripng_zebra_ipv6_delete(rp
);
484 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
485 ripng_aggregate_decrement_list(rp
, list
);
487 /* Re-use the first entry, and delete the others. */
488 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
489 if (tmp_rinfo
!= rinfo
) {
490 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
491 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
492 list_delete_node(list
, node
);
493 ripng_info_free(tmp_rinfo
);
496 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
497 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
498 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
500 if (ripng_route_rte(rinfo
)) {
501 ripng_timeout_update(rinfo
);
502 /* The ADD message implies an update. */
503 ripng_zebra_ipv6_add(rp
);
506 ripng_aggregate_increment(rp
, rinfo
);
508 /* Set the route change flag. */
509 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
511 /* Signal the output process to trigger an update. */
512 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
517 /* Delete one route from the ECMP list.
519 * null - the entry is freed, and other entries exist in the list
520 * the entry - the entry is the last one in the list; its metric is set
521 * to INFINITY, and the garbage collector is started for it
523 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
525 struct agg_node
*rp
= rinfo
->rp
;
526 struct list
*list
= (struct list
*)rp
->info
;
528 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
530 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
531 ripng_aggregate_decrement(rp
, rinfo
);
533 if (listcount(list
) > 1) {
534 /* Some other ECMP entries still exist. Just delete this entry.
536 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
537 listnode_delete(list
, rinfo
);
538 if (ripng_route_rte(rinfo
)
539 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
540 /* The ADD message implies the update. */
541 ripng_zebra_ipv6_add(rp
);
542 ripng_info_free(rinfo
);
545 assert(rinfo
== listgetdata(listhead(list
)));
547 /* This is the only entry left in the list. We must keep it in
548 * the list for garbage collection time, with INFINITY metric.
551 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
552 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
553 ripng
->garbage_time
);
555 if (ripng_route_rte(rinfo
)
556 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
557 ripng_zebra_ipv6_delete(rp
);
560 /* Set the route change flag on the first entry. */
561 rinfo
= listgetdata(listhead(list
));
562 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
564 /* Signal the output process to trigger an update. */
565 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
570 /* Timeout RIPng routes. */
571 static int ripng_timeout(struct thread
*t
)
573 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
577 static void ripng_timeout_update(struct ripng_info
*rinfo
)
579 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
580 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
581 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
582 ripng
->timeout_time
);
586 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
587 struct ripng_interface
*ri
)
589 struct distribute
*dist
;
590 struct access_list
*alist
;
591 struct prefix_list
*plist
;
592 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
595 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
597 /* Input distribute-list filtering. */
598 if (ri
->list
[ripng_distribute
]) {
599 if (access_list_apply(ri
->list
[ripng_distribute
],
602 if (IS_RIPNG_DEBUG_PACKET
)
603 zlog_debug("%s/%d filtered by distribute %s",
604 inet6_ntoa(p
->prefix
), p
->prefixlen
,
609 if (ri
->prefix
[ripng_distribute
]) {
610 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
613 if (IS_RIPNG_DEBUG_PACKET
)
614 zlog_debug("%s/%d filtered by prefix-list %s",
615 inet6_ntoa(p
->prefix
), p
->prefixlen
,
621 /* All interface filter check. */
622 dist
= distribute_lookup(NULL
);
624 if (dist
->list
[distribute
]) {
625 alist
= access_list_lookup(AFI_IP6
,
626 dist
->list
[distribute
]);
629 if (access_list_apply(alist
, (struct prefix
*)p
)
631 if (IS_RIPNG_DEBUG_PACKET
)
633 "%s/%d filtered by distribute %s",
634 inet6_ntoa(p
->prefix
),
635 p
->prefixlen
, inout
);
640 if (dist
->prefix
[distribute
]) {
641 plist
= prefix_list_lookup(AFI_IP6
,
642 dist
->prefix
[distribute
]);
645 if (prefix_list_apply(plist
, (struct prefix
*)p
)
647 if (IS_RIPNG_DEBUG_PACKET
)
649 "%s/%d filtered by prefix-list %s",
650 inet6_ntoa(p
->prefix
),
651 p
->prefixlen
, inout
);
660 /* Process RIPng route according to RFC2080. */
661 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
662 struct ripng_nexthop
*ripng_nexthop
,
663 struct interface
*ifp
)
666 struct prefix_ipv6 p
;
668 struct ripng_info
*rinfo
= NULL
, newinfo
;
669 struct ripng_interface
*ri
;
670 struct in6_addr
*nexthop
;
672 struct list
*list
= NULL
;
673 struct listnode
*node
= NULL
;
675 /* Make prefix structure. */
676 memset(&p
, 0, sizeof(struct prefix_ipv6
));
678 /* p.prefix = rte->addr; */
679 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
680 p
.prefixlen
= rte
->prefixlen
;
682 /* Make sure mask is applied. */
683 /* XXX We have to check the prefix is valid or not before call
687 /* Apply input filters. */
690 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
694 memset(&newinfo
, 0, sizeof(newinfo
));
695 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
696 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
697 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
698 newinfo
.nexthop
= ripng_nexthop
->address
;
700 newinfo
.nexthop
= from
->sin6_addr
;
701 newinfo
.from
= from
->sin6_addr
;
702 newinfo
.ifindex
= ifp
->ifindex
;
703 newinfo
.metric
= rte
->metric
;
704 newinfo
.metric_out
= rte
->metric
; /* XXX */
705 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
708 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
709 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
710 (struct prefix
*)&p
, RMAP_RIPNG
,
713 if (ret
== RMAP_DENYMATCH
) {
714 if (IS_RIPNG_DEBUG_PACKET
)
716 "RIPng %s/%d is filtered by route-map in",
717 inet6_ntoa(p
.prefix
), p
.prefixlen
);
721 /* Get back the object */
722 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
723 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
724 &ripng_nexthop
->address
)) {
725 /* the nexthop get changed by the routemap */
726 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
727 ripng_nexthop
->address
=
730 ripng_nexthop
->address
= in6addr_any
;
733 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
735 /* the nexthop get changed by the routemap */
736 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
737 ripng_nexthop
->flag
=
738 RIPNG_NEXTHOP_ADDRESS
;
739 ripng_nexthop
->address
=
744 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
746 newinfo
.metric_out
; /* XXX: the routemap uses the
750 /* Once the entry has been validated, update the metric by
751 * adding the cost of the network on wich the message
752 * arrived. If the result is greater than infinity, use infinity
753 * (RFC2453 Sec. 3.9.2)
756 /* Zebra ripngd can handle offset-list in. */
757 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
759 /* If offset-list does not modify the metric use interface's
762 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
764 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
765 rte
->metric
= RIPNG_METRIC_INFINITY
;
767 /* Set nexthop pointer. */
768 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
769 nexthop
= &ripng_nexthop
->address
;
771 nexthop
= &from
->sin6_addr
;
773 /* Lookup RIPng routing table. */
774 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
777 newinfo
.nexthop
= *nexthop
;
778 newinfo
.metric
= rte
->metric
;
779 newinfo
.tag
= ntohs(rte
->tag
);
781 /* Check to see whether there is already RIPng route on the table. */
782 if ((list
= rp
->info
) != NULL
)
783 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
784 /* Need to compare with redistributed entry or local
786 if (!ripng_route_rte(rinfo
))
789 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
790 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
793 if (!listnextnode(node
)) {
794 /* Not found in the list */
796 if (rte
->metric
> rinfo
->metric
) {
797 /* New route has a greater metric.
803 if (rte
->metric
< rinfo
->metric
)
804 /* New route has a smaller metric.
805 * Replace the ECMP list
806 * with the new one in below. */
809 /* Metrics are same. Unless ECMP is disabled,
810 * keep "rinfo" null and
811 * the new route is added in the ECMP list in
819 /* Redistributed route check. */
820 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
821 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
826 /* Local static route. */
827 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
828 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
829 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
830 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
837 /* Now, check to see whether there is already an explicit route
838 for the destination prefix. If there is no such route, add
839 this route to the routing table, unless the metric is
840 infinity (there is no point in adding a route which
842 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
843 ripng_ecmp_add(&newinfo
);
847 /* If there is an existing route, compare the next hop address
848 to the address of the router from which the datagram came.
849 If this datagram is from the same router as the existing
850 route, reinitialize the timeout. */
851 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
852 && (rinfo
->ifindex
== ifp
->ifindex
));
855 * RFC 2080 - Section 2.4.2:
856 * "If the new metric is the same as the old one, examine the
858 * for the existing route. If it is at least halfway to the
860 * point, switch to the new route. This heuristic is optional,
862 * highly recommended".
864 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
866 && (thread_timer_remain_second(rinfo
->t_timeout
)
867 < (ripng
->timeout_time
/ 2))) {
868 ripng_ecmp_replace(&newinfo
);
870 /* Next, compare the metrics. If the datagram is from the same
871 router as the existing route, and the new metric is different
872 than the old one; or, if the new metric is lower than the old
873 one; do the following actions: */
874 else if ((same
&& rinfo
->metric
!= rte
->metric
)
875 || rte
->metric
< rinfo
->metric
) {
876 if (listcount(list
) == 1) {
877 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
878 ripng_ecmp_replace(&newinfo
);
880 ripng_ecmp_delete(rinfo
);
882 if (newinfo
.metric
< rinfo
->metric
)
883 ripng_ecmp_replace(&newinfo
);
884 else /* newinfo.metric > rinfo->metric */
885 ripng_ecmp_delete(rinfo
);
887 } else /* same & no change */
888 ripng_timeout_update(rinfo
);
890 /* Unlock tempolary lock of the route. */
895 /* Add redistributed route to RIPng table. */
896 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
897 ifindex_t ifindex
, struct in6_addr
*nexthop
,
901 struct ripng_info
*rinfo
= NULL
, newinfo
;
902 struct list
*list
= NULL
;
904 /* Redistribute route */
905 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
907 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
910 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
912 memset(&newinfo
, 0, sizeof(struct ripng_info
));
914 newinfo
.sub_type
= sub_type
;
915 newinfo
.ifindex
= ifindex
;
917 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
920 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
921 newinfo
.nexthop
= *nexthop
;
923 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
924 rinfo
= listgetdata(listhead(list
));
926 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
927 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
928 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
933 /* Manually configured RIPng route check.
934 * They have the precedence on all the other entries.
936 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
937 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
938 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
939 if (type
!= ZEBRA_ROUTE_RIPNG
940 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
941 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
947 ripng_ecmp_replace(&newinfo
);
950 ripng_ecmp_add(&newinfo
);
952 if (IS_RIPNG_DEBUG_EVENT
) {
955 "Redistribute new prefix %s/%d on the interface %s",
956 inet6_ntoa(p
->prefix
), p
->prefixlen
,
957 ifindex2ifname(ifindex
, VRF_DEFAULT
));
960 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
961 inet6_ntoa(p
->prefix
), p
->prefixlen
,
962 inet6_ntoa(*nexthop
),
963 ifindex2ifname(ifindex
, VRF_DEFAULT
));
966 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
969 /* Delete redistributed route to RIPng table. */
970 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
974 struct ripng_info
*rinfo
;
976 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
978 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
981 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
984 struct list
*list
= rp
->info
;
986 if (list
!= NULL
&& listcount(list
) != 0) {
987 rinfo
= listgetdata(listhead(list
));
988 if (rinfo
!= NULL
&& rinfo
->type
== type
989 && rinfo
->sub_type
== sub_type
990 && rinfo
->ifindex
== ifindex
) {
991 /* Perform poisoned reverse. */
992 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
993 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
994 ripng_garbage_collect
,
995 ripng
->garbage_time
);
996 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
998 /* Aggregate count decrement. */
999 ripng_aggregate_decrement(rp
, rinfo
);
1001 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1003 if (IS_RIPNG_DEBUG_EVENT
)
1005 "Poisone %s/%d on the interface %s with an "
1006 "infinity metric [delete]",
1007 inet6_ntoa(p
->prefix
),
1009 ifindex2ifname(ifindex
,
1012 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1015 agg_unlock_node(rp
);
1019 /* Withdraw redistributed route. */
1020 void ripng_redistribute_withdraw(int type
)
1022 struct agg_node
*rp
;
1023 struct ripng_info
*rinfo
= NULL
;
1024 struct list
*list
= NULL
;
1029 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1030 if ((list
= rp
->info
) != NULL
) {
1031 rinfo
= listgetdata(listhead(list
));
1032 if ((rinfo
->type
== type
)
1033 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1034 /* Perform poisoned reverse. */
1035 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1036 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1037 ripng_garbage_collect
,
1038 ripng
->garbage_time
);
1039 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1041 /* Aggregate count decrement. */
1042 ripng_aggregate_decrement(rp
, rinfo
);
1044 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1046 if (IS_RIPNG_DEBUG_EVENT
) {
1047 struct prefix_ipv6
*p
=
1048 (struct prefix_ipv6
*)&rp
->p
;
1051 "Poisone %s/%d on the interface %s [withdraw]",
1052 inet6_ntoa(p
->prefix
),
1054 ifindex2ifname(rinfo
->ifindex
,
1058 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1063 /* RIP routing information. */
1064 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1065 struct sockaddr_in6
*from
,
1066 struct interface
*ifp
, int hoplimit
)
1070 struct ripng_nexthop nexthop
;
1072 /* RFC2080 2.4.2 Response Messages:
1073 The Response must be ignored if it is not from the RIPng port. */
1074 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1075 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1076 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1077 ripng_peer_bad_packet(from
);
1081 /* The datagram's IPv6 source address should be checked to see
1082 whether the datagram is from a valid neighbor; the source of the
1083 datagram must be a link-local address. */
1084 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1085 zlog_warn("RIPng packet comes from non link local address %s",
1086 inet6_ntoa(from
->sin6_addr
));
1087 ripng_peer_bad_packet(from
);
1091 /* It is also worth checking to see whether the response is from one
1092 of the router's own addresses. Interfaces on broadcast networks
1093 may receive copies of their own multicasts immediately. If a
1094 router processes its own output as new input, confusion is likely,
1095 and such datagrams must be ignored. */
1096 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1098 "RIPng packet comes from my own link local address %s",
1099 inet6_ntoa(from
->sin6_addr
));
1100 ripng_peer_bad_packet(from
);
1104 /* As an additional check, periodic advertisements must have their
1105 hop counts set to 255, and inbound, multicast packets sent from the
1106 RIPng port (i.e. periodic advertisement or triggered update
1107 packets) must be examined to ensure that the hop count is 255. */
1108 if (hoplimit
>= 0 && hoplimit
!= 255) {
1110 "RIPng packet comes with non 255 hop count %d from %s",
1111 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1112 ripng_peer_bad_packet(from
);
1116 /* Update RIPng peer. */
1117 ripng_peer_update(from
, packet
->version
);
1119 /* Reset nexthop. */
1120 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1121 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1123 /* Set RTE pointer. */
1126 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1127 /* First of all, we have to check this RTE is next hop RTE or
1128 not. Next hop RTE is completely different with normal RTE so
1129 we need special treatment. */
1130 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1131 ripng_nexthop_rte(rte
, from
, &nexthop
);
1135 /* RTE information validation. */
1137 /* - is the destination prefix valid (e.g., not a multicast
1138 prefix and not a link-local address) A link-local address
1139 should never be present in an RTE. */
1140 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1142 "Destination prefix is a multicast address %s/%d [%d]",
1143 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1145 ripng_peer_bad_route(from
);
1148 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1150 "Destination prefix is a link-local address %s/%d [%d]",
1151 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1153 ripng_peer_bad_route(from
);
1156 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1158 "Destination prefix is a loopback address %s/%d [%d]",
1159 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1161 ripng_peer_bad_route(from
);
1165 /* - is the prefix length valid (i.e., between 0 and 128,
1167 if (rte
->prefixlen
> 128) {
1168 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1169 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1170 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1171 ripng_peer_bad_route(from
);
1175 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1176 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1177 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1178 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1179 ripng_peer_bad_route(from
);
1183 /* Vincent: XXX Should we compute the direclty reachable nexthop
1184 * for our RIPng network ?
1187 /* Routing table updates. */
1188 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1192 /* Response to request message. */
1193 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1194 struct sockaddr_in6
*from
,
1195 struct interface
*ifp
)
1199 struct prefix_ipv6 p
;
1200 struct agg_node
*rp
;
1201 struct ripng_info
*rinfo
;
1202 struct ripng_interface
*ri
;
1204 /* Does not reponse to the requests on the loopback interfaces */
1205 if (if_is_loopback(ifp
))
1208 /* Check RIPng process is enabled on this interface. */
1213 /* When passive interface is specified, suppress responses */
1217 /* RIPng peer update. */
1218 ripng_peer_update(from
, packet
->version
);
1220 lim
= ((caddr_t
)packet
) + size
;
1223 /* The Request is processed entry by entry. If there are no
1224 entries, no response is given. */
1225 if (lim
== (caddr_t
)rte
)
1228 /* There is one special case. If there is exactly one entry in the
1229 request, and it has a destination prefix of zero, a prefix length
1230 of zero, and a metric of infinity (i.e., 16), then this is a
1231 request to send the entire routing table. In that case, a call
1232 is made to the output process to send the routing table to the
1233 requesting address/port. */
1234 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1235 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1236 /* All route with split horizon */
1237 ripng_output_process(ifp
, from
, ripng_all_route
);
1239 /* Except for this special case, processing is quite simple.
1240 Examine the list of RTEs in the Request one by one. For each
1241 entry, look up the destination in the router's routing
1242 database and, if there is a route, put that route's metric in
1243 the metric field of the RTE. If there is no explicit route
1244 to the specified destination, put infinity in the metric
1245 field. Once all the entries have been filled in, change the
1246 command from Request to Response and send the datagram back
1247 to the requestor. */
1248 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1249 p
.family
= AF_INET6
;
1251 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1252 p
.prefix
= rte
->addr
;
1253 p
.prefixlen
= rte
->prefixlen
;
1254 apply_mask_ipv6(&p
);
1256 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1259 rinfo
= listgetdata(
1260 listhead((struct list
*)rp
->info
));
1261 rte
->metric
= rinfo
->metric
;
1262 agg_unlock_node(rp
);
1264 rte
->metric
= RIPNG_METRIC_INFINITY
;
1266 packet
->command
= RIPNG_RESPONSE
;
1268 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1272 /* First entry point of reading RIPng packet. */
1273 static int ripng_read(struct thread
*thread
)
1277 struct sockaddr_in6 from
;
1278 struct ripng_packet
*packet
;
1279 ifindex_t ifindex
= 0;
1280 struct interface
*ifp
;
1283 /* Check ripng is active and alive. */
1284 assert(ripng
!= NULL
);
1285 assert(ripng
->sock
>= 0);
1287 /* Fetch thread data and set read pointer to empty for event
1288 managing. `sock' sould be same as ripng->sock. */
1289 sock
= THREAD_FD(thread
);
1290 ripng
->t_read
= NULL
;
1292 /* Add myself to the next event. */
1293 ripng_event(RIPNG_READ
, sock
);
1295 /* Read RIPng packet. */
1296 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1297 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1300 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1304 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1305 (4)) must be multiple size of one RTE size (20). */
1306 if (((len
- 4) % 20) != 0) {
1307 zlog_warn("RIPng invalid packet size %d from %s", len
,
1308 inet6_ntoa(from
.sin6_addr
));
1309 ripng_peer_bad_packet(&from
);
1313 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1314 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1316 /* RIPng packet received. */
1317 if (IS_RIPNG_DEBUG_EVENT
)
1318 zlog_debug("RIPng packet received from %s port %d on %s",
1319 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1320 ifp
? ifp
->name
: "unknown");
1322 /* Logging before packet checking. */
1323 if (IS_RIPNG_DEBUG_RECV
)
1324 ripng_packet_dump(packet
, len
, "RECV");
1326 /* Packet comes from unknown interface. */
1328 zlog_warn("RIPng packet comes from unknown interface %d",
1333 /* Packet version mismatch checking. */
1334 if (packet
->version
!= ripng
->version
) {
1336 "RIPng packet version %d doesn't fit to my version %d",
1337 packet
->version
, ripng
->version
);
1338 ripng_peer_bad_packet(&from
);
1342 /* Process RIPng packet. */
1343 switch (packet
->command
) {
1345 ripng_request_process(packet
, len
, &from
, ifp
);
1347 case RIPNG_RESPONSE
:
1348 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1351 zlog_warn("Invalid RIPng command %d", packet
->command
);
1352 ripng_peer_bad_packet(&from
);
1358 /* Walk down the RIPng routing table then clear changed flag. */
1359 static void ripng_clear_changed_flag(void)
1361 struct agg_node
*rp
;
1362 struct ripng_info
*rinfo
= NULL
;
1363 struct list
*list
= NULL
;
1364 struct listnode
*listnode
= NULL
;
1366 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1367 if ((list
= rp
->info
) != NULL
)
1368 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1369 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1370 /* This flag can be set only on the first entry.
1376 /* Regular update of RIPng route. Send all routing formation to RIPng
1377 enabled interface. */
1378 static int ripng_update(struct thread
*t
)
1380 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1381 struct interface
*ifp
;
1382 struct ripng_interface
*ri
;
1384 /* Clear update timer thread. */
1385 ripng
->t_update
= NULL
;
1387 /* Logging update event. */
1388 if (IS_RIPNG_DEBUG_EVENT
)
1389 zlog_debug("RIPng update timer expired!");
1391 /* Supply routes to each interface. */
1392 FOR_ALL_INTERFACES (vrf
, ifp
) {
1395 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1401 /* When passive interface is specified, suppress announce to the
1407 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1408 if (IS_RIPNG_DEBUG_EVENT
)
1410 "[Event] RIPng send to if %d is suppressed by config",
1414 #endif /* RIPNG_ADVANCED */
1416 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1419 /* Triggered updates may be suppressed if a regular update is due by
1420 the time the triggered update would be sent. */
1421 if (ripng
->t_triggered_interval
) {
1422 thread_cancel(ripng
->t_triggered_interval
);
1423 ripng
->t_triggered_interval
= NULL
;
1427 /* Reset flush event. */
1428 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1433 /* Triggered update interval timer. */
1434 static int ripng_triggered_interval(struct thread
*t
)
1436 ripng
->t_triggered_interval
= NULL
;
1438 if (ripng
->trigger
) {
1440 ripng_triggered_update(t
);
1445 /* Execute triggered update. */
1446 int ripng_triggered_update(struct thread
*t
)
1448 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1449 struct interface
*ifp
;
1450 struct ripng_interface
*ri
;
1453 ripng
->t_triggered_update
= NULL
;
1455 /* Cancel interval timer. */
1456 if (ripng
->t_triggered_interval
) {
1457 thread_cancel(ripng
->t_triggered_interval
);
1458 ripng
->t_triggered_interval
= NULL
;
1462 /* Logging triggered update. */
1463 if (IS_RIPNG_DEBUG_EVENT
)
1464 zlog_debug("RIPng triggered update!");
1466 /* Split Horizon processing is done when generating triggered
1467 updates as well as normal updates (see section 2.6). */
1468 FOR_ALL_INTERFACES (vrf
, ifp
) {
1471 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1477 /* When passive interface is specified, suppress announce to the
1482 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1485 /* Once all of the triggered updates have been generated, the route
1486 change flags should be cleared. */
1487 ripng_clear_changed_flag();
1489 /* After a triggered update is sent, a timer should be set for a
1490 random interval between 1 and 5 seconds. If other changes that
1491 would trigger updates occur before the timer expires, a single
1492 update is triggered when the timer expires. */
1493 interval
= (random() % 5) + 1;
1495 ripng
->t_triggered_interval
= NULL
;
1496 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1497 &ripng
->t_triggered_interval
);
1502 /* Write routing table entry to the stream and return next index of
1503 the routing table entry in the stream. */
1504 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1505 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1507 /* RIPng packet header. */
1509 stream_putc(s
, RIPNG_RESPONSE
);
1510 stream_putc(s
, RIPNG_V1
);
1514 /* Write routing table entry. */
1517 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1519 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1520 stream_putw(s
, tag
);
1522 stream_putc(s
, p
->prefixlen
);
1525 stream_putc(s
, metric
);
1530 /* Send RESPONSE message to specified destination. */
1531 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1535 struct agg_node
*rp
;
1536 struct ripng_info
*rinfo
;
1537 struct ripng_interface
*ri
;
1538 struct ripng_aggregate
*aggregate
;
1539 struct prefix_ipv6
*p
;
1540 struct list
*ripng_rte_list
;
1541 struct list
*list
= NULL
;
1542 struct listnode
*listnode
= NULL
;
1544 if (IS_RIPNG_DEBUG_EVENT
) {
1546 zlog_debug("RIPng update routes to neighbor %s",
1547 inet6_ntoa(to
->sin6_addr
));
1549 zlog_debug("RIPng update routes on interface %s",
1553 /* Get RIPng interface. */
1556 ripng_rte_list
= ripng_rte_new();
1558 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1559 if ((list
= rp
->info
) != NULL
1560 && (rinfo
= listgetdata(listhead(list
))) != NULL
1561 && rinfo
->suppress
== 0) {
1562 /* If no route-map are applied, the RTE will be these
1566 p
= (struct prefix_ipv6
*)&rp
->p
;
1567 rinfo
->metric_out
= rinfo
->metric
;
1568 rinfo
->tag_out
= rinfo
->tag
;
1569 memset(&rinfo
->nexthop_out
, 0,
1570 sizeof(rinfo
->nexthop_out
));
1571 /* In order to avoid some local loops,
1572 * if the RIPng route has a nexthop via this interface,
1574 * otherwise set it to 0. The nexthop should not be
1576 * beyond the local broadcast/multicast area in order
1577 * to avoid an IGP multi-level recursive look-up.
1579 if (rinfo
->ifindex
== ifp
->ifindex
)
1580 rinfo
->nexthop_out
= rinfo
->nexthop
;
1582 /* Apply output filters. */
1583 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1587 /* Changed route only output. */
1588 if (route_type
== ripng_changed_route
1589 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1592 /* Split horizon. */
1593 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1594 /* We perform split horizon for RIPng routes. */
1596 struct ripng_info
*tmp_rinfo
= NULL
;
1598 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1600 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1601 && tmp_rinfo
->ifindex
1610 /* Preparation for route-map. */
1611 rinfo
->metric_set
= 0;
1614 * and tag_out are already initialized.
1617 /* Interface route-map */
1618 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1619 ret
= route_map_apply(
1620 ri
->routemap
[RIPNG_FILTER_OUT
],
1621 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1623 if (ret
== RMAP_DENYMATCH
) {
1624 if (IS_RIPNG_DEBUG_PACKET
)
1626 "RIPng %s/%d is filtered by route-map out",
1627 inet6_ntoa(p
->prefix
),
1633 /* Redistribute route-map. */
1634 if (ripng
->route_map
[rinfo
->type
].name
) {
1635 ret
= route_map_apply(
1636 ripng
->route_map
[rinfo
->type
].map
,
1637 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1639 if (ret
== RMAP_DENYMATCH
) {
1640 if (IS_RIPNG_DEBUG_PACKET
)
1642 "RIPng %s/%d is filtered by route-map",
1643 inet6_ntoa(p
->prefix
),
1649 /* When the route-map does not set metric. */
1650 if (!rinfo
->metric_set
) {
1651 /* If the redistribute metric is set. */
1652 if (ripng
->route_map
[rinfo
->type
].metric_config
1653 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1655 ripng
->route_map
[rinfo
->type
]
1658 /* If the route is not connected or
1660 one, use default-metric value */
1661 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1663 != ZEBRA_ROUTE_CONNECT
1665 != RIPNG_METRIC_INFINITY
)
1667 ripng
->default_metric
;
1671 /* Apply offset-list */
1672 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1673 ripng_offset_list_apply_out(p
, ifp
,
1674 &rinfo
->metric_out
);
1676 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1677 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1679 /* Perform split-horizon with poisoned reverse
1682 if (ri
->split_horizon
1683 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1684 struct ripng_info
*tmp_rinfo
= NULL
;
1686 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1688 if ((tmp_rinfo
->type
1689 == ZEBRA_ROUTE_RIPNG
)
1690 && tmp_rinfo
->ifindex
1693 RIPNG_METRIC_INFINITY
;
1696 /* Add RTE to the list */
1697 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1700 /* Process the aggregated RTE entry */
1701 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1702 && aggregate
->suppress
== 0) {
1703 /* If no route-map are applied, the RTE will be these
1707 p
= (struct prefix_ipv6
*)&rp
->p
;
1708 aggregate
->metric_set
= 0;
1709 aggregate
->metric_out
= aggregate
->metric
;
1710 aggregate
->tag_out
= aggregate
->tag
;
1711 memset(&aggregate
->nexthop_out
, 0,
1712 sizeof(aggregate
->nexthop_out
));
1714 /* Apply output filters.*/
1715 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1719 /* Interface route-map */
1720 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1721 struct ripng_info newinfo
;
1723 /* let's cast the aggregate structure to
1725 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1726 /* the nexthop is :: */
1727 newinfo
.metric
= aggregate
->metric
;
1728 newinfo
.metric_out
= aggregate
->metric_out
;
1729 newinfo
.tag
= aggregate
->tag
;
1730 newinfo
.tag_out
= aggregate
->tag_out
;
1732 ret
= route_map_apply(
1733 ri
->routemap
[RIPNG_FILTER_OUT
],
1734 (struct prefix
*)p
, RMAP_RIPNG
,
1737 if (ret
== RMAP_DENYMATCH
) {
1738 if (IS_RIPNG_DEBUG_PACKET
)
1740 "RIPng %s/%d is filtered by route-map out",
1741 inet6_ntoa(p
->prefix
),
1746 aggregate
->metric_out
= newinfo
.metric_out
;
1747 aggregate
->tag_out
= newinfo
.tag_out
;
1748 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1749 aggregate
->nexthop_out
=
1750 newinfo
.nexthop_out
;
1753 /* There is no redistribute routemap for the aggregated
1756 /* Changed route only output. */
1757 /* XXX, vincent, in order to increase time convergence,
1758 * it should be announced if a child has changed.
1760 if (route_type
== ripng_changed_route
)
1763 /* Apply offset-list */
1764 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1765 ripng_offset_list_apply_out(
1766 p
, ifp
, &aggregate
->metric_out
);
1768 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1769 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1771 /* Add RTE to the list */
1772 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1776 /* Flush the list */
1777 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1778 ripng_rte_free(ripng_rte_list
);
1781 /* Create new RIPng instance and set it to global variable. */
1782 int ripng_create(int socket
)
1784 /* ripng should be NULL. */
1785 assert(ripng
== NULL
);
1787 /* Allocaste RIPng instance. */
1788 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1790 /* Default version and timer values. */
1791 ripng
->version
= RIPNG_V1
;
1792 ripng
->update_time
= yang_get_default_uint32(
1793 "%s/timers/update-interval", RIPNG_INSTANCE
);
1794 ripng
->timeout_time
= yang_get_default_uint32(
1795 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1796 ripng
->garbage_time
= yang_get_default_uint32(
1797 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1798 ripng
->default_metric
=
1799 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1800 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1803 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1804 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1806 /* Initialize RIPng routig table. */
1807 ripng
->table
= agg_table_init();
1808 ripng
->route
= agg_table_init();
1809 ripng
->aggregate
= agg_table_init();
1812 ripng
->sock
= socket
;
1815 ripng_event(RIPNG_READ
, ripng
->sock
);
1816 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1821 /* Send RIPng request to the interface. */
1822 int ripng_request(struct interface
*ifp
)
1825 struct ripng_packet ripng_packet
;
1827 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1829 if (if_is_loopback(ifp
))
1832 /* If interface is down, don't send RIP packet. */
1836 if (IS_RIPNG_DEBUG_EVENT
)
1837 zlog_debug("RIPng send request to %s", ifp
->name
);
1839 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1840 ripng_packet
.command
= RIPNG_REQUEST
;
1841 ripng_packet
.version
= RIPNG_V1
;
1842 rte
= ripng_packet
.rte
;
1843 rte
->metric
= RIPNG_METRIC_INFINITY
;
1845 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1850 static int ripng_update_jitter(int time
)
1852 return ((random() % (time
+ 1)) - (time
/ 2));
1855 void ripng_event(enum ripng_event event
, int sock
)
1861 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1863 case RIPNG_UPDATE_EVENT
:
1864 if (ripng
->t_update
) {
1865 thread_cancel(ripng
->t_update
);
1866 ripng
->t_update
= NULL
;
1868 /* Update timer jitter. */
1869 jitter
= ripng_update_jitter(ripng
->update_time
);
1871 ripng
->t_update
= NULL
;
1872 thread_add_timer(master
, ripng_update
, NULL
,
1873 sock
? 2 : ripng
->update_time
+ jitter
,
1876 case RIPNG_TRIGGERED_UPDATE
:
1877 if (ripng
->t_triggered_interval
)
1880 thread_add_event(master
, ripng_triggered_update
, NULL
,
1881 0, &ripng
->t_triggered_update
);
1889 /* Print out routes update time. */
1890 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1895 char timebuf
[TIME_BUF
];
1896 struct thread
*thread
;
1898 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1899 clock
= thread_timer_remain_second(thread
);
1900 tm
= gmtime(&clock
);
1901 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1902 vty_out(vty
, "%5s", timebuf
);
1903 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1904 clock
= thread_timer_remain_second(thread
);
1905 tm
= gmtime(&clock
);
1906 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1907 vty_out(vty
, "%5s", timebuf
);
1911 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1916 if (rinfo
->suppress
)
1919 switch (rinfo
->sub_type
) {
1920 case RIPNG_ROUTE_RTE
:
1923 case RIPNG_ROUTE_STATIC
:
1926 case RIPNG_ROUTE_DEFAULT
:
1929 case RIPNG_ROUTE_REDISTRIBUTE
:
1932 case RIPNG_ROUTE_INTERFACE
:
1943 DEFUN (show_ipv6_ripng
,
1944 show_ipv6_ripng_cmd
,
1948 "Show RIPng routes\n")
1950 struct agg_node
*rp
;
1951 struct ripng_info
*rinfo
;
1952 struct ripng_aggregate
*aggregate
;
1953 struct prefix_ipv6
*p
;
1954 struct list
*list
= NULL
;
1955 struct listnode
*listnode
= NULL
;
1961 /* Header of display. */
1963 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1965 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1966 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1967 " Network Next Hop Via Metric Tag Time\n");
1969 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1970 if ((aggregate
= rp
->aggregate
) != NULL
) {
1971 p
= (struct prefix_ipv6
*)&rp
->p
;
1974 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1975 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1978 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1982 vty_out(vty
, "%*s", 18, " ");
1984 vty_out(vty
, "%*s", 28, " ");
1985 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1986 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1989 if ((list
= rp
->info
) != NULL
)
1990 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1991 p
= (struct prefix_ipv6
*)&rp
->p
;
1994 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1995 zebra_route_char(rinfo
->type
),
1996 ripng_route_subtype_print(rinfo
),
1997 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2000 vty_out(vty
, "%c(%s) %s/%d ",
2001 zebra_route_char(rinfo
->type
),
2002 ripng_route_subtype_print(rinfo
),
2003 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2006 vty_out(vty
, "%*s", 18, " ");
2007 len
= vty_out(vty
, "%s",
2008 inet6_ntoa(rinfo
->nexthop
));
2012 vty_out(vty
, "%*s", len
, " ");
2015 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2016 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2019 ifindex2ifname(rinfo
->ifindex
,
2021 } else if (rinfo
->metric
2022 == RIPNG_METRIC_INFINITY
) {
2023 len
= vty_out(vty
, "kill");
2025 len
= vty_out(vty
, "self");
2029 vty_out(vty
, "%*s", len
, " ");
2031 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2032 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2035 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2036 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2037 /* RTE from remote RIP routers */
2038 ripng_vty_out_uptime(vty
, rinfo
);
2039 } else if (rinfo
->metric
2040 == RIPNG_METRIC_INFINITY
) {
2041 /* poisonous reversed routes (gc) */
2042 ripng_vty_out_uptime(vty
, rinfo
);
2052 DEFUN (show_ipv6_ripng_status
,
2053 show_ipv6_ripng_status_cmd
,
2054 "show ipv6 ripng status",
2057 "Show RIPng routes\n"
2058 "IPv6 routing protocol process parameters and statistics\n")
2060 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2061 struct interface
*ifp
;
2066 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2067 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2068 ripng
->update_time
);
2069 vty_out(vty
, " next due in %lu seconds\n",
2070 thread_timer_remain_second(ripng
->t_update
));
2071 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2072 vty_out(vty
, " garbage collect after %ld seconds\n",
2073 ripng
->garbage_time
);
2075 /* Filtering status show. */
2076 config_show_distribute(vty
);
2078 /* Default metric information. */
2079 vty_out(vty
, " Default redistribution metric is %d\n",
2080 ripng
->default_metric
);
2082 /* Redistribute information. */
2083 vty_out(vty
, " Redistributing:");
2084 ripng_redistribute_write(vty
, 0);
2087 vty_out(vty
, " Default version control: send version %d,",
2089 vty_out(vty
, " receive version %d \n", ripng
->version
);
2091 vty_out(vty
, " Interface Send Recv\n");
2093 FOR_ALL_INTERFACES (vrf
, ifp
) {
2094 struct ripng_interface
*ri
;
2098 if (ri
->enable_network
|| ri
->enable_interface
) {
2100 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2101 ripng
->version
, ripng
->version
);
2105 vty_out(vty
, " Routing for Networks:\n");
2106 ripng_network_write(vty
);
2108 vty_out(vty
, " Routing Information Sources:\n");
2110 " Gateway BadPackets BadRoutes Distance Last Update\n");
2111 ripng_peer_display(vty
);
2116 DEFUN (clear_ipv6_rip
,
2121 "Clear IPv6 RIP database\n")
2123 struct agg_node
*rp
;
2124 struct ripng_info
*rinfo
;
2126 struct listnode
*listnode
;
2128 /* Clear received RIPng routes */
2129 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2134 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2135 if (!ripng_route_rte(rinfo
))
2138 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2139 ripng_zebra_ipv6_delete(rp
);
2144 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2145 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2146 listnode_delete(list
, rinfo
);
2147 ripng_info_free(rinfo
);
2150 if (list_isempty(list
)) {
2153 agg_unlock_node(rp
);
2163 "Static route setup\n"
2164 "Set static RIPng route announcement\n")
2166 int idx_ipv6addr
= 1;
2168 struct prefix_ipv6 p
;
2169 struct agg_node
*rp
;
2171 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2172 (struct prefix_ipv6
*)&p
);
2174 vty_out(vty
, "Malformed address\n");
2175 return CMD_WARNING_CONFIG_FAILED
;
2177 apply_mask_ipv6(&p
);
2179 rp
= agg_node_get(ripng
->route
, (struct prefix
*)&p
);
2181 vty_out(vty
, "There is already same static route.\n");
2182 agg_unlock_node(rp
);
2185 rp
->info
= (void *)1;
2187 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2193 DEFUN (no_ripng_route
,
2195 "no route IPV6ADDR",
2197 "Static route setup\n"
2198 "Delete static RIPng route announcement\n")
2200 int idx_ipv6addr
= 2;
2202 struct prefix_ipv6 p
;
2203 struct agg_node
*rp
;
2205 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2206 (struct prefix_ipv6
*)&p
);
2208 vty_out(vty
, "Malformed address\n");
2209 return CMD_WARNING_CONFIG_FAILED
;
2211 apply_mask_ipv6(&p
);
2213 rp
= agg_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2215 vty_out(vty
, "Can't find static route.\n");
2216 return CMD_WARNING_CONFIG_FAILED
;
2219 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2220 agg_unlock_node(rp
);
2223 agg_unlock_node(rp
);
2228 DEFUN (ripng_aggregate_address
,
2229 ripng_aggregate_address_cmd
,
2230 "aggregate-address X:X::X:X/M",
2231 "Set aggregate RIPng route announcement\n"
2232 "Aggregate network\n")
2234 int idx_ipv6_prefixlen
= 1;
2237 struct agg_node
*node
;
2239 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2240 (struct prefix_ipv6
*)&p
);
2242 vty_out(vty
, "Malformed address\n");
2243 return CMD_WARNING_CONFIG_FAILED
;
2246 /* Check aggregate alredy exist or not. */
2247 node
= agg_node_get(ripng
->aggregate
, &p
);
2249 vty_out(vty
, "There is already same aggregate route.\n");
2250 agg_unlock_node(node
);
2253 node
->info
= (void *)1;
2255 ripng_aggregate_add(&p
);
2260 DEFUN (no_ripng_aggregate_address
,
2261 no_ripng_aggregate_address_cmd
,
2262 "no aggregate-address X:X::X:X/M",
2264 "Delete aggregate RIPng route announcement\n"
2265 "Aggregate network\n")
2267 int idx_ipv6_prefixlen
= 2;
2270 struct agg_node
*rn
;
2272 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2273 (struct prefix_ipv6
*)&p
);
2275 vty_out(vty
, "Malformed address\n");
2276 return CMD_WARNING_CONFIG_FAILED
;
2279 rn
= agg_node_lookup(ripng
->aggregate
, &p
);
2281 vty_out(vty
, "Can't find aggregate route.\n");
2282 return CMD_WARNING_CONFIG_FAILED
;
2284 agg_unlock_node(rn
);
2286 agg_unlock_node(rn
);
2288 ripng_aggregate_delete(&p
);
2294 /* RIPng update timer setup. */
2295 DEFUN (ripng_update_timer
,
2296 ripng_update_timer_cmd
,
2297 "update-timer SECOND",
2298 "Set RIPng update timer in seconds\n"
2301 unsigned long update
;
2302 char *endptr
= NULL
;
2304 update
= strtoul (argv
[0], &endptr
, 10);
2305 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2307 vty_out (vty
, "update timer value error\n");
2308 return CMD_WARNING_CONFIG_FAILED
;
2311 ripng
->update_time
= update
;
2313 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2317 DEFUN (no_ripng_update_timer
,
2318 no_ripng_update_timer_cmd
,
2319 "no update-timer SECOND",
2321 "Unset RIPng update timer in seconds\n"
2324 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2325 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2329 /* RIPng timeout timer setup. */
2330 DEFUN (ripng_timeout_timer
,
2331 ripng_timeout_timer_cmd
,
2332 "timeout-timer SECOND",
2333 "Set RIPng timeout timer in seconds\n"
2336 unsigned long timeout
;
2337 char *endptr
= NULL
;
2339 timeout
= strtoul (argv
[0], &endptr
, 10);
2340 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2342 vty_out (vty
, "timeout timer value error\n");
2343 return CMD_WARNING_CONFIG_FAILED
;
2346 ripng
->timeout_time
= timeout
;
2351 DEFUN (no_ripng_timeout_timer
,
2352 no_ripng_timeout_timer_cmd
,
2353 "no timeout-timer SECOND",
2355 "Unset RIPng timeout timer in seconds\n"
2358 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2362 /* RIPng garbage timer setup. */
2363 DEFUN (ripng_garbage_timer
,
2364 ripng_garbage_timer_cmd
,
2365 "garbage-timer SECOND",
2366 "Set RIPng garbage timer in seconds\n"
2369 unsigned long garbage
;
2370 char *endptr
= NULL
;
2372 garbage
= strtoul (argv
[0], &endptr
, 10);
2373 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2375 vty_out (vty
, "garbage timer value error\n");
2376 return CMD_WARNING_CONFIG_FAILED
;
2379 ripng
->garbage_time
= garbage
;
2384 DEFUN (no_ripng_garbage_timer
,
2385 no_ripng_garbage_timer_cmd
,
2386 "no garbage-timer SECOND",
2388 "Unset RIPng garbage timer in seconds\n"
2391 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2396 DEFUN (ripng_timers
,
2398 "timers basic (0-65535) (0-65535) (0-65535)",
2399 "RIPng timers setup\n"
2401 "Routing table update timer value in second. Default is 30.\n"
2402 "Routing information timeout timer. Default is 180.\n"
2403 "Garbage collection timer. Default is 120.\n")
2406 int idx_number_2
= 3;
2407 int idx_number_3
= 4;
2408 unsigned long update
;
2409 unsigned long timeout
;
2410 unsigned long garbage
;
2412 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2413 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2414 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2416 /* Set each timer value. */
2417 ripng
->update_time
= update
;
2418 ripng
->timeout_time
= timeout
;
2419 ripng
->garbage_time
= garbage
;
2421 /* Reset update timer thread. */
2422 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2427 DEFUN (no_ripng_timers
,
2428 no_ripng_timers_cmd
,
2429 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2431 "RIPng timers setup\n"
2433 "Routing table update timer value in second. Default is 30.\n"
2434 "Routing information timeout timer. Default is 180.\n"
2435 "Garbage collection timer. Default is 120.\n")
2437 /* Set each timer value to the default. */
2438 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2439 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2440 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2442 /* Reset update timer thread. */
2443 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2449 DEFUN (show_ipv6_protocols
,
2450 show_ipv6_protocols_cmd
,
2451 "show ipv6 protocols",
2454 "Routing protocol information\n")
2459 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2461 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2462 ripng
->update_time
, 0);
2464 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2465 ripng
->timeout_time
,
2466 ripng
->garbage_time
);
2468 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2469 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2475 /* Update ECMP routes to zebra when ECMP is disabled. */
2476 void ripng_ecmp_disable(void)
2478 struct agg_node
*rp
;
2479 struct ripng_info
*rinfo
, *tmp_rinfo
;
2481 struct listnode
*node
, *nextnode
;
2486 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2487 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2488 rinfo
= listgetdata(listhead(list
));
2489 if (!ripng_route_rte(rinfo
))
2492 /* Drop all other entries, except the first one. */
2493 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2494 if (tmp_rinfo
!= rinfo
) {
2495 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2497 tmp_rinfo
->t_garbage_collect
);
2498 list_delete_node(list
, node
);
2499 ripng_info_free(tmp_rinfo
);
2503 ripng_zebra_ipv6_add(rp
);
2505 /* Set the route change flag. */
2506 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2508 /* Signal the output process to trigger an update. */
2509 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2513 /* RIPng configuration write function. */
2514 static int ripng_config_write(struct vty
*vty
)
2516 struct lyd_node
*dnode
;
2518 struct agg_node
*rp
;
2520 dnode
= yang_dnode_get(running_config
->dnode
,
2521 "/frr-ripngd:ripngd/instance");
2523 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2525 ripng_redistribute_write(vty
, 1);
2527 /* RIPng aggregate routes. */
2528 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2529 rp
= agg_route_next(rp
))
2530 if (rp
->info
!= NULL
)
2531 vty_out(vty
, " aggregate-address %s/%d\n",
2532 inet6_ntoa(rp
->p
.u
.prefix6
),
2535 /* RIPng static routes. */
2536 for (rp
= agg_route_top(ripng
->route
); rp
;
2537 rp
= agg_route_next(rp
))
2538 if (rp
->info
!= NULL
)
2539 vty_out(vty
, " route %s/%d\n",
2540 inet6_ntoa(rp
->p
.u
.prefix6
),
2543 /* RIPng timers configuration. */
2544 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2545 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2546 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2547 vty_out(vty
, " timers basic %ld %ld %ld\n",
2548 ripng
->update_time
, ripng
->timeout_time
,
2549 ripng
->garbage_time
);
2552 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2553 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2554 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2555 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2556 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2557 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2560 config_write_distribute(vty
);
2562 config_write_if_rmap(vty
);
2570 /* RIPng node structure. */
2571 static struct cmd_node cmd_ripng_node
= {
2572 RIPNG_NODE
, "%s(config-router)# ", 1,
2575 static void ripng_distribute_update(struct distribute
*dist
)
2577 struct interface
*ifp
;
2578 struct ripng_interface
*ri
;
2579 struct access_list
*alist
;
2580 struct prefix_list
*plist
;
2585 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2591 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2592 alist
= access_list_lookup(AFI_IP6
,
2593 dist
->list
[DISTRIBUTE_V6_IN
]);
2595 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2597 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2599 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2601 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2602 alist
= access_list_lookup(AFI_IP6
,
2603 dist
->list
[DISTRIBUTE_V6_OUT
]);
2605 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2607 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2609 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2611 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2612 plist
= prefix_list_lookup(AFI_IP6
,
2613 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2615 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2617 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2619 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2621 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2622 plist
= prefix_list_lookup(AFI_IP6
,
2623 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2625 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2627 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2629 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2632 void ripng_distribute_update_interface(struct interface
*ifp
)
2634 struct distribute
*dist
;
2636 dist
= distribute_lookup(ifp
->name
);
2638 ripng_distribute_update(dist
);
2641 /* Update all interface's distribute list. */
2642 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2644 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2645 struct interface
*ifp
;
2647 FOR_ALL_INTERFACES (vrf
, ifp
)
2648 ripng_distribute_update_interface(ifp
);
2651 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2653 ripng_distribute_update_all(NULL
);
2656 /* delete all the added ripng routes. */
2660 struct agg_node
*rp
;
2661 struct ripng_info
*rinfo
;
2662 struct ripng_aggregate
*aggregate
;
2663 struct list
*list
= NULL
;
2664 struct listnode
*listnode
= NULL
;
2667 /* Clear RIPng routes */
2668 for (rp
= agg_route_top(ripng
->table
); rp
;
2669 rp
= agg_route_next(rp
)) {
2670 if ((list
= rp
->info
) != NULL
) {
2671 rinfo
= listgetdata(listhead(list
));
2672 if (ripng_route_rte(rinfo
))
2673 ripng_zebra_ipv6_delete(rp
);
2675 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2677 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2679 rinfo
->t_garbage_collect
);
2680 ripng_info_free(rinfo
);
2684 agg_unlock_node(rp
);
2687 if ((aggregate
= rp
->aggregate
) != NULL
) {
2688 ripng_aggregate_free(aggregate
);
2689 rp
->aggregate
= NULL
;
2690 agg_unlock_node(rp
);
2694 /* Cancel the RIPng timers */
2695 RIPNG_TIMER_OFF(ripng
->t_update
);
2696 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2697 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2699 /* Cancel the read thread */
2700 if (ripng
->t_read
) {
2701 thread_cancel(ripng
->t_read
);
2702 ripng
->t_read
= NULL
;
2705 /* Close the RIPng socket */
2706 if (ripng
->sock
>= 0) {
2711 /* Static RIPng route configuration. */
2712 for (rp
= agg_route_top(ripng
->route
); rp
;
2713 rp
= agg_route_next(rp
))
2716 agg_unlock_node(rp
);
2719 /* RIPng aggregated prefixes */
2720 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2721 rp
= agg_route_next(rp
))
2724 agg_unlock_node(rp
);
2727 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2728 if (ripng
->route_map
[i
].name
)
2729 free(ripng
->route_map
[i
].name
);
2731 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2732 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2733 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2735 stream_free(ripng
->ibuf
);
2736 stream_free(ripng
->obuf
);
2738 XFREE(MTYPE_RIPNG
, ripng
);
2742 ripng_clean_network();
2743 ripng_passive_interface_clean();
2744 ripng_offset_clean();
2745 ripng_interface_clean();
2746 ripng_redistribute_clean();
2749 /* Reset all values to the default settings. */
2752 /* Call ripd related reset functions. */
2753 ripng_debug_reset();
2754 ripng_route_map_reset();
2756 /* Call library reset functions. */
2758 access_list_reset();
2759 prefix_list_reset();
2761 distribute_list_reset();
2763 ripng_interface_reset();
2765 ripng_zclient_reset();
2768 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2770 struct interface
*ifp
;
2771 struct ripng_interface
*ri
;
2772 struct route_map
*rmap
;
2774 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2780 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2781 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2783 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2785 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2787 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2789 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2790 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2792 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2794 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2796 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2799 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2801 struct if_rmap
*if_rmap
;
2803 if_rmap
= if_rmap_lookup(ifp
->name
);
2805 ripng_if_rmap_update(if_rmap
);
2808 static void ripng_routemap_update_redistribute(void)
2813 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2814 if (ripng
->route_map
[i
].name
)
2815 ripng
->route_map
[i
].map
=
2816 route_map_lookup_by_name(
2817 ripng
->route_map
[i
].name
);
2822 static void ripng_routemap_update(const char *unused
)
2824 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2825 struct interface
*ifp
;
2827 FOR_ALL_INTERFACES (vrf
, ifp
)
2828 ripng_if_rmap_update_interface(ifp
);
2830 ripng_routemap_update_redistribute();
2833 /* Initialize ripng structure and set commands. */
2836 /* Install RIPNG_NODE. */
2837 install_node(&cmd_ripng_node
, ripng_config_write
);
2839 /* Install ripng commands. */
2840 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2841 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2843 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2845 install_default(RIPNG_NODE
);
2846 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2847 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
2848 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
2849 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
2851 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
2852 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
2854 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2855 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2856 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2857 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2858 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2859 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2860 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2866 /* Access list install. */
2868 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2869 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2871 /* Prefix list initialize.*/
2873 prefix_list_add_hook(ripng_distribute_update_all
);
2874 prefix_list_delete_hook(ripng_distribute_update_all
);
2876 /* Distribute list install. */
2877 distribute_list_init(RIPNG_NODE
);
2878 distribute_list_add_hook(ripng_distribute_update
);
2879 distribute_list_delete_hook(ripng_distribute_update
);
2881 /* Route-map for interface. */
2882 ripng_route_map_init();
2883 ripng_offset_init();
2885 route_map_add_hook(ripng_routemap_update
);
2886 route_map_delete_hook(ripng_routemap_update
);
2888 if_rmap_init(RIPNG_NODE
);
2889 if_rmap_hook_add(ripng_if_rmap_update
);
2890 if_rmap_hook_delete(ripng_if_rmap_update
);