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
,
55 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
56 struct distribute
*dist
);
59 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
61 int ripng_triggered_update(struct thread
*);
63 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
64 struct if_rmap
*if_rmap
);
66 /* RIPng next hop specification. */
67 struct ripng_nexthop
{
68 enum ripng_nexthop_type
{
72 struct in6_addr address
;
75 int ripng_route_rte(struct ripng_info
*rinfo
)
77 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
78 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
81 /* Allocate new ripng information. */
82 struct ripng_info
*ripng_info_new(void)
84 struct ripng_info
*new;
86 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
90 /* Free ripng information. */
91 void ripng_info_free(struct ripng_info
*rinfo
)
93 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
96 /* Create ripng socket. */
97 int ripng_make_socket(void)
101 struct sockaddr_in6 ripaddr
;
103 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
105 flog_err_sys(EC_LIB_SOCKET
, "Can't make ripng socket");
109 setsockopt_so_recvbuf(sock
, 8096);
110 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
113 #ifdef IPTOS_PREC_INTERNETCONTROL
114 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
118 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
121 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
124 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
128 memset(&ripaddr
, 0, sizeof(ripaddr
));
129 ripaddr
.sin6_family
= AF_INET6
;
131 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
132 #endif /* SIN6_LEN */
133 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
135 frr_elevate_privs(&ripngd_privs
) {
136 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
138 zlog_err("Can't bind ripng socket: %s.",
139 safe_strerror(errno
));
150 /* Send RIPng packet. */
151 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
152 struct interface
*ifp
)
157 struct cmsghdr
*cmsgptr
;
159 struct in6_pktinfo
*pkt
;
160 struct sockaddr_in6 addr
;
162 if (IS_RIPNG_DEBUG_SEND
) {
164 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
165 zlog_debug(" send interface %s", ifp
->name
);
166 zlog_debug(" send packet size %d", bufsize
);
169 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
170 addr
.sin6_family
= AF_INET6
;
172 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
173 #endif /* SIN6_LEN */
174 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
176 /* When destination is specified. */
178 addr
.sin6_addr
= to
->sin6_addr
;
179 addr
.sin6_port
= to
->sin6_port
;
181 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
182 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
185 memset(&msg
, 0, sizeof(msg
));
186 msg
.msg_name
= (void *)&addr
;
187 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
190 msg
.msg_control
= (void *)adata
;
191 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
194 iov
.iov_len
= bufsize
;
196 cmsgptr
= (struct cmsghdr
*)adata
;
197 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
198 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
199 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
201 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
202 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
203 pkt
->ipi6_ifindex
= ifp
->ifindex
;
205 ret
= sendmsg(ripng
->sock
, &msg
, 0);
209 flog_err_sys(EC_LIB_SOCKET
,
210 "RIPng send fail on %s to %s: %s",
211 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
212 safe_strerror(errno
));
214 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
215 ifp
->name
, safe_strerror(errno
));
221 /* Receive UDP RIPng packet from socket. */
222 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
223 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
229 struct cmsghdr
*cmsgptr
;
230 struct in6_addr dst
= {.s6_addr
= {0}};
232 memset(&dst
, 0, sizeof(struct in6_addr
));
234 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
235 point I can't determine size of cmsghdr */
238 /* Fill in message and iovec. */
239 memset(&msg
, 0, sizeof(msg
));
240 msg
.msg_name
= (void *)from
;
241 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
244 msg
.msg_control
= (void *)adata
;
245 msg
.msg_controllen
= sizeof adata
;
247 iov
.iov_len
= bufsize
;
249 /* If recvmsg fail return minus value. */
250 ret
= recvmsg(sock
, &msg
, 0);
254 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
255 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
256 /* I want interface index which this packet comes from. */
257 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
258 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
259 struct in6_pktinfo
*ptr
;
261 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
262 *ifindex
= ptr
->ipi6_ifindex
;
263 dst
= ptr
->ipi6_addr
;
267 "Interface index returned by IPV6_PKTINFO is zero");
270 /* Incoming packet's multicast hop limit. */
271 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
272 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
273 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
274 *hoplimit
= *phoplimit
;
278 /* Hoplimit check shold be done when destination address is
279 multicast address. */
280 if (!IN6_IS_ADDR_MULTICAST(&dst
))
286 /* Dump rip packet */
287 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
292 const char *command_str
;
294 /* Set command string. */
295 if (packet
->command
== RIPNG_REQUEST
)
296 command_str
= "request";
297 else if (packet
->command
== RIPNG_RESPONSE
)
298 command_str
= "response";
300 command_str
= "unknown";
302 /* Dump packet header. */
303 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
304 packet
->version
, size
);
306 /* Dump each routing table entry. */
309 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
310 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
311 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
314 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
315 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
316 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
320 /* RIPng next hop address RTE (Route Table Entry). */
321 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
322 struct ripng_nexthop
*nexthop
)
324 char buf
[INET6_BUFSIZ
];
326 /* Logging before checking RTE. */
327 if (IS_RIPNG_DEBUG_RECV
)
328 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
330 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
333 /* RFC2080 2.1.1 Next Hop:
334 The route tag and prefix length in the next hop RTE must be
335 set to zero on sending and ignored on receiption. */
336 if (ntohs(rte
->tag
) != 0)
338 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
340 (route_tag_t
)ntohs(rte
->tag
),
341 inet6_ntoa(from
->sin6_addr
));
343 if (rte
->prefixlen
!= 0)
345 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
346 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
348 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
349 next hop RTE indicates that the next hop address should be the
350 originator of the RIPng advertisement. An address specified as a
351 next hop must be a link-local address. */
352 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
353 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
354 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
358 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
359 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
360 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
364 /* The purpose of the next hop RTE is to eliminate packets being
365 routed through extra hops in the system. It is particularly useful
366 when RIPng is not being run on all of the routers on a network.
367 Note that next hop RTE is "advisory". That is, if the provided
368 information is ignored, a possibly sub-optimal, but absolutely
369 valid, route may be taken. If the received next hop address is not
370 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
371 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
372 inet6_ntoa(rte
->addr
),
373 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
375 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
376 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
381 /* If ifp has same link-local address then return 1. */
382 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
384 struct listnode
*node
;
385 struct connected
*connected
;
388 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
389 p
= connected
->address
;
391 if (p
->family
== AF_INET6
392 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
393 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
399 /* RIPng route garbage collect timer. */
400 static int ripng_garbage_collect(struct thread
*t
)
402 struct ripng_info
*rinfo
;
405 rinfo
= THREAD_ARG(t
);
406 rinfo
->t_garbage_collect
= NULL
;
408 /* Off timeout timer. */
409 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
411 /* Get route_node pointer. */
414 /* Unlock route_node. */
415 listnode_delete(rp
->info
, rinfo
);
416 if (list_isempty((struct list
*)rp
->info
)) {
417 list_delete((struct list
**)&rp
->info
);
421 /* Free RIPng routing information. */
422 ripng_info_free(rinfo
);
427 static void ripng_timeout_update(struct ripng_info
*rinfo
);
429 /* Add new route to the ECMP list.
430 * RETURN: the new entry added in the list, or NULL if it is not the first
431 * entry and ECMP is not allowed.
433 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
435 struct agg_node
*rp
= rinfo_new
->rp
;
436 struct ripng_info
*rinfo
= NULL
;
437 struct list
*list
= NULL
;
439 if (rp
->info
== NULL
)
440 rp
->info
= list_new();
441 list
= (struct list
*)rp
->info
;
443 /* If ECMP is not allowed and some entry already exists in the list,
445 if (listcount(list
) && !ripng
->ecmp
)
448 rinfo
= ripng_info_new();
449 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
450 listnode_add(list
, rinfo
);
452 if (ripng_route_rte(rinfo
)) {
453 ripng_timeout_update(rinfo
);
454 ripng_zebra_ipv6_add(rp
);
457 ripng_aggregate_increment(rp
, rinfo
);
459 /* Set the route change flag on the first entry. */
460 rinfo
= listgetdata(listhead(list
));
461 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
463 /* Signal the output process to trigger an update. */
464 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
469 /* Replace the ECMP list with the new route.
470 * RETURN: the new entry added in the list
472 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
474 struct agg_node
*rp
= rinfo_new
->rp
;
475 struct list
*list
= (struct list
*)rp
->info
;
476 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
477 struct listnode
*node
= NULL
, *nextnode
= NULL
;
479 if (list
== NULL
|| listcount(list
) == 0)
480 return ripng_ecmp_add(rinfo_new
);
482 /* Get the first entry */
483 rinfo
= listgetdata(listhead(list
));
485 /* Learnt route replaced by a local one. Delete it from zebra. */
486 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
487 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
488 ripng_zebra_ipv6_delete(rp
);
490 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
491 ripng_aggregate_decrement_list(rp
, list
);
493 /* Re-use the first entry, and delete the others. */
494 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
495 if (tmp_rinfo
!= rinfo
) {
496 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
497 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
498 list_delete_node(list
, node
);
499 ripng_info_free(tmp_rinfo
);
502 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
503 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
504 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
506 if (ripng_route_rte(rinfo
)) {
507 ripng_timeout_update(rinfo
);
508 /* The ADD message implies an update. */
509 ripng_zebra_ipv6_add(rp
);
512 ripng_aggregate_increment(rp
, rinfo
);
514 /* Set the route change flag. */
515 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
517 /* Signal the output process to trigger an update. */
518 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
523 /* Delete one route from the ECMP list.
525 * null - the entry is freed, and other entries exist in the list
526 * the entry - the entry is the last one in the list; its metric is set
527 * to INFINITY, and the garbage collector is started for it
529 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
531 struct agg_node
*rp
= rinfo
->rp
;
532 struct list
*list
= (struct list
*)rp
->info
;
534 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
536 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
537 ripng_aggregate_decrement(rp
, rinfo
);
539 if (listcount(list
) > 1) {
540 /* Some other ECMP entries still exist. Just delete this entry.
542 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
543 listnode_delete(list
, rinfo
);
544 if (ripng_route_rte(rinfo
)
545 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
546 /* The ADD message implies the update. */
547 ripng_zebra_ipv6_add(rp
);
548 ripng_info_free(rinfo
);
551 assert(rinfo
== listgetdata(listhead(list
)));
553 /* This is the only entry left in the list. We must keep it in
554 * the list for garbage collection time, with INFINITY metric.
557 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
558 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
559 ripng
->garbage_time
);
561 if (ripng_route_rte(rinfo
)
562 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
563 ripng_zebra_ipv6_delete(rp
);
566 /* Set the route change flag on the first entry. */
567 rinfo
= listgetdata(listhead(list
));
568 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
570 /* Signal the output process to trigger an update. */
571 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
576 /* Timeout RIPng routes. */
577 static int ripng_timeout(struct thread
*t
)
579 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
583 static void ripng_timeout_update(struct ripng_info
*rinfo
)
585 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
586 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
587 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
588 ripng
->timeout_time
);
592 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
593 struct ripng_interface
*ri
)
595 struct distribute
*dist
;
596 struct access_list
*alist
;
597 struct prefix_list
*plist
;
598 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
601 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
603 /* Input distribute-list filtering. */
604 if (ri
->list
[ripng_distribute
]) {
605 if (access_list_apply(ri
->list
[ripng_distribute
],
608 if (IS_RIPNG_DEBUG_PACKET
)
609 zlog_debug("%s/%d filtered by distribute %s",
610 inet6_ntoa(p
->prefix
), p
->prefixlen
,
615 if (ri
->prefix
[ripng_distribute
]) {
616 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
619 if (IS_RIPNG_DEBUG_PACKET
)
620 zlog_debug("%s/%d filtered by prefix-list %s",
621 inet6_ntoa(p
->prefix
), p
->prefixlen
,
627 /* All interface filter check. */
628 dist
= distribute_lookup(ripng
->distribute_ctx
, NULL
);
630 if (dist
->list
[distribute
]) {
631 alist
= access_list_lookup(AFI_IP6
,
632 dist
->list
[distribute
]);
635 if (access_list_apply(alist
, (struct prefix
*)p
)
637 if (IS_RIPNG_DEBUG_PACKET
)
639 "%s/%d filtered by distribute %s",
640 inet6_ntoa(p
->prefix
),
641 p
->prefixlen
, inout
);
646 if (dist
->prefix
[distribute
]) {
647 plist
= prefix_list_lookup(AFI_IP6
,
648 dist
->prefix
[distribute
]);
651 if (prefix_list_apply(plist
, (struct prefix
*)p
)
653 if (IS_RIPNG_DEBUG_PACKET
)
655 "%s/%d filtered by prefix-list %s",
656 inet6_ntoa(p
->prefix
),
657 p
->prefixlen
, inout
);
666 /* Process RIPng route according to RFC2080. */
667 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
668 struct ripng_nexthop
*ripng_nexthop
,
669 struct interface
*ifp
)
672 struct prefix_ipv6 p
;
674 struct ripng_info
*rinfo
= NULL
, newinfo
;
675 struct ripng_interface
*ri
;
676 struct in6_addr
*nexthop
;
678 struct list
*list
= NULL
;
679 struct listnode
*node
= NULL
;
681 /* Make prefix structure. */
682 memset(&p
, 0, sizeof(struct prefix_ipv6
));
684 /* p.prefix = rte->addr; */
685 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
686 p
.prefixlen
= rte
->prefixlen
;
688 /* Make sure mask is applied. */
689 /* XXX We have to check the prefix is valid or not before call
693 /* Apply input filters. */
696 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
700 memset(&newinfo
, 0, sizeof(newinfo
));
701 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
702 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
703 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
704 newinfo
.nexthop
= ripng_nexthop
->address
;
706 newinfo
.nexthop
= from
->sin6_addr
;
707 newinfo
.from
= from
->sin6_addr
;
708 newinfo
.ifindex
= ifp
->ifindex
;
709 newinfo
.metric
= rte
->metric
;
710 newinfo
.metric_out
= rte
->metric
; /* XXX */
711 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
714 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
715 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
716 (struct prefix
*)&p
, RMAP_RIPNG
,
719 if (ret
== RMAP_DENYMATCH
) {
720 if (IS_RIPNG_DEBUG_PACKET
)
722 "RIPng %s/%d is filtered by route-map in",
723 inet6_ntoa(p
.prefix
), p
.prefixlen
);
727 /* Get back the object */
728 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
729 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
730 &ripng_nexthop
->address
)) {
731 /* the nexthop get changed by the routemap */
732 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
733 ripng_nexthop
->address
=
736 ripng_nexthop
->address
= in6addr_any
;
739 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
741 /* the nexthop get changed by the routemap */
742 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
743 ripng_nexthop
->flag
=
744 RIPNG_NEXTHOP_ADDRESS
;
745 ripng_nexthop
->address
=
750 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
752 newinfo
.metric_out
; /* XXX: the routemap uses the
756 /* Once the entry has been validated, update the metric by
757 * adding the cost of the network on wich the message
758 * arrived. If the result is greater than infinity, use infinity
759 * (RFC2453 Sec. 3.9.2)
762 /* Zebra ripngd can handle offset-list in. */
763 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
765 /* If offset-list does not modify the metric use interface's
768 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
770 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
771 rte
->metric
= RIPNG_METRIC_INFINITY
;
773 /* Set nexthop pointer. */
774 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
775 nexthop
= &ripng_nexthop
->address
;
777 nexthop
= &from
->sin6_addr
;
779 /* Lookup RIPng routing table. */
780 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
783 newinfo
.nexthop
= *nexthop
;
784 newinfo
.metric
= rte
->metric
;
785 newinfo
.tag
= ntohs(rte
->tag
);
787 /* Check to see whether there is already RIPng route on the table. */
788 if ((list
= rp
->info
) != NULL
)
789 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
790 /* Need to compare with redistributed entry or local
792 if (!ripng_route_rte(rinfo
))
795 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
796 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
799 if (!listnextnode(node
)) {
800 /* Not found in the list */
802 if (rte
->metric
> rinfo
->metric
) {
803 /* New route has a greater metric.
809 if (rte
->metric
< rinfo
->metric
)
810 /* New route has a smaller metric.
811 * Replace the ECMP list
812 * with the new one in below. */
815 /* Metrics are same. Unless ECMP is disabled,
816 * keep "rinfo" null and
817 * the new route is added in the ECMP list in
825 /* Redistributed route check. */
826 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
827 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
832 /* Local static route. */
833 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
834 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
835 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
836 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
843 /* Now, check to see whether there is already an explicit route
844 for the destination prefix. If there is no such route, add
845 this route to the routing table, unless the metric is
846 infinity (there is no point in adding a route which
848 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
849 ripng_ecmp_add(&newinfo
);
853 /* If there is an existing route, compare the next hop address
854 to the address of the router from which the datagram came.
855 If this datagram is from the same router as the existing
856 route, reinitialize the timeout. */
857 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
858 && (rinfo
->ifindex
== ifp
->ifindex
));
861 * RFC 2080 - Section 2.4.2:
862 * "If the new metric is the same as the old one, examine the
864 * for the existing route. If it is at least halfway to the
866 * point, switch to the new route. This heuristic is optional,
868 * highly recommended".
870 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
872 && (thread_timer_remain_second(rinfo
->t_timeout
)
873 < (ripng
->timeout_time
/ 2))) {
874 ripng_ecmp_replace(&newinfo
);
876 /* Next, compare the metrics. If the datagram is from the same
877 router as the existing route, and the new metric is different
878 than the old one; or, if the new metric is lower than the old
879 one; do the following actions: */
880 else if ((same
&& rinfo
->metric
!= rte
->metric
)
881 || rte
->metric
< rinfo
->metric
) {
882 if (listcount(list
) == 1) {
883 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
884 ripng_ecmp_replace(&newinfo
);
886 ripng_ecmp_delete(rinfo
);
888 if (newinfo
.metric
< rinfo
->metric
)
889 ripng_ecmp_replace(&newinfo
);
890 else /* newinfo.metric > rinfo->metric */
891 ripng_ecmp_delete(rinfo
);
893 } else /* same & no change */
894 ripng_timeout_update(rinfo
);
896 /* Unlock tempolary lock of the route. */
901 /* Add redistributed route to RIPng table. */
902 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
903 ifindex_t ifindex
, struct in6_addr
*nexthop
,
907 struct ripng_info
*rinfo
= NULL
, newinfo
;
908 struct list
*list
= NULL
;
910 /* Redistribute route */
911 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
913 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
916 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
918 memset(&newinfo
, 0, sizeof(struct ripng_info
));
920 newinfo
.sub_type
= sub_type
;
921 newinfo
.ifindex
= ifindex
;
923 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
926 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
927 newinfo
.nexthop
= *nexthop
;
929 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
930 rinfo
= listgetdata(listhead(list
));
932 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
933 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
934 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
939 /* Manually configured RIPng route check.
940 * They have the precedence on all the other entries.
942 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
943 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
944 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
945 if (type
!= ZEBRA_ROUTE_RIPNG
946 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
947 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
953 ripng_ecmp_replace(&newinfo
);
956 ripng_ecmp_add(&newinfo
);
958 if (IS_RIPNG_DEBUG_EVENT
) {
961 "Redistribute new prefix %s/%d on the interface %s",
962 inet6_ntoa(p
->prefix
), p
->prefixlen
,
963 ifindex2ifname(ifindex
, VRF_DEFAULT
));
966 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
967 inet6_ntoa(p
->prefix
), p
->prefixlen
,
968 inet6_ntoa(*nexthop
),
969 ifindex2ifname(ifindex
, VRF_DEFAULT
));
972 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
975 /* Delete redistributed route to RIPng table. */
976 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
980 struct ripng_info
*rinfo
;
982 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
984 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
987 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
990 struct list
*list
= rp
->info
;
992 if (list
!= NULL
&& listcount(list
) != 0) {
993 rinfo
= listgetdata(listhead(list
));
994 if (rinfo
!= NULL
&& rinfo
->type
== type
995 && rinfo
->sub_type
== sub_type
996 && rinfo
->ifindex
== ifindex
) {
997 /* Perform poisoned reverse. */
998 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
999 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1000 ripng_garbage_collect
,
1001 ripng
->garbage_time
);
1002 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1004 /* Aggregate count decrement. */
1005 ripng_aggregate_decrement(rp
, rinfo
);
1007 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1009 if (IS_RIPNG_DEBUG_EVENT
)
1011 "Poisone %s/%d on the interface %s with an "
1012 "infinity metric [delete]",
1013 inet6_ntoa(p
->prefix
),
1015 ifindex2ifname(ifindex
,
1018 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1021 agg_unlock_node(rp
);
1025 /* Withdraw redistributed route. */
1026 void ripng_redistribute_withdraw(int type
)
1028 struct agg_node
*rp
;
1029 struct ripng_info
*rinfo
= NULL
;
1030 struct list
*list
= NULL
;
1035 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1036 if ((list
= rp
->info
) != NULL
) {
1037 rinfo
= listgetdata(listhead(list
));
1038 if ((rinfo
->type
== type
)
1039 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1040 /* Perform poisoned reverse. */
1041 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1042 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1043 ripng_garbage_collect
,
1044 ripng
->garbage_time
);
1045 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1047 /* Aggregate count decrement. */
1048 ripng_aggregate_decrement(rp
, rinfo
);
1050 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1052 if (IS_RIPNG_DEBUG_EVENT
) {
1053 struct prefix_ipv6
*p
=
1054 (struct prefix_ipv6
*)&rp
->p
;
1057 "Poisone %s/%d on the interface %s [withdraw]",
1058 inet6_ntoa(p
->prefix
),
1060 ifindex2ifname(rinfo
->ifindex
,
1064 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1069 /* RIP routing information. */
1070 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1071 struct sockaddr_in6
*from
,
1072 struct interface
*ifp
, int hoplimit
)
1076 struct ripng_nexthop nexthop
;
1078 /* RFC2080 2.4.2 Response Messages:
1079 The Response must be ignored if it is not from the RIPng port. */
1080 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1081 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1082 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1083 ripng_peer_bad_packet(from
);
1087 /* The datagram's IPv6 source address should be checked to see
1088 whether the datagram is from a valid neighbor; the source of the
1089 datagram must be a link-local address. */
1090 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1091 zlog_warn("RIPng packet comes from non link local address %s",
1092 inet6_ntoa(from
->sin6_addr
));
1093 ripng_peer_bad_packet(from
);
1097 /* It is also worth checking to see whether the response is from one
1098 of the router's own addresses. Interfaces on broadcast networks
1099 may receive copies of their own multicasts immediately. If a
1100 router processes its own output as new input, confusion is likely,
1101 and such datagrams must be ignored. */
1102 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1104 "RIPng packet comes from my own link local address %s",
1105 inet6_ntoa(from
->sin6_addr
));
1106 ripng_peer_bad_packet(from
);
1110 /* As an additional check, periodic advertisements must have their
1111 hop counts set to 255, and inbound, multicast packets sent from the
1112 RIPng port (i.e. periodic advertisement or triggered update
1113 packets) must be examined to ensure that the hop count is 255. */
1114 if (hoplimit
>= 0 && hoplimit
!= 255) {
1116 "RIPng packet comes with non 255 hop count %d from %s",
1117 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1118 ripng_peer_bad_packet(from
);
1122 /* Update RIPng peer. */
1123 ripng_peer_update(from
, packet
->version
);
1125 /* Reset nexthop. */
1126 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1127 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1129 /* Set RTE pointer. */
1132 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1133 /* First of all, we have to check this RTE is next hop RTE or
1134 not. Next hop RTE is completely different with normal RTE so
1135 we need special treatment. */
1136 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1137 ripng_nexthop_rte(rte
, from
, &nexthop
);
1141 /* RTE information validation. */
1143 /* - is the destination prefix valid (e.g., not a multicast
1144 prefix and not a link-local address) A link-local address
1145 should never be present in an RTE. */
1146 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1148 "Destination prefix is a multicast address %s/%d [%d]",
1149 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1151 ripng_peer_bad_route(from
);
1154 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1156 "Destination prefix is a link-local address %s/%d [%d]",
1157 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1159 ripng_peer_bad_route(from
);
1162 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1164 "Destination prefix is a loopback address %s/%d [%d]",
1165 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1167 ripng_peer_bad_route(from
);
1171 /* - is the prefix length valid (i.e., between 0 and 128,
1173 if (rte
->prefixlen
> 128) {
1174 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1175 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1176 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1177 ripng_peer_bad_route(from
);
1181 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1182 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1183 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1184 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1185 ripng_peer_bad_route(from
);
1189 /* Vincent: XXX Should we compute the direclty reachable nexthop
1190 * for our RIPng network ?
1193 /* Routing table updates. */
1194 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1198 /* Response to request message. */
1199 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1200 struct sockaddr_in6
*from
,
1201 struct interface
*ifp
)
1205 struct prefix_ipv6 p
;
1206 struct agg_node
*rp
;
1207 struct ripng_info
*rinfo
;
1208 struct ripng_interface
*ri
;
1210 /* Does not reponse to the requests on the loopback interfaces */
1211 if (if_is_loopback(ifp
))
1214 /* Check RIPng process is enabled on this interface. */
1219 /* When passive interface is specified, suppress responses */
1223 /* RIPng peer update. */
1224 ripng_peer_update(from
, packet
->version
);
1226 lim
= ((caddr_t
)packet
) + size
;
1229 /* The Request is processed entry by entry. If there are no
1230 entries, no response is given. */
1231 if (lim
== (caddr_t
)rte
)
1234 /* There is one special case. If there is exactly one entry in the
1235 request, and it has a destination prefix of zero, a prefix length
1236 of zero, and a metric of infinity (i.e., 16), then this is a
1237 request to send the entire routing table. In that case, a call
1238 is made to the output process to send the routing table to the
1239 requesting address/port. */
1240 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1241 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1242 /* All route with split horizon */
1243 ripng_output_process(ifp
, from
, ripng_all_route
);
1245 /* Except for this special case, processing is quite simple.
1246 Examine the list of RTEs in the Request one by one. For each
1247 entry, look up the destination in the router's routing
1248 database and, if there is a route, put that route's metric in
1249 the metric field of the RTE. If there is no explicit route
1250 to the specified destination, put infinity in the metric
1251 field. Once all the entries have been filled in, change the
1252 command from Request to Response and send the datagram back
1253 to the requestor. */
1254 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1255 p
.family
= AF_INET6
;
1257 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1258 p
.prefix
= rte
->addr
;
1259 p
.prefixlen
= rte
->prefixlen
;
1260 apply_mask_ipv6(&p
);
1262 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1265 rinfo
= listgetdata(
1266 listhead((struct list
*)rp
->info
));
1267 rte
->metric
= rinfo
->metric
;
1268 agg_unlock_node(rp
);
1270 rte
->metric
= RIPNG_METRIC_INFINITY
;
1272 packet
->command
= RIPNG_RESPONSE
;
1274 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1278 /* First entry point of reading RIPng packet. */
1279 static int ripng_read(struct thread
*thread
)
1283 struct sockaddr_in6 from
;
1284 struct ripng_packet
*packet
;
1285 ifindex_t ifindex
= 0;
1286 struct interface
*ifp
;
1289 /* Check ripng is active and alive. */
1290 assert(ripng
!= NULL
);
1291 assert(ripng
->sock
>= 0);
1293 /* Fetch thread data and set read pointer to empty for event
1294 managing. `sock' sould be same as ripng->sock. */
1295 sock
= THREAD_FD(thread
);
1296 ripng
->t_read
= NULL
;
1298 /* Add myself to the next event. */
1299 ripng_event(RIPNG_READ
, sock
);
1301 /* Read RIPng packet. */
1302 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1303 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1306 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1310 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1311 (4)) must be multiple size of one RTE size (20). */
1312 if (((len
- 4) % 20) != 0) {
1313 zlog_warn("RIPng invalid packet size %d from %s", len
,
1314 inet6_ntoa(from
.sin6_addr
));
1315 ripng_peer_bad_packet(&from
);
1319 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1320 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1322 /* RIPng packet received. */
1323 if (IS_RIPNG_DEBUG_EVENT
)
1324 zlog_debug("RIPng packet received from %s port %d on %s",
1325 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1326 ifp
? ifp
->name
: "unknown");
1328 /* Logging before packet checking. */
1329 if (IS_RIPNG_DEBUG_RECV
)
1330 ripng_packet_dump(packet
, len
, "RECV");
1332 /* Packet comes from unknown interface. */
1334 zlog_warn("RIPng packet comes from unknown interface %d",
1339 /* Packet version mismatch checking. */
1340 if (packet
->version
!= ripng
->version
) {
1342 "RIPng packet version %d doesn't fit to my version %d",
1343 packet
->version
, ripng
->version
);
1344 ripng_peer_bad_packet(&from
);
1348 /* Process RIPng packet. */
1349 switch (packet
->command
) {
1351 ripng_request_process(packet
, len
, &from
, ifp
);
1353 case RIPNG_RESPONSE
:
1354 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1357 zlog_warn("Invalid RIPng command %d", packet
->command
);
1358 ripng_peer_bad_packet(&from
);
1364 /* Walk down the RIPng routing table then clear changed flag. */
1365 static void ripng_clear_changed_flag(void)
1367 struct agg_node
*rp
;
1368 struct ripng_info
*rinfo
= NULL
;
1369 struct list
*list
= NULL
;
1370 struct listnode
*listnode
= NULL
;
1372 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1373 if ((list
= rp
->info
) != NULL
)
1374 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1375 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1376 /* This flag can be set only on the first entry.
1382 /* Regular update of RIPng route. Send all routing formation to RIPng
1383 enabled interface. */
1384 static int ripng_update(struct thread
*t
)
1386 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1387 struct interface
*ifp
;
1388 struct ripng_interface
*ri
;
1390 /* Clear update timer thread. */
1391 ripng
->t_update
= NULL
;
1393 /* Logging update event. */
1394 if (IS_RIPNG_DEBUG_EVENT
)
1395 zlog_debug("RIPng update timer expired!");
1397 /* Supply routes to each interface. */
1398 FOR_ALL_INTERFACES (vrf
, ifp
) {
1401 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1407 /* When passive interface is specified, suppress announce to the
1413 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1414 if (IS_RIPNG_DEBUG_EVENT
)
1416 "[Event] RIPng send to if %d is suppressed by config",
1420 #endif /* RIPNG_ADVANCED */
1422 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1425 /* Triggered updates may be suppressed if a regular update is due by
1426 the time the triggered update would be sent. */
1427 if (ripng
->t_triggered_interval
) {
1428 thread_cancel(ripng
->t_triggered_interval
);
1429 ripng
->t_triggered_interval
= NULL
;
1433 /* Reset flush event. */
1434 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1439 /* Triggered update interval timer. */
1440 static int ripng_triggered_interval(struct thread
*t
)
1442 ripng
->t_triggered_interval
= NULL
;
1444 if (ripng
->trigger
) {
1446 ripng_triggered_update(t
);
1451 /* Execute triggered update. */
1452 int ripng_triggered_update(struct thread
*t
)
1454 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1455 struct interface
*ifp
;
1456 struct ripng_interface
*ri
;
1459 ripng
->t_triggered_update
= NULL
;
1461 /* Cancel interval timer. */
1462 if (ripng
->t_triggered_interval
) {
1463 thread_cancel(ripng
->t_triggered_interval
);
1464 ripng
->t_triggered_interval
= NULL
;
1468 /* Logging triggered update. */
1469 if (IS_RIPNG_DEBUG_EVENT
)
1470 zlog_debug("RIPng triggered update!");
1472 /* Split Horizon processing is done when generating triggered
1473 updates as well as normal updates (see section 2.6). */
1474 FOR_ALL_INTERFACES (vrf
, ifp
) {
1477 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1483 /* When passive interface is specified, suppress announce to the
1488 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1491 /* Once all of the triggered updates have been generated, the route
1492 change flags should be cleared. */
1493 ripng_clear_changed_flag();
1495 /* After a triggered update is sent, a timer should be set for a
1496 random interval between 1 and 5 seconds. If other changes that
1497 would trigger updates occur before the timer expires, a single
1498 update is triggered when the timer expires. */
1499 interval
= (random() % 5) + 1;
1501 ripng
->t_triggered_interval
= NULL
;
1502 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1503 &ripng
->t_triggered_interval
);
1508 /* Write routing table entry to the stream and return next index of
1509 the routing table entry in the stream. */
1510 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1511 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1513 /* RIPng packet header. */
1515 stream_putc(s
, RIPNG_RESPONSE
);
1516 stream_putc(s
, RIPNG_V1
);
1520 /* Write routing table entry. */
1523 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1525 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1526 stream_putw(s
, tag
);
1528 stream_putc(s
, p
->prefixlen
);
1531 stream_putc(s
, metric
);
1536 /* Send RESPONSE message to specified destination. */
1537 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1541 struct agg_node
*rp
;
1542 struct ripng_info
*rinfo
;
1543 struct ripng_interface
*ri
;
1544 struct ripng_aggregate
*aggregate
;
1545 struct prefix_ipv6
*p
;
1546 struct list
*ripng_rte_list
;
1547 struct list
*list
= NULL
;
1548 struct listnode
*listnode
= NULL
;
1550 if (IS_RIPNG_DEBUG_EVENT
) {
1552 zlog_debug("RIPng update routes to neighbor %s",
1553 inet6_ntoa(to
->sin6_addr
));
1555 zlog_debug("RIPng update routes on interface %s",
1559 /* Get RIPng interface. */
1562 ripng_rte_list
= ripng_rte_new();
1564 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1565 if ((list
= rp
->info
) != NULL
1566 && (rinfo
= listgetdata(listhead(list
))) != NULL
1567 && rinfo
->suppress
== 0) {
1568 /* If no route-map are applied, the RTE will be these
1572 p
= (struct prefix_ipv6
*)&rp
->p
;
1573 rinfo
->metric_out
= rinfo
->metric
;
1574 rinfo
->tag_out
= rinfo
->tag
;
1575 memset(&rinfo
->nexthop_out
, 0,
1576 sizeof(rinfo
->nexthop_out
));
1577 /* In order to avoid some local loops,
1578 * if the RIPng route has a nexthop via this interface,
1580 * otherwise set it to 0. The nexthop should not be
1582 * beyond the local broadcast/multicast area in order
1583 * to avoid an IGP multi-level recursive look-up.
1585 if (rinfo
->ifindex
== ifp
->ifindex
)
1586 rinfo
->nexthop_out
= rinfo
->nexthop
;
1588 /* Apply output filters. */
1589 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1593 /* Changed route only output. */
1594 if (route_type
== ripng_changed_route
1595 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1598 /* Split horizon. */
1599 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1600 /* We perform split horizon for RIPng routes. */
1602 struct ripng_info
*tmp_rinfo
= NULL
;
1604 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1606 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1607 && tmp_rinfo
->ifindex
1616 /* Preparation for route-map. */
1617 rinfo
->metric_set
= 0;
1620 * and tag_out are already initialized.
1623 /* Interface route-map */
1624 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1625 ret
= route_map_apply(
1626 ri
->routemap
[RIPNG_FILTER_OUT
],
1627 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1629 if (ret
== RMAP_DENYMATCH
) {
1630 if (IS_RIPNG_DEBUG_PACKET
)
1632 "RIPng %s/%d is filtered by route-map out",
1633 inet6_ntoa(p
->prefix
),
1639 /* Redistribute route-map. */
1640 if (ripng
->route_map
[rinfo
->type
].name
) {
1641 ret
= route_map_apply(
1642 ripng
->route_map
[rinfo
->type
].map
,
1643 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1645 if (ret
== RMAP_DENYMATCH
) {
1646 if (IS_RIPNG_DEBUG_PACKET
)
1648 "RIPng %s/%d is filtered by route-map",
1649 inet6_ntoa(p
->prefix
),
1655 /* When the route-map does not set metric. */
1656 if (!rinfo
->metric_set
) {
1657 /* If the redistribute metric is set. */
1658 if (ripng
->route_map
[rinfo
->type
].metric_config
1659 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1661 ripng
->route_map
[rinfo
->type
]
1664 /* If the route is not connected or
1666 one, use default-metric value */
1667 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1669 != ZEBRA_ROUTE_CONNECT
1671 != RIPNG_METRIC_INFINITY
)
1673 ripng
->default_metric
;
1677 /* Apply offset-list */
1678 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1679 ripng_offset_list_apply_out(p
, ifp
,
1680 &rinfo
->metric_out
);
1682 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1683 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1685 /* Perform split-horizon with poisoned reverse
1688 if (ri
->split_horizon
1689 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1690 struct ripng_info
*tmp_rinfo
= NULL
;
1692 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1694 if ((tmp_rinfo
->type
1695 == ZEBRA_ROUTE_RIPNG
)
1696 && tmp_rinfo
->ifindex
1699 RIPNG_METRIC_INFINITY
;
1702 /* Add RTE to the list */
1703 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1706 /* Process the aggregated RTE entry */
1707 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1708 && aggregate
->suppress
== 0) {
1709 /* If no route-map are applied, the RTE will be these
1713 p
= (struct prefix_ipv6
*)&rp
->p
;
1714 aggregate
->metric_set
= 0;
1715 aggregate
->metric_out
= aggregate
->metric
;
1716 aggregate
->tag_out
= aggregate
->tag
;
1717 memset(&aggregate
->nexthop_out
, 0,
1718 sizeof(aggregate
->nexthop_out
));
1720 /* Apply output filters.*/
1721 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1725 /* Interface route-map */
1726 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1727 struct ripng_info newinfo
;
1729 /* let's cast the aggregate structure to
1731 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1732 /* the nexthop is :: */
1733 newinfo
.metric
= aggregate
->metric
;
1734 newinfo
.metric_out
= aggregate
->metric_out
;
1735 newinfo
.tag
= aggregate
->tag
;
1736 newinfo
.tag_out
= aggregate
->tag_out
;
1738 ret
= route_map_apply(
1739 ri
->routemap
[RIPNG_FILTER_OUT
],
1740 (struct prefix
*)p
, RMAP_RIPNG
,
1743 if (ret
== RMAP_DENYMATCH
) {
1744 if (IS_RIPNG_DEBUG_PACKET
)
1746 "RIPng %s/%d is filtered by route-map out",
1747 inet6_ntoa(p
->prefix
),
1752 aggregate
->metric_out
= newinfo
.metric_out
;
1753 aggregate
->tag_out
= newinfo
.tag_out
;
1754 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1755 aggregate
->nexthop_out
=
1756 newinfo
.nexthop_out
;
1759 /* There is no redistribute routemap for the aggregated
1762 /* Changed route only output. */
1763 /* XXX, vincent, in order to increase time convergence,
1764 * it should be announced if a child has changed.
1766 if (route_type
== ripng_changed_route
)
1769 /* Apply offset-list */
1770 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1771 ripng_offset_list_apply_out(
1772 p
, ifp
, &aggregate
->metric_out
);
1774 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1775 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1777 /* Add RTE to the list */
1778 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1782 /* Flush the list */
1783 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1784 ripng_rte_free(ripng_rte_list
);
1787 /* Create new RIPng instance and set it to global variable. */
1788 int ripng_create(int socket
)
1790 /* ripng should be NULL. */
1791 assert(ripng
== NULL
);
1793 /* Allocaste RIPng instance. */
1794 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1796 /* Default version and timer values. */
1797 ripng
->version
= RIPNG_V1
;
1798 ripng
->update_time
= yang_get_default_uint32(
1799 "%s/timers/update-interval", RIPNG_INSTANCE
);
1800 ripng
->timeout_time
= yang_get_default_uint32(
1801 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1802 ripng
->garbage_time
= yang_get_default_uint32(
1803 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1804 ripng
->default_metric
=
1805 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1806 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1809 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1810 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1812 /* Initialize RIPng routig table. */
1813 ripng
->table
= agg_table_init();
1815 /* Distribute list install. */
1816 ripng
->distribute_ctx
= distribute_list_ctx_create(
1817 vrf_lookup_by_id(VRF_DEFAULT
));
1818 distribute_list_add_hook(ripng
->distribute_ctx
,
1819 ripng_distribute_update
);
1820 distribute_list_delete_hook(ripng
->distribute_ctx
,
1821 ripng_distribute_update
);
1823 /* if rmap install. */
1824 ripng
->if_rmap_ctx
= if_rmap_ctx_create(VRF_DEFAULT_NAME
);
1825 if_rmap_hook_add(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1826 if_rmap_hook_delete(ripng
->if_rmap_ctx
, ripng_if_rmap_update
);
1829 ripng
->sock
= socket
;
1832 ripng_event(RIPNG_READ
, ripng
->sock
);
1833 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1838 /* Send RIPng request to the interface. */
1839 int ripng_request(struct interface
*ifp
)
1842 struct ripng_packet ripng_packet
;
1844 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1846 if (if_is_loopback(ifp
))
1849 /* If interface is down, don't send RIP packet. */
1853 if (IS_RIPNG_DEBUG_EVENT
)
1854 zlog_debug("RIPng send request to %s", ifp
->name
);
1856 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1857 ripng_packet
.command
= RIPNG_REQUEST
;
1858 ripng_packet
.version
= RIPNG_V1
;
1859 rte
= ripng_packet
.rte
;
1860 rte
->metric
= RIPNG_METRIC_INFINITY
;
1862 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1867 static int ripng_update_jitter(int time
)
1869 return ((random() % (time
+ 1)) - (time
/ 2));
1872 void ripng_event(enum ripng_event event
, int sock
)
1878 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1880 case RIPNG_UPDATE_EVENT
:
1881 if (ripng
->t_update
) {
1882 thread_cancel(ripng
->t_update
);
1883 ripng
->t_update
= NULL
;
1885 /* Update timer jitter. */
1886 jitter
= ripng_update_jitter(ripng
->update_time
);
1888 ripng
->t_update
= NULL
;
1889 thread_add_timer(master
, ripng_update
, NULL
,
1890 sock
? 2 : ripng
->update_time
+ jitter
,
1893 case RIPNG_TRIGGERED_UPDATE
:
1894 if (ripng
->t_triggered_interval
)
1897 thread_add_event(master
, ripng_triggered_update
, NULL
,
1898 0, &ripng
->t_triggered_update
);
1906 /* Print out routes update time. */
1907 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1912 char timebuf
[TIME_BUF
];
1913 struct thread
*thread
;
1915 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1916 clock
= thread_timer_remain_second(thread
);
1917 tm
= gmtime(&clock
);
1918 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1919 vty_out(vty
, "%5s", timebuf
);
1920 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1921 clock
= thread_timer_remain_second(thread
);
1922 tm
= gmtime(&clock
);
1923 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1924 vty_out(vty
, "%5s", timebuf
);
1928 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1933 if (rinfo
->suppress
)
1936 switch (rinfo
->sub_type
) {
1937 case RIPNG_ROUTE_RTE
:
1940 case RIPNG_ROUTE_STATIC
:
1943 case RIPNG_ROUTE_DEFAULT
:
1946 case RIPNG_ROUTE_REDISTRIBUTE
:
1949 case RIPNG_ROUTE_INTERFACE
:
1960 DEFUN (show_ipv6_ripng
,
1961 show_ipv6_ripng_cmd
,
1965 "Show RIPng routes\n")
1967 struct agg_node
*rp
;
1968 struct ripng_info
*rinfo
;
1969 struct ripng_aggregate
*aggregate
;
1970 struct prefix_ipv6
*p
;
1971 struct list
*list
= NULL
;
1972 struct listnode
*listnode
= NULL
;
1978 /* Header of display. */
1980 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1982 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1983 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1984 " Network Next Hop Via Metric Tag Time\n");
1986 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1987 if ((aggregate
= rp
->aggregate
) != NULL
) {
1988 p
= (struct prefix_ipv6
*)&rp
->p
;
1991 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1992 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1995 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1999 vty_out(vty
, "%*s", 18, " ");
2001 vty_out(vty
, "%*s", 28, " ");
2002 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2003 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2006 if ((list
= rp
->info
) != NULL
)
2007 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2008 p
= (struct prefix_ipv6
*)&rp
->p
;
2011 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2012 zebra_route_char(rinfo
->type
),
2013 ripng_route_subtype_print(rinfo
),
2014 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2017 vty_out(vty
, "%c(%s) %s/%d ",
2018 zebra_route_char(rinfo
->type
),
2019 ripng_route_subtype_print(rinfo
),
2020 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2023 vty_out(vty
, "%*s", 18, " ");
2024 len
= vty_out(vty
, "%s",
2025 inet6_ntoa(rinfo
->nexthop
));
2029 vty_out(vty
, "%*s", len
, " ");
2032 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2033 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2036 ifindex2ifname(rinfo
->ifindex
,
2038 } else if (rinfo
->metric
2039 == RIPNG_METRIC_INFINITY
) {
2040 len
= vty_out(vty
, "kill");
2042 len
= vty_out(vty
, "self");
2046 vty_out(vty
, "%*s", len
, " ");
2048 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2049 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2052 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2053 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2054 /* RTE from remote RIP routers */
2055 ripng_vty_out_uptime(vty
, rinfo
);
2056 } else if (rinfo
->metric
2057 == RIPNG_METRIC_INFINITY
) {
2058 /* poisonous reversed routes (gc) */
2059 ripng_vty_out_uptime(vty
, rinfo
);
2069 DEFUN (show_ipv6_ripng_status
,
2070 show_ipv6_ripng_status_cmd
,
2071 "show ipv6 ripng status",
2074 "Show RIPng routes\n"
2075 "IPv6 routing protocol process parameters and statistics\n")
2077 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2078 struct interface
*ifp
;
2083 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2084 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2085 ripng
->update_time
);
2086 vty_out(vty
, " next due in %lu seconds\n",
2087 thread_timer_remain_second(ripng
->t_update
));
2088 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2089 vty_out(vty
, " garbage collect after %u seconds\n",
2090 ripng
->garbage_time
);
2092 /* Filtering status show. */
2093 config_show_distribute(vty
, ripng
->distribute_ctx
);
2095 /* Default metric information. */
2096 vty_out(vty
, " Default redistribution metric is %d\n",
2097 ripng
->default_metric
);
2099 /* Redistribute information. */
2100 vty_out(vty
, " Redistributing:");
2101 ripng_redistribute_write(vty
);
2104 vty_out(vty
, " Default version control: send version %d,",
2106 vty_out(vty
, " receive version %d \n", ripng
->version
);
2108 vty_out(vty
, " Interface Send Recv\n");
2110 FOR_ALL_INTERFACES (vrf
, ifp
) {
2111 struct ripng_interface
*ri
;
2115 if (ri
->enable_network
|| ri
->enable_interface
) {
2117 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2118 ripng
->version
, ripng
->version
);
2122 vty_out(vty
, " Routing for Networks:\n");
2123 ripng_network_write(vty
);
2125 vty_out(vty
, " Routing Information Sources:\n");
2127 " Gateway BadPackets BadRoutes Distance Last Update\n");
2128 ripng_peer_display(vty
);
2134 /* RIPng update timer setup. */
2135 DEFUN (ripng_update_timer
,
2136 ripng_update_timer_cmd
,
2137 "update-timer SECOND",
2138 "Set RIPng update timer in seconds\n"
2141 unsigned long update
;
2142 char *endptr
= NULL
;
2144 update
= strtoul (argv
[0], &endptr
, 10);
2145 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2147 vty_out (vty
, "update timer value error\n");
2148 return CMD_WARNING_CONFIG_FAILED
;
2151 ripng
->update_time
= update
;
2153 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2157 DEFUN (no_ripng_update_timer
,
2158 no_ripng_update_timer_cmd
,
2159 "no update-timer SECOND",
2161 "Unset RIPng update timer in seconds\n"
2164 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2165 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2169 /* RIPng timeout timer setup. */
2170 DEFUN (ripng_timeout_timer
,
2171 ripng_timeout_timer_cmd
,
2172 "timeout-timer SECOND",
2173 "Set RIPng timeout timer in seconds\n"
2176 unsigned long timeout
;
2177 char *endptr
= NULL
;
2179 timeout
= strtoul (argv
[0], &endptr
, 10);
2180 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2182 vty_out (vty
, "timeout timer value error\n");
2183 return CMD_WARNING_CONFIG_FAILED
;
2186 ripng
->timeout_time
= timeout
;
2191 DEFUN (no_ripng_timeout_timer
,
2192 no_ripng_timeout_timer_cmd
,
2193 "no timeout-timer SECOND",
2195 "Unset RIPng timeout timer in seconds\n"
2198 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2202 /* RIPng garbage timer setup. */
2203 DEFUN (ripng_garbage_timer
,
2204 ripng_garbage_timer_cmd
,
2205 "garbage-timer SECOND",
2206 "Set RIPng garbage timer in seconds\n"
2209 unsigned long garbage
;
2210 char *endptr
= NULL
;
2212 garbage
= strtoul (argv
[0], &endptr
, 10);
2213 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2215 vty_out (vty
, "garbage timer value error\n");
2216 return CMD_WARNING_CONFIG_FAILED
;
2219 ripng
->garbage_time
= garbage
;
2224 DEFUN (no_ripng_garbage_timer
,
2225 no_ripng_garbage_timer_cmd
,
2226 "no garbage-timer SECOND",
2228 "Unset RIPng garbage timer in seconds\n"
2231 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2237 DEFUN (show_ipv6_protocols
,
2238 show_ipv6_protocols_cmd
,
2239 "show ipv6 protocols",
2242 "Routing protocol information\n")
2247 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2249 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2250 ripng
->update_time
, 0);
2252 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2253 ripng
->timeout_time
,
2254 ripng
->garbage_time
);
2256 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2257 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2263 /* Update ECMP routes to zebra when ECMP is disabled. */
2264 void ripng_ecmp_disable(void)
2266 struct agg_node
*rp
;
2267 struct ripng_info
*rinfo
, *tmp_rinfo
;
2269 struct listnode
*node
, *nextnode
;
2274 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2275 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2276 rinfo
= listgetdata(listhead(list
));
2277 if (!ripng_route_rte(rinfo
))
2280 /* Drop all other entries, except the first one. */
2281 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2282 if (tmp_rinfo
!= rinfo
) {
2283 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2285 tmp_rinfo
->t_garbage_collect
);
2286 list_delete_node(list
, node
);
2287 ripng_info_free(tmp_rinfo
);
2291 ripng_zebra_ipv6_add(rp
);
2293 /* Set the route change flag. */
2294 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2296 /* Signal the output process to trigger an update. */
2297 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2301 /* RIPng configuration write function. */
2302 static int ripng_config_write(struct vty
*vty
)
2304 struct lyd_node
*dnode
;
2307 dnode
= yang_dnode_get(running_config
->dnode
,
2308 "/frr-ripngd:ripngd/instance");
2310 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2312 config_write_distribute(vty
,
2313 ripng
->distribute_ctx
);
2315 config_write_if_rmap(vty
, ripng
->if_rmap_ctx
);
2323 /* RIPng node structure. */
2324 static struct cmd_node cmd_ripng_node
= {
2325 RIPNG_NODE
, "%s(config-router)# ", 1,
2328 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2329 struct distribute
*dist
)
2331 struct interface
*ifp
;
2332 struct ripng_interface
*ri
;
2333 struct access_list
*alist
;
2334 struct prefix_list
*plist
;
2339 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2345 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2346 alist
= access_list_lookup(AFI_IP6
,
2347 dist
->list
[DISTRIBUTE_V6_IN
]);
2349 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2351 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2353 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2355 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2356 alist
= access_list_lookup(AFI_IP6
,
2357 dist
->list
[DISTRIBUTE_V6_OUT
]);
2359 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2361 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2363 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2365 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2366 plist
= prefix_list_lookup(AFI_IP6
,
2367 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2369 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2371 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2373 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2375 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2376 plist
= prefix_list_lookup(AFI_IP6
,
2377 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2379 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2381 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2383 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2386 void ripng_distribute_update_interface(struct interface
*ifp
)
2388 struct distribute
*dist
;
2392 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2394 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2397 /* Update all interface's distribute list. */
2398 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2400 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2401 struct interface
*ifp
;
2403 FOR_ALL_INTERFACES (vrf
, ifp
)
2404 ripng_distribute_update_interface(ifp
);
2407 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2409 ripng_distribute_update_all(NULL
);
2412 /* delete all the added ripng routes. */
2413 void ripng_clean(void)
2416 struct agg_node
*rp
;
2417 struct ripng_info
*rinfo
;
2418 struct ripng_aggregate
*aggregate
;
2419 struct list
*list
= NULL
;
2420 struct listnode
*listnode
= NULL
;
2423 /* Clear RIPng routes */
2424 for (rp
= agg_route_top(ripng
->table
); rp
;
2425 rp
= agg_route_next(rp
)) {
2426 if ((list
= rp
->info
) != NULL
) {
2427 rinfo
= listgetdata(listhead(list
));
2428 if (ripng_route_rte(rinfo
))
2429 ripng_zebra_ipv6_delete(rp
);
2431 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2433 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2435 rinfo
->t_garbage_collect
);
2436 ripng_info_free(rinfo
);
2440 agg_unlock_node(rp
);
2443 if ((aggregate
= rp
->aggregate
) != NULL
) {
2444 ripng_aggregate_free(aggregate
);
2445 rp
->aggregate
= NULL
;
2446 agg_unlock_node(rp
);
2450 /* Cancel the RIPng timers */
2451 RIPNG_TIMER_OFF(ripng
->t_update
);
2452 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2453 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2455 /* Cancel the read thread */
2456 if (ripng
->t_read
) {
2457 thread_cancel(ripng
->t_read
);
2458 ripng
->t_read
= NULL
;
2461 /* Close the RIPng socket */
2462 if (ripng
->sock
>= 0) {
2467 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2468 if (ripng
->route_map
[i
].name
)
2469 free(ripng
->route_map
[i
].name
);
2471 agg_table_finish(ripng
->table
);
2473 stream_free(ripng
->ibuf
);
2474 stream_free(ripng
->obuf
);
2476 distribute_list_delete(&ripng
->distribute_ctx
);
2477 XFREE(MTYPE_RIPNG
, ripng
);
2481 ripng_clean_network();
2482 ripng_passive_interface_clean();
2483 ripng_offset_clean();
2484 ripng_interface_clean();
2485 ripng_redistribute_clean();
2486 if_rmap_terminate();
2489 static void ripng_if_rmap_update(struct if_rmap_ctx
*ctx
,
2490 struct if_rmap
*if_rmap
)
2492 struct interface
*ifp
= NULL
;
2493 struct ripng_interface
*ri
;
2494 struct route_map
*rmap
;
2495 struct vrf
*vrf
= NULL
;
2498 vrf
= vrf_lookup_by_name(ctx
->name
);
2500 ifp
= if_lookup_by_name(if_rmap
->ifname
, vrf
->vrf_id
);
2506 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2507 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2509 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2511 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2513 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2515 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2516 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2518 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2520 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2522 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2525 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2527 struct if_rmap
*if_rmap
;
2528 struct if_rmap_ctx
*ctx
;
2530 if (ifp
->vrf_id
!= VRF_DEFAULT
)
2534 ctx
= ripng
->if_rmap_ctx
;
2537 if_rmap
= if_rmap_lookup(ctx
, ifp
->name
);
2539 ripng_if_rmap_update(ctx
, if_rmap
);
2542 static void ripng_routemap_update_redistribute(void)
2547 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2548 if (ripng
->route_map
[i
].name
) {
2549 ripng
->route_map
[i
].map
=
2550 route_map_lookup_by_name(
2551 ripng
->route_map
[i
].name
);
2552 route_map_counter_increment(
2553 ripng
->route_map
[i
].map
);
2559 static void ripng_routemap_update(const char *unused
)
2561 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2562 struct interface
*ifp
;
2564 FOR_ALL_INTERFACES (vrf
, ifp
)
2565 ripng_if_rmap_update_interface(ifp
);
2567 ripng_routemap_update_redistribute();
2570 /* Initialize ripng structure and set commands. */
2571 void ripng_init(void)
2573 /* Install RIPNG_NODE. */
2574 install_node(&cmd_ripng_node
, ripng_config_write
);
2576 /* Install ripng commands. */
2577 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2578 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2580 install_default(RIPNG_NODE
);
2583 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2584 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2585 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2586 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2587 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2588 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2589 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2595 /* Access list install. */
2597 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2598 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2600 /* Prefix list initialize.*/
2602 prefix_list_add_hook(ripng_distribute_update_all
);
2603 prefix_list_delete_hook(ripng_distribute_update_all
);
2605 /* Distribute list install. */
2606 distribute_list_init(RIPNG_NODE
);
2608 /* Route-map for interface. */
2609 ripng_route_map_init();
2610 ripng_offset_init();
2612 route_map_add_hook(ripng_routemap_update
);
2613 route_map_delete_hook(ripng_routemap_update
);
2615 if_rmap_init(RIPNG_NODE
);