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 /* RIPng next hop specification. */
64 struct ripng_nexthop
{
65 enum ripng_nexthop_type
{
69 struct in6_addr address
;
72 int ripng_route_rte(struct ripng_info
*rinfo
)
74 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
75 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
78 /* Allocate new ripng information. */
79 struct ripng_info
*ripng_info_new()
81 struct ripng_info
*new;
83 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
87 /* Free ripng information. */
88 void ripng_info_free(struct ripng_info
*rinfo
)
90 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
93 /* Create ripng socket. */
94 int ripng_make_socket(void)
98 struct sockaddr_in6 ripaddr
;
100 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
102 flog_err_sys(EC_LIB_SOCKET
, "Can't make ripng socket");
106 setsockopt_so_recvbuf(sock
, 8096);
107 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
110 #ifdef IPTOS_PREC_INTERNETCONTROL
111 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
115 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
118 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
121 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
125 memset(&ripaddr
, 0, sizeof(ripaddr
));
126 ripaddr
.sin6_family
= AF_INET6
;
128 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
129 #endif /* SIN6_LEN */
130 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
132 frr_elevate_privs(&ripngd_privs
) {
133 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
135 zlog_err("Can't bind ripng socket: %s.",
136 safe_strerror(errno
));
147 /* Send RIPng packet. */
148 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
149 struct interface
*ifp
)
154 struct cmsghdr
*cmsgptr
;
156 struct in6_pktinfo
*pkt
;
157 struct sockaddr_in6 addr
;
159 if (IS_RIPNG_DEBUG_SEND
) {
161 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
162 zlog_debug(" send interface %s", ifp
->name
);
163 zlog_debug(" send packet size %d", bufsize
);
166 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
167 addr
.sin6_family
= AF_INET6
;
169 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
170 #endif /* SIN6_LEN */
171 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
173 /* When destination is specified. */
175 addr
.sin6_addr
= to
->sin6_addr
;
176 addr
.sin6_port
= to
->sin6_port
;
178 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
179 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
182 memset(&msg
, 0, sizeof(msg
));
183 msg
.msg_name
= (void *)&addr
;
184 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
187 msg
.msg_control
= (void *)adata
;
188 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
191 iov
.iov_len
= bufsize
;
193 cmsgptr
= (struct cmsghdr
*)adata
;
194 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
195 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
196 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
198 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
199 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
200 pkt
->ipi6_ifindex
= ifp
->ifindex
;
202 ret
= sendmsg(ripng
->sock
, &msg
, 0);
206 flog_err_sys(EC_LIB_SOCKET
,
207 "RIPng send fail on %s to %s: %s",
208 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
209 safe_strerror(errno
));
211 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
212 ifp
->name
, safe_strerror(errno
));
218 /* Receive UDP RIPng packet from socket. */
219 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
220 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
226 struct cmsghdr
*cmsgptr
;
227 struct in6_addr dst
= {.s6_addr
= {0}};
229 memset(&dst
, 0, sizeof(struct in6_addr
));
231 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
232 point I can't determine size of cmsghdr */
235 /* Fill in message and iovec. */
236 memset(&msg
, 0, sizeof(msg
));
237 msg
.msg_name
= (void *)from
;
238 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
241 msg
.msg_control
= (void *)adata
;
242 msg
.msg_controllen
= sizeof adata
;
244 iov
.iov_len
= bufsize
;
246 /* If recvmsg fail return minus value. */
247 ret
= recvmsg(sock
, &msg
, 0);
251 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
252 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
253 /* I want interface index which this packet comes from. */
254 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
255 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
256 struct in6_pktinfo
*ptr
;
258 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
259 *ifindex
= ptr
->ipi6_ifindex
;
260 dst
= ptr
->ipi6_addr
;
264 "Interface index returned by IPV6_PKTINFO is zero");
267 /* Incoming packet's multicast hop limit. */
268 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
269 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
270 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
271 *hoplimit
= *phoplimit
;
275 /* Hoplimit check shold be done when destination address is
276 multicast address. */
277 if (!IN6_IS_ADDR_MULTICAST(&dst
))
283 /* Dump rip packet */
284 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
289 const char *command_str
;
291 /* Set command string. */
292 if (packet
->command
== RIPNG_REQUEST
)
293 command_str
= "request";
294 else if (packet
->command
== RIPNG_RESPONSE
)
295 command_str
= "response";
297 command_str
= "unknown";
299 /* Dump packet header. */
300 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
301 packet
->version
, size
);
303 /* Dump each routing table entry. */
306 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
307 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
308 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
311 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
312 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
313 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
317 /* RIPng next hop address RTE (Route Table Entry). */
318 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
319 struct ripng_nexthop
*nexthop
)
321 char buf
[INET6_BUFSIZ
];
323 /* Logging before checking RTE. */
324 if (IS_RIPNG_DEBUG_RECV
)
325 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
327 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
330 /* RFC2080 2.1.1 Next Hop:
331 The route tag and prefix length in the next hop RTE must be
332 set to zero on sending and ignored on receiption. */
333 if (ntohs(rte
->tag
) != 0)
335 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
337 (route_tag_t
)ntohs(rte
->tag
),
338 inet6_ntoa(from
->sin6_addr
));
340 if (rte
->prefixlen
!= 0)
342 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
343 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
345 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
346 next hop RTE indicates that the next hop address should be the
347 originator of the RIPng advertisement. An address specified as a
348 next hop must be a link-local address. */
349 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
350 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
351 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
355 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
356 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
357 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
361 /* The purpose of the next hop RTE is to eliminate packets being
362 routed through extra hops in the system. It is particularly useful
363 when RIPng is not being run on all of the routers on a network.
364 Note that next hop RTE is "advisory". That is, if the provided
365 information is ignored, a possibly sub-optimal, but absolutely
366 valid, route may be taken. If the received next hop address is not
367 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
368 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
369 inet6_ntoa(rte
->addr
),
370 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
372 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
373 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
378 /* If ifp has same link-local address then return 1. */
379 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
381 struct listnode
*node
;
382 struct connected
*connected
;
385 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
386 p
= connected
->address
;
388 if (p
->family
== AF_INET6
389 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
390 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
396 /* RIPng route garbage collect timer. */
397 static int ripng_garbage_collect(struct thread
*t
)
399 struct ripng_info
*rinfo
;
402 rinfo
= THREAD_ARG(t
);
403 rinfo
->t_garbage_collect
= NULL
;
405 /* Off timeout timer. */
406 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
408 /* Get route_node pointer. */
411 /* Unlock route_node. */
412 listnode_delete(rp
->info
, rinfo
);
413 if (list_isempty((struct list
*)rp
->info
)) {
414 list_delete((struct list
**)&rp
->info
);
418 /* Free RIPng routing information. */
419 ripng_info_free(rinfo
);
424 static void ripng_timeout_update(struct ripng_info
*rinfo
);
426 /* Add new route to the ECMP list.
427 * RETURN: the new entry added in the list, or NULL if it is not the first
428 * entry and ECMP is not allowed.
430 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
432 struct agg_node
*rp
= rinfo_new
->rp
;
433 struct ripng_info
*rinfo
= NULL
;
434 struct list
*list
= NULL
;
436 if (rp
->info
== NULL
)
437 rp
->info
= list_new();
438 list
= (struct list
*)rp
->info
;
440 /* If ECMP is not allowed and some entry already exists in the list,
442 if (listcount(list
) && !ripng
->ecmp
)
445 rinfo
= ripng_info_new();
446 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
447 listnode_add(list
, rinfo
);
449 if (ripng_route_rte(rinfo
)) {
450 ripng_timeout_update(rinfo
);
451 ripng_zebra_ipv6_add(rp
);
454 ripng_aggregate_increment(rp
, rinfo
);
456 /* Set the route change flag on the first entry. */
457 rinfo
= listgetdata(listhead(list
));
458 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
460 /* Signal the output process to trigger an update. */
461 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
466 /* Replace the ECMP list with the new route.
467 * RETURN: the new entry added in the list
469 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
471 struct agg_node
*rp
= rinfo_new
->rp
;
472 struct list
*list
= (struct list
*)rp
->info
;
473 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
474 struct listnode
*node
= NULL
, *nextnode
= NULL
;
476 if (list
== NULL
|| listcount(list
) == 0)
477 return ripng_ecmp_add(rinfo_new
);
479 /* Get the first entry */
480 rinfo
= listgetdata(listhead(list
));
482 /* Learnt route replaced by a local one. Delete it from zebra. */
483 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
484 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
485 ripng_zebra_ipv6_delete(rp
);
487 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
488 ripng_aggregate_decrement_list(rp
, list
);
490 /* Re-use the first entry, and delete the others. */
491 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
492 if (tmp_rinfo
!= rinfo
) {
493 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
494 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
495 list_delete_node(list
, node
);
496 ripng_info_free(tmp_rinfo
);
499 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
500 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
501 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
503 if (ripng_route_rte(rinfo
)) {
504 ripng_timeout_update(rinfo
);
505 /* The ADD message implies an update. */
506 ripng_zebra_ipv6_add(rp
);
509 ripng_aggregate_increment(rp
, rinfo
);
511 /* Set the route change flag. */
512 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
514 /* Signal the output process to trigger an update. */
515 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
520 /* Delete one route from the ECMP list.
522 * null - the entry is freed, and other entries exist in the list
523 * the entry - the entry is the last one in the list; its metric is set
524 * to INFINITY, and the garbage collector is started for it
526 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
528 struct agg_node
*rp
= rinfo
->rp
;
529 struct list
*list
= (struct list
*)rp
->info
;
531 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
533 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
534 ripng_aggregate_decrement(rp
, rinfo
);
536 if (listcount(list
) > 1) {
537 /* Some other ECMP entries still exist. Just delete this entry.
539 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
540 listnode_delete(list
, rinfo
);
541 if (ripng_route_rte(rinfo
)
542 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
543 /* The ADD message implies the update. */
544 ripng_zebra_ipv6_add(rp
);
545 ripng_info_free(rinfo
);
548 assert(rinfo
== listgetdata(listhead(list
)));
550 /* This is the only entry left in the list. We must keep it in
551 * the list for garbage collection time, with INFINITY metric.
554 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
555 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
556 ripng
->garbage_time
);
558 if (ripng_route_rte(rinfo
)
559 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
560 ripng_zebra_ipv6_delete(rp
);
563 /* Set the route change flag on the first entry. */
564 rinfo
= listgetdata(listhead(list
));
565 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
567 /* Signal the output process to trigger an update. */
568 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
573 /* Timeout RIPng routes. */
574 static int ripng_timeout(struct thread
*t
)
576 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
580 static void ripng_timeout_update(struct ripng_info
*rinfo
)
582 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
583 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
584 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
585 ripng
->timeout_time
);
589 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
590 struct ripng_interface
*ri
)
592 struct distribute
*dist
;
593 struct access_list
*alist
;
594 struct prefix_list
*plist
;
595 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
598 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
600 /* Input distribute-list filtering. */
601 if (ri
->list
[ripng_distribute
]) {
602 if (access_list_apply(ri
->list
[ripng_distribute
],
605 if (IS_RIPNG_DEBUG_PACKET
)
606 zlog_debug("%s/%d filtered by distribute %s",
607 inet6_ntoa(p
->prefix
), p
->prefixlen
,
612 if (ri
->prefix
[ripng_distribute
]) {
613 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
616 if (IS_RIPNG_DEBUG_PACKET
)
617 zlog_debug("%s/%d filtered by prefix-list %s",
618 inet6_ntoa(p
->prefix
), p
->prefixlen
,
624 /* All interface filter check. */
625 dist
= distribute_lookup(ripng
->distribute_ctx
, NULL
);
627 if (dist
->list
[distribute
]) {
628 alist
= access_list_lookup(AFI_IP6
,
629 dist
->list
[distribute
]);
632 if (access_list_apply(alist
, (struct prefix
*)p
)
634 if (IS_RIPNG_DEBUG_PACKET
)
636 "%s/%d filtered by distribute %s",
637 inet6_ntoa(p
->prefix
),
638 p
->prefixlen
, inout
);
643 if (dist
->prefix
[distribute
]) {
644 plist
= prefix_list_lookup(AFI_IP6
,
645 dist
->prefix
[distribute
]);
648 if (prefix_list_apply(plist
, (struct prefix
*)p
)
650 if (IS_RIPNG_DEBUG_PACKET
)
652 "%s/%d filtered by prefix-list %s",
653 inet6_ntoa(p
->prefix
),
654 p
->prefixlen
, inout
);
663 /* Process RIPng route according to RFC2080. */
664 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
665 struct ripng_nexthop
*ripng_nexthop
,
666 struct interface
*ifp
)
669 struct prefix_ipv6 p
;
671 struct ripng_info
*rinfo
= NULL
, newinfo
;
672 struct ripng_interface
*ri
;
673 struct in6_addr
*nexthop
;
675 struct list
*list
= NULL
;
676 struct listnode
*node
= NULL
;
678 /* Make prefix structure. */
679 memset(&p
, 0, sizeof(struct prefix_ipv6
));
681 /* p.prefix = rte->addr; */
682 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
683 p
.prefixlen
= rte
->prefixlen
;
685 /* Make sure mask is applied. */
686 /* XXX We have to check the prefix is valid or not before call
690 /* Apply input filters. */
693 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
697 memset(&newinfo
, 0, sizeof(newinfo
));
698 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
699 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
700 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
701 newinfo
.nexthop
= ripng_nexthop
->address
;
703 newinfo
.nexthop
= from
->sin6_addr
;
704 newinfo
.from
= from
->sin6_addr
;
705 newinfo
.ifindex
= ifp
->ifindex
;
706 newinfo
.metric
= rte
->metric
;
707 newinfo
.metric_out
= rte
->metric
; /* XXX */
708 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
711 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
712 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
713 (struct prefix
*)&p
, RMAP_RIPNG
,
716 if (ret
== RMAP_DENYMATCH
) {
717 if (IS_RIPNG_DEBUG_PACKET
)
719 "RIPng %s/%d is filtered by route-map in",
720 inet6_ntoa(p
.prefix
), p
.prefixlen
);
724 /* Get back the object */
725 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
726 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
727 &ripng_nexthop
->address
)) {
728 /* the nexthop get changed by the routemap */
729 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
730 ripng_nexthop
->address
=
733 ripng_nexthop
->address
= in6addr_any
;
736 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
738 /* the nexthop get changed by the routemap */
739 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
740 ripng_nexthop
->flag
=
741 RIPNG_NEXTHOP_ADDRESS
;
742 ripng_nexthop
->address
=
747 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
749 newinfo
.metric_out
; /* XXX: the routemap uses the
753 /* Once the entry has been validated, update the metric by
754 * adding the cost of the network on wich the message
755 * arrived. If the result is greater than infinity, use infinity
756 * (RFC2453 Sec. 3.9.2)
759 /* Zebra ripngd can handle offset-list in. */
760 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
762 /* If offset-list does not modify the metric use interface's
765 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
767 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
768 rte
->metric
= RIPNG_METRIC_INFINITY
;
770 /* Set nexthop pointer. */
771 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
772 nexthop
= &ripng_nexthop
->address
;
774 nexthop
= &from
->sin6_addr
;
776 /* Lookup RIPng routing table. */
777 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
780 newinfo
.nexthop
= *nexthop
;
781 newinfo
.metric
= rte
->metric
;
782 newinfo
.tag
= ntohs(rte
->tag
);
784 /* Check to see whether there is already RIPng route on the table. */
785 if ((list
= rp
->info
) != NULL
)
786 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
787 /* Need to compare with redistributed entry or local
789 if (!ripng_route_rte(rinfo
))
792 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
793 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
796 if (!listnextnode(node
)) {
797 /* Not found in the list */
799 if (rte
->metric
> rinfo
->metric
) {
800 /* New route has a greater metric.
806 if (rte
->metric
< rinfo
->metric
)
807 /* New route has a smaller metric.
808 * Replace the ECMP list
809 * with the new one in below. */
812 /* Metrics are same. Unless ECMP is disabled,
813 * keep "rinfo" null and
814 * the new route is added in the ECMP list in
822 /* Redistributed route check. */
823 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
824 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
829 /* Local static route. */
830 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
831 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
832 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
833 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
840 /* Now, check to see whether there is already an explicit route
841 for the destination prefix. If there is no such route, add
842 this route to the routing table, unless the metric is
843 infinity (there is no point in adding a route which
845 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
846 ripng_ecmp_add(&newinfo
);
850 /* If there is an existing route, compare the next hop address
851 to the address of the router from which the datagram came.
852 If this datagram is from the same router as the existing
853 route, reinitialize the timeout. */
854 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
855 && (rinfo
->ifindex
== ifp
->ifindex
));
858 * RFC 2080 - Section 2.4.2:
859 * "If the new metric is the same as the old one, examine the
861 * for the existing route. If it is at least halfway to the
863 * point, switch to the new route. This heuristic is optional,
865 * highly recommended".
867 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
869 && (thread_timer_remain_second(rinfo
->t_timeout
)
870 < (ripng
->timeout_time
/ 2))) {
871 ripng_ecmp_replace(&newinfo
);
873 /* Next, compare the metrics. If the datagram is from the same
874 router as the existing route, and the new metric is different
875 than the old one; or, if the new metric is lower than the old
876 one; do the following actions: */
877 else if ((same
&& rinfo
->metric
!= rte
->metric
)
878 || rte
->metric
< rinfo
->metric
) {
879 if (listcount(list
) == 1) {
880 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
881 ripng_ecmp_replace(&newinfo
);
883 ripng_ecmp_delete(rinfo
);
885 if (newinfo
.metric
< rinfo
->metric
)
886 ripng_ecmp_replace(&newinfo
);
887 else /* newinfo.metric > rinfo->metric */
888 ripng_ecmp_delete(rinfo
);
890 } else /* same & no change */
891 ripng_timeout_update(rinfo
);
893 /* Unlock tempolary lock of the route. */
898 /* Add redistributed route to RIPng table. */
899 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
900 ifindex_t ifindex
, struct in6_addr
*nexthop
,
904 struct ripng_info
*rinfo
= NULL
, newinfo
;
905 struct list
*list
= NULL
;
907 /* Redistribute route */
908 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
910 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
913 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
915 memset(&newinfo
, 0, sizeof(struct ripng_info
));
917 newinfo
.sub_type
= sub_type
;
918 newinfo
.ifindex
= ifindex
;
920 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
923 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
924 newinfo
.nexthop
= *nexthop
;
926 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
927 rinfo
= listgetdata(listhead(list
));
929 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
930 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
931 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
936 /* Manually configured RIPng route check.
937 * They have the precedence on all the other entries.
939 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
940 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
941 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
942 if (type
!= ZEBRA_ROUTE_RIPNG
943 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
944 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
950 ripng_ecmp_replace(&newinfo
);
953 ripng_ecmp_add(&newinfo
);
955 if (IS_RIPNG_DEBUG_EVENT
) {
958 "Redistribute new prefix %s/%d on the interface %s",
959 inet6_ntoa(p
->prefix
), p
->prefixlen
,
960 ifindex2ifname(ifindex
, VRF_DEFAULT
));
963 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
964 inet6_ntoa(p
->prefix
), p
->prefixlen
,
965 inet6_ntoa(*nexthop
),
966 ifindex2ifname(ifindex
, VRF_DEFAULT
));
969 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
972 /* Delete redistributed route to RIPng table. */
973 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
977 struct ripng_info
*rinfo
;
979 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
981 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
984 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
987 struct list
*list
= rp
->info
;
989 if (list
!= NULL
&& listcount(list
) != 0) {
990 rinfo
= listgetdata(listhead(list
));
991 if (rinfo
!= NULL
&& rinfo
->type
== type
992 && rinfo
->sub_type
== sub_type
993 && rinfo
->ifindex
== ifindex
) {
994 /* Perform poisoned reverse. */
995 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
996 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
997 ripng_garbage_collect
,
998 ripng
->garbage_time
);
999 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1001 /* Aggregate count decrement. */
1002 ripng_aggregate_decrement(rp
, rinfo
);
1004 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1006 if (IS_RIPNG_DEBUG_EVENT
)
1008 "Poisone %s/%d on the interface %s with an "
1009 "infinity metric [delete]",
1010 inet6_ntoa(p
->prefix
),
1012 ifindex2ifname(ifindex
,
1015 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1018 agg_unlock_node(rp
);
1022 /* Withdraw redistributed route. */
1023 void ripng_redistribute_withdraw(int type
)
1025 struct agg_node
*rp
;
1026 struct ripng_info
*rinfo
= NULL
;
1027 struct list
*list
= NULL
;
1032 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1033 if ((list
= rp
->info
) != NULL
) {
1034 rinfo
= listgetdata(listhead(list
));
1035 if ((rinfo
->type
== type
)
1036 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1037 /* Perform poisoned reverse. */
1038 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1039 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1040 ripng_garbage_collect
,
1041 ripng
->garbage_time
);
1042 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1044 /* Aggregate count decrement. */
1045 ripng_aggregate_decrement(rp
, rinfo
);
1047 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1049 if (IS_RIPNG_DEBUG_EVENT
) {
1050 struct prefix_ipv6
*p
=
1051 (struct prefix_ipv6
*)&rp
->p
;
1054 "Poisone %s/%d on the interface %s [withdraw]",
1055 inet6_ntoa(p
->prefix
),
1057 ifindex2ifname(rinfo
->ifindex
,
1061 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1066 /* RIP routing information. */
1067 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1068 struct sockaddr_in6
*from
,
1069 struct interface
*ifp
, int hoplimit
)
1073 struct ripng_nexthop nexthop
;
1075 /* RFC2080 2.4.2 Response Messages:
1076 The Response must be ignored if it is not from the RIPng port. */
1077 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1078 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1079 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1080 ripng_peer_bad_packet(from
);
1084 /* The datagram's IPv6 source address should be checked to see
1085 whether the datagram is from a valid neighbor; the source of the
1086 datagram must be a link-local address. */
1087 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1088 zlog_warn("RIPng packet comes from non link local address %s",
1089 inet6_ntoa(from
->sin6_addr
));
1090 ripng_peer_bad_packet(from
);
1094 /* It is also worth checking to see whether the response is from one
1095 of the router's own addresses. Interfaces on broadcast networks
1096 may receive copies of their own multicasts immediately. If a
1097 router processes its own output as new input, confusion is likely,
1098 and such datagrams must be ignored. */
1099 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1101 "RIPng packet comes from my own link local address %s",
1102 inet6_ntoa(from
->sin6_addr
));
1103 ripng_peer_bad_packet(from
);
1107 /* As an additional check, periodic advertisements must have their
1108 hop counts set to 255, and inbound, multicast packets sent from the
1109 RIPng port (i.e. periodic advertisement or triggered update
1110 packets) must be examined to ensure that the hop count is 255. */
1111 if (hoplimit
>= 0 && hoplimit
!= 255) {
1113 "RIPng packet comes with non 255 hop count %d from %s",
1114 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1115 ripng_peer_bad_packet(from
);
1119 /* Update RIPng peer. */
1120 ripng_peer_update(from
, packet
->version
);
1122 /* Reset nexthop. */
1123 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1124 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1126 /* Set RTE pointer. */
1129 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1130 /* First of all, we have to check this RTE is next hop RTE or
1131 not. Next hop RTE is completely different with normal RTE so
1132 we need special treatment. */
1133 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1134 ripng_nexthop_rte(rte
, from
, &nexthop
);
1138 /* RTE information validation. */
1140 /* - is the destination prefix valid (e.g., not a multicast
1141 prefix and not a link-local address) A link-local address
1142 should never be present in an RTE. */
1143 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1145 "Destination prefix is a multicast address %s/%d [%d]",
1146 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1148 ripng_peer_bad_route(from
);
1151 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1153 "Destination prefix is a link-local address %s/%d [%d]",
1154 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1156 ripng_peer_bad_route(from
);
1159 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1161 "Destination prefix is a loopback address %s/%d [%d]",
1162 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1164 ripng_peer_bad_route(from
);
1168 /* - is the prefix length valid (i.e., between 0 and 128,
1170 if (rte
->prefixlen
> 128) {
1171 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1172 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1173 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1174 ripng_peer_bad_route(from
);
1178 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1179 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1180 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1181 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1182 ripng_peer_bad_route(from
);
1186 /* Vincent: XXX Should we compute the direclty reachable nexthop
1187 * for our RIPng network ?
1190 /* Routing table updates. */
1191 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1195 /* Response to request message. */
1196 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1197 struct sockaddr_in6
*from
,
1198 struct interface
*ifp
)
1202 struct prefix_ipv6 p
;
1203 struct agg_node
*rp
;
1204 struct ripng_info
*rinfo
;
1205 struct ripng_interface
*ri
;
1207 /* Does not reponse to the requests on the loopback interfaces */
1208 if (if_is_loopback(ifp
))
1211 /* Check RIPng process is enabled on this interface. */
1216 /* When passive interface is specified, suppress responses */
1220 /* RIPng peer update. */
1221 ripng_peer_update(from
, packet
->version
);
1223 lim
= ((caddr_t
)packet
) + size
;
1226 /* The Request is processed entry by entry. If there are no
1227 entries, no response is given. */
1228 if (lim
== (caddr_t
)rte
)
1231 /* There is one special case. If there is exactly one entry in the
1232 request, and it has a destination prefix of zero, a prefix length
1233 of zero, and a metric of infinity (i.e., 16), then this is a
1234 request to send the entire routing table. In that case, a call
1235 is made to the output process to send the routing table to the
1236 requesting address/port. */
1237 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1238 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1239 /* All route with split horizon */
1240 ripng_output_process(ifp
, from
, ripng_all_route
);
1242 /* Except for this special case, processing is quite simple.
1243 Examine the list of RTEs in the Request one by one. For each
1244 entry, look up the destination in the router's routing
1245 database and, if there is a route, put that route's metric in
1246 the metric field of the RTE. If there is no explicit route
1247 to the specified destination, put infinity in the metric
1248 field. Once all the entries have been filled in, change the
1249 command from Request to Response and send the datagram back
1250 to the requestor. */
1251 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1252 p
.family
= AF_INET6
;
1254 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1255 p
.prefix
= rte
->addr
;
1256 p
.prefixlen
= rte
->prefixlen
;
1257 apply_mask_ipv6(&p
);
1259 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1262 rinfo
= listgetdata(
1263 listhead((struct list
*)rp
->info
));
1264 rte
->metric
= rinfo
->metric
;
1265 agg_unlock_node(rp
);
1267 rte
->metric
= RIPNG_METRIC_INFINITY
;
1269 packet
->command
= RIPNG_RESPONSE
;
1271 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1275 /* First entry point of reading RIPng packet. */
1276 static int ripng_read(struct thread
*thread
)
1280 struct sockaddr_in6 from
;
1281 struct ripng_packet
*packet
;
1282 ifindex_t ifindex
= 0;
1283 struct interface
*ifp
;
1286 /* Check ripng is active and alive. */
1287 assert(ripng
!= NULL
);
1288 assert(ripng
->sock
>= 0);
1290 /* Fetch thread data and set read pointer to empty for event
1291 managing. `sock' sould be same as ripng->sock. */
1292 sock
= THREAD_FD(thread
);
1293 ripng
->t_read
= NULL
;
1295 /* Add myself to the next event. */
1296 ripng_event(RIPNG_READ
, sock
);
1298 /* Read RIPng packet. */
1299 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1300 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1303 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1307 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1308 (4)) must be multiple size of one RTE size (20). */
1309 if (((len
- 4) % 20) != 0) {
1310 zlog_warn("RIPng invalid packet size %d from %s", len
,
1311 inet6_ntoa(from
.sin6_addr
));
1312 ripng_peer_bad_packet(&from
);
1316 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1317 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1319 /* RIPng packet received. */
1320 if (IS_RIPNG_DEBUG_EVENT
)
1321 zlog_debug("RIPng packet received from %s port %d on %s",
1322 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1323 ifp
? ifp
->name
: "unknown");
1325 /* Logging before packet checking. */
1326 if (IS_RIPNG_DEBUG_RECV
)
1327 ripng_packet_dump(packet
, len
, "RECV");
1329 /* Packet comes from unknown interface. */
1331 zlog_warn("RIPng packet comes from unknown interface %d",
1336 /* Packet version mismatch checking. */
1337 if (packet
->version
!= ripng
->version
) {
1339 "RIPng packet version %d doesn't fit to my version %d",
1340 packet
->version
, ripng
->version
);
1341 ripng_peer_bad_packet(&from
);
1345 /* Process RIPng packet. */
1346 switch (packet
->command
) {
1348 ripng_request_process(packet
, len
, &from
, ifp
);
1350 case RIPNG_RESPONSE
:
1351 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1354 zlog_warn("Invalid RIPng command %d", packet
->command
);
1355 ripng_peer_bad_packet(&from
);
1361 /* Walk down the RIPng routing table then clear changed flag. */
1362 static void ripng_clear_changed_flag(void)
1364 struct agg_node
*rp
;
1365 struct ripng_info
*rinfo
= NULL
;
1366 struct list
*list
= NULL
;
1367 struct listnode
*listnode
= NULL
;
1369 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1370 if ((list
= rp
->info
) != NULL
)
1371 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1372 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1373 /* This flag can be set only on the first entry.
1379 /* Regular update of RIPng route. Send all routing formation to RIPng
1380 enabled interface. */
1381 static int ripng_update(struct thread
*t
)
1383 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1384 struct interface
*ifp
;
1385 struct ripng_interface
*ri
;
1387 /* Clear update timer thread. */
1388 ripng
->t_update
= NULL
;
1390 /* Logging update event. */
1391 if (IS_RIPNG_DEBUG_EVENT
)
1392 zlog_debug("RIPng update timer expired!");
1394 /* Supply routes to each interface. */
1395 FOR_ALL_INTERFACES (vrf
, ifp
) {
1398 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1404 /* When passive interface is specified, suppress announce to the
1410 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1411 if (IS_RIPNG_DEBUG_EVENT
)
1413 "[Event] RIPng send to if %d is suppressed by config",
1417 #endif /* RIPNG_ADVANCED */
1419 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1422 /* Triggered updates may be suppressed if a regular update is due by
1423 the time the triggered update would be sent. */
1424 if (ripng
->t_triggered_interval
) {
1425 thread_cancel(ripng
->t_triggered_interval
);
1426 ripng
->t_triggered_interval
= NULL
;
1430 /* Reset flush event. */
1431 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1436 /* Triggered update interval timer. */
1437 static int ripng_triggered_interval(struct thread
*t
)
1439 ripng
->t_triggered_interval
= NULL
;
1441 if (ripng
->trigger
) {
1443 ripng_triggered_update(t
);
1448 /* Execute triggered update. */
1449 int ripng_triggered_update(struct thread
*t
)
1451 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1452 struct interface
*ifp
;
1453 struct ripng_interface
*ri
;
1456 ripng
->t_triggered_update
= NULL
;
1458 /* Cancel interval timer. */
1459 if (ripng
->t_triggered_interval
) {
1460 thread_cancel(ripng
->t_triggered_interval
);
1461 ripng
->t_triggered_interval
= NULL
;
1465 /* Logging triggered update. */
1466 if (IS_RIPNG_DEBUG_EVENT
)
1467 zlog_debug("RIPng triggered update!");
1469 /* Split Horizon processing is done when generating triggered
1470 updates as well as normal updates (see section 2.6). */
1471 FOR_ALL_INTERFACES (vrf
, ifp
) {
1474 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1480 /* When passive interface is specified, suppress announce to the
1485 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1488 /* Once all of the triggered updates have been generated, the route
1489 change flags should be cleared. */
1490 ripng_clear_changed_flag();
1492 /* After a triggered update is sent, a timer should be set for a
1493 random interval between 1 and 5 seconds. If other changes that
1494 would trigger updates occur before the timer expires, a single
1495 update is triggered when the timer expires. */
1496 interval
= (random() % 5) + 1;
1498 ripng
->t_triggered_interval
= NULL
;
1499 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1500 &ripng
->t_triggered_interval
);
1505 /* Write routing table entry to the stream and return next index of
1506 the routing table entry in the stream. */
1507 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1508 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1510 /* RIPng packet header. */
1512 stream_putc(s
, RIPNG_RESPONSE
);
1513 stream_putc(s
, RIPNG_V1
);
1517 /* Write routing table entry. */
1520 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1522 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1523 stream_putw(s
, tag
);
1525 stream_putc(s
, p
->prefixlen
);
1528 stream_putc(s
, metric
);
1533 /* Send RESPONSE message to specified destination. */
1534 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1538 struct agg_node
*rp
;
1539 struct ripng_info
*rinfo
;
1540 struct ripng_interface
*ri
;
1541 struct ripng_aggregate
*aggregate
;
1542 struct prefix_ipv6
*p
;
1543 struct list
*ripng_rte_list
;
1544 struct list
*list
= NULL
;
1545 struct listnode
*listnode
= NULL
;
1547 if (IS_RIPNG_DEBUG_EVENT
) {
1549 zlog_debug("RIPng update routes to neighbor %s",
1550 inet6_ntoa(to
->sin6_addr
));
1552 zlog_debug("RIPng update routes on interface %s",
1556 /* Get RIPng interface. */
1559 ripng_rte_list
= ripng_rte_new();
1561 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1562 if ((list
= rp
->info
) != NULL
1563 && (rinfo
= listgetdata(listhead(list
))) != NULL
1564 && rinfo
->suppress
== 0) {
1565 /* If no route-map are applied, the RTE will be these
1569 p
= (struct prefix_ipv6
*)&rp
->p
;
1570 rinfo
->metric_out
= rinfo
->metric
;
1571 rinfo
->tag_out
= rinfo
->tag
;
1572 memset(&rinfo
->nexthop_out
, 0,
1573 sizeof(rinfo
->nexthop_out
));
1574 /* In order to avoid some local loops,
1575 * if the RIPng route has a nexthop via this interface,
1577 * otherwise set it to 0. The nexthop should not be
1579 * beyond the local broadcast/multicast area in order
1580 * to avoid an IGP multi-level recursive look-up.
1582 if (rinfo
->ifindex
== ifp
->ifindex
)
1583 rinfo
->nexthop_out
= rinfo
->nexthop
;
1585 /* Apply output filters. */
1586 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1590 /* Changed route only output. */
1591 if (route_type
== ripng_changed_route
1592 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1595 /* Split horizon. */
1596 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1597 /* We perform split horizon for RIPng routes. */
1599 struct ripng_info
*tmp_rinfo
= NULL
;
1601 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1603 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1604 && tmp_rinfo
->ifindex
1613 /* Preparation for route-map. */
1614 rinfo
->metric_set
= 0;
1617 * and tag_out are already initialized.
1620 /* Interface route-map */
1621 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1622 ret
= route_map_apply(
1623 ri
->routemap
[RIPNG_FILTER_OUT
],
1624 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1626 if (ret
== RMAP_DENYMATCH
) {
1627 if (IS_RIPNG_DEBUG_PACKET
)
1629 "RIPng %s/%d is filtered by route-map out",
1630 inet6_ntoa(p
->prefix
),
1636 /* Redistribute route-map. */
1637 if (ripng
->route_map
[rinfo
->type
].name
) {
1638 ret
= route_map_apply(
1639 ripng
->route_map
[rinfo
->type
].map
,
1640 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1642 if (ret
== RMAP_DENYMATCH
) {
1643 if (IS_RIPNG_DEBUG_PACKET
)
1645 "RIPng %s/%d is filtered by route-map",
1646 inet6_ntoa(p
->prefix
),
1652 /* When the route-map does not set metric. */
1653 if (!rinfo
->metric_set
) {
1654 /* If the redistribute metric is set. */
1655 if (ripng
->route_map
[rinfo
->type
].metric_config
1656 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1658 ripng
->route_map
[rinfo
->type
]
1661 /* If the route is not connected or
1663 one, use default-metric value */
1664 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1666 != ZEBRA_ROUTE_CONNECT
1668 != RIPNG_METRIC_INFINITY
)
1670 ripng
->default_metric
;
1674 /* Apply offset-list */
1675 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1676 ripng_offset_list_apply_out(p
, ifp
,
1677 &rinfo
->metric_out
);
1679 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1680 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1682 /* Perform split-horizon with poisoned reverse
1685 if (ri
->split_horizon
1686 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1687 struct ripng_info
*tmp_rinfo
= NULL
;
1689 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1691 if ((tmp_rinfo
->type
1692 == ZEBRA_ROUTE_RIPNG
)
1693 && tmp_rinfo
->ifindex
1696 RIPNG_METRIC_INFINITY
;
1699 /* Add RTE to the list */
1700 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1703 /* Process the aggregated RTE entry */
1704 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1705 && aggregate
->suppress
== 0) {
1706 /* If no route-map are applied, the RTE will be these
1710 p
= (struct prefix_ipv6
*)&rp
->p
;
1711 aggregate
->metric_set
= 0;
1712 aggregate
->metric_out
= aggregate
->metric
;
1713 aggregate
->tag_out
= aggregate
->tag
;
1714 memset(&aggregate
->nexthop_out
, 0,
1715 sizeof(aggregate
->nexthop_out
));
1717 /* Apply output filters.*/
1718 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1722 /* Interface route-map */
1723 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1724 struct ripng_info newinfo
;
1726 /* let's cast the aggregate structure to
1728 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1729 /* the nexthop is :: */
1730 newinfo
.metric
= aggregate
->metric
;
1731 newinfo
.metric_out
= aggregate
->metric_out
;
1732 newinfo
.tag
= aggregate
->tag
;
1733 newinfo
.tag_out
= aggregate
->tag_out
;
1735 ret
= route_map_apply(
1736 ri
->routemap
[RIPNG_FILTER_OUT
],
1737 (struct prefix
*)p
, RMAP_RIPNG
,
1740 if (ret
== RMAP_DENYMATCH
) {
1741 if (IS_RIPNG_DEBUG_PACKET
)
1743 "RIPng %s/%d is filtered by route-map out",
1744 inet6_ntoa(p
->prefix
),
1749 aggregate
->metric_out
= newinfo
.metric_out
;
1750 aggregate
->tag_out
= newinfo
.tag_out
;
1751 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1752 aggregate
->nexthop_out
=
1753 newinfo
.nexthop_out
;
1756 /* There is no redistribute routemap for the aggregated
1759 /* Changed route only output. */
1760 /* XXX, vincent, in order to increase time convergence,
1761 * it should be announced if a child has changed.
1763 if (route_type
== ripng_changed_route
)
1766 /* Apply offset-list */
1767 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1768 ripng_offset_list_apply_out(
1769 p
, ifp
, &aggregate
->metric_out
);
1771 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1772 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1774 /* Add RTE to the list */
1775 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1779 /* Flush the list */
1780 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1781 ripng_rte_free(ripng_rte_list
);
1784 /* Create new RIPng instance and set it to global variable. */
1785 int ripng_create(int socket
)
1787 /* ripng should be NULL. */
1788 assert(ripng
== NULL
);
1790 /* Allocaste RIPng instance. */
1791 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1793 /* Default version and timer values. */
1794 ripng
->version
= RIPNG_V1
;
1795 ripng
->update_time
= yang_get_default_uint32(
1796 "%s/timers/update-interval", RIPNG_INSTANCE
);
1797 ripng
->timeout_time
= yang_get_default_uint32(
1798 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1799 ripng
->garbage_time
= yang_get_default_uint32(
1800 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1801 ripng
->default_metric
=
1802 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1803 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1806 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1807 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1809 /* Initialize RIPng routig table. */
1810 ripng
->table
= agg_table_init();
1812 /* Distribute list install. */
1813 ripng
->distribute_ctx
= distribute_list_ctx_create(
1814 vrf_lookup_by_id(VRF_DEFAULT
));
1815 distribute_list_add_hook(ripng
->distribute_ctx
,
1816 ripng_distribute_update
);
1817 distribute_list_delete_hook(ripng
->distribute_ctx
,
1818 ripng_distribute_update
);
1820 ripng
->sock
= socket
;
1823 ripng_event(RIPNG_READ
, ripng
->sock
);
1824 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1829 /* Send RIPng request to the interface. */
1830 int ripng_request(struct interface
*ifp
)
1833 struct ripng_packet ripng_packet
;
1835 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1837 if (if_is_loopback(ifp
))
1840 /* If interface is down, don't send RIP packet. */
1844 if (IS_RIPNG_DEBUG_EVENT
)
1845 zlog_debug("RIPng send request to %s", ifp
->name
);
1847 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1848 ripng_packet
.command
= RIPNG_REQUEST
;
1849 ripng_packet
.version
= RIPNG_V1
;
1850 rte
= ripng_packet
.rte
;
1851 rte
->metric
= RIPNG_METRIC_INFINITY
;
1853 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1858 static int ripng_update_jitter(int time
)
1860 return ((random() % (time
+ 1)) - (time
/ 2));
1863 void ripng_event(enum ripng_event event
, int sock
)
1869 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1871 case RIPNG_UPDATE_EVENT
:
1872 if (ripng
->t_update
) {
1873 thread_cancel(ripng
->t_update
);
1874 ripng
->t_update
= NULL
;
1876 /* Update timer jitter. */
1877 jitter
= ripng_update_jitter(ripng
->update_time
);
1879 ripng
->t_update
= NULL
;
1880 thread_add_timer(master
, ripng_update
, NULL
,
1881 sock
? 2 : ripng
->update_time
+ jitter
,
1884 case RIPNG_TRIGGERED_UPDATE
:
1885 if (ripng
->t_triggered_interval
)
1888 thread_add_event(master
, ripng_triggered_update
, NULL
,
1889 0, &ripng
->t_triggered_update
);
1897 /* Print out routes update time. */
1898 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1903 char timebuf
[TIME_BUF
];
1904 struct thread
*thread
;
1906 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1907 clock
= thread_timer_remain_second(thread
);
1908 tm
= gmtime(&clock
);
1909 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1910 vty_out(vty
, "%5s", timebuf
);
1911 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1912 clock
= thread_timer_remain_second(thread
);
1913 tm
= gmtime(&clock
);
1914 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1915 vty_out(vty
, "%5s", timebuf
);
1919 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1924 if (rinfo
->suppress
)
1927 switch (rinfo
->sub_type
) {
1928 case RIPNG_ROUTE_RTE
:
1931 case RIPNG_ROUTE_STATIC
:
1934 case RIPNG_ROUTE_DEFAULT
:
1937 case RIPNG_ROUTE_REDISTRIBUTE
:
1940 case RIPNG_ROUTE_INTERFACE
:
1951 DEFUN (show_ipv6_ripng
,
1952 show_ipv6_ripng_cmd
,
1956 "Show RIPng routes\n")
1958 struct agg_node
*rp
;
1959 struct ripng_info
*rinfo
;
1960 struct ripng_aggregate
*aggregate
;
1961 struct prefix_ipv6
*p
;
1962 struct list
*list
= NULL
;
1963 struct listnode
*listnode
= NULL
;
1969 /* Header of display. */
1971 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1973 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1974 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1975 " Network Next Hop Via Metric Tag Time\n");
1977 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1978 if ((aggregate
= rp
->aggregate
) != NULL
) {
1979 p
= (struct prefix_ipv6
*)&rp
->p
;
1982 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1983 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1986 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1990 vty_out(vty
, "%*s", 18, " ");
1992 vty_out(vty
, "%*s", 28, " ");
1993 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1994 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1997 if ((list
= rp
->info
) != NULL
)
1998 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1999 p
= (struct prefix_ipv6
*)&rp
->p
;
2002 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2003 zebra_route_char(rinfo
->type
),
2004 ripng_route_subtype_print(rinfo
),
2005 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2008 vty_out(vty
, "%c(%s) %s/%d ",
2009 zebra_route_char(rinfo
->type
),
2010 ripng_route_subtype_print(rinfo
),
2011 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2014 vty_out(vty
, "%*s", 18, " ");
2015 len
= vty_out(vty
, "%s",
2016 inet6_ntoa(rinfo
->nexthop
));
2020 vty_out(vty
, "%*s", len
, " ");
2023 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2024 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2027 ifindex2ifname(rinfo
->ifindex
,
2029 } else if (rinfo
->metric
2030 == RIPNG_METRIC_INFINITY
) {
2031 len
= vty_out(vty
, "kill");
2033 len
= vty_out(vty
, "self");
2037 vty_out(vty
, "%*s", len
, " ");
2039 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2040 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2043 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2044 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2045 /* RTE from remote RIP routers */
2046 ripng_vty_out_uptime(vty
, rinfo
);
2047 } else if (rinfo
->metric
2048 == RIPNG_METRIC_INFINITY
) {
2049 /* poisonous reversed routes (gc) */
2050 ripng_vty_out_uptime(vty
, rinfo
);
2060 DEFUN (show_ipv6_ripng_status
,
2061 show_ipv6_ripng_status_cmd
,
2062 "show ipv6 ripng status",
2065 "Show RIPng routes\n"
2066 "IPv6 routing protocol process parameters and statistics\n")
2068 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2069 struct interface
*ifp
;
2074 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2075 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2076 ripng
->update_time
);
2077 vty_out(vty
, " next due in %lu seconds\n",
2078 thread_timer_remain_second(ripng
->t_update
));
2079 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2080 vty_out(vty
, " garbage collect after %u seconds\n",
2081 ripng
->garbage_time
);
2083 /* Filtering status show. */
2084 config_show_distribute(vty
, ripng
->distribute_ctx
);
2086 /* Default metric information. */
2087 vty_out(vty
, " Default redistribution metric is %d\n",
2088 ripng
->default_metric
);
2090 /* Redistribute information. */
2091 vty_out(vty
, " Redistributing:");
2092 ripng_redistribute_write(vty
);
2095 vty_out(vty
, " Default version control: send version %d,",
2097 vty_out(vty
, " receive version %d \n", ripng
->version
);
2099 vty_out(vty
, " Interface Send Recv\n");
2101 FOR_ALL_INTERFACES (vrf
, ifp
) {
2102 struct ripng_interface
*ri
;
2106 if (ri
->enable_network
|| ri
->enable_interface
) {
2108 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2109 ripng
->version
, ripng
->version
);
2113 vty_out(vty
, " Routing for Networks:\n");
2114 ripng_network_write(vty
);
2116 vty_out(vty
, " Routing Information Sources:\n");
2118 " Gateway BadPackets BadRoutes Distance Last Update\n");
2119 ripng_peer_display(vty
);
2125 /* RIPng update timer setup. */
2126 DEFUN (ripng_update_timer
,
2127 ripng_update_timer_cmd
,
2128 "update-timer SECOND",
2129 "Set RIPng update timer in seconds\n"
2132 unsigned long update
;
2133 char *endptr
= NULL
;
2135 update
= strtoul (argv
[0], &endptr
, 10);
2136 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2138 vty_out (vty
, "update timer value error\n");
2139 return CMD_WARNING_CONFIG_FAILED
;
2142 ripng
->update_time
= update
;
2144 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2148 DEFUN (no_ripng_update_timer
,
2149 no_ripng_update_timer_cmd
,
2150 "no update-timer SECOND",
2152 "Unset RIPng update timer in seconds\n"
2155 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2156 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2160 /* RIPng timeout timer setup. */
2161 DEFUN (ripng_timeout_timer
,
2162 ripng_timeout_timer_cmd
,
2163 "timeout-timer SECOND",
2164 "Set RIPng timeout timer in seconds\n"
2167 unsigned long timeout
;
2168 char *endptr
= NULL
;
2170 timeout
= strtoul (argv
[0], &endptr
, 10);
2171 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2173 vty_out (vty
, "timeout timer value error\n");
2174 return CMD_WARNING_CONFIG_FAILED
;
2177 ripng
->timeout_time
= timeout
;
2182 DEFUN (no_ripng_timeout_timer
,
2183 no_ripng_timeout_timer_cmd
,
2184 "no timeout-timer SECOND",
2186 "Unset RIPng timeout timer in seconds\n"
2189 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2193 /* RIPng garbage timer setup. */
2194 DEFUN (ripng_garbage_timer
,
2195 ripng_garbage_timer_cmd
,
2196 "garbage-timer SECOND",
2197 "Set RIPng garbage timer in seconds\n"
2200 unsigned long garbage
;
2201 char *endptr
= NULL
;
2203 garbage
= strtoul (argv
[0], &endptr
, 10);
2204 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2206 vty_out (vty
, "garbage timer value error\n");
2207 return CMD_WARNING_CONFIG_FAILED
;
2210 ripng
->garbage_time
= garbage
;
2215 DEFUN (no_ripng_garbage_timer
,
2216 no_ripng_garbage_timer_cmd
,
2217 "no garbage-timer SECOND",
2219 "Unset RIPng garbage timer in seconds\n"
2222 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2228 DEFUN (show_ipv6_protocols
,
2229 show_ipv6_protocols_cmd
,
2230 "show ipv6 protocols",
2233 "Routing protocol information\n")
2238 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2240 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2241 ripng
->update_time
, 0);
2243 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2244 ripng
->timeout_time
,
2245 ripng
->garbage_time
);
2247 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2248 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2254 /* Update ECMP routes to zebra when ECMP is disabled. */
2255 void ripng_ecmp_disable(void)
2257 struct agg_node
*rp
;
2258 struct ripng_info
*rinfo
, *tmp_rinfo
;
2260 struct listnode
*node
, *nextnode
;
2265 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2266 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2267 rinfo
= listgetdata(listhead(list
));
2268 if (!ripng_route_rte(rinfo
))
2271 /* Drop all other entries, except the first one. */
2272 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2273 if (tmp_rinfo
!= rinfo
) {
2274 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2276 tmp_rinfo
->t_garbage_collect
);
2277 list_delete_node(list
, node
);
2278 ripng_info_free(tmp_rinfo
);
2282 ripng_zebra_ipv6_add(rp
);
2284 /* Set the route change flag. */
2285 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2287 /* Signal the output process to trigger an update. */
2288 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2292 /* RIPng configuration write function. */
2293 static int ripng_config_write(struct vty
*vty
)
2295 struct lyd_node
*dnode
;
2298 dnode
= yang_dnode_get(running_config
->dnode
,
2299 "/frr-ripngd:ripngd/instance");
2301 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2303 config_write_distribute(vty
,
2304 ripng
->distribute_ctx
);
2306 config_write_if_rmap(vty
);
2314 /* RIPng node structure. */
2315 static struct cmd_node cmd_ripng_node
= {
2316 RIPNG_NODE
, "%s(config-router)# ", 1,
2319 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2320 struct distribute
*dist
)
2322 struct interface
*ifp
;
2323 struct ripng_interface
*ri
;
2324 struct access_list
*alist
;
2325 struct prefix_list
*plist
;
2330 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2336 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2337 alist
= access_list_lookup(AFI_IP6
,
2338 dist
->list
[DISTRIBUTE_V6_IN
]);
2340 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2342 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2344 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2346 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2347 alist
= access_list_lookup(AFI_IP6
,
2348 dist
->list
[DISTRIBUTE_V6_OUT
]);
2350 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2352 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2354 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2356 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2357 plist
= prefix_list_lookup(AFI_IP6
,
2358 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2360 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2362 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2364 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2366 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2367 plist
= prefix_list_lookup(AFI_IP6
,
2368 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2370 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2372 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2374 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2377 void ripng_distribute_update_interface(struct interface
*ifp
)
2379 struct distribute
*dist
;
2383 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2385 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2388 /* Update all interface's distribute list. */
2389 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2391 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2392 struct interface
*ifp
;
2394 FOR_ALL_INTERFACES (vrf
, ifp
)
2395 ripng_distribute_update_interface(ifp
);
2398 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2400 ripng_distribute_update_all(NULL
);
2403 /* delete all the added ripng routes. */
2407 struct agg_node
*rp
;
2408 struct ripng_info
*rinfo
;
2409 struct ripng_aggregate
*aggregate
;
2410 struct list
*list
= NULL
;
2411 struct listnode
*listnode
= NULL
;
2414 /* Clear RIPng routes */
2415 for (rp
= agg_route_top(ripng
->table
); rp
;
2416 rp
= agg_route_next(rp
)) {
2417 if ((list
= rp
->info
) != NULL
) {
2418 rinfo
= listgetdata(listhead(list
));
2419 if (ripng_route_rte(rinfo
))
2420 ripng_zebra_ipv6_delete(rp
);
2422 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2424 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2426 rinfo
->t_garbage_collect
);
2427 ripng_info_free(rinfo
);
2431 agg_unlock_node(rp
);
2434 if ((aggregate
= rp
->aggregate
) != NULL
) {
2435 ripng_aggregate_free(aggregate
);
2436 rp
->aggregate
= NULL
;
2437 agg_unlock_node(rp
);
2441 /* Cancel the RIPng timers */
2442 RIPNG_TIMER_OFF(ripng
->t_update
);
2443 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2444 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2446 /* Cancel the read thread */
2447 if (ripng
->t_read
) {
2448 thread_cancel(ripng
->t_read
);
2449 ripng
->t_read
= NULL
;
2452 /* Close the RIPng socket */
2453 if (ripng
->sock
>= 0) {
2458 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2459 if (ripng
->route_map
[i
].name
)
2460 free(ripng
->route_map
[i
].name
);
2462 agg_table_finish(ripng
->table
);
2464 stream_free(ripng
->ibuf
);
2465 stream_free(ripng
->obuf
);
2467 distribute_list_delete(&ripng
->distribute_ctx
);
2468 XFREE(MTYPE_RIPNG
, ripng
);
2472 ripng_clean_network();
2473 ripng_passive_interface_clean();
2474 ripng_offset_clean();
2475 ripng_interface_clean();
2476 ripng_redistribute_clean();
2479 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2481 struct interface
*ifp
;
2482 struct ripng_interface
*ri
;
2483 struct route_map
*rmap
;
2485 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2491 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2492 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2494 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2496 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2498 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2500 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2501 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2503 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2505 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2507 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2510 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2512 struct if_rmap
*if_rmap
;
2514 if_rmap
= if_rmap_lookup(ifp
->name
);
2516 ripng_if_rmap_update(if_rmap
);
2519 static void ripng_routemap_update_redistribute(void)
2524 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2525 if (ripng
->route_map
[i
].name
)
2526 ripng
->route_map
[i
].map
=
2527 route_map_lookup_by_name(
2528 ripng
->route_map
[i
].name
);
2533 static void ripng_routemap_update(const char *unused
)
2535 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2536 struct interface
*ifp
;
2538 FOR_ALL_INTERFACES (vrf
, ifp
)
2539 ripng_if_rmap_update_interface(ifp
);
2541 ripng_routemap_update_redistribute();
2544 /* Initialize ripng structure and set commands. */
2547 /* Install RIPNG_NODE. */
2548 install_node(&cmd_ripng_node
, ripng_config_write
);
2550 /* Install ripng commands. */
2551 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2552 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2554 install_default(RIPNG_NODE
);
2557 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2558 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2559 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2560 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2561 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2562 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2563 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2569 /* Access list install. */
2571 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2572 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2574 /* Prefix list initialize.*/
2576 prefix_list_add_hook(ripng_distribute_update_all
);
2577 prefix_list_delete_hook(ripng_distribute_update_all
);
2579 /* Distribute list install. */
2580 distribute_list_init(RIPNG_NODE
);
2582 /* Route-map for interface. */
2583 ripng_route_map_init();
2584 ripng_offset_init();
2586 route_map_add_hook(ripng_routemap_update
);
2587 route_map_delete_hook(ripng_routemap_update
);
2589 if_rmap_init(RIPNG_NODE
);
2590 if_rmap_hook_add(ripng_if_rmap_update
);
2591 if_rmap_hook_delete(ripng_if_rmap_update
);