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"
40 #include "ripngd/ripngd.h"
41 #include "ripngd/ripng_route.h"
42 #include "ripngd/ripng_debug.h"
43 #include "ripngd/ripng_nexthop.h"
45 /* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48 struct ripng
*ripng
= NULL
;
50 enum { ripng_all_route
,
55 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
57 int ripng_triggered_update(struct thread
*);
59 /* RIPng next hop specification. */
60 struct ripng_nexthop
{
61 enum ripng_nexthop_type
{
65 struct in6_addr address
;
68 static int ripng_route_rte(struct ripng_info
*rinfo
)
70 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
71 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
74 /* Allocate new ripng information. */
75 struct ripng_info
*ripng_info_new()
77 struct ripng_info
*new;
79 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
83 /* Free ripng information. */
84 void ripng_info_free(struct ripng_info
*rinfo
)
86 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
89 /* Create ripng socket. */
90 static int ripng_make_socket(void)
94 struct sockaddr_in6 ripaddr
;
96 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
98 flog_err_sys(LIB_ERR_SOCKET
, "Can't make ripng socket");
102 setsockopt_so_recvbuf(sock
, 8096);
103 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
106 #ifdef IPTOS_PREC_INTERNETCONTROL
107 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
111 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
114 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
117 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
121 memset(&ripaddr
, 0, sizeof(ripaddr
));
122 ripaddr
.sin6_family
= AF_INET6
;
124 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
125 #endif /* SIN6_LEN */
126 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
128 frr_elevate_privs(&ripngd_privs
) {
129 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
131 zlog_err("Can't bind ripng socket: %s.",
132 safe_strerror(errno
));
143 /* Send RIPng packet. */
144 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
145 struct interface
*ifp
)
150 struct cmsghdr
*cmsgptr
;
152 struct in6_pktinfo
*pkt
;
153 struct sockaddr_in6 addr
;
155 if (IS_RIPNG_DEBUG_SEND
) {
157 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
158 zlog_debug(" send interface %s", ifp
->name
);
159 zlog_debug(" send packet size %d", bufsize
);
162 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
163 addr
.sin6_family
= AF_INET6
;
165 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
166 #endif /* SIN6_LEN */
167 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
169 /* When destination is specified. */
171 addr
.sin6_addr
= to
->sin6_addr
;
172 addr
.sin6_port
= to
->sin6_port
;
174 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
175 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
178 memset(&msg
, 0, sizeof(msg
));
179 msg
.msg_name
= (void *)&addr
;
180 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
183 msg
.msg_control
= (void *)adata
;
184 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
187 iov
.iov_len
= bufsize
;
189 cmsgptr
= (struct cmsghdr
*)adata
;
190 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
191 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
192 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
194 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
195 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
196 pkt
->ipi6_ifindex
= ifp
->ifindex
;
198 ret
= sendmsg(ripng
->sock
, &msg
, 0);
202 flog_err_sys(LIB_ERR_SOCKET
,
203 "RIPng send fail on %s to %s: %s",
204 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
205 safe_strerror(errno
));
207 flog_err_sys(LIB_ERR_SOCKET
,
208 "RIPng send fail on %s: %s", ifp
->name
,
209 safe_strerror(errno
));
215 /* Receive UDP RIPng packet from socket. */
216 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
217 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
223 struct cmsghdr
*cmsgptr
;
224 struct in6_addr dst
= {.s6_addr
= {0}};
226 memset(&dst
, 0, sizeof(struct in6_addr
));
228 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
229 point I can't determine size of cmsghdr */
232 /* Fill in message and iovec. */
233 memset(&msg
, 0, sizeof(msg
));
234 msg
.msg_name
= (void *)from
;
235 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
238 msg
.msg_control
= (void *)adata
;
239 msg
.msg_controllen
= sizeof adata
;
241 iov
.iov_len
= bufsize
;
243 /* If recvmsg fail return minus value. */
244 ret
= recvmsg(sock
, &msg
, 0);
248 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
249 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
250 /* I want interface index which this packet comes from. */
251 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
252 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
253 struct in6_pktinfo
*ptr
;
255 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
256 *ifindex
= ptr
->ipi6_ifindex
;
257 dst
= ptr
->ipi6_addr
;
261 "Interface index returned by IPV6_PKTINFO is zero");
264 /* Incoming packet's multicast hop limit. */
265 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
266 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
267 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
268 *hoplimit
= *phoplimit
;
272 /* Hoplimit check shold be done when destination address is
273 multicast address. */
274 if (!IN6_IS_ADDR_MULTICAST(&dst
))
280 /* Dump rip packet */
281 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
286 const char *command_str
;
288 /* Set command string. */
289 if (packet
->command
== RIPNG_REQUEST
)
290 command_str
= "request";
291 else if (packet
->command
== RIPNG_RESPONSE
)
292 command_str
= "response";
294 command_str
= "unknown";
296 /* Dump packet header. */
297 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
298 packet
->version
, size
);
300 /* Dump each routing table entry. */
303 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
304 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
305 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
308 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
309 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
310 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
314 /* RIPng next hop address RTE (Route Table Entry). */
315 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
316 struct ripng_nexthop
*nexthop
)
318 char buf
[INET6_BUFSIZ
];
320 /* Logging before checking RTE. */
321 if (IS_RIPNG_DEBUG_RECV
)
322 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
324 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
327 /* RFC2080 2.1.1 Next Hop:
328 The route tag and prefix length in the next hop RTE must be
329 set to zero on sending and ignored on receiption. */
330 if (ntohs(rte
->tag
) != 0)
332 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
334 (route_tag_t
)ntohs(rte
->tag
),
335 inet6_ntoa(from
->sin6_addr
));
337 if (rte
->prefixlen
!= 0)
339 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
340 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
342 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
343 next hop RTE indicates that the next hop address should be the
344 originator of the RIPng advertisement. An address specified as a
345 next hop must be a link-local address. */
346 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
347 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
348 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
352 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
353 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
354 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
358 /* The purpose of the next hop RTE is to eliminate packets being
359 routed through extra hops in the system. It is particularly useful
360 when RIPng is not being run on all of the routers on a network.
361 Note that next hop RTE is "advisory". That is, if the provided
362 information is ignored, a possibly sub-optimal, but absolutely
363 valid, route may be taken. If the received next hop address is not
364 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
365 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
366 inet6_ntoa(rte
->addr
),
367 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
369 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
370 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
375 /* If ifp has same link-local address then return 1. */
376 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
378 struct listnode
*node
;
379 struct connected
*connected
;
382 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
383 p
= connected
->address
;
385 if (p
->family
== AF_INET6
386 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
387 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
393 /* RIPng route garbage collect timer. */
394 static int ripng_garbage_collect(struct thread
*t
)
396 struct ripng_info
*rinfo
;
399 rinfo
= THREAD_ARG(t
);
400 rinfo
->t_garbage_collect
= NULL
;
402 /* Off timeout timer. */
403 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
405 /* Get route_node pointer. */
408 /* Unlock route_node. */
409 listnode_delete(rp
->info
, rinfo
);
410 if (list_isempty((struct list
*)rp
->info
)) {
411 list_delete_and_null((struct list
**)&rp
->info
);
415 /* Free RIPng routing information. */
416 ripng_info_free(rinfo
);
421 static void ripng_timeout_update(struct ripng_info
*rinfo
);
423 /* Add new route to the ECMP list.
424 * RETURN: the new entry added in the list, or NULL if it is not the first
425 * entry and ECMP is not allowed.
427 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
429 struct agg_node
*rp
= rinfo_new
->rp
;
430 struct ripng_info
*rinfo
= NULL
;
431 struct list
*list
= NULL
;
433 if (rp
->info
== NULL
)
434 rp
->info
= list_new();
435 list
= (struct list
*)rp
->info
;
437 /* If ECMP is not allowed and some entry already exists in the list,
439 if (listcount(list
) && !ripng
->ecmp
)
442 rinfo
= ripng_info_new();
443 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
444 listnode_add(list
, rinfo
);
446 if (ripng_route_rte(rinfo
)) {
447 ripng_timeout_update(rinfo
);
448 ripng_zebra_ipv6_add(rp
);
451 ripng_aggregate_increment(rp
, rinfo
);
453 /* Set the route change flag on the first entry. */
454 rinfo
= listgetdata(listhead(list
));
455 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
457 /* Signal the output process to trigger an update. */
458 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
463 /* Replace the ECMP list with the new route.
464 * RETURN: the new entry added in the list
466 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
468 struct agg_node
*rp
= rinfo_new
->rp
;
469 struct list
*list
= (struct list
*)rp
->info
;
470 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
471 struct listnode
*node
= NULL
, *nextnode
= NULL
;
473 if (list
== NULL
|| listcount(list
) == 0)
474 return ripng_ecmp_add(rinfo_new
);
476 /* Get the first entry */
477 rinfo
= listgetdata(listhead(list
));
479 /* Learnt route replaced by a local one. Delete it from zebra. */
480 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
481 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
482 ripng_zebra_ipv6_delete(rp
);
484 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
485 ripng_aggregate_decrement_list(rp
, list
);
487 /* Re-use the first entry, and delete the others. */
488 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
489 if (tmp_rinfo
!= rinfo
) {
490 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
491 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
492 list_delete_node(list
, node
);
493 ripng_info_free(tmp_rinfo
);
496 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
497 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
498 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
500 if (ripng_route_rte(rinfo
)) {
501 ripng_timeout_update(rinfo
);
502 /* The ADD message implies an update. */
503 ripng_zebra_ipv6_add(rp
);
506 ripng_aggregate_increment(rp
, rinfo
);
508 /* Set the route change flag. */
509 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
511 /* Signal the output process to trigger an update. */
512 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
517 /* Delete one route from the ECMP list.
519 * null - the entry is freed, and other entries exist in the list
520 * the entry - the entry is the last one in the list; its metric is set
521 * to INFINITY, and the garbage collector is started for it
523 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
525 struct agg_node
*rp
= rinfo
->rp
;
526 struct list
*list
= (struct list
*)rp
->info
;
528 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
530 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
531 ripng_aggregate_decrement(rp
, rinfo
);
533 if (listcount(list
) > 1) {
534 /* Some other ECMP entries still exist. Just delete this entry.
536 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
537 listnode_delete(list
, rinfo
);
538 if (ripng_route_rte(rinfo
)
539 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
540 /* The ADD message implies the update. */
541 ripng_zebra_ipv6_add(rp
);
542 ripng_info_free(rinfo
);
545 assert(rinfo
== listgetdata(listhead(list
)));
547 /* This is the only entry left in the list. We must keep it in
548 * the list for garbage collection time, with INFINITY metric.
551 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
552 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
553 ripng
->garbage_time
);
555 if (ripng_route_rte(rinfo
)
556 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
557 ripng_zebra_ipv6_delete(rp
);
560 /* Set the route change flag on the first entry. */
561 rinfo
= listgetdata(listhead(list
));
562 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
564 /* Signal the output process to trigger an update. */
565 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
570 /* Timeout RIPng routes. */
571 static int ripng_timeout(struct thread
*t
)
573 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
577 static void ripng_timeout_update(struct ripng_info
*rinfo
)
579 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
580 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
581 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
582 ripng
->timeout_time
);
586 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
587 struct ripng_interface
*ri
)
589 struct distribute
*dist
;
590 struct access_list
*alist
;
591 struct prefix_list
*plist
;
592 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
595 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
597 /* Input distribute-list filtering. */
598 if (ri
->list
[ripng_distribute
]) {
599 if (access_list_apply(ri
->list
[ripng_distribute
],
602 if (IS_RIPNG_DEBUG_PACKET
)
603 zlog_debug("%s/%d filtered by distribute %s",
604 inet6_ntoa(p
->prefix
), p
->prefixlen
,
609 if (ri
->prefix
[ripng_distribute
]) {
610 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
613 if (IS_RIPNG_DEBUG_PACKET
)
614 zlog_debug("%s/%d filtered by prefix-list %s",
615 inet6_ntoa(p
->prefix
), p
->prefixlen
,
621 /* All interface filter check. */
622 dist
= distribute_lookup(NULL
);
624 if (dist
->list
[distribute
]) {
625 alist
= access_list_lookup(AFI_IP6
,
626 dist
->list
[distribute
]);
629 if (access_list_apply(alist
, (struct prefix
*)p
)
631 if (IS_RIPNG_DEBUG_PACKET
)
633 "%s/%d filtered by distribute %s",
634 inet6_ntoa(p
->prefix
),
635 p
->prefixlen
, inout
);
640 if (dist
->prefix
[distribute
]) {
641 plist
= prefix_list_lookup(AFI_IP6
,
642 dist
->prefix
[distribute
]);
645 if (prefix_list_apply(plist
, (struct prefix
*)p
)
647 if (IS_RIPNG_DEBUG_PACKET
)
649 "%s/%d filtered by prefix-list %s",
650 inet6_ntoa(p
->prefix
),
651 p
->prefixlen
, inout
);
660 /* Process RIPng route according to RFC2080. */
661 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
662 struct ripng_nexthop
*ripng_nexthop
,
663 struct interface
*ifp
)
666 struct prefix_ipv6 p
;
668 struct ripng_info
*rinfo
= NULL
, newinfo
;
669 struct ripng_interface
*ri
;
670 struct in6_addr
*nexthop
;
672 struct list
*list
= NULL
;
673 struct listnode
*node
= NULL
;
675 /* Make prefix structure. */
676 memset(&p
, 0, sizeof(struct prefix_ipv6
));
678 /* p.prefix = rte->addr; */
679 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
680 p
.prefixlen
= rte
->prefixlen
;
682 /* Make sure mask is applied. */
683 /* XXX We have to check the prefix is valid or not before call
687 /* Apply input filters. */
690 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
694 memset(&newinfo
, 0, sizeof(newinfo
));
695 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
696 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
697 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
698 newinfo
.nexthop
= ripng_nexthop
->address
;
700 newinfo
.nexthop
= from
->sin6_addr
;
701 newinfo
.from
= from
->sin6_addr
;
702 newinfo
.ifindex
= ifp
->ifindex
;
703 newinfo
.metric
= rte
->metric
;
704 newinfo
.metric_out
= rte
->metric
; /* XXX */
705 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
708 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
711 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
712 (struct prefix
*)&p
, RMAP_RIPNG
,
715 if (ret
== RMAP_DENYMATCH
) {
716 if (IS_RIPNG_DEBUG_PACKET
)
718 "RIPng %s/%d is filtered by route-map in",
719 inet6_ntoa(p
.prefix
), p
.prefixlen
);
723 /* Get back the object */
724 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
725 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
726 &ripng_nexthop
->address
)) {
727 /* the nexthop get changed by the routemap */
728 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
729 ripng_nexthop
->address
=
732 ripng_nexthop
->address
= in6addr_any
;
735 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
737 /* the nexthop get changed by the routemap */
738 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
739 ripng_nexthop
->flag
=
740 RIPNG_NEXTHOP_ADDRESS
;
741 ripng_nexthop
->address
=
746 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
748 newinfo
.metric_out
; /* XXX: the routemap uses the
752 /* Once the entry has been validated, update the metric by
753 * adding the cost of the network on wich the message
754 * arrived. If the result is greater than infinity, use infinity
755 * (RFC2453 Sec. 3.9.2)
758 /* Zebra ripngd can handle offset-list in. */
759 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
761 /* If offset-list does not modify the metric use interface's
764 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
766 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
767 rte
->metric
= RIPNG_METRIC_INFINITY
;
769 /* Set nexthop pointer. */
770 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
771 nexthop
= &ripng_nexthop
->address
;
773 nexthop
= &from
->sin6_addr
;
775 /* Lookup RIPng routing table. */
776 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
779 newinfo
.nexthop
= *nexthop
;
780 newinfo
.metric
= rte
->metric
;
781 newinfo
.tag
= ntohs(rte
->tag
);
783 /* Check to see whether there is already RIPng route on the table. */
784 if ((list
= rp
->info
) != NULL
)
785 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
786 /* Need to compare with redistributed entry or local
788 if (!ripng_route_rte(rinfo
))
791 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
792 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
795 if (!listnextnode(node
)) {
796 /* Not found in the list */
798 if (rte
->metric
> rinfo
->metric
) {
799 /* New route has a greater metric.
805 if (rte
->metric
< rinfo
->metric
)
806 /* New route has a smaller metric.
807 * Replace the ECMP list
808 * with the new one in below. */
811 /* Metrics are same. Unless ECMP is disabled,
812 * keep "rinfo" null and
813 * the new route is added in the ECMP list in
821 /* Redistributed route check. */
822 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
823 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
828 /* Local static route. */
829 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
830 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
831 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
832 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
839 /* Now, check to see whether there is already an explicit route
840 for the destination prefix. If there is no such route, add
841 this route to the routing table, unless the metric is
842 infinity (there is no point in adding a route which
844 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
845 ripng_ecmp_add(&newinfo
);
849 /* If there is an existing route, compare the next hop address
850 to the address of the router from which the datagram came.
851 If this datagram is from the same router as the existing
852 route, reinitialize the timeout. */
853 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
854 && (rinfo
->ifindex
== ifp
->ifindex
));
857 * RFC 2080 - Section 2.4.2:
858 * "If the new metric is the same as the old one, examine the
860 * for the existing route. If it is at least halfway to the
862 * point, switch to the new route. This heuristic is optional,
864 * highly recommended".
866 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
868 && (thread_timer_remain_second(rinfo
->t_timeout
)
869 < (ripng
->timeout_time
/ 2))) {
870 ripng_ecmp_replace(&newinfo
);
872 /* Next, compare the metrics. If the datagram is from the same
873 router as the existing route, and the new metric is different
874 than the old one; or, if the new metric is lower than the old
875 one; do the following actions: */
876 else if ((same
&& rinfo
->metric
!= rte
->metric
)
877 || rte
->metric
< rinfo
->metric
) {
878 if (listcount(list
) == 1) {
879 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
880 ripng_ecmp_replace(&newinfo
);
882 ripng_ecmp_delete(rinfo
);
884 if (newinfo
.metric
< rinfo
->metric
)
885 ripng_ecmp_replace(&newinfo
);
886 else /* newinfo.metric > rinfo->metric */
887 ripng_ecmp_delete(rinfo
);
889 } else /* same & no change */
890 ripng_timeout_update(rinfo
);
892 /* Unlock tempolary lock of the route. */
897 /* Add redistributed route to RIPng table. */
898 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
899 ifindex_t ifindex
, struct in6_addr
*nexthop
,
903 struct ripng_info
*rinfo
= NULL
, newinfo
;
904 struct list
*list
= NULL
;
906 /* Redistribute route */
907 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
909 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
912 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
914 memset(&newinfo
, 0, sizeof(struct ripng_info
));
916 newinfo
.sub_type
= sub_type
;
917 newinfo
.ifindex
= ifindex
;
919 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
922 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
923 newinfo
.nexthop
= *nexthop
;
925 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
926 rinfo
= listgetdata(listhead(list
));
928 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
929 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
930 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
935 /* Manually configured RIPng route check.
936 * They have the precedence on all the other entries.
938 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
939 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
940 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
941 if (type
!= ZEBRA_ROUTE_RIPNG
942 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
943 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
949 ripng_ecmp_replace(&newinfo
);
952 ripng_ecmp_add(&newinfo
);
954 if (IS_RIPNG_DEBUG_EVENT
) {
957 "Redistribute new prefix %s/%d on the interface %s",
958 inet6_ntoa(p
->prefix
), p
->prefixlen
,
959 ifindex2ifname(ifindex
, VRF_DEFAULT
));
962 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
963 inet6_ntoa(p
->prefix
), p
->prefixlen
,
964 inet6_ntoa(*nexthop
),
965 ifindex2ifname(ifindex
, VRF_DEFAULT
));
968 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
971 /* Delete redistributed route to RIPng table. */
972 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
976 struct ripng_info
*rinfo
;
978 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
980 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
983 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
986 struct list
*list
= rp
->info
;
988 if (list
!= NULL
&& listcount(list
) != 0) {
989 rinfo
= listgetdata(listhead(list
));
990 if (rinfo
!= NULL
&& rinfo
->type
== type
991 && rinfo
->sub_type
== sub_type
992 && rinfo
->ifindex
== ifindex
) {
993 /* Perform poisoned reverse. */
994 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
995 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
996 ripng_garbage_collect
,
997 ripng
->garbage_time
);
998 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1000 /* Aggregate count decrement. */
1001 ripng_aggregate_decrement(rp
, rinfo
);
1003 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1005 if (IS_RIPNG_DEBUG_EVENT
)
1007 "Poisone %s/%d on the interface %s with an "
1008 "infinity metric [delete]",
1009 inet6_ntoa(p
->prefix
),
1011 ifindex2ifname(ifindex
,
1014 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1017 agg_unlock_node(rp
);
1021 /* Withdraw redistributed route. */
1022 void ripng_redistribute_withdraw(int type
)
1024 struct agg_node
*rp
;
1025 struct ripng_info
*rinfo
= NULL
;
1026 struct list
*list
= NULL
;
1031 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1032 if ((list
= rp
->info
) != NULL
) {
1033 rinfo
= listgetdata(listhead(list
));
1034 if ((rinfo
->type
== type
)
1035 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1036 /* Perform poisoned reverse. */
1037 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1038 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1039 ripng_garbage_collect
,
1040 ripng
->garbage_time
);
1041 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1043 /* Aggregate count decrement. */
1044 ripng_aggregate_decrement(rp
, rinfo
);
1046 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1048 if (IS_RIPNG_DEBUG_EVENT
) {
1049 struct prefix_ipv6
*p
=
1050 (struct prefix_ipv6
*)&rp
->p
;
1053 "Poisone %s/%d on the interface %s [withdraw]",
1054 inet6_ntoa(p
->prefix
),
1056 ifindex2ifname(rinfo
->ifindex
,
1060 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1065 /* RIP routing information. */
1066 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1067 struct sockaddr_in6
*from
,
1068 struct interface
*ifp
, int hoplimit
)
1072 struct ripng_nexthop nexthop
;
1074 /* RFC2080 2.4.2 Response Messages:
1075 The Response must be ignored if it is not from the RIPng port. */
1076 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1077 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1078 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1079 ripng_peer_bad_packet(from
);
1083 /* The datagram's IPv6 source address should be checked to see
1084 whether the datagram is from a valid neighbor; the source of the
1085 datagram must be a link-local address. */
1086 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1087 zlog_warn("RIPng packet comes from non link local address %s",
1088 inet6_ntoa(from
->sin6_addr
));
1089 ripng_peer_bad_packet(from
);
1093 /* It is also worth checking to see whether the response is from one
1094 of the router's own addresses. Interfaces on broadcast networks
1095 may receive copies of their own multicasts immediately. If a
1096 router processes its own output as new input, confusion is likely,
1097 and such datagrams must be ignored. */
1098 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1100 "RIPng packet comes from my own link local address %s",
1101 inet6_ntoa(from
->sin6_addr
));
1102 ripng_peer_bad_packet(from
);
1106 /* As an additional check, periodic advertisements must have their
1107 hop counts set to 255, and inbound, multicast packets sent from the
1108 RIPng port (i.e. periodic advertisement or triggered update
1109 packets) must be examined to ensure that the hop count is 255. */
1110 if (hoplimit
>= 0 && hoplimit
!= 255) {
1112 "RIPng packet comes with non 255 hop count %d from %s",
1113 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1114 ripng_peer_bad_packet(from
);
1118 /* Update RIPng peer. */
1119 ripng_peer_update(from
, packet
->version
);
1121 /* Reset nexthop. */
1122 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1123 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1125 /* Set RTE pointer. */
1128 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1129 /* First of all, we have to check this RTE is next hop RTE or
1130 not. Next hop RTE is completely different with normal RTE so
1131 we need special treatment. */
1132 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1133 ripng_nexthop_rte(rte
, from
, &nexthop
);
1137 /* RTE information validation. */
1139 /* - is the destination prefix valid (e.g., not a multicast
1140 prefix and not a link-local address) A link-local address
1141 should never be present in an RTE. */
1142 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1144 "Destination prefix is a multicast address %s/%d [%d]",
1145 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1147 ripng_peer_bad_route(from
);
1150 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1152 "Destination prefix is a link-local address %s/%d [%d]",
1153 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1155 ripng_peer_bad_route(from
);
1158 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1160 "Destination prefix is a loopback address %s/%d [%d]",
1161 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1163 ripng_peer_bad_route(from
);
1167 /* - is the prefix length valid (i.e., between 0 and 128,
1169 if (rte
->prefixlen
> 128) {
1170 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1171 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1172 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1173 ripng_peer_bad_route(from
);
1177 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1178 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1179 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1180 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1181 ripng_peer_bad_route(from
);
1185 /* Vincent: XXX Should we compute the direclty reachable nexthop
1186 * for our RIPng network ?
1189 /* Routing table updates. */
1190 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1194 /* Response to request message. */
1195 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1196 struct sockaddr_in6
*from
,
1197 struct interface
*ifp
)
1201 struct prefix_ipv6 p
;
1202 struct agg_node
*rp
;
1203 struct ripng_info
*rinfo
;
1204 struct ripng_interface
*ri
;
1206 /* Does not reponse to the requests on the loopback interfaces */
1207 if (if_is_loopback(ifp
))
1210 /* Check RIPng process is enabled on this interface. */
1215 /* When passive interface is specified, suppress responses */
1219 /* RIPng peer update. */
1220 ripng_peer_update(from
, packet
->version
);
1222 lim
= ((caddr_t
)packet
) + size
;
1225 /* The Request is processed entry by entry. If there are no
1226 entries, no response is given. */
1227 if (lim
== (caddr_t
)rte
)
1230 /* There is one special case. If there is exactly one entry in the
1231 request, and it has a destination prefix of zero, a prefix length
1232 of zero, and a metric of infinity (i.e., 16), then this is a
1233 request to send the entire routing table. In that case, a call
1234 is made to the output process to send the routing table to the
1235 requesting address/port. */
1236 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1237 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1238 /* All route with split horizon */
1239 ripng_output_process(ifp
, from
, ripng_all_route
);
1241 /* Except for this special case, processing is quite simple.
1242 Examine the list of RTEs in the Request one by one. For each
1243 entry, look up the destination in the router's routing
1244 database and, if there is a route, put that route's metric in
1245 the metric field of the RTE. If there is no explicit route
1246 to the specified destination, put infinity in the metric
1247 field. Once all the entries have been filled in, change the
1248 command from Request to Response and send the datagram back
1249 to the requestor. */
1250 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1251 p
.family
= AF_INET6
;
1253 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1254 p
.prefix
= rte
->addr
;
1255 p
.prefixlen
= rte
->prefixlen
;
1256 apply_mask_ipv6(&p
);
1258 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1261 rinfo
= listgetdata(
1262 listhead((struct list
*)rp
->info
));
1263 rte
->metric
= rinfo
->metric
;
1264 agg_unlock_node(rp
);
1266 rte
->metric
= RIPNG_METRIC_INFINITY
;
1268 packet
->command
= RIPNG_RESPONSE
;
1270 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1274 /* First entry point of reading RIPng packet. */
1275 static int ripng_read(struct thread
*thread
)
1279 struct sockaddr_in6 from
;
1280 struct ripng_packet
*packet
;
1281 ifindex_t ifindex
= 0;
1282 struct interface
*ifp
;
1285 /* Check ripng is active and alive. */
1286 assert(ripng
!= NULL
);
1287 assert(ripng
->sock
>= 0);
1289 /* Fetch thread data and set read pointer to empty for event
1290 managing. `sock' sould be same as ripng->sock. */
1291 sock
= THREAD_FD(thread
);
1292 ripng
->t_read
= NULL
;
1294 /* Add myself to the next event. */
1295 ripng_event(RIPNG_READ
, sock
);
1297 /* Read RIPng packet. */
1298 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1299 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1302 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1306 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1307 (4)) must be multiple size of one RTE size (20). */
1308 if (((len
- 4) % 20) != 0) {
1309 zlog_warn("RIPng invalid packet size %d from %s", len
,
1310 inet6_ntoa(from
.sin6_addr
));
1311 ripng_peer_bad_packet(&from
);
1315 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1316 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1318 /* RIPng packet received. */
1319 if (IS_RIPNG_DEBUG_EVENT
)
1320 zlog_debug("RIPng packet received from %s port %d on %s",
1321 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1322 ifp
? ifp
->name
: "unknown");
1324 /* Logging before packet checking. */
1325 if (IS_RIPNG_DEBUG_RECV
)
1326 ripng_packet_dump(packet
, len
, "RECV");
1328 /* Packet comes from unknown interface. */
1330 zlog_warn("RIPng packet comes from unknown interface %d",
1335 /* Packet version mismatch checking. */
1336 if (packet
->version
!= ripng
->version
) {
1338 "RIPng packet version %d doesn't fit to my version %d",
1339 packet
->version
, ripng
->version
);
1340 ripng_peer_bad_packet(&from
);
1344 /* Process RIPng packet. */
1345 switch (packet
->command
) {
1347 ripng_request_process(packet
, len
, &from
, ifp
);
1349 case RIPNG_RESPONSE
:
1350 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1353 zlog_warn("Invalid RIPng command %d", packet
->command
);
1354 ripng_peer_bad_packet(&from
);
1360 /* Walk down the RIPng routing table then clear changed flag. */
1361 static void ripng_clear_changed_flag(void)
1363 struct agg_node
*rp
;
1364 struct ripng_info
*rinfo
= NULL
;
1365 struct list
*list
= NULL
;
1366 struct listnode
*listnode
= NULL
;
1368 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1369 if ((list
= rp
->info
) != NULL
)
1370 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1371 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1372 /* This flag can be set only on the first entry.
1378 /* Regular update of RIPng route. Send all routing formation to RIPng
1379 enabled interface. */
1380 static int ripng_update(struct thread
*t
)
1382 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1383 struct interface
*ifp
;
1384 struct ripng_interface
*ri
;
1386 /* Clear update timer thread. */
1387 ripng
->t_update
= NULL
;
1389 /* Logging update event. */
1390 if (IS_RIPNG_DEBUG_EVENT
)
1391 zlog_debug("RIPng update timer expired!");
1393 /* Supply routes to each interface. */
1394 FOR_ALL_INTERFACES (vrf
, ifp
) {
1397 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1403 /* When passive interface is specified, suppress announce to the
1409 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1410 if (IS_RIPNG_DEBUG_EVENT
)
1412 "[Event] RIPng send to if %d is suppressed by config",
1416 #endif /* RIPNG_ADVANCED */
1418 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1421 /* Triggered updates may be suppressed if a regular update is due by
1422 the time the triggered update would be sent. */
1423 if (ripng
->t_triggered_interval
) {
1424 thread_cancel(ripng
->t_triggered_interval
);
1425 ripng
->t_triggered_interval
= NULL
;
1429 /* Reset flush event. */
1430 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1435 /* Triggered update interval timer. */
1436 static int ripng_triggered_interval(struct thread
*t
)
1438 ripng
->t_triggered_interval
= NULL
;
1440 if (ripng
->trigger
) {
1442 ripng_triggered_update(t
);
1447 /* Execute triggered update. */
1448 int ripng_triggered_update(struct thread
*t
)
1450 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1451 struct interface
*ifp
;
1452 struct ripng_interface
*ri
;
1455 ripng
->t_triggered_update
= NULL
;
1457 /* Cancel interval timer. */
1458 if (ripng
->t_triggered_interval
) {
1459 thread_cancel(ripng
->t_triggered_interval
);
1460 ripng
->t_triggered_interval
= NULL
;
1464 /* Logging triggered update. */
1465 if (IS_RIPNG_DEBUG_EVENT
)
1466 zlog_debug("RIPng triggered update!");
1468 /* Split Horizon processing is done when generating triggered
1469 updates as well as normal updates (see section 2.6). */
1470 FOR_ALL_INTERFACES (vrf
, ifp
) {
1473 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1479 /* When passive interface is specified, suppress announce to the
1484 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1487 /* Once all of the triggered updates have been generated, the route
1488 change flags should be cleared. */
1489 ripng_clear_changed_flag();
1491 /* After a triggered update is sent, a timer should be set for a
1492 random interval between 1 and 5 seconds. If other changes that
1493 would trigger updates occur before the timer expires, a single
1494 update is triggered when the timer expires. */
1495 interval
= (random() % 5) + 1;
1497 ripng
->t_triggered_interval
= NULL
;
1498 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1499 &ripng
->t_triggered_interval
);
1504 /* Write routing table entry to the stream and return next index of
1505 the routing table entry in the stream. */
1506 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1507 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1509 /* RIPng packet header. */
1511 stream_putc(s
, RIPNG_RESPONSE
);
1512 stream_putc(s
, RIPNG_V1
);
1516 /* Write routing table entry. */
1519 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1521 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1522 stream_putw(s
, tag
);
1524 stream_putc(s
, p
->prefixlen
);
1527 stream_putc(s
, metric
);
1532 /* Send RESPONSE message to specified destination. */
1533 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1537 struct agg_node
*rp
;
1538 struct ripng_info
*rinfo
;
1539 struct ripng_interface
*ri
;
1540 struct ripng_aggregate
*aggregate
;
1541 struct prefix_ipv6
*p
;
1542 struct list
*ripng_rte_list
;
1543 struct list
*list
= NULL
;
1544 struct listnode
*listnode
= NULL
;
1546 if (IS_RIPNG_DEBUG_EVENT
) {
1548 zlog_debug("RIPng update routes to neighbor %s",
1549 inet6_ntoa(to
->sin6_addr
));
1551 zlog_debug("RIPng update routes on interface %s",
1555 /* Get RIPng interface. */
1558 ripng_rte_list
= ripng_rte_new();
1560 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1561 if ((list
= rp
->info
) != NULL
1562 && (rinfo
= listgetdata(listhead(list
))) != NULL
1563 && rinfo
->suppress
== 0) {
1564 /* If no route-map are applied, the RTE will be these
1568 p
= (struct prefix_ipv6
*)&rp
->p
;
1569 rinfo
->metric_out
= rinfo
->metric
;
1570 rinfo
->tag_out
= rinfo
->tag
;
1571 memset(&rinfo
->nexthop_out
, 0,
1572 sizeof(rinfo
->nexthop_out
));
1573 /* In order to avoid some local loops,
1574 * if the RIPng route has a nexthop via this interface,
1576 * otherwise set it to 0. The nexthop should not be
1578 * beyond the local broadcast/multicast area in order
1579 * to avoid an IGP multi-level recursive look-up.
1581 if (rinfo
->ifindex
== ifp
->ifindex
)
1582 rinfo
->nexthop_out
= rinfo
->nexthop
;
1584 /* Apply output filters. */
1585 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1589 /* Changed route only output. */
1590 if (route_type
== ripng_changed_route
1591 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1594 /* Split horizon. */
1595 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1596 /* We perform split horizon for RIPng routes. */
1598 struct ripng_info
*tmp_rinfo
= NULL
;
1600 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1602 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1603 && tmp_rinfo
->ifindex
1612 /* Preparation for route-map. */
1613 rinfo
->metric_set
= 0;
1616 * and tag_out are already initialized.
1619 /* Interface route-map */
1620 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1623 ret
= route_map_apply(
1624 ri
->routemap
[RIPNG_FILTER_OUT
],
1625 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1627 if (ret
== RMAP_DENYMATCH
) {
1628 if (IS_RIPNG_DEBUG_PACKET
)
1630 "RIPng %s/%d is filtered by route-map out",
1631 inet6_ntoa(p
->prefix
),
1637 /* Redistribute route-map. */
1638 if (ripng
->route_map
[rinfo
->type
].name
) {
1641 ret
= route_map_apply(
1642 ripng
->route_map
[rinfo
->type
].map
,
1643 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1645 if (ret
== RMAP_DENYMATCH
) {
1646 if (IS_RIPNG_DEBUG_PACKET
)
1648 "RIPng %s/%d is filtered by route-map",
1649 inet6_ntoa(p
->prefix
),
1655 /* When the route-map does not set metric. */
1656 if (!rinfo
->metric_set
) {
1657 /* If the redistribute metric is set. */
1658 if (ripng
->route_map
[rinfo
->type
].metric_config
1659 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1661 ripng
->route_map
[rinfo
->type
]
1664 /* If the route is not connected or
1666 one, use default-metric value */
1667 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1669 != ZEBRA_ROUTE_CONNECT
1671 != RIPNG_METRIC_INFINITY
)
1673 ripng
->default_metric
;
1677 /* Apply offset-list */
1678 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1679 ripng_offset_list_apply_out(p
, ifp
,
1680 &rinfo
->metric_out
);
1682 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1683 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1685 /* Perform split-horizon with poisoned reverse
1688 if (ri
->split_horizon
1689 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1690 struct ripng_info
*tmp_rinfo
= NULL
;
1692 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1694 if ((tmp_rinfo
->type
1695 == ZEBRA_ROUTE_RIPNG
)
1696 && tmp_rinfo
->ifindex
1699 RIPNG_METRIC_INFINITY
;
1702 /* Add RTE to the list */
1703 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1706 /* Process the aggregated RTE entry */
1707 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1708 && aggregate
->suppress
== 0) {
1709 /* If no route-map are applied, the RTE will be these
1713 p
= (struct prefix_ipv6
*)&rp
->p
;
1714 aggregate
->metric_set
= 0;
1715 aggregate
->metric_out
= aggregate
->metric
;
1716 aggregate
->tag_out
= aggregate
->tag
;
1717 memset(&aggregate
->nexthop_out
, 0,
1718 sizeof(aggregate
->nexthop_out
));
1720 /* Apply output filters.*/
1721 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1725 /* Interface route-map */
1726 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1728 struct ripng_info newinfo
;
1730 /* let's cast the aggregate structure to
1732 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1733 /* the nexthop is :: */
1734 newinfo
.metric
= aggregate
->metric
;
1735 newinfo
.metric_out
= aggregate
->metric_out
;
1736 newinfo
.tag
= aggregate
->tag
;
1737 newinfo
.tag_out
= aggregate
->tag_out
;
1739 ret
= route_map_apply(
1740 ri
->routemap
[RIPNG_FILTER_OUT
],
1741 (struct prefix
*)p
, RMAP_RIPNG
,
1744 if (ret
== RMAP_DENYMATCH
) {
1745 if (IS_RIPNG_DEBUG_PACKET
)
1747 "RIPng %s/%d is filtered by route-map out",
1748 inet6_ntoa(p
->prefix
),
1753 aggregate
->metric_out
= newinfo
.metric_out
;
1754 aggregate
->tag_out
= newinfo
.tag_out
;
1755 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1756 aggregate
->nexthop_out
=
1757 newinfo
.nexthop_out
;
1760 /* There is no redistribute routemap for the aggregated
1763 /* Changed route only output. */
1764 /* XXX, vincent, in order to increase time convergence,
1765 * it should be announced if a child has changed.
1767 if (route_type
== ripng_changed_route
)
1770 /* Apply offset-list */
1771 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1772 ripng_offset_list_apply_out(
1773 p
, ifp
, &aggregate
->metric_out
);
1775 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1776 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1778 /* Add RTE to the list */
1779 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1783 /* Flush the list */
1784 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1785 ripng_rte_free(ripng_rte_list
);
1788 /* Create new RIPng instance and set it to global variable. */
1789 static int ripng_create(void)
1791 /* ripng should be NULL. */
1792 assert(ripng
== NULL
);
1794 /* Allocaste RIPng instance. */
1795 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1797 /* Default version and timer values. */
1798 ripng
->version
= RIPNG_V1
;
1799 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1800 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1801 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1802 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1805 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1806 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1808 /* Initialize RIPng routig table. */
1809 ripng
->table
= agg_table_init();
1810 ripng
->route
= agg_table_init();
1811 ripng
->aggregate
= agg_table_init();
1814 ripng
->sock
= ripng_make_socket();
1815 if (ripng
->sock
< 0)
1819 ripng_event(RIPNG_READ
, ripng
->sock
);
1820 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1825 /* Send RIPng request to the interface. */
1826 int ripng_request(struct interface
*ifp
)
1829 struct ripng_packet ripng_packet
;
1831 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1833 if (if_is_loopback(ifp
))
1836 /* If interface is down, don't send RIP packet. */
1840 if (IS_RIPNG_DEBUG_EVENT
)
1841 zlog_debug("RIPng send request to %s", ifp
->name
);
1843 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1844 ripng_packet
.command
= RIPNG_REQUEST
;
1845 ripng_packet
.version
= RIPNG_V1
;
1846 rte
= ripng_packet
.rte
;
1847 rte
->metric
= RIPNG_METRIC_INFINITY
;
1849 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1854 static int ripng_update_jitter(int time
)
1856 return ((random() % (time
+ 1)) - (time
/ 2));
1859 void ripng_event(enum ripng_event event
, int sock
)
1865 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1867 case RIPNG_UPDATE_EVENT
:
1868 if (ripng
->t_update
) {
1869 thread_cancel(ripng
->t_update
);
1870 ripng
->t_update
= NULL
;
1872 /* Update timer jitter. */
1873 jitter
= ripng_update_jitter(ripng
->update_time
);
1875 ripng
->t_update
= NULL
;
1876 thread_add_timer(master
, ripng_update
, NULL
,
1877 sock
? 2 : ripng
->update_time
+ jitter
,
1880 case RIPNG_TRIGGERED_UPDATE
:
1881 if (ripng
->t_triggered_interval
)
1884 thread_add_event(master
, ripng_triggered_update
, NULL
,
1885 0, &ripng
->t_triggered_update
);
1893 /* Print out routes update time. */
1894 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1899 char timebuf
[TIME_BUF
];
1900 struct thread
*thread
;
1902 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1903 clock
= thread_timer_remain_second(thread
);
1904 tm
= gmtime(&clock
);
1905 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1906 vty_out(vty
, "%5s", timebuf
);
1907 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1908 clock
= thread_timer_remain_second(thread
);
1909 tm
= gmtime(&clock
);
1910 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1911 vty_out(vty
, "%5s", timebuf
);
1915 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1920 if (rinfo
->suppress
)
1923 switch (rinfo
->sub_type
) {
1924 case RIPNG_ROUTE_RTE
:
1927 case RIPNG_ROUTE_STATIC
:
1930 case RIPNG_ROUTE_DEFAULT
:
1933 case RIPNG_ROUTE_REDISTRIBUTE
:
1936 case RIPNG_ROUTE_INTERFACE
:
1947 DEFUN (show_ipv6_ripng
,
1948 show_ipv6_ripng_cmd
,
1952 "Show RIPng routes\n")
1954 struct agg_node
*rp
;
1955 struct ripng_info
*rinfo
;
1956 struct ripng_aggregate
*aggregate
;
1957 struct prefix_ipv6
*p
;
1958 struct list
*list
= NULL
;
1959 struct listnode
*listnode
= NULL
;
1965 /* Header of display. */
1967 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1969 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1970 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1971 " Network Next Hop Via Metric Tag Time\n");
1973 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1974 if ((aggregate
= rp
->aggregate
) != NULL
) {
1975 p
= (struct prefix_ipv6
*)&rp
->p
;
1978 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1979 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1982 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1986 vty_out(vty
, "%*s", 18, " ");
1988 vty_out(vty
, "%*s", 28, " ");
1989 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1990 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1993 if ((list
= rp
->info
) != NULL
)
1994 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1995 p
= (struct prefix_ipv6
*)&rp
->p
;
1998 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1999 zebra_route_char(rinfo
->type
),
2000 ripng_route_subtype_print(rinfo
),
2001 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2004 vty_out(vty
, "%c(%s) %s/%d ",
2005 zebra_route_char(rinfo
->type
),
2006 ripng_route_subtype_print(rinfo
),
2007 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2010 vty_out(vty
, "%*s", 18, " ");
2011 len
= vty_out(vty
, "%s",
2012 inet6_ntoa(rinfo
->nexthop
));
2016 vty_out(vty
, "%*s", len
, " ");
2019 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2020 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2023 ifindex2ifname(rinfo
->ifindex
,
2025 } else if (rinfo
->metric
2026 == RIPNG_METRIC_INFINITY
) {
2027 len
= vty_out(vty
, "kill");
2029 len
= vty_out(vty
, "self");
2033 vty_out(vty
, "%*s", len
, " ");
2035 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2036 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2039 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2040 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2041 /* RTE from remote RIP routers */
2042 ripng_vty_out_uptime(vty
, rinfo
);
2043 } else if (rinfo
->metric
2044 == RIPNG_METRIC_INFINITY
) {
2045 /* poisonous reversed routes (gc) */
2046 ripng_vty_out_uptime(vty
, rinfo
);
2056 DEFUN (show_ipv6_ripng_status
,
2057 show_ipv6_ripng_status_cmd
,
2058 "show ipv6 ripng status",
2061 "Show RIPng routes\n"
2062 "IPv6 routing protocol process parameters and statistics\n")
2064 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2065 struct interface
*ifp
;
2070 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2071 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2072 ripng
->update_time
);
2073 vty_out(vty
, " next due in %lu seconds\n",
2074 thread_timer_remain_second(ripng
->t_update
));
2075 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2076 vty_out(vty
, " garbage collect after %ld seconds\n",
2077 ripng
->garbage_time
);
2079 /* Filtering status show. */
2080 config_show_distribute(vty
);
2082 /* Default metric information. */
2083 vty_out(vty
, " Default redistribution metric is %d\n",
2084 ripng
->default_metric
);
2086 /* Redistribute information. */
2087 vty_out(vty
, " Redistributing:");
2088 ripng_redistribute_write(vty
, 0);
2091 vty_out(vty
, " Default version control: send version %d,",
2093 vty_out(vty
, " receive version %d \n", ripng
->version
);
2095 vty_out(vty
, " Interface Send Recv\n");
2097 FOR_ALL_INTERFACES (vrf
, ifp
) {
2098 struct ripng_interface
*ri
;
2102 if (ri
->enable_network
|| ri
->enable_interface
) {
2104 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2105 ripng
->version
, ripng
->version
);
2109 vty_out(vty
, " Routing for Networks:\n");
2110 ripng_network_write(vty
, 0);
2112 vty_out(vty
, " Routing Information Sources:\n");
2114 " Gateway BadPackets BadRoutes Distance Last Update\n");
2115 ripng_peer_display(vty
);
2120 DEFUN (clear_ipv6_rip
,
2125 "Clear IPv6 RIP database\n")
2127 struct agg_node
*rp
;
2128 struct ripng_info
*rinfo
;
2130 struct listnode
*listnode
;
2132 /* Clear received RIPng routes */
2133 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2138 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2139 if (!ripng_route_rte(rinfo
))
2142 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2143 ripng_zebra_ipv6_delete(rp
);
2148 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2149 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2150 listnode_delete(list
, rinfo
);
2151 ripng_info_free(rinfo
);
2154 if (list_isempty(list
)) {
2155 list_delete_and_null(&list
);
2157 agg_unlock_node(rp
);
2164 DEFUN_NOSH (router_ripng
,
2167 "Enable a routing process\n"
2168 "Make RIPng instance command\n")
2172 vty
->node
= RIPNG_NODE
;
2175 ret
= ripng_create();
2177 /* Notice to user we couldn't create RIPng. */
2179 zlog_warn("can't create RIPng");
2180 return CMD_WARNING_CONFIG_FAILED
;
2187 DEFUN (no_router_ripng
,
2188 no_router_ripng_cmd
,
2191 "Enable a routing process\n"
2192 "Make RIPng instance command\n")
2202 "Static route setup\n"
2203 "Set static RIPng route announcement\n")
2205 int idx_ipv6addr
= 1;
2207 struct prefix_ipv6 p
;
2208 struct agg_node
*rp
;
2210 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2211 (struct prefix_ipv6
*)&p
);
2213 vty_out(vty
, "Malformed address\n");
2214 return CMD_WARNING_CONFIG_FAILED
;
2216 apply_mask_ipv6(&p
);
2218 rp
= agg_node_get(ripng
->route
, (struct prefix
*)&p
);
2220 vty_out(vty
, "There is already same static route.\n");
2221 agg_unlock_node(rp
);
2224 rp
->info
= (void *)1;
2226 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2232 DEFUN (no_ripng_route
,
2234 "no route IPV6ADDR",
2236 "Static route setup\n"
2237 "Delete static RIPng route announcement\n")
2239 int idx_ipv6addr
= 2;
2241 struct prefix_ipv6 p
;
2242 struct agg_node
*rp
;
2244 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2245 (struct prefix_ipv6
*)&p
);
2247 vty_out(vty
, "Malformed address\n");
2248 return CMD_WARNING_CONFIG_FAILED
;
2250 apply_mask_ipv6(&p
);
2252 rp
= agg_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2254 vty_out(vty
, "Can't find static route.\n");
2255 return CMD_WARNING_CONFIG_FAILED
;
2258 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2259 agg_unlock_node(rp
);
2262 agg_unlock_node(rp
);
2267 DEFUN (ripng_aggregate_address
,
2268 ripng_aggregate_address_cmd
,
2269 "aggregate-address X:X::X:X/M",
2270 "Set aggregate RIPng route announcement\n"
2271 "Aggregate network\n")
2273 int idx_ipv6_prefixlen
= 1;
2276 struct agg_node
*node
;
2278 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2279 (struct prefix_ipv6
*)&p
);
2281 vty_out(vty
, "Malformed address\n");
2282 return CMD_WARNING_CONFIG_FAILED
;
2285 /* Check aggregate alredy exist or not. */
2286 node
= agg_node_get(ripng
->aggregate
, &p
);
2288 vty_out(vty
, "There is already same aggregate route.\n");
2289 agg_unlock_node(node
);
2292 node
->info
= (void *)1;
2294 ripng_aggregate_add(&p
);
2299 DEFUN (no_ripng_aggregate_address
,
2300 no_ripng_aggregate_address_cmd
,
2301 "no aggregate-address X:X::X:X/M",
2303 "Delete aggregate RIPng route announcement\n"
2304 "Aggregate network\n")
2306 int idx_ipv6_prefixlen
= 2;
2309 struct agg_node
*rn
;
2311 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2312 (struct prefix_ipv6
*)&p
);
2314 vty_out(vty
, "Malformed address\n");
2315 return CMD_WARNING_CONFIG_FAILED
;
2318 rn
= agg_node_lookup(ripng
->aggregate
, &p
);
2320 vty_out(vty
, "Can't find aggregate route.\n");
2321 return CMD_WARNING_CONFIG_FAILED
;
2323 agg_unlock_node(rn
);
2325 agg_unlock_node(rn
);
2327 ripng_aggregate_delete(&p
);
2332 DEFUN (ripng_default_metric
,
2333 ripng_default_metric_cmd
,
2334 "default-metric (1-16)",
2335 "Set a metric of redistribute routes\n"
2340 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2345 DEFUN (no_ripng_default_metric
,
2346 no_ripng_default_metric_cmd
,
2347 "no default-metric [(1-16)]",
2349 "Set a metric of redistribute routes\n"
2353 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2360 /* RIPng update timer setup. */
2361 DEFUN (ripng_update_timer
,
2362 ripng_update_timer_cmd
,
2363 "update-timer SECOND",
2364 "Set RIPng update timer in seconds\n"
2367 unsigned long update
;
2368 char *endptr
= NULL
;
2370 update
= strtoul (argv
[0], &endptr
, 10);
2371 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2373 vty_out (vty
, "update timer value error\n");
2374 return CMD_WARNING_CONFIG_FAILED
;
2377 ripng
->update_time
= update
;
2379 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2383 DEFUN (no_ripng_update_timer
,
2384 no_ripng_update_timer_cmd
,
2385 "no update-timer SECOND",
2387 "Unset RIPng update timer in seconds\n"
2390 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2391 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2395 /* RIPng timeout timer setup. */
2396 DEFUN (ripng_timeout_timer
,
2397 ripng_timeout_timer_cmd
,
2398 "timeout-timer SECOND",
2399 "Set RIPng timeout timer in seconds\n"
2402 unsigned long timeout
;
2403 char *endptr
= NULL
;
2405 timeout
= strtoul (argv
[0], &endptr
, 10);
2406 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2408 vty_out (vty
, "timeout timer value error\n");
2409 return CMD_WARNING_CONFIG_FAILED
;
2412 ripng
->timeout_time
= timeout
;
2417 DEFUN (no_ripng_timeout_timer
,
2418 no_ripng_timeout_timer_cmd
,
2419 "no timeout-timer SECOND",
2421 "Unset RIPng timeout timer in seconds\n"
2424 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2428 /* RIPng garbage timer setup. */
2429 DEFUN (ripng_garbage_timer
,
2430 ripng_garbage_timer_cmd
,
2431 "garbage-timer SECOND",
2432 "Set RIPng garbage timer in seconds\n"
2435 unsigned long garbage
;
2436 char *endptr
= NULL
;
2438 garbage
= strtoul (argv
[0], &endptr
, 10);
2439 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2441 vty_out (vty
, "garbage timer value error\n");
2442 return CMD_WARNING_CONFIG_FAILED
;
2445 ripng
->garbage_time
= garbage
;
2450 DEFUN (no_ripng_garbage_timer
,
2451 no_ripng_garbage_timer_cmd
,
2452 "no garbage-timer SECOND",
2454 "Unset RIPng garbage timer in seconds\n"
2457 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2462 DEFUN (ripng_timers
,
2464 "timers basic (0-65535) (0-65535) (0-65535)",
2465 "RIPng timers setup\n"
2467 "Routing table update timer value in second. Default is 30.\n"
2468 "Routing information timeout timer. Default is 180.\n"
2469 "Garbage collection timer. Default is 120.\n")
2472 int idx_number_2
= 3;
2473 int idx_number_3
= 4;
2474 unsigned long update
;
2475 unsigned long timeout
;
2476 unsigned long garbage
;
2478 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2479 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2480 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2482 /* Set each timer value. */
2483 ripng
->update_time
= update
;
2484 ripng
->timeout_time
= timeout
;
2485 ripng
->garbage_time
= garbage
;
2487 /* Reset update timer thread. */
2488 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2493 DEFUN (no_ripng_timers
,
2494 no_ripng_timers_cmd
,
2495 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2497 "RIPng timers setup\n"
2499 "Routing table update timer value in second. Default is 30.\n"
2500 "Routing information timeout timer. Default is 180.\n"
2501 "Garbage collection timer. Default is 120.\n")
2503 /* Set each timer value to the default. */
2504 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2505 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2506 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2508 /* Reset update timer thread. */
2509 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2515 DEFUN (show_ipv6_protocols
,
2516 show_ipv6_protocols_cmd
,
2517 "show ipv6 protocols",
2520 "Routing protocol information\n")
2525 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2527 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2528 ripng
->update_time
, 0);
2530 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2531 ripng
->timeout_time
,
2532 ripng
->garbage_time
);
2534 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2535 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2541 /* Please be carefull to use this command. */
2542 DEFUN (ripng_default_information_originate
,
2543 ripng_default_information_originate_cmd
,
2544 "default-information originate",
2545 "Default route information\n"
2546 "Distribute default route\n")
2548 struct prefix_ipv6 p
;
2550 if (!ripng
->default_information
) {
2551 ripng
->default_information
= 1;
2553 str2prefix_ipv6("::/0", &p
);
2554 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2561 DEFUN (no_ripng_default_information_originate
,
2562 no_ripng_default_information_originate_cmd
,
2563 "no default-information originate",
2565 "Default route information\n"
2566 "Distribute default route\n")
2568 struct prefix_ipv6 p
;
2570 if (ripng
->default_information
) {
2571 ripng
->default_information
= 0;
2573 str2prefix_ipv6("::/0", &p
);
2574 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2575 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2581 /* Update ECMP routes to zebra when ECMP is disabled. */
2582 static void ripng_ecmp_disable(void)
2584 struct agg_node
*rp
;
2585 struct ripng_info
*rinfo
, *tmp_rinfo
;
2587 struct listnode
*node
, *nextnode
;
2592 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2593 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2594 rinfo
= listgetdata(listhead(list
));
2595 if (!ripng_route_rte(rinfo
))
2598 /* Drop all other entries, except the first one. */
2599 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2600 if (tmp_rinfo
!= rinfo
) {
2601 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2603 tmp_rinfo
->t_garbage_collect
);
2604 list_delete_node(list
, node
);
2605 ripng_info_free(tmp_rinfo
);
2609 ripng_zebra_ipv6_add(rp
);
2611 /* Set the route change flag. */
2612 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2614 /* Signal the output process to trigger an update. */
2615 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2619 DEFUN (ripng_allow_ecmp
,
2620 ripng_allow_ecmp_cmd
,
2622 "Allow Equal Cost MultiPath\n")
2625 vty_out(vty
, "ECMP is already enabled.\n");
2630 zlog_info("ECMP is enabled.");
2634 DEFUN (no_ripng_allow_ecmp
,
2635 no_ripng_allow_ecmp_cmd
,
2638 "Allow Equal Cost MultiPath\n")
2641 vty_out(vty
, "ECMP is already disabled.\n");
2646 zlog_info("ECMP is disabled.");
2647 ripng_ecmp_disable();
2651 /* RIPng configuration write function. */
2652 static int ripng_config_write(struct vty
*vty
)
2654 int ripng_network_write(struct vty
*, int);
2655 void ripng_redistribute_write(struct vty
*, int);
2657 struct agg_node
*rp
;
2662 vty_out(vty
, "router ripng\n");
2664 if (ripng
->default_information
)
2665 vty_out(vty
, " default-information originate\n");
2667 ripng_network_write(vty
, 1);
2669 /* RIPng default metric configuration */
2670 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2671 vty_out(vty
, " default-metric %d\n",
2672 ripng
->default_metric
);
2674 ripng_redistribute_write(vty
, 1);
2676 /* RIP offset-list configuration. */
2677 config_write_ripng_offset_list(vty
);
2679 /* RIPng aggregate routes. */
2680 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2681 rp
= agg_route_next(rp
))
2682 if (rp
->info
!= NULL
)
2683 vty_out(vty
, " aggregate-address %s/%d\n",
2684 inet6_ntoa(rp
->p
.u
.prefix6
),
2687 /* ECMP configuration. */
2689 vty_out(vty
, " allow-ecmp\n");
2691 /* RIPng static routes. */
2692 for (rp
= agg_route_top(ripng
->route
); rp
;
2693 rp
= agg_route_next(rp
))
2694 if (rp
->info
!= NULL
)
2695 vty_out(vty
, " route %s/%d\n",
2696 inet6_ntoa(rp
->p
.u
.prefix6
),
2699 /* RIPng timers configuration. */
2700 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2701 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2702 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2703 vty_out(vty
, " timers basic %ld %ld %ld\n",
2704 ripng
->update_time
, ripng
->timeout_time
,
2705 ripng
->garbage_time
);
2708 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2709 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2710 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2711 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2712 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2713 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2716 write
+= config_write_distribute(vty
);
2718 write
+= config_write_if_rmap(vty
);
2725 /* RIPng node structure. */
2726 static struct cmd_node cmd_ripng_node
= {
2727 RIPNG_NODE
, "%s(config-router)# ", 1,
2730 static void ripng_distribute_update(struct distribute
*dist
)
2732 struct interface
*ifp
;
2733 struct ripng_interface
*ri
;
2734 struct access_list
*alist
;
2735 struct prefix_list
*plist
;
2740 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2746 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2747 alist
= access_list_lookup(AFI_IP6
,
2748 dist
->list
[DISTRIBUTE_V6_IN
]);
2750 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2752 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2754 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2756 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2757 alist
= access_list_lookup(AFI_IP6
,
2758 dist
->list
[DISTRIBUTE_V6_OUT
]);
2760 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2762 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2764 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2766 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2767 plist
= prefix_list_lookup(AFI_IP6
,
2768 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2770 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2772 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2774 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2776 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2777 plist
= prefix_list_lookup(AFI_IP6
,
2778 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2780 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2782 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2784 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2787 void ripng_distribute_update_interface(struct interface
*ifp
)
2789 struct distribute
*dist
;
2791 dist
= distribute_lookup(ifp
->name
);
2793 ripng_distribute_update(dist
);
2796 /* Update all interface's distribute list. */
2797 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2799 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2800 struct interface
*ifp
;
2802 FOR_ALL_INTERFACES (vrf
, ifp
)
2803 ripng_distribute_update_interface(ifp
);
2806 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2808 ripng_distribute_update_all(NULL
);
2811 /* delete all the added ripng routes. */
2815 struct agg_node
*rp
;
2816 struct ripng_info
*rinfo
;
2817 struct ripng_aggregate
*aggregate
;
2818 struct list
*list
= NULL
;
2819 struct listnode
*listnode
= NULL
;
2822 /* Clear RIPng routes */
2823 for (rp
= agg_route_top(ripng
->table
); rp
;
2824 rp
= agg_route_next(rp
)) {
2825 if ((list
= rp
->info
) != NULL
) {
2826 rinfo
= listgetdata(listhead(list
));
2827 if (ripng_route_rte(rinfo
))
2828 ripng_zebra_ipv6_delete(rp
);
2830 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2832 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2834 rinfo
->t_garbage_collect
);
2835 ripng_info_free(rinfo
);
2837 list_delete_and_null(&list
);
2839 agg_unlock_node(rp
);
2842 if ((aggregate
= rp
->aggregate
) != NULL
) {
2843 ripng_aggregate_free(aggregate
);
2844 rp
->aggregate
= NULL
;
2845 agg_unlock_node(rp
);
2849 /* Cancel the RIPng timers */
2850 RIPNG_TIMER_OFF(ripng
->t_update
);
2851 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2852 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2854 /* Cancel the read thread */
2855 if (ripng
->t_read
) {
2856 thread_cancel(ripng
->t_read
);
2857 ripng
->t_read
= NULL
;
2860 /* Close the RIPng socket */
2861 if (ripng
->sock
>= 0) {
2866 /* Static RIPng route configuration. */
2867 for (rp
= agg_route_top(ripng
->route
); rp
;
2868 rp
= agg_route_next(rp
))
2871 agg_unlock_node(rp
);
2874 /* RIPng aggregated prefixes */
2875 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2876 rp
= agg_route_next(rp
))
2879 agg_unlock_node(rp
);
2882 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2883 if (ripng
->route_map
[i
].name
)
2884 free(ripng
->route_map
[i
].name
);
2886 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2887 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2888 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2890 stream_free(ripng
->ibuf
);
2891 stream_free(ripng
->obuf
);
2893 XFREE(MTYPE_RIPNG
, ripng
);
2897 ripng_clean_network();
2898 ripng_passive_interface_clean();
2899 ripng_offset_clean();
2900 ripng_interface_clean();
2901 ripng_redistribute_clean();
2904 /* Reset all values to the default settings. */
2907 /* Call ripd related reset functions. */
2908 ripng_debug_reset();
2909 ripng_route_map_reset();
2911 /* Call library reset functions. */
2913 access_list_reset();
2914 prefix_list_reset();
2916 distribute_list_reset();
2918 ripng_interface_reset();
2920 ripng_zclient_reset();
2923 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2925 struct interface
*ifp
;
2926 struct ripng_interface
*ri
;
2927 struct route_map
*rmap
;
2929 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2935 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2936 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2938 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2940 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2942 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2944 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2945 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2947 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2949 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2951 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2954 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2956 struct if_rmap
*if_rmap
;
2958 if_rmap
= if_rmap_lookup(ifp
->name
);
2960 ripng_if_rmap_update(if_rmap
);
2963 static void ripng_routemap_update_redistribute(void)
2968 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2969 if (ripng
->route_map
[i
].name
)
2970 ripng
->route_map
[i
].map
=
2971 route_map_lookup_by_name(
2972 ripng
->route_map
[i
].name
);
2977 static void ripng_routemap_update(const char *unused
)
2979 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2980 struct interface
*ifp
;
2982 FOR_ALL_INTERFACES (vrf
, ifp
)
2983 ripng_if_rmap_update_interface(ifp
);
2985 ripng_routemap_update_redistribute();
2988 /* Initialize ripng structure and set commands. */
2991 /* Install RIPNG_NODE. */
2992 install_node(&cmd_ripng_node
, ripng_config_write
);
2994 /* Install ripng commands. */
2995 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2996 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2998 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
3000 install_element(CONFIG_NODE
, &router_ripng_cmd
);
3001 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
3003 install_default(RIPNG_NODE
);
3004 install_element(RIPNG_NODE
, &ripng_route_cmd
);
3005 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
3006 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3007 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3009 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3010 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3012 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3013 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3015 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3016 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3017 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3018 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3019 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3020 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3021 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3024 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3025 install_element(RIPNG_NODE
,
3026 &no_ripng_default_information_originate_cmd
);
3028 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3029 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3034 /* Access list install. */
3036 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3037 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3039 /* Prefix list initialize.*/
3041 prefix_list_add_hook(ripng_distribute_update_all
);
3042 prefix_list_delete_hook(ripng_distribute_update_all
);
3044 /* Distribute list install. */
3045 distribute_list_init(RIPNG_NODE
);
3046 distribute_list_add_hook(ripng_distribute_update
);
3047 distribute_list_delete_hook(ripng_distribute_update
);
3049 /* Route-map for interface. */
3050 ripng_route_map_init();
3051 ripng_offset_init();
3053 route_map_add_hook(ripng_routemap_update
);
3054 route_map_delete_hook(ripng_routemap_update
);
3056 if_rmap_init(RIPNG_NODE
);
3057 if_rmap_hook_add(ripng_if_rmap_update
);
3058 if_rmap_hook_delete(ripng_if_rmap_update
);