2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "agg_table.h"
33 #include "distribute.h"
38 #include "lib_errors.h"
39 #include "northbound_cli.h"
41 #include "ripngd/ripngd.h"
42 #include "ripngd/ripng_route.h"
43 #include "ripngd/ripng_debug.h"
44 #include "ripngd/ripng_nexthop.h"
46 enum { ripng_all_route
,
50 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
51 struct distribute
*dist
);
54 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
55 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
57 static void ripng_instance_disable(struct ripng
*ripng
);
59 int ripng_triggered_update(struct thread
*);
61 /* Generate rb-tree of RIPng instances. */
62 static inline int ripng_instance_compare(const struct ripng
*a
,
63 const struct ripng
*b
)
65 return strcmp(a
->vrf_name
, b
->vrf_name
);
67 RB_GENERATE(ripng_instance_head
, ripng
, entry
, ripng_instance_compare
)
69 struct ripng_instance_head ripng_instances
= RB_INITIALIZER(&ripng_instances
);
71 /* RIPng next hop specification. */
72 struct ripng_nexthop
{
73 enum ripng_nexthop_type
{
77 struct in6_addr address
;
80 int ripng_route_rte(struct ripng_info
*rinfo
)
82 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
83 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
86 /* Allocate new ripng information. */
87 struct ripng_info
*ripng_info_new()
89 struct ripng_info
*new;
91 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
95 /* Free ripng information. */
96 void ripng_info_free(struct ripng_info
*rinfo
)
98 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
101 struct ripng
*ripng_info_get_instance(const struct ripng_info
*rinfo
)
103 return agg_get_table_info(agg_get_table(rinfo
->rp
));
106 /* Create ripng socket. */
107 int ripng_make_socket(struct vrf
*vrf
)
111 struct sockaddr_in6 ripaddr
;
112 const char *vrf_dev
= NULL
;
114 /* Make datagram socket. */
115 if (vrf
->vrf_id
!= VRF_DEFAULT
)
117 frr_elevate_privs(&ripngd_privs
)
119 sock
= vrf_socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
,
120 vrf
->vrf_id
, vrf_dev
);
122 flog_err_sys(EC_LIB_SOCKET
,
123 "Cannot create UDP socket: %s",
124 safe_strerror(errno
));
129 sockopt_reuseaddr(sock
);
130 sockopt_reuseport(sock
);
131 setsockopt_so_recvbuf(sock
, 8096);
132 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
135 #ifdef IPTOS_PREC_INTERNETCONTROL
136 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
140 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
143 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
146 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
150 memset(&ripaddr
, 0, sizeof(ripaddr
));
151 ripaddr
.sin6_family
= AF_INET6
;
153 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
154 #endif /* SIN6_LEN */
155 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
157 frr_elevate_privs(&ripngd_privs
) {
158 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
160 zlog_err("Can't bind ripng socket: %s.",
161 safe_strerror(errno
));
172 /* Send RIPng packet. */
173 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
174 struct interface
*ifp
)
176 struct ripng_interface
*ri
= ifp
->info
;
177 struct ripng
*ripng
= ri
->ripng
;
181 struct cmsghdr
*cmsgptr
;
182 char adata
[256] = {};
183 struct in6_pktinfo
*pkt
;
184 struct sockaddr_in6 addr
;
186 if (IS_RIPNG_DEBUG_SEND
) {
188 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
189 zlog_debug(" send interface %s", ifp
->name
);
190 zlog_debug(" send packet size %d", bufsize
);
193 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
194 addr
.sin6_family
= AF_INET6
;
196 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
197 #endif /* SIN6_LEN */
198 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
200 /* When destination is specified. */
202 addr
.sin6_addr
= to
->sin6_addr
;
203 addr
.sin6_port
= to
->sin6_port
;
205 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
206 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
209 memset(&msg
, 0, sizeof(msg
));
210 msg
.msg_name
= (void *)&addr
;
211 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
214 msg
.msg_control
= (void *)adata
;
215 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
218 iov
.iov_len
= bufsize
;
220 cmsgptr
= (struct cmsghdr
*)adata
;
221 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
222 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
223 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
225 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
226 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
227 pkt
->ipi6_ifindex
= ifp
->ifindex
;
229 ret
= sendmsg(ripng
->sock
, &msg
, 0);
233 flog_err_sys(EC_LIB_SOCKET
,
234 "RIPng send fail on %s to %s: %s",
235 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
236 safe_strerror(errno
));
238 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
239 ifp
->name
, safe_strerror(errno
));
245 /* Receive UDP RIPng packet from socket. */
246 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
247 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
253 struct cmsghdr
*cmsgptr
;
254 struct in6_addr dst
= {.s6_addr
= {0}};
256 memset(&dst
, 0, sizeof(struct in6_addr
));
258 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
259 point I can't determine size of cmsghdr */
262 /* Fill in message and iovec. */
263 memset(&msg
, 0, sizeof(msg
));
264 msg
.msg_name
= (void *)from
;
265 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
268 msg
.msg_control
= (void *)adata
;
269 msg
.msg_controllen
= sizeof adata
;
271 iov
.iov_len
= bufsize
;
273 /* If recvmsg fail return minus value. */
274 ret
= recvmsg(sock
, &msg
, 0);
278 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
279 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
280 /* I want interface index which this packet comes from. */
281 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
282 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
283 struct in6_pktinfo
*ptr
;
285 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
286 *ifindex
= ptr
->ipi6_ifindex
;
287 dst
= ptr
->ipi6_addr
;
291 "Interface index returned by IPV6_PKTINFO is zero");
294 /* Incoming packet's multicast hop limit. */
295 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
296 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
297 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
298 *hoplimit
= *phoplimit
;
302 /* Hoplimit check shold be done when destination address is
303 multicast address. */
304 if (!IN6_IS_ADDR_MULTICAST(&dst
))
310 /* Dump rip packet */
311 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
316 const char *command_str
;
318 /* Set command string. */
319 if (packet
->command
== RIPNG_REQUEST
)
320 command_str
= "request";
321 else if (packet
->command
== RIPNG_RESPONSE
)
322 command_str
= "response";
324 command_str
= "unknown";
326 /* Dump packet header. */
327 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
328 packet
->version
, size
);
330 /* Dump each routing table entry. */
333 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
334 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
335 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
338 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
339 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
340 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
344 /* RIPng next hop address RTE (Route Table Entry). */
345 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
346 struct ripng_nexthop
*nexthop
)
348 char buf
[INET6_BUFSIZ
];
350 /* Logging before checking RTE. */
351 if (IS_RIPNG_DEBUG_RECV
)
352 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
354 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
357 /* RFC2080 2.1.1 Next Hop:
358 The route tag and prefix length in the next hop RTE must be
359 set to zero on sending and ignored on receiption. */
360 if (ntohs(rte
->tag
) != 0)
362 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
364 (route_tag_t
)ntohs(rte
->tag
),
365 inet6_ntoa(from
->sin6_addr
));
367 if (rte
->prefixlen
!= 0)
369 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
370 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
372 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
373 next hop RTE indicates that the next hop address should be the
374 originator of the RIPng advertisement. An address specified as a
375 next hop must be a link-local address. */
376 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
377 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
378 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
382 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
383 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
384 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
388 /* The purpose of the next hop RTE is to eliminate packets being
389 routed through extra hops in the system. It is particularly useful
390 when RIPng is not being run on all of the routers on a network.
391 Note that next hop RTE is "advisory". That is, if the provided
392 information is ignored, a possibly sub-optimal, but absolutely
393 valid, route may be taken. If the received next hop address is not
394 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
395 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
396 inet6_ntoa(rte
->addr
),
397 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
399 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
400 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
405 /* If ifp has same link-local address then return 1. */
406 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
408 struct listnode
*node
;
409 struct connected
*connected
;
412 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
413 p
= connected
->address
;
415 if (p
->family
== AF_INET6
416 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
417 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
423 /* RIPng route garbage collect timer. */
424 static int ripng_garbage_collect(struct thread
*t
)
426 struct ripng_info
*rinfo
;
429 rinfo
= THREAD_ARG(t
);
430 rinfo
->t_garbage_collect
= NULL
;
432 /* Off timeout timer. */
433 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
435 /* Get route_node pointer. */
438 /* Unlock route_node. */
439 listnode_delete(rp
->info
, rinfo
);
440 if (list_isempty((struct list
*)rp
->info
)) {
441 list_delete((struct list
**)&rp
->info
);
445 /* Free RIPng routing information. */
446 ripng_info_free(rinfo
);
451 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
);
453 /* Add new route to the ECMP list.
454 * RETURN: the new entry added in the list, or NULL if it is not the first
455 * entry and ECMP is not allowed.
457 struct ripng_info
*ripng_ecmp_add(struct ripng
*ripng
,
458 struct ripng_info
*rinfo_new
)
460 struct agg_node
*rp
= rinfo_new
->rp
;
461 struct ripng_info
*rinfo
= NULL
;
462 struct list
*list
= NULL
;
464 if (rp
->info
== NULL
)
465 rp
->info
= list_new();
466 list
= (struct list
*)rp
->info
;
468 /* If ECMP is not allowed and some entry already exists in the list,
470 if (listcount(list
) && !ripng
->ecmp
)
473 rinfo
= ripng_info_new();
474 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
475 listnode_add(list
, rinfo
);
477 if (ripng_route_rte(rinfo
)) {
478 ripng_timeout_update(ripng
, rinfo
);
479 ripng_zebra_ipv6_add(ripng
, rp
);
482 ripng_aggregate_increment(rp
, rinfo
);
484 /* Set the route change flag on the first entry. */
485 rinfo
= listgetdata(listhead(list
));
486 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
488 /* Signal the output process to trigger an update. */
489 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
494 /* Replace the ECMP list with the new route.
495 * RETURN: the new entry added in the list
497 struct ripng_info
*ripng_ecmp_replace(struct ripng
*ripng
,
498 struct ripng_info
*rinfo_new
)
500 struct agg_node
*rp
= rinfo_new
->rp
;
501 struct list
*list
= (struct list
*)rp
->info
;
502 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
503 struct listnode
*node
= NULL
, *nextnode
= NULL
;
505 if (list
== NULL
|| listcount(list
) == 0)
506 return ripng_ecmp_add(ripng
, rinfo_new
);
508 /* Get the first entry */
509 rinfo
= listgetdata(listhead(list
));
511 /* Learnt route replaced by a local one. Delete it from zebra. */
512 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
513 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
514 ripng_zebra_ipv6_delete(ripng
, rp
);
516 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
517 ripng_aggregate_decrement_list(rp
, list
);
519 /* Re-use the first entry, and delete the others. */
520 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
521 if (tmp_rinfo
!= rinfo
) {
522 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
523 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
524 list_delete_node(list
, node
);
525 ripng_info_free(tmp_rinfo
);
528 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
529 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
530 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
532 if (ripng_route_rte(rinfo
)) {
533 ripng_timeout_update(ripng
, rinfo
);
534 /* The ADD message implies an update. */
535 ripng_zebra_ipv6_add(ripng
, rp
);
538 ripng_aggregate_increment(rp
, rinfo
);
540 /* Set the route change flag. */
541 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
543 /* Signal the output process to trigger an update. */
544 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
549 /* Delete one route from the ECMP list.
551 * null - the entry is freed, and other entries exist in the list
552 * the entry - the entry is the last one in the list; its metric is set
553 * to INFINITY, and the garbage collector is started for it
555 struct ripng_info
*ripng_ecmp_delete(struct ripng
*ripng
,
556 struct ripng_info
*rinfo
)
558 struct agg_node
*rp
= rinfo
->rp
;
559 struct list
*list
= (struct list
*)rp
->info
;
561 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
563 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
564 ripng_aggregate_decrement(rp
, rinfo
);
566 if (listcount(list
) > 1) {
567 /* Some other ECMP entries still exist. Just delete this entry.
569 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
570 listnode_delete(list
, rinfo
);
571 if (ripng_route_rte(rinfo
)
572 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
573 /* The ADD message implies the update. */
574 ripng_zebra_ipv6_add(ripng
, rp
);
575 ripng_info_free(rinfo
);
578 assert(rinfo
== listgetdata(listhead(list
)));
580 /* This is the only entry left in the list. We must keep it in
581 * the list for garbage collection time, with INFINITY metric.
584 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
585 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
586 ripng
->garbage_time
);
588 if (ripng_route_rte(rinfo
)
589 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
590 ripng_zebra_ipv6_delete(ripng
, rp
);
593 /* Set the route change flag on the first entry. */
594 rinfo
= listgetdata(listhead(list
));
595 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
597 /* Signal the output process to trigger an update. */
598 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
603 /* Timeout RIPng routes. */
604 static int ripng_timeout(struct thread
*t
)
606 struct ripng_info
*rinfo
= THREAD_ARG(t
);
607 struct ripng
*ripng
= ripng_info_get_instance(rinfo
);
609 ripng_ecmp_delete(ripng
, rinfo
);
614 static void ripng_timeout_update(struct ripng
*ripng
, struct ripng_info
*rinfo
)
616 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
617 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
618 thread_add_timer(master
, ripng_timeout
, rinfo
,
619 ripng
->timeout_time
, &rinfo
->t_timeout
);
623 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
624 struct ripng_interface
*ri
)
626 struct distribute
*dist
;
627 struct access_list
*alist
;
628 struct prefix_list
*plist
;
629 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
632 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
634 /* Input distribute-list filtering. */
635 if (ri
->list
[ripng_distribute
]) {
636 if (access_list_apply(ri
->list
[ripng_distribute
],
639 if (IS_RIPNG_DEBUG_PACKET
)
640 zlog_debug("%s/%d filtered by distribute %s",
641 inet6_ntoa(p
->prefix
), p
->prefixlen
,
646 if (ri
->prefix
[ripng_distribute
]) {
647 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
650 if (IS_RIPNG_DEBUG_PACKET
)
651 zlog_debug("%s/%d filtered by prefix-list %s",
652 inet6_ntoa(p
->prefix
), p
->prefixlen
,
658 /* All interface filter check. */
659 dist
= distribute_lookup(ri
->ripng
->distribute_ctx
, NULL
);
661 if (dist
->list
[distribute
]) {
662 alist
= access_list_lookup(AFI_IP6
,
663 dist
->list
[distribute
]);
666 if (access_list_apply(alist
, (struct prefix
*)p
)
668 if (IS_RIPNG_DEBUG_PACKET
)
670 "%s/%d filtered by distribute %s",
671 inet6_ntoa(p
->prefix
),
672 p
->prefixlen
, inout
);
677 if (dist
->prefix
[distribute
]) {
678 plist
= prefix_list_lookup(AFI_IP6
,
679 dist
->prefix
[distribute
]);
682 if (prefix_list_apply(plist
, (struct prefix
*)p
)
684 if (IS_RIPNG_DEBUG_PACKET
)
686 "%s/%d filtered by prefix-list %s",
687 inet6_ntoa(p
->prefix
),
688 p
->prefixlen
, inout
);
697 /* Process RIPng route according to RFC2080. */
698 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
699 struct ripng_nexthop
*ripng_nexthop
,
700 struct interface
*ifp
)
703 struct prefix_ipv6 p
;
705 struct ripng_info
*rinfo
= NULL
, newinfo
;
706 struct ripng_interface
*ri
;
708 struct in6_addr
*nexthop
;
710 struct list
*list
= NULL
;
711 struct listnode
*node
= NULL
;
713 /* Make prefix structure. */
714 memset(&p
, 0, sizeof(struct prefix_ipv6
));
716 /* p.prefix = rte->addr; */
717 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
718 p
.prefixlen
= rte
->prefixlen
;
720 /* Make sure mask is applied. */
721 /* XXX We have to check the prefix is valid or not before call
728 /* Apply input filters. */
729 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
733 memset(&newinfo
, 0, sizeof(newinfo
));
734 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
735 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
736 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
737 newinfo
.nexthop
= ripng_nexthop
->address
;
739 newinfo
.nexthop
= from
->sin6_addr
;
740 newinfo
.from
= from
->sin6_addr
;
741 newinfo
.ifindex
= ifp
->ifindex
;
742 newinfo
.metric
= rte
->metric
;
743 newinfo
.metric_out
= rte
->metric
; /* XXX */
744 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
747 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
748 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
749 (struct prefix
*)&p
, RMAP_RIPNG
,
752 if (ret
== RMAP_DENYMATCH
) {
753 if (IS_RIPNG_DEBUG_PACKET
)
755 "RIPng %s/%d is filtered by route-map in",
756 inet6_ntoa(p
.prefix
), p
.prefixlen
);
760 /* Get back the object */
761 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
762 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
763 &ripng_nexthop
->address
)) {
764 /* the nexthop get changed by the routemap */
765 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
766 ripng_nexthop
->address
=
769 ripng_nexthop
->address
= in6addr_any
;
772 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
774 /* the nexthop get changed by the routemap */
775 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
776 ripng_nexthop
->flag
=
777 RIPNG_NEXTHOP_ADDRESS
;
778 ripng_nexthop
->address
=
783 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
785 newinfo
.metric_out
; /* XXX: the routemap uses the
789 /* Once the entry has been validated, update the metric by
790 * adding the cost of the network on wich the message
791 * arrived. If the result is greater than infinity, use infinity
792 * (RFC2453 Sec. 3.9.2)
795 /* Zebra ripngd can handle offset-list in. */
796 ret
= ripng_offset_list_apply_in(ripng
, &p
, ifp
, &rte
->metric
);
798 /* If offset-list does not modify the metric use interface's
801 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
803 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
804 rte
->metric
= RIPNG_METRIC_INFINITY
;
806 /* Set nexthop pointer. */
807 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
808 nexthop
= &ripng_nexthop
->address
;
810 nexthop
= &from
->sin6_addr
;
812 /* Lookup RIPng routing table. */
813 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
816 newinfo
.nexthop
= *nexthop
;
817 newinfo
.metric
= rte
->metric
;
818 newinfo
.tag
= ntohs(rte
->tag
);
820 /* Check to see whether there is already RIPng route on the table. */
821 if ((list
= rp
->info
) != NULL
)
822 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
823 /* Need to compare with redistributed entry or local
825 if (!ripng_route_rte(rinfo
))
828 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
829 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
832 if (!listnextnode(node
)) {
833 /* Not found in the list */
835 if (rte
->metric
> rinfo
->metric
) {
836 /* New route has a greater metric.
842 if (rte
->metric
< rinfo
->metric
)
843 /* New route has a smaller metric.
844 * Replace the ECMP list
845 * with the new one in below. */
848 /* Metrics are same. Unless ECMP is disabled,
849 * keep "rinfo" null and
850 * the new route is added in the ECMP list in
858 /* Redistributed route check. */
859 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
860 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
865 /* Local static route. */
866 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
867 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
868 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
869 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
876 /* Now, check to see whether there is already an explicit route
877 for the destination prefix. If there is no such route, add
878 this route to the routing table, unless the metric is
879 infinity (there is no point in adding a route which
881 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
882 ripng_ecmp_add(ripng
, &newinfo
);
886 /* If there is an existing route, compare the next hop address
887 to the address of the router from which the datagram came.
888 If this datagram is from the same router as the existing
889 route, reinitialize the timeout. */
890 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
891 && (rinfo
->ifindex
== ifp
->ifindex
));
894 * RFC 2080 - Section 2.4.2:
895 * "If the new metric is the same as the old one, examine the
897 * for the existing route. If it is at least halfway to the
899 * point, switch to the new route. This heuristic is optional,
901 * highly recommended".
903 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
905 && (thread_timer_remain_second(rinfo
->t_timeout
)
906 < (ripng
->timeout_time
/ 2))) {
907 ripng_ecmp_replace(ripng
, &newinfo
);
909 /* Next, compare the metrics. If the datagram is from the same
910 router as the existing route, and the new metric is different
911 than the old one; or, if the new metric is lower than the old
912 one; do the following actions: */
913 else if ((same
&& rinfo
->metric
!= rte
->metric
)
914 || rte
->metric
< rinfo
->metric
) {
915 if (listcount(list
) == 1) {
916 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
917 ripng_ecmp_replace(ripng
, &newinfo
);
919 ripng_ecmp_delete(ripng
, rinfo
);
921 if (newinfo
.metric
< rinfo
->metric
)
922 ripng_ecmp_replace(ripng
, &newinfo
);
923 else /* newinfo.metric > rinfo->metric */
924 ripng_ecmp_delete(ripng
, rinfo
);
926 } else /* same & no change */
927 ripng_timeout_update(ripng
, rinfo
);
929 /* Unlock tempolary lock of the route. */
934 /* Add redistributed route to RIPng table. */
935 void ripng_redistribute_add(struct ripng
*ripng
, int type
, int sub_type
,
936 struct prefix_ipv6
*p
, ifindex_t ifindex
,
937 struct in6_addr
*nexthop
, route_tag_t tag
)
940 struct ripng_info
*rinfo
= NULL
, newinfo
;
941 struct list
*list
= NULL
;
943 /* Redistribute route */
944 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
946 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
949 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
951 memset(&newinfo
, 0, sizeof(struct ripng_info
));
953 newinfo
.sub_type
= sub_type
;
954 newinfo
.ifindex
= ifindex
;
956 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
959 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
960 newinfo
.nexthop
= *nexthop
;
962 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
963 rinfo
= listgetdata(listhead(list
));
965 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
966 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
967 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
972 /* Manually configured RIPng route check.
973 * They have the precedence on all the other entries.
975 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
976 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
977 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
978 if (type
!= ZEBRA_ROUTE_RIPNG
979 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
980 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
986 ripng_ecmp_replace(ripng
, &newinfo
);
989 ripng_ecmp_add(ripng
, &newinfo
);
991 if (IS_RIPNG_DEBUG_EVENT
) {
994 "Redistribute new prefix %s/%d on the interface %s",
995 inet6_ntoa(p
->prefix
), p
->prefixlen
,
996 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
999 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
1000 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1001 inet6_ntoa(*nexthop
),
1002 ifindex2ifname(ifindex
, ripng
->vrf
->vrf_id
));
1005 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1008 /* Delete redistributed route to RIPng table. */
1009 void ripng_redistribute_delete(struct ripng
*ripng
, int type
, int sub_type
,
1010 struct prefix_ipv6
*p
, ifindex_t ifindex
)
1012 struct agg_node
*rp
;
1013 struct ripng_info
*rinfo
;
1015 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
1017 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
1020 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
1023 struct list
*list
= rp
->info
;
1025 if (list
!= NULL
&& listcount(list
) != 0) {
1026 rinfo
= listgetdata(listhead(list
));
1027 if (rinfo
!= NULL
&& rinfo
->type
== type
1028 && rinfo
->sub_type
== sub_type
1029 && rinfo
->ifindex
== ifindex
) {
1030 /* Perform poisoned reverse. */
1031 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1032 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1033 ripng_garbage_collect
,
1034 ripng
->garbage_time
);
1035 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1037 /* Aggregate count decrement. */
1038 ripng_aggregate_decrement(rp
, rinfo
);
1040 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1042 if (IS_RIPNG_DEBUG_EVENT
)
1044 "Poisone %s/%d on the interface %s with an "
1045 "infinity metric [delete]",
1046 inet6_ntoa(p
->prefix
),
1050 ripng
->vrf
->vrf_id
));
1052 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1055 agg_unlock_node(rp
);
1059 /* Withdraw redistributed route. */
1060 void ripng_redistribute_withdraw(struct ripng
*ripng
, int type
)
1062 struct agg_node
*rp
;
1063 struct ripng_info
*rinfo
= NULL
;
1064 struct list
*list
= NULL
;
1066 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1067 if ((list
= rp
->info
) != NULL
) {
1068 rinfo
= listgetdata(listhead(list
));
1069 if ((rinfo
->type
== type
)
1070 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1071 /* Perform poisoned reverse. */
1072 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1073 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1074 ripng_garbage_collect
,
1075 ripng
->garbage_time
);
1076 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1078 /* Aggregate count decrement. */
1079 ripng_aggregate_decrement(rp
, rinfo
);
1081 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1083 if (IS_RIPNG_DEBUG_EVENT
) {
1084 struct prefix_ipv6
*p
=
1085 (struct prefix_ipv6
*)&rp
->p
;
1088 "Poisone %s/%d on the interface %s [withdraw]",
1089 inet6_ntoa(p
->prefix
),
1093 ripng
->vrf
->vrf_id
));
1096 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
1101 /* RIP routing information. */
1102 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1103 struct sockaddr_in6
*from
,
1104 struct interface
*ifp
, int hoplimit
)
1106 struct ripng_interface
*ri
= ifp
->info
;
1107 struct ripng
*ripng
= ri
->ripng
;
1110 struct ripng_nexthop nexthop
;
1112 /* RFC2080 2.4.2 Response Messages:
1113 The Response must be ignored if it is not from the RIPng port. */
1114 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1115 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1116 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1117 ripng_peer_bad_packet(ripng
, from
);
1121 /* The datagram's IPv6 source address should be checked to see
1122 whether the datagram is from a valid neighbor; the source of the
1123 datagram must be a link-local address. */
1124 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1125 zlog_warn("RIPng packet comes from non link local address %s",
1126 inet6_ntoa(from
->sin6_addr
));
1127 ripng_peer_bad_packet(ripng
, from
);
1131 /* It is also worth checking to see whether the response is from one
1132 of the router's own addresses. Interfaces on broadcast networks
1133 may receive copies of their own multicasts immediately. If a
1134 router processes its own output as new input, confusion is likely,
1135 and such datagrams must be ignored. */
1136 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1138 "RIPng packet comes from my own link local address %s",
1139 inet6_ntoa(from
->sin6_addr
));
1140 ripng_peer_bad_packet(ripng
, from
);
1144 /* As an additional check, periodic advertisements must have their
1145 hop counts set to 255, and inbound, multicast packets sent from the
1146 RIPng port (i.e. periodic advertisement or triggered update
1147 packets) must be examined to ensure that the hop count is 255. */
1148 if (hoplimit
>= 0 && hoplimit
!= 255) {
1150 "RIPng packet comes with non 255 hop count %d from %s",
1151 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1152 ripng_peer_bad_packet(ripng
, from
);
1156 /* Update RIPng peer. */
1157 ripng_peer_update(ripng
, from
, packet
->version
);
1159 /* Reset nexthop. */
1160 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1161 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1163 /* Set RTE pointer. */
1166 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1167 /* First of all, we have to check this RTE is next hop RTE or
1168 not. Next hop RTE is completely different with normal RTE so
1169 we need special treatment. */
1170 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1171 ripng_nexthop_rte(rte
, from
, &nexthop
);
1175 /* RTE information validation. */
1177 /* - is the destination prefix valid (e.g., not a multicast
1178 prefix and not a link-local address) A link-local address
1179 should never be present in an RTE. */
1180 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1182 "Destination prefix is a multicast address %s/%d [%d]",
1183 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1185 ripng_peer_bad_route(ripng
, from
);
1188 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1190 "Destination prefix is a link-local address %s/%d [%d]",
1191 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1193 ripng_peer_bad_route(ripng
, from
);
1196 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1198 "Destination prefix is a loopback address %s/%d [%d]",
1199 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1201 ripng_peer_bad_route(ripng
, from
);
1205 /* - is the prefix length valid (i.e., between 0 and 128,
1207 if (rte
->prefixlen
> 128) {
1208 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1209 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1210 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1211 ripng_peer_bad_route(ripng
, from
);
1215 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1216 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1217 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1218 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1219 ripng_peer_bad_route(ripng
, from
);
1223 /* Vincent: XXX Should we compute the direclty reachable nexthop
1224 * for our RIPng network ?
1227 /* Routing table updates. */
1228 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1232 /* Response to request message. */
1233 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1234 struct sockaddr_in6
*from
,
1235 struct interface
*ifp
)
1237 struct ripng
*ripng
;
1240 struct prefix_ipv6 p
;
1241 struct agg_node
*rp
;
1242 struct ripng_info
*rinfo
;
1243 struct ripng_interface
*ri
;
1245 /* Does not reponse to the requests on the loopback interfaces */
1246 if (if_is_loopback(ifp
))
1249 /* Check RIPng process is enabled on this interface. */
1255 /* When passive interface is specified, suppress responses */
1259 /* RIPng peer update. */
1260 ripng_peer_update(ripng
, from
, packet
->version
);
1262 lim
= ((caddr_t
)packet
) + size
;
1265 /* The Request is processed entry by entry. If there are no
1266 entries, no response is given. */
1267 if (lim
== (caddr_t
)rte
)
1270 /* There is one special case. If there is exactly one entry in the
1271 request, and it has a destination prefix of zero, a prefix length
1272 of zero, and a metric of infinity (i.e., 16), then this is a
1273 request to send the entire routing table. In that case, a call
1274 is made to the output process to send the routing table to the
1275 requesting address/port. */
1276 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1277 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1278 /* All route with split horizon */
1279 ripng_output_process(ifp
, from
, ripng_all_route
);
1281 /* Except for this special case, processing is quite simple.
1282 Examine the list of RTEs in the Request one by one. For each
1283 entry, look up the destination in the router's routing
1284 database and, if there is a route, put that route's metric in
1285 the metric field of the RTE. If there is no explicit route
1286 to the specified destination, put infinity in the metric
1287 field. Once all the entries have been filled in, change the
1288 command from Request to Response and send the datagram back
1289 to the requestor. */
1290 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1291 p
.family
= AF_INET6
;
1293 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1294 p
.prefix
= rte
->addr
;
1295 p
.prefixlen
= rte
->prefixlen
;
1296 apply_mask_ipv6(&p
);
1298 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1301 rinfo
= listgetdata(
1302 listhead((struct list
*)rp
->info
));
1303 rte
->metric
= rinfo
->metric
;
1304 agg_unlock_node(rp
);
1306 rte
->metric
= RIPNG_METRIC_INFINITY
;
1308 packet
->command
= RIPNG_RESPONSE
;
1310 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1314 /* First entry point of reading RIPng packet. */
1315 static int ripng_read(struct thread
*thread
)
1317 struct ripng
*ripng
= THREAD_ARG(thread
);
1320 struct sockaddr_in6 from
;
1321 struct ripng_packet
*packet
;
1322 ifindex_t ifindex
= 0;
1323 struct interface
*ifp
;
1326 /* Check ripng is active and alive. */
1327 assert(ripng
!= NULL
);
1328 assert(ripng
->sock
>= 0);
1330 /* Fetch thread data and set read pointer to empty for event
1331 managing. `sock' sould be same as ripng->sock. */
1332 sock
= THREAD_FD(thread
);
1333 ripng
->t_read
= NULL
;
1335 /* Add myself to the next event. */
1336 ripng_event(ripng
, RIPNG_READ
, sock
);
1338 /* Read RIPng packet. */
1339 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1340 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1343 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1344 ripng
->vrf_name
, safe_strerror(errno
));
1348 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1349 (4)) must be multiple size of one RTE size (20). */
1350 if (((len
- 4) % 20) != 0) {
1351 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len
,
1352 inet6_ntoa(from
.sin6_addr
), ripng
->vrf_name
);
1353 ripng_peer_bad_packet(ripng
, &from
);
1357 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1358 ifp
= if_lookup_by_index(ifindex
, ripng
->vrf
->vrf_id
);
1360 /* RIPng packet received. */
1361 if (IS_RIPNG_DEBUG_EVENT
)
1363 "RIPng packet received from %s port %d on %s (VRF %s)",
1364 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1365 ifp
? ifp
->name
: "unknown", ripng
->vrf_name
);
1367 /* Logging before packet checking. */
1368 if (IS_RIPNG_DEBUG_RECV
)
1369 ripng_packet_dump(packet
, len
, "RECV");
1371 /* Packet comes from unknown interface. */
1374 "RIPng packet comes from unknown interface %d (VRF %s)",
1375 ifindex
, ripng
->vrf_name
);
1379 /* Packet version mismatch checking. */
1380 if (packet
->version
!= ripng
->version
) {
1382 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1383 packet
->version
, ripng
->version
, ripng
->vrf_name
);
1384 ripng_peer_bad_packet(ripng
, &from
);
1388 /* Process RIPng packet. */
1389 switch (packet
->command
) {
1391 ripng_request_process(packet
, len
, &from
, ifp
);
1393 case RIPNG_RESPONSE
:
1394 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1397 zlog_warn("Invalid RIPng command %d (VRF %s)", packet
->command
,
1399 ripng_peer_bad_packet(ripng
, &from
);
1405 /* Walk down the RIPng routing table then clear changed flag. */
1406 static void ripng_clear_changed_flag(struct ripng
*ripng
)
1408 struct agg_node
*rp
;
1409 struct ripng_info
*rinfo
= NULL
;
1410 struct list
*list
= NULL
;
1411 struct listnode
*listnode
= NULL
;
1413 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1414 if ((list
= rp
->info
) != NULL
)
1415 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1416 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1417 /* This flag can be set only on the first entry.
1423 /* Regular update of RIPng route. Send all routing formation to RIPng
1424 enabled interface. */
1425 static int ripng_update(struct thread
*t
)
1427 struct ripng
*ripng
= THREAD_ARG(t
);
1428 struct interface
*ifp
;
1429 struct ripng_interface
*ri
;
1431 /* Clear update timer thread. */
1432 ripng
->t_update
= NULL
;
1434 /* Logging update event. */
1435 if (IS_RIPNG_DEBUG_EVENT
)
1436 zlog_debug("RIPng update timer expired!");
1438 /* Supply routes to each interface. */
1439 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1442 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1448 /* When passive interface is specified, suppress announce to the
1454 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1455 if (IS_RIPNG_DEBUG_EVENT
)
1457 "[Event] RIPng send to if %d is suppressed by config",
1461 #endif /* RIPNG_ADVANCED */
1463 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1466 /* Triggered updates may be suppressed if a regular update is due by
1467 the time the triggered update would be sent. */
1468 if (ripng
->t_triggered_interval
) {
1469 thread_cancel(ripng
->t_triggered_interval
);
1470 ripng
->t_triggered_interval
= NULL
;
1474 /* Reset flush event. */
1475 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 0);
1480 /* Triggered update interval timer. */
1481 static int ripng_triggered_interval(struct thread
*t
)
1483 struct ripng
*ripng
= THREAD_ARG(t
);
1485 ripng
->t_triggered_interval
= NULL
;
1487 if (ripng
->trigger
) {
1489 ripng_triggered_update(t
);
1494 /* Execute triggered update. */
1495 int ripng_triggered_update(struct thread
*t
)
1497 struct ripng
*ripng
= THREAD_ARG(t
);
1498 struct interface
*ifp
;
1499 struct ripng_interface
*ri
;
1502 ripng
->t_triggered_update
= NULL
;
1504 /* Cancel interval timer. */
1505 if (ripng
->t_triggered_interval
) {
1506 thread_cancel(ripng
->t_triggered_interval
);
1507 ripng
->t_triggered_interval
= NULL
;
1511 /* Logging triggered update. */
1512 if (IS_RIPNG_DEBUG_EVENT
)
1513 zlog_debug("RIPng triggered update!");
1515 /* Split Horizon processing is done when generating triggered
1516 updates as well as normal updates (see section 2.6). */
1517 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
1520 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1526 /* When passive interface is specified, suppress announce to the
1531 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1534 /* Once all of the triggered updates have been generated, the route
1535 change flags should be cleared. */
1536 ripng_clear_changed_flag(ripng
);
1538 /* After a triggered update is sent, a timer should be set for a
1539 random interval between 1 and 5 seconds. If other changes that
1540 would trigger updates occur before the timer expires, a single
1541 update is triggered when the timer expires. */
1542 interval
= (random() % 5) + 1;
1544 ripng
->t_triggered_interval
= NULL
;
1545 thread_add_timer(master
, ripng_triggered_interval
, ripng
, interval
,
1546 &ripng
->t_triggered_interval
);
1551 /* Write routing table entry to the stream and return next index of
1552 the routing table entry in the stream. */
1553 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1554 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1556 /* RIPng packet header. */
1558 stream_putc(s
, RIPNG_RESPONSE
);
1559 stream_putc(s
, RIPNG_V1
);
1563 /* Write routing table entry. */
1566 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1568 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1569 stream_putw(s
, tag
);
1571 stream_putc(s
, p
->prefixlen
);
1574 stream_putc(s
, metric
);
1579 /* Send RESPONSE message to specified destination. */
1580 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1583 struct ripng
*ripng
;
1585 struct agg_node
*rp
;
1586 struct ripng_info
*rinfo
;
1587 struct ripng_interface
*ri
;
1588 struct ripng_aggregate
*aggregate
;
1589 struct prefix_ipv6
*p
;
1590 struct list
*ripng_rte_list
;
1591 struct list
*list
= NULL
;
1592 struct listnode
*listnode
= NULL
;
1594 if (IS_RIPNG_DEBUG_EVENT
) {
1596 zlog_debug("RIPng update routes to neighbor %s",
1597 inet6_ntoa(to
->sin6_addr
));
1599 zlog_debug("RIPng update routes on interface %s",
1603 /* Get RIPng interface and instance. */
1607 ripng_rte_list
= ripng_rte_new();
1609 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1610 if ((list
= rp
->info
) != NULL
1611 && (rinfo
= listgetdata(listhead(list
))) != NULL
1612 && rinfo
->suppress
== 0) {
1613 /* If no route-map are applied, the RTE will be these
1617 p
= (struct prefix_ipv6
*)&rp
->p
;
1618 rinfo
->metric_out
= rinfo
->metric
;
1619 rinfo
->tag_out
= rinfo
->tag
;
1620 memset(&rinfo
->nexthop_out
, 0,
1621 sizeof(rinfo
->nexthop_out
));
1622 /* In order to avoid some local loops,
1623 * if the RIPng route has a nexthop via this interface,
1625 * otherwise set it to 0. The nexthop should not be
1627 * beyond the local broadcast/multicast area in order
1628 * to avoid an IGP multi-level recursive look-up.
1630 if (rinfo
->ifindex
== ifp
->ifindex
)
1631 rinfo
->nexthop_out
= rinfo
->nexthop
;
1633 /* Apply output filters. */
1634 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1638 /* Changed route only output. */
1639 if (route_type
== ripng_changed_route
1640 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1643 /* Split horizon. */
1644 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1645 /* We perform split horizon for RIPng routes. */
1647 struct ripng_info
*tmp_rinfo
= NULL
;
1649 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1651 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1652 && tmp_rinfo
->ifindex
1661 /* Preparation for route-map. */
1662 rinfo
->metric_set
= 0;
1665 * and tag_out are already initialized.
1668 /* Interface route-map */
1669 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1670 ret
= route_map_apply(
1671 ri
->routemap
[RIPNG_FILTER_OUT
],
1672 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1674 if (ret
== RMAP_DENYMATCH
) {
1675 if (IS_RIPNG_DEBUG_PACKET
)
1677 "RIPng %s/%d is filtered by route-map out",
1678 inet6_ntoa(p
->prefix
),
1684 /* Redistribute route-map. */
1685 if (ripng
->route_map
[rinfo
->type
].name
) {
1686 ret
= route_map_apply(
1687 ripng
->route_map
[rinfo
->type
].map
,
1688 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1690 if (ret
== RMAP_DENYMATCH
) {
1691 if (IS_RIPNG_DEBUG_PACKET
)
1693 "RIPng %s/%d is filtered by route-map",
1694 inet6_ntoa(p
->prefix
),
1700 /* When the route-map does not set metric. */
1701 if (!rinfo
->metric_set
) {
1702 /* If the redistribute metric is set. */
1703 if (ripng
->route_map
[rinfo
->type
].metric_config
1704 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1706 ripng
->route_map
[rinfo
->type
]
1709 /* If the route is not connected or
1711 one, use default-metric value */
1712 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1714 != ZEBRA_ROUTE_CONNECT
1716 != RIPNG_METRIC_INFINITY
)
1718 ripng
->default_metric
;
1722 /* Apply offset-list */
1723 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1724 ripng_offset_list_apply_out(ripng
, p
, ifp
,
1725 &rinfo
->metric_out
);
1727 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1728 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1730 /* Perform split-horizon with poisoned reverse
1733 if (ri
->split_horizon
1734 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1735 struct ripng_info
*tmp_rinfo
= NULL
;
1737 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1739 if ((tmp_rinfo
->type
1740 == ZEBRA_ROUTE_RIPNG
)
1741 && tmp_rinfo
->ifindex
1744 RIPNG_METRIC_INFINITY
;
1747 /* Add RTE to the list */
1748 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1751 /* Process the aggregated RTE entry */
1752 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1753 && aggregate
->suppress
== 0) {
1754 /* If no route-map are applied, the RTE will be these
1758 p
= (struct prefix_ipv6
*)&rp
->p
;
1759 aggregate
->metric_set
= 0;
1760 aggregate
->metric_out
= aggregate
->metric
;
1761 aggregate
->tag_out
= aggregate
->tag
;
1762 memset(&aggregate
->nexthop_out
, 0,
1763 sizeof(aggregate
->nexthop_out
));
1765 /* Apply output filters.*/
1766 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1770 /* Interface route-map */
1771 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1772 struct ripng_info newinfo
;
1774 /* let's cast the aggregate structure to
1776 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1777 /* the nexthop is :: */
1778 newinfo
.metric
= aggregate
->metric
;
1779 newinfo
.metric_out
= aggregate
->metric_out
;
1780 newinfo
.tag
= aggregate
->tag
;
1781 newinfo
.tag_out
= aggregate
->tag_out
;
1783 ret
= route_map_apply(
1784 ri
->routemap
[RIPNG_FILTER_OUT
],
1785 (struct prefix
*)p
, RMAP_RIPNG
,
1788 if (ret
== RMAP_DENYMATCH
) {
1789 if (IS_RIPNG_DEBUG_PACKET
)
1791 "RIPng %s/%d is filtered by route-map out",
1792 inet6_ntoa(p
->prefix
),
1797 aggregate
->metric_out
= newinfo
.metric_out
;
1798 aggregate
->tag_out
= newinfo
.tag_out
;
1799 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1800 aggregate
->nexthop_out
=
1801 newinfo
.nexthop_out
;
1804 /* There is no redistribute routemap for the aggregated
1807 /* Changed route only output. */
1808 /* XXX, vincent, in order to increase time convergence,
1809 * it should be announced if a child has changed.
1811 if (route_type
== ripng_changed_route
)
1814 /* Apply offset-list */
1815 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1816 ripng_offset_list_apply_out(
1817 ripng
, p
, ifp
, &aggregate
->metric_out
);
1819 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1820 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1822 /* Add RTE to the list */
1823 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1827 /* Flush the list */
1828 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1829 ripng_rte_free(ripng_rte_list
);
1832 struct ripng
*ripng_lookup_by_vrf_id(vrf_id_t vrf_id
)
1836 vrf
= vrf_lookup_by_id(vrf_id
);
1843 struct ripng
*ripng_lookup_by_vrf_name(const char *vrf_name
)
1847 ripng
.vrf_name
= (char *)vrf_name
;
1849 return RB_FIND(ripng_instance_head
, &ripng_instances
, &ripng
);
1852 /* Create new RIPng instance and set it to global variable. */
1853 struct ripng
*ripng_create(const char *vrf_name
, struct vrf
*vrf
, int socket
)
1855 struct ripng
*ripng
;
1857 /* Allocaste RIPng instance. */
1858 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1859 ripng
->vrf_name
= XSTRDUP(MTYPE_RIPNG_VRF_NAME
, vrf_name
);
1861 /* Default version and timer values. */
1862 ripng
->version
= RIPNG_V1
;
1863 ripng
->update_time
= yang_get_default_uint32(
1864 "%s/timers/update-interval", RIPNG_INSTANCE
);
1865 ripng
->timeout_time
= yang_get_default_uint32(
1866 "%s/timers/holddown-interval", RIPNG_INSTANCE
);
1867 ripng
->garbage_time
= yang_get_default_uint32(
1868 "%s/timers/flush-interval", RIPNG_INSTANCE
);
1869 ripng
->default_metric
=
1870 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE
);
1871 ripng
->ecmp
= yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE
);
1874 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1875 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1877 /* Initialize RIPng data structures. */
1878 ripng
->table
= agg_table_init();
1879 agg_set_table_info(ripng
->table
, ripng
);
1880 ripng
->peer_list
= list_new();
1881 ripng
->peer_list
->cmp
= (int (*)(void *, void *))ripng_peer_list_cmp
;
1882 ripng
->peer_list
->del
= ripng_peer_list_del
;
1883 ripng
->enable_if
= vector_init(1);
1884 ripng
->enable_network
= agg_table_init();
1885 ripng
->passive_interface
= vector_init(1);
1886 ripng
->offset_list_master
= list_new();
1887 ripng
->offset_list_master
->cmp
=
1888 (int (*)(void *, void *))offset_list_cmp
;
1889 ripng
->offset_list_master
->del
=
1890 (void (*)(void *))ripng_offset_list_del
;
1891 ripng
->distribute_ctx
= distribute_list_ctx_create(vrf
);
1892 distribute_list_add_hook(ripng
->distribute_ctx
,
1893 ripng_distribute_update
);
1894 distribute_list_delete_hook(ripng
->distribute_ctx
,
1895 ripng_distribute_update
);
1898 /* Enable the routing instance if possible. */
1899 if (vrf
&& vrf_is_enabled(vrf
))
1900 ripng_instance_enable(ripng
, vrf
, socket
);
1906 RB_INSERT(ripng_instance_head
, &ripng_instances
, ripng
);
1911 /* Send RIPng request to the interface. */
1912 int ripng_request(struct interface
*ifp
)
1915 struct ripng_packet ripng_packet
;
1917 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1919 if (if_is_loopback(ifp
))
1922 /* If interface is down, don't send RIP packet. */
1926 if (IS_RIPNG_DEBUG_EVENT
)
1927 zlog_debug("RIPng send request to %s", ifp
->name
);
1929 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1930 ripng_packet
.command
= RIPNG_REQUEST
;
1931 ripng_packet
.version
= RIPNG_V1
;
1932 rte
= ripng_packet
.rte
;
1933 rte
->metric
= RIPNG_METRIC_INFINITY
;
1935 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1940 static int ripng_update_jitter(int time
)
1942 return ((random() % (time
+ 1)) - (time
/ 2));
1945 void ripng_event(struct ripng
*ripng
, enum ripng_event event
, int sock
)
1951 thread_add_read(master
, ripng_read
, ripng
, sock
,
1954 case RIPNG_UPDATE_EVENT
:
1955 if (ripng
->t_update
) {
1956 thread_cancel(ripng
->t_update
);
1957 ripng
->t_update
= NULL
;
1959 /* Update timer jitter. */
1960 jitter
= ripng_update_jitter(ripng
->update_time
);
1962 ripng
->t_update
= NULL
;
1963 thread_add_timer(master
, ripng_update
, ripng
,
1964 sock
? 2 : ripng
->update_time
+ jitter
,
1967 case RIPNG_TRIGGERED_UPDATE
:
1968 if (ripng
->t_triggered_interval
)
1971 thread_add_event(master
, ripng_triggered_update
, ripng
,
1972 0, &ripng
->t_triggered_update
);
1980 /* Print out routes update time. */
1981 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1986 char timebuf
[TIME_BUF
];
1987 struct thread
*thread
;
1989 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1990 clock
= thread_timer_remain_second(thread
);
1991 tm
= gmtime(&clock
);
1992 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1993 vty_out(vty
, "%5s", timebuf
);
1994 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1995 clock
= thread_timer_remain_second(thread
);
1996 tm
= gmtime(&clock
);
1997 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1998 vty_out(vty
, "%5s", timebuf
);
2002 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
2007 if (rinfo
->suppress
)
2010 switch (rinfo
->sub_type
) {
2011 case RIPNG_ROUTE_RTE
:
2014 case RIPNG_ROUTE_STATIC
:
2017 case RIPNG_ROUTE_DEFAULT
:
2020 case RIPNG_ROUTE_REDISTRIBUTE
:
2023 case RIPNG_ROUTE_INTERFACE
:
2034 DEFUN (show_ipv6_ripng
,
2035 show_ipv6_ripng_cmd
,
2036 "show ipv6 ripng [vrf NAME]",
2039 "Show RIPng routes\n"
2042 struct ripng
*ripng
;
2043 struct agg_node
*rp
;
2044 struct ripng_info
*rinfo
;
2045 struct ripng_aggregate
*aggregate
;
2046 struct prefix_ipv6
*p
;
2047 struct list
*list
= NULL
;
2048 struct listnode
*listnode
= NULL
;
2050 const char *vrf_name
;
2053 if (argv_find(argv
, argc
, "vrf", &idx
))
2054 vrf_name
= argv
[idx
+ 1]->arg
;
2056 vrf_name
= VRF_DEFAULT_NAME
;
2058 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2060 vty_out(vty
, "%% RIPng instance not found\n");
2063 if (!ripng
->enabled
) {
2064 vty_out(vty
, "%% RIPng instance is disabled\n");
2068 /* Header of display. */
2070 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2072 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2073 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2074 " Network Next Hop Via Metric Tag Time\n");
2076 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2077 if ((aggregate
= rp
->aggregate
) != NULL
) {
2078 p
= (struct prefix_ipv6
*)&rp
->p
;
2081 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
2082 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
2085 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
2089 vty_out(vty
, "%*s", 18, " ");
2091 vty_out(vty
, "%*s", 28, " ");
2092 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
2093 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2096 if ((list
= rp
->info
) != NULL
)
2097 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2098 p
= (struct prefix_ipv6
*)&rp
->p
;
2101 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2102 zebra_route_char(rinfo
->type
),
2103 ripng_route_subtype_print(rinfo
),
2104 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2107 vty_out(vty
, "%c(%s) %s/%d ",
2108 zebra_route_char(rinfo
->type
),
2109 ripng_route_subtype_print(rinfo
),
2110 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2113 vty_out(vty
, "%*s", 18, " ");
2114 len
= vty_out(vty
, "%s",
2115 inet6_ntoa(rinfo
->nexthop
));
2119 vty_out(vty
, "%*s", len
, " ");
2122 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2123 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2128 ripng
->vrf
->vrf_id
));
2129 } else if (rinfo
->metric
2130 == RIPNG_METRIC_INFINITY
) {
2131 len
= vty_out(vty
, "kill");
2133 len
= vty_out(vty
, "self");
2137 vty_out(vty
, "%*s", len
, " ");
2139 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2140 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2143 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2144 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2145 /* RTE from remote RIP routers */
2146 ripng_vty_out_uptime(vty
, rinfo
);
2147 } else if (rinfo
->metric
2148 == RIPNG_METRIC_INFINITY
) {
2149 /* poisonous reversed routes (gc) */
2150 ripng_vty_out_uptime(vty
, rinfo
);
2160 DEFUN (show_ipv6_ripng_status
,
2161 show_ipv6_ripng_status_cmd
,
2162 "show ipv6 ripng [vrf NAME] status",
2165 "Show RIPng routes\n"
2167 "IPv6 routing protocol process parameters and statistics\n")
2169 struct ripng
*ripng
;
2170 struct interface
*ifp
;
2171 const char *vrf_name
;
2174 if (argv_find(argv
, argc
, "vrf", &idx
))
2175 vrf_name
= argv
[idx
+ 1]->arg
;
2177 vrf_name
= VRF_DEFAULT_NAME
;
2179 ripng
= ripng_lookup_by_vrf_name(vrf_name
);
2181 vty_out(vty
, "%% RIPng instance not found\n");
2184 if (!ripng
->enabled
) {
2185 vty_out(vty
, "%% RIPng instance is disabled\n");
2189 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2190 vty_out(vty
, " Sending updates every %u seconds with +/-50%%,",
2191 ripng
->update_time
);
2192 vty_out(vty
, " next due in %lu seconds\n",
2193 thread_timer_remain_second(ripng
->t_update
));
2194 vty_out(vty
, " Timeout after %u seconds,", ripng
->timeout_time
);
2195 vty_out(vty
, " garbage collect after %u seconds\n",
2196 ripng
->garbage_time
);
2198 /* Filtering status show. */
2199 config_show_distribute(vty
, ripng
->distribute_ctx
);
2201 /* Default metric information. */
2202 vty_out(vty
, " Default redistribution metric is %d\n",
2203 ripng
->default_metric
);
2205 /* Redistribute information. */
2206 vty_out(vty
, " Redistributing:");
2207 ripng_redistribute_write(vty
, ripng
);
2210 vty_out(vty
, " Default version control: send version %d,",
2212 vty_out(vty
, " receive version %d \n", ripng
->version
);
2214 vty_out(vty
, " Interface Send Recv\n");
2216 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
2217 struct ripng_interface
*ri
;
2221 if (ri
->enable_network
|| ri
->enable_interface
) {
2223 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2224 ripng
->version
, ripng
->version
);
2228 vty_out(vty
, " Routing for Networks:\n");
2229 ripng_network_write(vty
, ripng
);
2231 vty_out(vty
, " Routing Information Sources:\n");
2233 " Gateway BadPackets BadRoutes Distance Last Update\n");
2234 ripng_peer_display(vty
, ripng
);
2240 /* RIPng update timer setup. */
2241 DEFUN (ripng_update_timer
,
2242 ripng_update_timer_cmd
,
2243 "update-timer SECOND",
2244 "Set RIPng update timer in seconds\n"
2247 unsigned long update
;
2248 char *endptr
= NULL
;
2250 update
= strtoul (argv
[0], &endptr
, 10);
2251 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2253 vty_out (vty
, "update timer value error\n");
2254 return CMD_WARNING_CONFIG_FAILED
;
2257 ripng
->update_time
= update
;
2259 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2263 DEFUN (no_ripng_update_timer
,
2264 no_ripng_update_timer_cmd
,
2265 "no update-timer SECOND",
2267 "Unset RIPng update timer in seconds\n"
2270 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2271 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2275 /* RIPng timeout timer setup. */
2276 DEFUN (ripng_timeout_timer
,
2277 ripng_timeout_timer_cmd
,
2278 "timeout-timer SECOND",
2279 "Set RIPng timeout timer in seconds\n"
2282 unsigned long timeout
;
2283 char *endptr
= NULL
;
2285 timeout
= strtoul (argv
[0], &endptr
, 10);
2286 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2288 vty_out (vty
, "timeout timer value error\n");
2289 return CMD_WARNING_CONFIG_FAILED
;
2292 ripng
->timeout_time
= timeout
;
2297 DEFUN (no_ripng_timeout_timer
,
2298 no_ripng_timeout_timer_cmd
,
2299 "no timeout-timer SECOND",
2301 "Unset RIPng timeout timer in seconds\n"
2304 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2308 /* RIPng garbage timer setup. */
2309 DEFUN (ripng_garbage_timer
,
2310 ripng_garbage_timer_cmd
,
2311 "garbage-timer SECOND",
2312 "Set RIPng garbage timer in seconds\n"
2315 unsigned long garbage
;
2316 char *endptr
= NULL
;
2318 garbage
= strtoul (argv
[0], &endptr
, 10);
2319 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2321 vty_out (vty
, "garbage timer value error\n");
2322 return CMD_WARNING_CONFIG_FAILED
;
2325 ripng
->garbage_time
= garbage
;
2330 DEFUN (no_ripng_garbage_timer
,
2331 no_ripng_garbage_timer_cmd
,
2332 "no garbage-timer SECOND",
2334 "Unset RIPng garbage timer in seconds\n"
2337 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2343 DEFUN (show_ipv6_protocols
,
2344 show_ipv6_protocols_cmd
,
2345 "show ipv6 protocols",
2348 "Routing protocol information\n")
2353 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2355 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2356 ripng
->update_time
, 0);
2358 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2359 ripng
->timeout_time
,
2360 ripng
->garbage_time
);
2362 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2363 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2369 /* Update ECMP routes to zebra when ECMP is disabled. */
2370 void ripng_ecmp_disable(struct ripng
*ripng
)
2372 struct agg_node
*rp
;
2373 struct ripng_info
*rinfo
, *tmp_rinfo
;
2375 struct listnode
*node
, *nextnode
;
2380 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2381 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2382 rinfo
= listgetdata(listhead(list
));
2383 if (!ripng_route_rte(rinfo
))
2386 /* Drop all other entries, except the first one. */
2387 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2388 if (tmp_rinfo
!= rinfo
) {
2389 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2391 tmp_rinfo
->t_garbage_collect
);
2392 list_delete_node(list
, node
);
2393 ripng_info_free(tmp_rinfo
);
2397 ripng_zebra_ipv6_add(ripng
, rp
);
2399 /* Set the route change flag. */
2400 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2402 /* Signal the output process to trigger an update. */
2403 ripng_event(ripng
, RIPNG_TRIGGERED_UPDATE
, 0);
2407 /* RIPng configuration write function. */
2408 static int ripng_config_write(struct vty
*vty
)
2410 struct ripng
*ripng
;
2413 RB_FOREACH(ripng
, ripng_instance_head
, &ripng_instances
) {
2414 char xpath
[XPATH_MAXLEN
];
2415 struct lyd_node
*dnode
;
2417 snprintf(xpath
, sizeof(xpath
),
2418 "/frr-ripngd:ripngd/instance[vrf='%s']",
2421 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
2424 nb_cli_show_dnode_cmds(vty
, dnode
, false);
2426 config_write_distribute(vty
, ripng
->distribute_ctx
);
2427 if (strmatch(ripng
->vrf_name
, VRF_DEFAULT_NAME
))
2428 config_write_if_rmap(vty
);
2436 /* RIPng node structure. */
2437 static struct cmd_node cmd_ripng_node
= {
2438 RIPNG_NODE
, "%s(config-router)# ", 1,
2441 static void ripng_distribute_update(struct distribute_ctx
*ctx
,
2442 struct distribute
*dist
)
2444 struct interface
*ifp
;
2445 struct ripng_interface
*ri
;
2446 struct access_list
*alist
;
2447 struct prefix_list
*plist
;
2449 if (!ctx
->vrf
|| !dist
->ifname
)
2452 ifp
= if_lookup_by_name(dist
->ifname
, ctx
->vrf
->vrf_id
);
2458 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2459 alist
= access_list_lookup(AFI_IP6
,
2460 dist
->list
[DISTRIBUTE_V6_IN
]);
2462 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2464 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2466 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2468 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2469 alist
= access_list_lookup(AFI_IP6
,
2470 dist
->list
[DISTRIBUTE_V6_OUT
]);
2472 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2474 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2476 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2478 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2479 plist
= prefix_list_lookup(AFI_IP6
,
2480 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2482 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2484 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2486 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2488 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2489 plist
= prefix_list_lookup(AFI_IP6
,
2490 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2492 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2494 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2496 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2499 void ripng_distribute_update_interface(struct interface
*ifp
)
2501 struct ripng_interface
*ri
= ifp
->info
;
2502 struct ripng
*ripng
= ri
->ripng
;
2503 struct distribute
*dist
;
2507 dist
= distribute_lookup(ripng
->distribute_ctx
, ifp
->name
);
2509 ripng_distribute_update(ripng
->distribute_ctx
, dist
);
2512 /* Update all interface's distribute list. */
2513 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2515 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2516 struct interface
*ifp
;
2518 FOR_ALL_INTERFACES (vrf
, ifp
)
2519 ripng_distribute_update_interface(ifp
);
2522 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2524 ripng_distribute_update_all(NULL
);
2527 /* delete all the added ripng routes. */
2528 void ripng_clean(struct ripng
*ripng
)
2531 ripng_instance_disable(ripng
);
2533 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2534 if (ripng
->route_map
[i
].name
)
2535 free(ripng
->route_map
[i
].name
);
2537 agg_table_finish(ripng
->table
);
2538 list_delete(&ripng
->peer_list
);
2539 distribute_list_delete(&ripng
->distribute_ctx
);
2541 stream_free(ripng
->ibuf
);
2542 stream_free(ripng
->obuf
);
2544 ripng_clean_network(ripng
);
2545 ripng_passive_interface_clean(ripng
);
2546 vector_free(ripng
->enable_if
);
2547 agg_table_finish(ripng
->enable_network
);
2548 vector_free(ripng
->passive_interface
);
2549 list_delete(&ripng
->offset_list_master
);
2550 ripng_interface_clean(ripng
);
2551 ripng_redistribute_clean(ripng
);
2553 RB_REMOVE(ripng_instance_head
, &ripng_instances
, ripng
);
2554 XFREE(MTYPE_RIPNG_VRF_NAME
, ripng
->vrf_name
);
2555 XFREE(MTYPE_RIPNG
, ripng
);
2558 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2560 struct interface
*ifp
;
2561 struct ripng_interface
*ri
;
2562 struct route_map
*rmap
;
2564 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2570 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2571 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2573 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2575 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2577 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2579 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2580 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2582 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2584 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2586 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2589 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2591 struct if_rmap
*if_rmap
;
2593 if_rmap
= if_rmap_lookup(ifp
->name
);
2595 ripng_if_rmap_update(if_rmap
);
2598 static void ripng_routemap_update_redistribute(struct ripng
*ripng
)
2600 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2601 if (ripng
->route_map
[i
].name
)
2602 ripng
->route_map
[i
].map
= route_map_lookup_by_name(
2603 ripng
->route_map
[i
].name
);
2607 static void ripng_routemap_update(const char *unused
)
2609 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2610 struct ripng
*ripng
;
2611 struct interface
*ifp
;
2613 FOR_ALL_INTERFACES (vrf
, ifp
)
2614 ripng_if_rmap_update_interface(ifp
);
2618 ripng_routemap_update_redistribute(ripng
);
2621 /* Link RIPng instance to VRF. */
2622 static void ripng_vrf_link(struct ripng
*ripng
, struct vrf
*vrf
)
2624 struct interface
*ifp
;
2627 ripng
->distribute_ctx
->vrf
= vrf
;
2630 FOR_ALL_INTERFACES (vrf
, ifp
)
2631 ripng_interface_sync(ifp
);
2634 /* Unlink RIPng instance from VRF. */
2635 static void ripng_vrf_unlink(struct ripng
*ripng
, struct vrf
*vrf
)
2637 struct interface
*ifp
;
2640 ripng
->distribute_ctx
->vrf
= NULL
;
2643 FOR_ALL_INTERFACES (vrf
, ifp
)
2644 ripng_interface_sync(ifp
);
2647 static void ripng_instance_enable(struct ripng
*ripng
, struct vrf
*vrf
,
2652 ripng_vrf_link(ripng
, vrf
);
2653 ripng
->enabled
= true;
2655 /* Create read and timer thread. */
2656 ripng_event(ripng
, RIPNG_READ
, ripng
->sock
);
2657 ripng_event(ripng
, RIPNG_UPDATE_EVENT
, 1);
2659 ripng_zebra_vrf_register(vrf
);
2662 static void ripng_instance_disable(struct ripng
*ripng
)
2664 struct vrf
*vrf
= ripng
->vrf
;
2665 struct agg_node
*rp
;
2667 /* Clear RIPng routes */
2668 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2669 struct ripng_aggregate
*aggregate
;
2672 if ((list
= rp
->info
) != NULL
) {
2673 struct ripng_info
*rinfo
;
2674 struct listnode
*listnode
;
2676 rinfo
= listgetdata(listhead(list
));
2677 if (ripng_route_rte(rinfo
))
2678 ripng_zebra_ipv6_delete(ripng
, rp
);
2680 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2681 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2682 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2683 ripng_info_free(rinfo
);
2687 agg_unlock_node(rp
);
2690 if ((aggregate
= rp
->aggregate
) != NULL
) {
2691 ripng_aggregate_free(aggregate
);
2692 rp
->aggregate
= NULL
;
2693 agg_unlock_node(rp
);
2697 /* Cancel the RIPng timers */
2698 RIPNG_TIMER_OFF(ripng
->t_update
);
2699 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2700 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2702 /* Cancel the read thread */
2703 if (ripng
->t_read
) {
2704 thread_cancel(ripng
->t_read
);
2705 ripng
->t_read
= NULL
;
2708 /* Close the RIPng socket */
2709 if (ripng
->sock
>= 0) {
2714 /* Clear existing peers. */
2715 list_delete_all_node(ripng
->peer_list
);
2717 ripng_zebra_vrf_deregister(vrf
);
2719 ripng_vrf_unlink(ripng
, vrf
);
2720 ripng
->enabled
= false;
2723 static int ripng_vrf_new(struct vrf
*vrf
)
2725 if (IS_RIPNG_DEBUG_EVENT
)
2726 zlog_debug("%s: VRF created: %s(%u)", __func__
, vrf
->name
,
2732 static int ripng_vrf_delete(struct vrf
*vrf
)
2734 if (IS_RIPNG_DEBUG_EVENT
)
2735 zlog_debug("%s: VRF deleted: %s(%u)", __func__
, vrf
->name
,
2741 static int ripng_vrf_enable(struct vrf
*vrf
)
2743 struct ripng
*ripng
;
2746 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2747 if (!ripng
|| ripng
->enabled
)
2750 if (IS_RIPNG_DEBUG_EVENT
)
2751 zlog_debug("%s: VRF %s(%u) enabled", __func__
, vrf
->name
,
2754 /* Activate the VRF RIPng instance. */
2755 if (!ripng
->enabled
) {
2756 socket
= ripng_make_socket(vrf
);
2760 ripng_instance_enable(ripng
, vrf
, socket
);
2766 static int ripng_vrf_disable(struct vrf
*vrf
)
2768 struct ripng
*ripng
;
2770 ripng
= ripng_lookup_by_vrf_name(vrf
->name
);
2771 if (!ripng
|| !ripng
->enabled
)
2774 if (IS_RIPNG_DEBUG_EVENT
)
2775 zlog_debug("%s: VRF %s(%u) disabled", __func__
, vrf
->name
,
2778 /* Deactivate the VRF RIPng instance. */
2780 ripng_instance_disable(ripng
);
2785 void ripng_vrf_init(void)
2787 vrf_init(ripng_vrf_new
, ripng_vrf_enable
, ripng_vrf_disable
,
2788 ripng_vrf_delete
, NULL
);
2791 void ripng_vrf_terminate(void)
2796 /* Initialize ripng structure and set commands. */
2799 /* Install RIPNG_NODE. */
2800 install_node(&cmd_ripng_node
, ripng_config_write
);
2802 /* Install ripng commands. */
2803 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2804 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2806 install_default(RIPNG_NODE
);
2809 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
2810 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
2811 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
2812 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
2813 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
2814 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
2815 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
2821 /* Access list install. */
2823 access_list_add_hook(ripng_distribute_update_all_wrapper
);
2824 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
2826 /* Prefix list initialize.*/
2828 prefix_list_add_hook(ripng_distribute_update_all
);
2829 prefix_list_delete_hook(ripng_distribute_update_all
);
2831 /* Distribute list install. */
2832 distribute_list_init(RIPNG_NODE
);
2834 /* Route-map for interface. */
2835 ripng_route_map_init();
2837 route_map_add_hook(ripng_routemap_update
);
2838 route_map_delete_hook(ripng_routemap_update
);
2840 if_rmap_init(RIPNG_NODE
);
2841 if_rmap_hook_add(ripng_if_rmap_update
);
2842 if_rmap_hook_delete(ripng_if_rmap_update
);