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
33 #include "distribute.h"
39 #include "ripngd/ripngd.h"
40 #include "ripngd/ripng_route.h"
41 #include "ripngd/ripng_debug.h"
42 #include "ripngd/ripng_nexthop.h"
44 /* RIPng structure which includes many parameters related to RIPng
45 protocol. If ripng couldn't active or ripng doesn't configured,
46 ripng->fd must be negative value. */
47 struct ripng
*ripng
= NULL
;
49 enum { ripng_all_route
,
53 extern struct zebra_privs_t ripngd_privs
;
56 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
58 int ripng_triggered_update(struct thread
*);
60 /* RIPng next hop specification. */
61 struct ripng_nexthop
{
62 enum ripng_nexthop_type
{
66 struct in6_addr address
;
69 static int ripng_route_rte(struct ripng_info
*rinfo
)
71 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
72 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
75 /* Allocate new ripng information. */
76 struct ripng_info
*ripng_info_new()
78 struct ripng_info
*new;
80 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
84 /* Free ripng information. */
85 void ripng_info_free(struct ripng_info
*rinfo
)
87 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
90 /* Create ripng socket. */
91 static int ripng_make_socket(void)
95 struct sockaddr_in6 ripaddr
;
97 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
99 zlog_err("Can't make ripng socket");
103 setsockopt_so_recvbuf(sock
, 8096);
104 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
107 #ifdef IPTOS_PREC_INTERNETCONTROL
108 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
112 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
115 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
118 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
122 memset(&ripaddr
, 0, sizeof(ripaddr
));
123 ripaddr
.sin6_family
= AF_INET6
;
125 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
126 #endif /* SIN6_LEN */
127 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
129 if (ripngd_privs
.change(ZPRIVS_RAISE
))
130 zlog_err("ripng_make_socket: could not raise privs");
132 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
134 zlog_err("Can't bind ripng socket: %s.", safe_strerror(errno
));
135 if (ripngd_privs
.change(ZPRIVS_LOWER
))
136 zlog_err("ripng_make_socket: could not lower privs");
139 if (ripngd_privs
.change(ZPRIVS_LOWER
))
140 zlog_err("ripng_make_socket: could not lower privs");
144 /* Send RIPng packet. */
145 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
146 struct interface
*ifp
)
151 struct cmsghdr
*cmsgptr
;
153 struct in6_pktinfo
*pkt
;
154 struct sockaddr_in6 addr
;
156 if (IS_RIPNG_DEBUG_SEND
) {
158 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
159 zlog_debug(" send interface %s", ifp
->name
);
160 zlog_debug(" send packet size %d", bufsize
);
163 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
164 addr
.sin6_family
= AF_INET6
;
166 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
167 #endif /* SIN6_LEN */
168 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
170 /* When destination is specified. */
172 addr
.sin6_addr
= to
->sin6_addr
;
173 addr
.sin6_port
= to
->sin6_port
;
175 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
176 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
179 memset(&msg
, 0, sizeof(msg
));
180 msg
.msg_name
= (void *)&addr
;
181 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
184 msg
.msg_control
= (void *)adata
;
185 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
188 iov
.iov_len
= bufsize
;
190 cmsgptr
= (struct cmsghdr
*)adata
;
191 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
192 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
193 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
195 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
196 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
197 pkt
->ipi6_ifindex
= ifp
->ifindex
;
199 ret
= sendmsg(ripng
->sock
, &msg
, 0);
203 zlog_err("RIPng send fail on %s to %s: %s", ifp
->name
,
204 inet6_ntoa(to
->sin6_addr
),
205 safe_strerror(errno
));
207 zlog_err("RIPng send fail on %s: %s", ifp
->name
,
208 safe_strerror(errno
));
214 /* Receive UDP RIPng packet from socket. */
215 static int ripng_recv_packet(int sock
, u_char
*buf
, int bufsize
,
216 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
222 struct cmsghdr
*cmsgptr
;
223 struct in6_addr dst
= {.s6_addr
= {0}};
225 memset(&dst
, 0, sizeof(struct in6_addr
));
227 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
228 point I can't determine size of cmsghdr */
231 /* Fill in message and iovec. */
232 memset(&msg
, 0, sizeof(msg
));
233 msg
.msg_name
= (void *)from
;
234 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
237 msg
.msg_control
= (void *)adata
;
238 msg
.msg_controllen
= sizeof adata
;
240 iov
.iov_len
= bufsize
;
242 /* If recvmsg fail return minus value. */
243 ret
= recvmsg(sock
, &msg
, 0);
247 for (cmsgptr
= ZCMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
248 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
249 /* I want interface index which this packet comes from. */
250 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
251 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
252 struct in6_pktinfo
*ptr
;
254 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
255 *ifindex
= ptr
->ipi6_ifindex
;
256 dst
= ptr
->ipi6_addr
;
260 "Interface index returned by IPV6_PKTINFO is zero");
263 /* Incoming packet's multicast hop limit. */
264 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
265 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
266 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
267 *hoplimit
= *phoplimit
;
271 /* Hoplimit check shold be done when destination address is
272 multicast address. */
273 if (!IN6_IS_ADDR_MULTICAST(&dst
))
279 /* Dump rip packet */
280 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
285 const char *command_str
;
287 /* Set command string. */
288 if (packet
->command
== RIPNG_REQUEST
)
289 command_str
= "request";
290 else if (packet
->command
== RIPNG_RESPONSE
)
291 command_str
= "response";
293 command_str
= "unknown";
295 /* Dump packet header. */
296 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
297 packet
->version
, size
);
299 /* Dump each routing table entry. */
302 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
303 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
304 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
307 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
308 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
309 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
313 /* RIPng next hop address RTE (Route Table Entry). */
314 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
315 struct ripng_nexthop
*nexthop
)
317 char buf
[INET6_BUFSIZ
];
319 /* Logging before checking RTE. */
320 if (IS_RIPNG_DEBUG_RECV
)
321 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
323 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
326 /* RFC2080 2.1.1 Next Hop:
327 The route tag and prefix length in the next hop RTE must be
328 set to zero on sending and ignored on receiption. */
329 if (ntohs(rte
->tag
) != 0)
331 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
333 (route_tag_t
)ntohs(rte
->tag
),
334 inet6_ntoa(from
->sin6_addr
));
336 if (rte
->prefixlen
!= 0)
338 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
339 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
341 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
342 next hop RTE indicates that the next hop address should be the
343 originator of the RIPng advertisement. An address specified as a
344 next hop must be a link-local address. */
345 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
346 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
347 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
351 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
352 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
353 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
357 /* The purpose of the next hop RTE is to eliminate packets being
358 routed through extra hops in the system. It is particularly useful
359 when RIPng is not being run on all of the routers on a network.
360 Note that next hop RTE is "advisory". That is, if the provided
361 information is ignored, a possibly sub-optimal, but absolutely
362 valid, route may be taken. If the received next hop address is not
363 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
364 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
365 inet6_ntoa(rte
->addr
),
366 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
368 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
369 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
374 /* If ifp has same link-local address then return 1. */
375 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
377 struct listnode
*node
;
378 struct connected
*connected
;
381 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
382 p
= connected
->address
;
384 if (p
->family
== AF_INET6
385 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
386 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
392 /* RIPng route garbage collect timer. */
393 static int ripng_garbage_collect(struct thread
*t
)
395 struct ripng_info
*rinfo
;
396 struct route_node
*rp
;
398 rinfo
= THREAD_ARG(t
);
399 rinfo
->t_garbage_collect
= NULL
;
401 /* Off timeout timer. */
402 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
404 /* Get route_node pointer. */
407 /* Unlock route_node. */
408 listnode_delete(rp
->info
, rinfo
);
409 if (list_isempty((struct list
*)rp
->info
)) {
412 route_unlock_node(rp
);
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 route_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 route_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 route_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
;
667 struct route_node
*rp
;
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
= route_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.
801 route_unlock_node(rp
);
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
) {
824 route_unlock_node(rp
);
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
) {
833 route_unlock_node(rp
);
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
);
847 /* If there is an existing route, compare the next hop address
848 to the address of the router from which the datagram came.
849 If this datagram is from the same router as the existing
850 route, reinitialize the timeout. */
851 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
852 && (rinfo
->ifindex
== ifp
->ifindex
));
855 * RFC 2080 - Section 2.4.2:
856 * "If the new metric is the same as the old one, examine the
858 * for the existing route. If it is at least halfway to the
860 * point, switch to the new route. This heuristic is optional,
862 * highly recommended".
864 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
866 && (thread_timer_remain_second(rinfo
->t_timeout
)
867 < (ripng
->timeout_time
/ 2))) {
868 ripng_ecmp_replace(&newinfo
);
870 /* Next, compare the metrics. If the datagram is from the same
871 router as the existing route, and the new metric is different
872 than the old one; or, if the new metric is lower than the old
873 one; do the following actions: */
874 else if ((same
&& rinfo
->metric
!= rte
->metric
)
875 || rte
->metric
< rinfo
->metric
) {
876 if (listcount(list
) == 1) {
877 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
878 ripng_ecmp_replace(&newinfo
);
880 ripng_ecmp_delete(rinfo
);
882 if (newinfo
.metric
< rinfo
->metric
)
883 ripng_ecmp_replace(&newinfo
);
884 else /* newinfo.metric > rinfo->metric */
885 ripng_ecmp_delete(rinfo
);
887 } else /* same & no change */
888 ripng_timeout_update(rinfo
);
890 /* Unlock tempolary lock of the route. */
891 route_unlock_node(rp
);
895 /* Add redistributed route to RIPng table. */
896 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
897 ifindex_t ifindex
, struct in6_addr
*nexthop
,
900 struct route_node
*rp
;
901 struct ripng_info
*rinfo
= NULL
, newinfo
;
902 struct list
*list
= NULL
;
904 /* Redistribute route */
905 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
907 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
910 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
912 memset(&newinfo
, 0, sizeof(struct ripng_info
));
914 newinfo
.sub_type
= sub_type
;
915 newinfo
.ifindex
= ifindex
;
917 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
920 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
921 newinfo
.nexthop
= *nexthop
;
923 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
924 rinfo
= listgetdata(listhead(list
));
926 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
927 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
928 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
929 route_unlock_node(rp
);
933 /* Manually configured RIPng route check.
934 * They have the precedence on all the other entries.
936 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
937 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
938 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
939 if (type
!= ZEBRA_ROUTE_RIPNG
940 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
941 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
942 route_unlock_node(rp
);
947 ripng_ecmp_replace(&newinfo
);
948 route_unlock_node(rp
);
950 ripng_ecmp_add(&newinfo
);
952 if (IS_RIPNG_DEBUG_EVENT
) {
955 "Redistribute new prefix %s/%d on the interface %s",
956 inet6_ntoa(p
->prefix
), p
->prefixlen
,
957 ifindex2ifname(ifindex
, VRF_DEFAULT
));
960 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
961 inet6_ntoa(p
->prefix
), p
->prefixlen
,
962 inet6_ntoa(*nexthop
),
963 ifindex2ifname(ifindex
, VRF_DEFAULT
));
966 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
969 /* Delete redistributed route to RIPng table. */
970 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
973 struct route_node
*rp
;
974 struct ripng_info
*rinfo
;
976 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
978 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
981 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
984 struct list
*list
= rp
->info
;
986 if (list
!= NULL
&& listcount(list
) != 0) {
987 rinfo
= listgetdata(listhead(list
));
988 if (rinfo
!= NULL
&& rinfo
->type
== type
989 && rinfo
->sub_type
== sub_type
990 && rinfo
->ifindex
== ifindex
) {
991 /* Perform poisoned reverse. */
992 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
993 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
994 ripng_garbage_collect
,
995 ripng
->garbage_time
);
996 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
998 /* Aggregate count decrement. */
999 ripng_aggregate_decrement(rp
, rinfo
);
1001 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1003 if (IS_RIPNG_DEBUG_EVENT
)
1005 "Poisone %s/%d on the interface %s with an "
1006 "infinity metric [delete]",
1007 inet6_ntoa(p
->prefix
),
1009 ifindex2ifname(ifindex
,
1012 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1015 route_unlock_node(rp
);
1019 /* Withdraw redistributed route. */
1020 void ripng_redistribute_withdraw(int type
)
1022 struct route_node
*rp
;
1023 struct ripng_info
*rinfo
= NULL
;
1024 struct list
*list
= NULL
;
1029 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1030 if ((list
= rp
->info
) != NULL
) {
1031 rinfo
= listgetdata(listhead(list
));
1032 if ((rinfo
->type
== type
)
1033 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1034 /* Perform poisoned reverse. */
1035 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1036 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1037 ripng_garbage_collect
,
1038 ripng
->garbage_time
);
1039 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1041 /* Aggregate count decrement. */
1042 ripng_aggregate_decrement(rp
, rinfo
);
1044 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1046 if (IS_RIPNG_DEBUG_EVENT
) {
1047 struct prefix_ipv6
*p
=
1048 (struct prefix_ipv6
*)&rp
->p
;
1051 "Poisone %s/%d on the interface %s [withdraw]",
1052 inet6_ntoa(p
->prefix
),
1054 ifindex2ifname(rinfo
->ifindex
,
1058 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1063 /* RIP routing information. */
1064 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1065 struct sockaddr_in6
*from
,
1066 struct interface
*ifp
, int hoplimit
)
1070 struct ripng_nexthop nexthop
;
1072 /* RFC2080 2.4.2 Response Messages:
1073 The Response must be ignored if it is not from the RIPng port. */
1074 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1075 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1076 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1077 ripng_peer_bad_packet(from
);
1081 /* The datagram's IPv6 source address should be checked to see
1082 whether the datagram is from a valid neighbor; the source of the
1083 datagram must be a link-local address. */
1084 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1085 zlog_warn("RIPng packet comes from non link local address %s",
1086 inet6_ntoa(from
->sin6_addr
));
1087 ripng_peer_bad_packet(from
);
1091 /* It is also worth checking to see whether the response is from one
1092 of the router's own addresses. Interfaces on broadcast networks
1093 may receive copies of their own multicasts immediately. If a
1094 router processes its own output as new input, confusion is likely,
1095 and such datagrams must be ignored. */
1096 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1098 "RIPng packet comes from my own link local address %s",
1099 inet6_ntoa(from
->sin6_addr
));
1100 ripng_peer_bad_packet(from
);
1104 /* As an additional check, periodic advertisements must have their
1105 hop counts set to 255, and inbound, multicast packets sent from the
1106 RIPng port (i.e. periodic advertisement or triggered update
1107 packets) must be examined to ensure that the hop count is 255. */
1108 if (hoplimit
>= 0 && hoplimit
!= 255) {
1110 "RIPng packet comes with non 255 hop count %d from %s",
1111 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1112 ripng_peer_bad_packet(from
);
1116 /* Update RIPng peer. */
1117 ripng_peer_update(from
, packet
->version
);
1119 /* Reset nexthop. */
1120 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1121 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1123 /* Set RTE pointer. */
1126 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1127 /* First of all, we have to check this RTE is next hop RTE or
1128 not. Next hop RTE is completely different with normal RTE so
1129 we need special treatment. */
1130 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1131 ripng_nexthop_rte(rte
, from
, &nexthop
);
1135 /* RTE information validation. */
1137 /* - is the destination prefix valid (e.g., not a multicast
1138 prefix and not a link-local address) A link-local address
1139 should never be present in an RTE. */
1140 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1142 "Destination prefix is a multicast address %s/%d [%d]",
1143 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1145 ripng_peer_bad_route(from
);
1148 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1150 "Destination prefix is a link-local address %s/%d [%d]",
1151 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1153 ripng_peer_bad_route(from
);
1156 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1158 "Destination prefix is a loopback address %s/%d [%d]",
1159 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1161 ripng_peer_bad_route(from
);
1165 /* - is the prefix length valid (i.e., between 0 and 128,
1167 if (rte
->prefixlen
> 128) {
1168 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1169 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1170 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1171 ripng_peer_bad_route(from
);
1175 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1176 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1177 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1178 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1179 ripng_peer_bad_route(from
);
1183 /* Vincent: XXX Should we compute the direclty reachable nexthop
1184 * for our RIPng network ?
1187 /* Routing table updates. */
1188 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1192 /* Response to request message. */
1193 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1194 struct sockaddr_in6
*from
,
1195 struct interface
*ifp
)
1199 struct prefix_ipv6 p
;
1200 struct route_node
*rp
;
1201 struct ripng_info
*rinfo
;
1202 struct ripng_interface
*ri
;
1204 /* Does not reponse to the requests on the loopback interfaces */
1205 if (if_is_loopback(ifp
))
1208 /* Check RIPng process is enabled on this interface. */
1213 /* When passive interface is specified, suppress responses */
1217 /* RIPng peer update. */
1218 ripng_peer_update(from
, packet
->version
);
1220 lim
= ((caddr_t
)packet
) + size
;
1223 /* The Request is processed entry by entry. If there are no
1224 entries, no response is given. */
1225 if (lim
== (caddr_t
)rte
)
1228 /* There is one special case. If there is exactly one entry in the
1229 request, and it has a destination prefix of zero, a prefix length
1230 of zero, and a metric of infinity (i.e., 16), then this is a
1231 request to send the entire routing table. In that case, a call
1232 is made to the output process to send the routing table to the
1233 requesting address/port. */
1234 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1235 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1236 /* All route with split horizon */
1237 ripng_output_process(ifp
, from
, ripng_all_route
);
1239 /* Except for this special case, processing is quite simple.
1240 Examine the list of RTEs in the Request one by one. For each
1241 entry, look up the destination in the router's routing
1242 database and, if there is a route, put that route's metric in
1243 the metric field of the RTE. If there is no explicit route
1244 to the specified destination, put infinity in the metric
1245 field. Once all the entries have been filled in, change the
1246 command from Request to Response and send the datagram back
1247 to the requestor. */
1248 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1249 p
.family
= AF_INET6
;
1251 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1252 p
.prefix
= rte
->addr
;
1253 p
.prefixlen
= rte
->prefixlen
;
1254 apply_mask_ipv6(&p
);
1256 rp
= route_node_lookup(ripng
->table
,
1257 (struct prefix
*)&p
);
1260 rinfo
= listgetdata(
1261 listhead((struct list
*)rp
->info
));
1262 rte
->metric
= rinfo
->metric
;
1263 route_unlock_node(rp
);
1265 rte
->metric
= RIPNG_METRIC_INFINITY
;
1267 packet
->command
= RIPNG_RESPONSE
;
1269 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1273 /* First entry point of reading RIPng packet. */
1274 static int ripng_read(struct thread
*thread
)
1278 struct sockaddr_in6 from
;
1279 struct ripng_packet
*packet
;
1280 ifindex_t ifindex
= 0;
1281 struct interface
*ifp
;
1284 /* Check ripng is active and alive. */
1285 assert(ripng
!= NULL
);
1286 assert(ripng
->sock
>= 0);
1288 /* Fetch thread data and set read pointer to empty for event
1289 managing. `sock' sould be same as ripng->sock. */
1290 sock
= THREAD_FD(thread
);
1291 ripng
->t_read
= NULL
;
1293 /* Add myself to the next event. */
1294 ripng_event(RIPNG_READ
, sock
);
1296 /* Read RIPng packet. */
1297 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1298 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1301 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1305 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1306 (4)) must be multiple size of one RTE size (20). */
1307 if (((len
- 4) % 20) != 0) {
1308 zlog_warn("RIPng invalid packet size %d from %s", len
,
1309 inet6_ntoa(from
.sin6_addr
));
1310 ripng_peer_bad_packet(&from
);
1314 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1315 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1317 /* RIPng packet received. */
1318 if (IS_RIPNG_DEBUG_EVENT
)
1319 zlog_debug("RIPng packet received from %s port %d on %s",
1320 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1321 ifp
? ifp
->name
: "unknown");
1323 /* Logging before packet checking. */
1324 if (IS_RIPNG_DEBUG_RECV
)
1325 ripng_packet_dump(packet
, len
, "RECV");
1327 /* Packet comes from unknown interface. */
1329 zlog_warn("RIPng packet comes from unknown interface %d",
1334 /* Packet version mismatch checking. */
1335 if (packet
->version
!= ripng
->version
) {
1337 "RIPng packet version %d doesn't fit to my version %d",
1338 packet
->version
, ripng
->version
);
1339 ripng_peer_bad_packet(&from
);
1343 /* Process RIPng packet. */
1344 switch (packet
->command
) {
1346 ripng_request_process(packet
, len
, &from
, ifp
);
1348 case RIPNG_RESPONSE
:
1349 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1352 zlog_warn("Invalid RIPng command %d", packet
->command
);
1353 ripng_peer_bad_packet(&from
);
1359 /* Walk down the RIPng routing table then clear changed flag. */
1360 static void ripng_clear_changed_flag(void)
1362 struct route_node
*rp
;
1363 struct ripng_info
*rinfo
= NULL
;
1364 struct list
*list
= NULL
;
1365 struct listnode
*listnode
= NULL
;
1367 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1368 if ((list
= rp
->info
) != NULL
)
1369 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1370 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1371 /* This flag can be set only on the first entry.
1377 /* Regular update of RIPng route. Send all routing formation to RIPng
1378 enabled interface. */
1379 static int ripng_update(struct thread
*t
)
1381 struct listnode
*node
;
1382 struct interface
*ifp
;
1383 struct ripng_interface
*ri
;
1385 /* Clear update timer thread. */
1386 ripng
->t_update
= NULL
;
1388 /* Logging update event. */
1389 if (IS_RIPNG_DEBUG_EVENT
)
1390 zlog_debug("RIPng update timer expired!");
1392 /* Supply routes to each interface. */
1393 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1396 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1402 /* When passive interface is specified, suppress announce to the
1408 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1409 if (IS_RIPNG_DEBUG_EVENT
)
1411 "[Event] RIPng send to if %d is suppressed by config",
1415 #endif /* RIPNG_ADVANCED */
1417 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1420 /* Triggered updates may be suppressed if a regular update is due by
1421 the time the triggered update would be sent. */
1422 if (ripng
->t_triggered_interval
) {
1423 thread_cancel(ripng
->t_triggered_interval
);
1424 ripng
->t_triggered_interval
= NULL
;
1428 /* Reset flush event. */
1429 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1434 /* Triggered update interval timer. */
1435 static int ripng_triggered_interval(struct thread
*t
)
1437 ripng
->t_triggered_interval
= NULL
;
1439 if (ripng
->trigger
) {
1441 ripng_triggered_update(t
);
1446 /* Execute triggered update. */
1447 int ripng_triggered_update(struct thread
*t
)
1449 struct listnode
*node
;
1450 struct interface
*ifp
;
1451 struct ripng_interface
*ri
;
1454 ripng
->t_triggered_update
= NULL
;
1456 /* Cancel interval timer. */
1457 if (ripng
->t_triggered_interval
) {
1458 thread_cancel(ripng
->t_triggered_interval
);
1459 ripng
->t_triggered_interval
= NULL
;
1463 /* Logging triggered update. */
1464 if (IS_RIPNG_DEBUG_EVENT
)
1465 zlog_debug("RIPng triggered update!");
1467 /* Split Horizon processing is done when generating triggered
1468 updates as well as normal updates (see section 2.6). */
1469 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1472 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1478 /* When passive interface is specified, suppress announce to the
1483 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1486 /* Once all of the triggered updates have been generated, the route
1487 change flags should be cleared. */
1488 ripng_clear_changed_flag();
1490 /* After a triggered update is sent, a timer should be set for a
1491 random interval between 1 and 5 seconds. If other changes that
1492 would trigger updates occur before the timer expires, a single
1493 update is triggered when the timer expires. */
1494 interval
= (random() % 5) + 1;
1496 ripng
->t_triggered_interval
= NULL
;
1497 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1498 &ripng
->t_triggered_interval
);
1503 /* Write routing table entry to the stream and return next index of
1504 the routing table entry in the stream. */
1505 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1506 struct in6_addr
*nexthop
, u_int16_t tag
, u_char metric
)
1508 /* RIPng packet header. */
1510 stream_putc(s
, RIPNG_RESPONSE
);
1511 stream_putc(s
, RIPNG_V1
);
1515 /* Write routing table entry. */
1517 stream_write(s
, (u_char
*)&p
->prefix
, sizeof(struct in6_addr
));
1519 stream_write(s
, (u_char
*)nexthop
, sizeof(struct in6_addr
));
1520 stream_putw(s
, tag
);
1522 stream_putc(s
, p
->prefixlen
);
1525 stream_putc(s
, metric
);
1530 /* Send RESPONSE message to specified destination. */
1531 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1535 struct route_node
*rp
;
1536 struct ripng_info
*rinfo
;
1537 struct ripng_interface
*ri
;
1538 struct ripng_aggregate
*aggregate
;
1539 struct prefix_ipv6
*p
;
1540 struct list
*ripng_rte_list
;
1541 struct list
*list
= NULL
;
1542 struct listnode
*listnode
= NULL
;
1544 if (IS_RIPNG_DEBUG_EVENT
) {
1546 zlog_debug("RIPng update routes to neighbor %s",
1547 inet6_ntoa(to
->sin6_addr
));
1549 zlog_debug("RIPng update routes on interface %s",
1553 /* Get RIPng interface. */
1556 ripng_rte_list
= ripng_rte_new();
1558 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1559 if ((list
= rp
->info
) != NULL
1560 && (rinfo
= listgetdata(listhead(list
))) != NULL
1561 && rinfo
->suppress
== 0) {
1562 /* If no route-map are applied, the RTE will be these
1566 p
= (struct prefix_ipv6
*)&rp
->p
;
1567 rinfo
->metric_out
= rinfo
->metric
;
1568 rinfo
->tag_out
= rinfo
->tag
;
1569 memset(&rinfo
->nexthop_out
, 0,
1570 sizeof(rinfo
->nexthop_out
));
1571 /* In order to avoid some local loops,
1572 * if the RIPng route has a nexthop via this interface,
1574 * otherwise set it to 0. The nexthop should not be
1576 * beyond the local broadcast/multicast area in order
1577 * to avoid an IGP multi-level recursive look-up.
1579 if (rinfo
->ifindex
== ifp
->ifindex
)
1580 rinfo
->nexthop_out
= rinfo
->nexthop
;
1582 /* Apply output filters. */
1583 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1587 /* Changed route only output. */
1588 if (route_type
== ripng_changed_route
1589 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1592 /* Split horizon. */
1593 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1594 /* We perform split horizon for RIPng routes. */
1596 struct ripng_info
*tmp_rinfo
= NULL
;
1598 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1600 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1601 && tmp_rinfo
->ifindex
1610 /* Preparation for route-map. */
1611 rinfo
->metric_set
= 0;
1614 * and tag_out are already initialized.
1617 /* Interface route-map */
1618 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1621 ret
= route_map_apply(
1622 ri
->routemap
[RIPNG_FILTER_OUT
],
1623 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1625 if (ret
== RMAP_DENYMATCH
) {
1626 if (IS_RIPNG_DEBUG_PACKET
)
1628 "RIPng %s/%d is filtered by route-map out",
1629 inet6_ntoa(p
->prefix
),
1635 /* Redistribute route-map. */
1636 if (ripng
->route_map
[rinfo
->type
].name
) {
1639 ret
= route_map_apply(
1640 ripng
->route_map
[rinfo
->type
].map
,
1641 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1643 if (ret
== RMAP_DENYMATCH
) {
1644 if (IS_RIPNG_DEBUG_PACKET
)
1646 "RIPng %s/%d is filtered by route-map",
1647 inet6_ntoa(p
->prefix
),
1653 /* When the route-map does not set metric. */
1654 if (!rinfo
->metric_set
) {
1655 /* If the redistribute metric is set. */
1656 if (ripng
->route_map
[rinfo
->type
].metric_config
1657 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1659 ripng
->route_map
[rinfo
->type
]
1662 /* If the route is not connected or
1664 one, use default-metric value */
1665 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1667 != ZEBRA_ROUTE_CONNECT
1669 != RIPNG_METRIC_INFINITY
)
1671 ripng
->default_metric
;
1675 /* Apply offset-list */
1676 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1677 ripng_offset_list_apply_out(p
, ifp
,
1678 &rinfo
->metric_out
);
1680 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1681 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1683 /* Perform split-horizon with poisoned reverse
1686 if (ri
->split_horizon
1687 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1688 struct ripng_info
*tmp_rinfo
= NULL
;
1690 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1692 if ((tmp_rinfo
->type
1693 == ZEBRA_ROUTE_RIPNG
)
1694 && tmp_rinfo
->ifindex
1697 RIPNG_METRIC_INFINITY
;
1700 /* Add RTE to the list */
1701 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1704 /* Process the aggregated RTE entry */
1705 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1706 && aggregate
->suppress
== 0) {
1707 /* If no route-map are applied, the RTE will be these
1711 p
= (struct prefix_ipv6
*)&rp
->p
;
1712 aggregate
->metric_set
= 0;
1713 aggregate
->metric_out
= aggregate
->metric
;
1714 aggregate
->tag_out
= aggregate
->tag
;
1715 memset(&aggregate
->nexthop_out
, 0,
1716 sizeof(aggregate
->nexthop_out
));
1718 /* Apply output filters.*/
1719 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1723 /* Interface route-map */
1724 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1726 struct ripng_info newinfo
;
1728 /* let's cast the aggregate structure to
1730 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1731 /* the nexthop is :: */
1732 newinfo
.metric
= aggregate
->metric
;
1733 newinfo
.metric_out
= aggregate
->metric_out
;
1734 newinfo
.tag
= aggregate
->tag
;
1735 newinfo
.tag_out
= aggregate
->tag_out
;
1737 ret
= route_map_apply(
1738 ri
->routemap
[RIPNG_FILTER_OUT
],
1739 (struct prefix
*)p
, RMAP_RIPNG
,
1742 if (ret
== RMAP_DENYMATCH
) {
1743 if (IS_RIPNG_DEBUG_PACKET
)
1745 "RIPng %s/%d is filtered by route-map out",
1746 inet6_ntoa(p
->prefix
),
1751 aggregate
->metric_out
= newinfo
.metric_out
;
1752 aggregate
->tag_out
= newinfo
.tag_out
;
1753 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1754 aggregate
->nexthop_out
=
1755 newinfo
.nexthop_out
;
1758 /* There is no redistribute routemap for the aggregated
1761 /* Changed route only output. */
1762 /* XXX, vincent, in order to increase time convergence,
1763 * it should be announced if a child has changed.
1765 if (route_type
== ripng_changed_route
)
1768 /* Apply offset-list */
1769 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1770 ripng_offset_list_apply_out(
1771 p
, ifp
, &aggregate
->metric_out
);
1773 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1774 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1776 /* Add RTE to the list */
1777 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1781 /* Flush the list */
1782 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1783 ripng_rte_free(ripng_rte_list
);
1786 /* Create new RIPng instance and set it to global variable. */
1787 static int ripng_create(void)
1789 /* ripng should be NULL. */
1790 assert(ripng
== NULL
);
1792 /* Allocaste RIPng instance. */
1793 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1795 /* Default version and timer values. */
1796 ripng
->version
= RIPNG_V1
;
1797 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1798 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1799 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1800 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1803 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1804 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1806 /* Initialize RIPng routig table. */
1807 ripng
->table
= route_table_init();
1808 ripng
->route
= route_table_init();
1809 ripng
->aggregate
= route_table_init();
1812 ripng
->sock
= ripng_make_socket();
1813 if (ripng
->sock
< 0)
1817 ripng_event(RIPNG_READ
, ripng
->sock
);
1818 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1823 /* Send RIPng request to the interface. */
1824 int ripng_request(struct interface
*ifp
)
1827 struct ripng_packet ripng_packet
;
1829 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1831 if (if_is_loopback(ifp
))
1834 /* If interface is down, don't send RIP packet. */
1838 if (IS_RIPNG_DEBUG_EVENT
)
1839 zlog_debug("RIPng send request to %s", ifp
->name
);
1841 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1842 ripng_packet
.command
= RIPNG_REQUEST
;
1843 ripng_packet
.version
= RIPNG_V1
;
1844 rte
= ripng_packet
.rte
;
1845 rte
->metric
= RIPNG_METRIC_INFINITY
;
1847 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1852 static int ripng_update_jitter(int time
)
1854 return ((random() % (time
+ 1)) - (time
/ 2));
1857 void ripng_event(enum ripng_event event
, int sock
)
1863 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1865 case RIPNG_UPDATE_EVENT
:
1866 if (ripng
->t_update
) {
1867 thread_cancel(ripng
->t_update
);
1868 ripng
->t_update
= NULL
;
1870 /* Update timer jitter. */
1871 jitter
= ripng_update_jitter(ripng
->update_time
);
1873 ripng
->t_update
= NULL
;
1874 thread_add_timer(master
, ripng_update
, NULL
,
1875 sock
? 2 : ripng
->update_time
+ jitter
,
1878 case RIPNG_TRIGGERED_UPDATE
:
1879 if (ripng
->t_triggered_interval
)
1882 thread_add_event(master
, ripng_triggered_update
, NULL
,
1883 0, &ripng
->t_triggered_update
);
1891 /* Print out routes update time. */
1892 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1897 char timebuf
[TIME_BUF
];
1898 struct thread
*thread
;
1900 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1901 clock
= thread_timer_remain_second(thread
);
1902 tm
= gmtime(&clock
);
1903 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1904 vty_out(vty
, "%5s", timebuf
);
1905 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1906 clock
= thread_timer_remain_second(thread
);
1907 tm
= gmtime(&clock
);
1908 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1909 vty_out(vty
, "%5s", timebuf
);
1913 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1918 if (rinfo
->suppress
)
1921 switch (rinfo
->sub_type
) {
1922 case RIPNG_ROUTE_RTE
:
1925 case RIPNG_ROUTE_STATIC
:
1928 case RIPNG_ROUTE_DEFAULT
:
1931 case RIPNG_ROUTE_REDISTRIBUTE
:
1934 case RIPNG_ROUTE_INTERFACE
:
1945 DEFUN (show_ipv6_ripng
,
1946 show_ipv6_ripng_cmd
,
1950 "Show RIPng routes\n")
1952 struct route_node
*rp
;
1953 struct ripng_info
*rinfo
;
1954 struct ripng_aggregate
*aggregate
;
1955 struct prefix_ipv6
*p
;
1956 struct list
*list
= NULL
;
1957 struct listnode
*listnode
= NULL
;
1963 /* Header of display. */
1965 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1967 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1968 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1969 " Network Next Hop Via Metric Tag Time\n");
1971 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1972 if ((aggregate
= rp
->aggregate
) != NULL
) {
1973 p
= (struct prefix_ipv6
*)&rp
->p
;
1976 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1977 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1980 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1984 vty_out(vty
, "%*s", 18, " ");
1986 vty_out(vty
, "%*s", 28, " ");
1987 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1988 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1991 if ((list
= rp
->info
) != NULL
)
1992 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1993 p
= (struct prefix_ipv6
*)&rp
->p
;
1996 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1997 zebra_route_char(rinfo
->type
),
1998 ripng_route_subtype_print(rinfo
),
1999 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2002 vty_out(vty
, "%c(%s) %s/%d ",
2003 zebra_route_char(rinfo
->type
),
2004 ripng_route_subtype_print(rinfo
),
2005 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2008 vty_out(vty
, "%*s", 18, " ");
2009 len
= vty_out(vty
, "%s",
2010 inet6_ntoa(rinfo
->nexthop
));
2014 len
= vty_out(vty
, "%*s", len
, " ");
2017 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2018 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2021 ifindex2ifname(rinfo
->ifindex
,
2023 } else if (rinfo
->metric
2024 == RIPNG_METRIC_INFINITY
) {
2025 len
= vty_out(vty
, "kill");
2027 len
= vty_out(vty
, "self");
2031 vty_out(vty
, "%*s", len
, " ");
2033 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2034 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2037 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2038 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2039 /* RTE from remote RIP routers */
2040 ripng_vty_out_uptime(vty
, rinfo
);
2041 } else if (rinfo
->metric
2042 == RIPNG_METRIC_INFINITY
) {
2043 /* poisonous reversed routes (gc) */
2044 ripng_vty_out_uptime(vty
, rinfo
);
2054 DEFUN (show_ipv6_ripng_status
,
2055 show_ipv6_ripng_status_cmd
,
2056 "show ipv6 ripng status",
2059 "Show RIPng routes\n"
2060 "IPv6 routing protocol process parameters and statistics\n")
2062 struct listnode
*node
;
2063 struct interface
*ifp
;
2068 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2069 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2070 ripng
->update_time
);
2071 vty_out(vty
, " next due in %lu seconds\n",
2072 thread_timer_remain_second(ripng
->t_update
));
2073 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2074 vty_out(vty
, " garbage collect after %ld seconds\n",
2075 ripng
->garbage_time
);
2077 /* Filtering status show. */
2078 config_show_distribute(vty
);
2080 /* Default metric information. */
2081 vty_out(vty
, " Default redistribution metric is %d\n",
2082 ripng
->default_metric
);
2084 /* Redistribute information. */
2085 vty_out(vty
, " Redistributing:");
2086 ripng_redistribute_write(vty
, 0);
2089 vty_out(vty
, " Default version control: send version %d,",
2091 vty_out(vty
, " receive version %d \n", ripng
->version
);
2093 vty_out(vty
, " Interface Send Recv\n");
2095 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
2096 struct ripng_interface
*ri
;
2100 if (ri
->enable_network
|| ri
->enable_interface
) {
2102 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2103 ripng
->version
, ripng
->version
);
2107 vty_out(vty
, " Routing for Networks:\n");
2108 ripng_network_write(vty
, 0);
2110 vty_out(vty
, " Routing Information Sources:\n");
2112 " Gateway BadPackets BadRoutes Distance Last Update\n");
2113 ripng_peer_display(vty
);
2118 DEFUN (clear_ipv6_rip
,
2123 "Clear IPv6 RIP database\n")
2125 struct route_node
*rp
;
2126 struct ripng_info
*rinfo
;
2128 struct listnode
*listnode
;
2130 /* Clear received RIPng routes */
2131 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2136 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2137 if (!ripng_route_rte(rinfo
))
2140 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2141 ripng_zebra_ipv6_delete(rp
);
2146 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2147 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2148 listnode_delete(list
, rinfo
);
2149 ripng_info_free(rinfo
);
2152 if (list_isempty(list
)) {
2155 route_unlock_node(rp
);
2162 DEFUN_NOSH (router_ripng
,
2165 "Enable a routing process\n"
2166 "Make RIPng instance command\n")
2170 vty
->node
= RIPNG_NODE
;
2173 ret
= ripng_create();
2175 /* Notice to user we couldn't create RIPng. */
2177 zlog_warn("can't create RIPng");
2178 return CMD_WARNING_CONFIG_FAILED
;
2185 DEFUN (no_router_ripng
,
2186 no_router_ripng_cmd
,
2189 "Enable a routing process\n"
2190 "Make RIPng instance command\n")
2200 "Static route setup\n"
2201 "Set static RIPng route announcement\n")
2203 int idx_ipv6addr
= 1;
2205 struct prefix_ipv6 p
;
2206 struct route_node
*rp
;
2208 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2209 (struct prefix_ipv6
*)&p
);
2211 vty_out(vty
, "Malformed address\n");
2212 return CMD_WARNING_CONFIG_FAILED
;
2214 apply_mask_ipv6(&p
);
2216 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2218 vty_out(vty
, "There is already same static route.\n");
2219 route_unlock_node(rp
);
2220 return CMD_WARNING_CONFIG_FAILED
;
2222 rp
->info
= (void *)1;
2224 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2230 DEFUN (no_ripng_route
,
2232 "no route IPV6ADDR",
2234 "Static route setup\n"
2235 "Delete static RIPng route announcement\n")
2237 int idx_ipv6addr
= 2;
2239 struct prefix_ipv6 p
;
2240 struct route_node
*rp
;
2242 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2243 (struct prefix_ipv6
*)&p
);
2245 vty_out(vty
, "Malformed address\n");
2246 return CMD_WARNING_CONFIG_FAILED
;
2248 apply_mask_ipv6(&p
);
2250 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2252 vty_out(vty
, "Can't find static route.\n");
2253 return CMD_WARNING_CONFIG_FAILED
;
2256 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2257 route_unlock_node(rp
);
2260 route_unlock_node(rp
);
2265 DEFUN (ripng_aggregate_address
,
2266 ripng_aggregate_address_cmd
,
2267 "aggregate-address X:X::X:X/M",
2268 "Set aggregate RIPng route announcement\n"
2269 "Aggregate network\n")
2271 int idx_ipv6_prefixlen
= 1;
2274 struct route_node
*node
;
2276 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2277 (struct prefix_ipv6
*)&p
);
2279 vty_out(vty
, "Malformed address\n");
2280 return CMD_WARNING_CONFIG_FAILED
;
2283 /* Check aggregate alredy exist or not. */
2284 node
= route_node_get(ripng
->aggregate
, &p
);
2286 vty_out(vty
, "There is already same aggregate route.\n");
2287 route_unlock_node(node
);
2288 return CMD_WARNING_CONFIG_FAILED
;
2290 node
->info
= (void *)1;
2292 ripng_aggregate_add(&p
);
2297 DEFUN (no_ripng_aggregate_address
,
2298 no_ripng_aggregate_address_cmd
,
2299 "no aggregate-address X:X::X:X/M",
2301 "Delete aggregate RIPng route announcement\n"
2302 "Aggregate network\n")
2304 int idx_ipv6_prefixlen
= 2;
2307 struct route_node
*rn
;
2309 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2310 (struct prefix_ipv6
*)&p
);
2312 vty_out(vty
, "Malformed address\n");
2313 return CMD_WARNING_CONFIG_FAILED
;
2316 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2318 vty_out(vty
, "Can't find aggregate route.\n");
2319 return CMD_WARNING_CONFIG_FAILED
;
2321 route_unlock_node(rn
);
2323 route_unlock_node(rn
);
2325 ripng_aggregate_delete(&p
);
2330 DEFUN (ripng_default_metric
,
2331 ripng_default_metric_cmd
,
2332 "default-metric (1-16)",
2333 "Set a metric of redistribute routes\n"
2338 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2343 DEFUN (no_ripng_default_metric
,
2344 no_ripng_default_metric_cmd
,
2345 "no default-metric [(1-16)]",
2347 "Set a metric of redistribute routes\n"
2351 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2358 /* RIPng update timer setup. */
2359 DEFUN (ripng_update_timer
,
2360 ripng_update_timer_cmd
,
2361 "update-timer SECOND",
2362 "Set RIPng update timer in seconds\n"
2365 unsigned long update
;
2366 char *endptr
= NULL
;
2368 update
= strtoul (argv
[0], &endptr
, 10);
2369 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2371 vty_out (vty
, "update timer value error\n");
2372 return CMD_WARNING_CONFIG_FAILED
;
2375 ripng
->update_time
= update
;
2377 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2381 DEFUN (no_ripng_update_timer
,
2382 no_ripng_update_timer_cmd
,
2383 "no update-timer SECOND",
2385 "Unset RIPng update timer in seconds\n"
2388 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2389 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2393 /* RIPng timeout timer setup. */
2394 DEFUN (ripng_timeout_timer
,
2395 ripng_timeout_timer_cmd
,
2396 "timeout-timer SECOND",
2397 "Set RIPng timeout timer in seconds\n"
2400 unsigned long timeout
;
2401 char *endptr
= NULL
;
2403 timeout
= strtoul (argv
[0], &endptr
, 10);
2404 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2406 vty_out (vty
, "timeout timer value error\n");
2407 return CMD_WARNING_CONFIG_FAILED
;
2410 ripng
->timeout_time
= timeout
;
2415 DEFUN (no_ripng_timeout_timer
,
2416 no_ripng_timeout_timer_cmd
,
2417 "no timeout-timer SECOND",
2419 "Unset RIPng timeout timer in seconds\n"
2422 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2426 /* RIPng garbage timer setup. */
2427 DEFUN (ripng_garbage_timer
,
2428 ripng_garbage_timer_cmd
,
2429 "garbage-timer SECOND",
2430 "Set RIPng garbage timer in seconds\n"
2433 unsigned long garbage
;
2434 char *endptr
= NULL
;
2436 garbage
= strtoul (argv
[0], &endptr
, 10);
2437 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2439 vty_out (vty
, "garbage timer value error\n");
2440 return CMD_WARNING_CONFIG_FAILED
;
2443 ripng
->garbage_time
= garbage
;
2448 DEFUN (no_ripng_garbage_timer
,
2449 no_ripng_garbage_timer_cmd
,
2450 "no garbage-timer SECOND",
2452 "Unset RIPng garbage timer in seconds\n"
2455 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2460 DEFUN (ripng_timers
,
2462 "timers basic (0-65535) (0-65535) (0-65535)",
2463 "RIPng timers setup\n"
2465 "Routing table update timer value in second. Default is 30.\n"
2466 "Routing information timeout timer. Default is 180.\n"
2467 "Garbage collection timer. Default is 120.\n")
2470 int idx_number_2
= 3;
2471 int idx_number_3
= 4;
2472 unsigned long update
;
2473 unsigned long timeout
;
2474 unsigned long garbage
;
2476 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2477 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2478 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2480 /* Set each timer value. */
2481 ripng
->update_time
= update
;
2482 ripng
->timeout_time
= timeout
;
2483 ripng
->garbage_time
= garbage
;
2485 /* Reset update timer thread. */
2486 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2491 DEFUN (no_ripng_timers
,
2492 no_ripng_timers_cmd
,
2493 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2495 "RIPng timers setup\n"
2497 "Routing table update timer value in second. Default is 30.\n"
2498 "Routing information timeout timer. Default is 180.\n"
2499 "Garbage collection timer. Default is 120.\n")
2501 /* Set each timer value to the default. */
2502 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2503 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2504 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2506 /* Reset update timer thread. */
2507 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2513 DEFUN (show_ipv6_protocols
,
2514 show_ipv6_protocols_cmd
,
2515 "show ipv6 protocols",
2518 "Routing protocol information\n")
2523 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2525 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2526 ripng
->update_time
, 0);
2528 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2529 ripng
->timeout_time
,
2530 ripng
->garbage_time
);
2532 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2533 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2539 /* Please be carefull to use this command. */
2540 DEFUN (ripng_default_information_originate
,
2541 ripng_default_information_originate_cmd
,
2542 "default-information originate",
2543 "Default route information\n"
2544 "Distribute default route\n")
2546 struct prefix_ipv6 p
;
2548 if (!ripng
->default_information
) {
2549 ripng
->default_information
= 1;
2551 str2prefix_ipv6("::/0", &p
);
2552 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2559 DEFUN (no_ripng_default_information_originate
,
2560 no_ripng_default_information_originate_cmd
,
2561 "no default-information originate",
2563 "Default route information\n"
2564 "Distribute default route\n")
2566 struct prefix_ipv6 p
;
2568 if (ripng
->default_information
) {
2569 ripng
->default_information
= 0;
2571 str2prefix_ipv6("::/0", &p
);
2572 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2573 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2579 /* Update ECMP routes to zebra when ECMP is disabled. */
2580 static void ripng_ecmp_disable(void)
2582 struct route_node
*rp
;
2583 struct ripng_info
*rinfo
, *tmp_rinfo
;
2585 struct listnode
*node
, *nextnode
;
2590 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2591 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2592 rinfo
= listgetdata(listhead(list
));
2593 if (!ripng_route_rte(rinfo
))
2596 /* Drop all other entries, except the first one. */
2597 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2598 if (tmp_rinfo
!= rinfo
) {
2599 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2601 tmp_rinfo
->t_garbage_collect
);
2602 list_delete_node(list
, node
);
2603 ripng_info_free(tmp_rinfo
);
2607 ripng_zebra_ipv6_add(rp
);
2609 /* Set the route change flag. */
2610 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2612 /* Signal the output process to trigger an update. */
2613 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2617 DEFUN (ripng_allow_ecmp
,
2618 ripng_allow_ecmp_cmd
,
2620 "Allow Equal Cost MultiPath\n")
2623 vty_out(vty
, "ECMP is already enabled.\n");
2624 return CMD_WARNING_CONFIG_FAILED
;
2628 zlog_info("ECMP is enabled.");
2632 DEFUN (no_ripng_allow_ecmp
,
2633 no_ripng_allow_ecmp_cmd
,
2636 "Allow Equal Cost MultiPath\n")
2639 vty_out(vty
, "ECMP is already disabled.\n");
2640 return CMD_WARNING_CONFIG_FAILED
;
2644 zlog_info("ECMP is disabled.");
2645 ripng_ecmp_disable();
2649 /* RIPng configuration write function. */
2650 static int ripng_config_write(struct vty
*vty
)
2652 int ripng_network_write(struct vty
*, int);
2653 void ripng_redistribute_write(struct vty
*, int);
2655 struct route_node
*rp
;
2660 vty_out(vty
, "router ripng\n");
2662 if (ripng
->default_information
)
2663 vty_out(vty
, " default-information originate\n");
2665 ripng_network_write(vty
, 1);
2667 /* RIPng default metric configuration */
2668 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2669 vty_out(vty
, " default-metric %d\n",
2670 ripng
->default_metric
);
2672 ripng_redistribute_write(vty
, 1);
2674 /* RIP offset-list configuration. */
2675 config_write_ripng_offset_list(vty
);
2677 /* RIPng aggregate routes. */
2678 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2679 if (rp
->info
!= NULL
)
2680 vty_out(vty
, " aggregate-address %s/%d\n",
2681 inet6_ntoa(rp
->p
.u
.prefix6
),
2684 /* ECMP configuration. */
2686 vty_out(vty
, " allow-ecmp\n");
2688 /* RIPng static routes. */
2689 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2690 if (rp
->info
!= NULL
)
2691 vty_out(vty
, " route %s/%d\n",
2692 inet6_ntoa(rp
->p
.u
.prefix6
),
2695 /* RIPng timers configuration. */
2696 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2697 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2698 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2699 vty_out(vty
, " timers basic %ld %ld %ld\n",
2700 ripng
->update_time
, ripng
->timeout_time
,
2701 ripng
->garbage_time
);
2704 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2705 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2706 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2707 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2708 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2709 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2712 write
+= config_write_distribute(vty
);
2714 write
+= config_write_if_rmap(vty
);
2721 /* RIPng node structure. */
2722 static struct cmd_node cmd_ripng_node
= {
2723 RIPNG_NODE
, "%s(config-router)# ", 1,
2726 static void ripng_distribute_update(struct distribute
*dist
)
2728 struct interface
*ifp
;
2729 struct ripng_interface
*ri
;
2730 struct access_list
*alist
;
2731 struct prefix_list
*plist
;
2736 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2742 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2743 alist
= access_list_lookup(AFI_IP6
,
2744 dist
->list
[DISTRIBUTE_V6_IN
]);
2746 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2748 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2750 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2752 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2753 alist
= access_list_lookup(AFI_IP6
,
2754 dist
->list
[DISTRIBUTE_V6_OUT
]);
2756 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2758 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2760 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2762 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2763 plist
= prefix_list_lookup(AFI_IP6
,
2764 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2766 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2768 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2770 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2772 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2773 plist
= prefix_list_lookup(AFI_IP6
,
2774 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2776 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2778 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2780 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2783 void ripng_distribute_update_interface(struct interface
*ifp
)
2785 struct distribute
*dist
;
2787 dist
= distribute_lookup(ifp
->name
);
2789 ripng_distribute_update(dist
);
2792 /* Update all interface's distribute list. */
2793 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2795 struct interface
*ifp
;
2796 struct listnode
*node
;
2798 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2799 ripng_distribute_update_interface(ifp
);
2802 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2804 ripng_distribute_update_all(NULL
);
2807 /* delete all the added ripng routes. */
2811 struct route_node
*rp
;
2812 struct ripng_info
*rinfo
;
2813 struct ripng_aggregate
*aggregate
;
2814 struct list
*list
= NULL
;
2815 struct listnode
*listnode
= NULL
;
2818 /* Clear RIPng routes */
2819 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2820 if ((list
= rp
->info
) != NULL
) {
2821 rinfo
= listgetdata(listhead(list
));
2822 if (ripng_route_rte(rinfo
))
2823 ripng_zebra_ipv6_delete(rp
);
2825 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2827 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2829 rinfo
->t_garbage_collect
);
2830 ripng_info_free(rinfo
);
2834 route_unlock_node(rp
);
2837 if ((aggregate
= rp
->aggregate
) != NULL
) {
2838 ripng_aggregate_free(aggregate
);
2839 rp
->aggregate
= NULL
;
2840 route_unlock_node(rp
);
2844 /* Cancel the RIPng timers */
2845 RIPNG_TIMER_OFF(ripng
->t_update
);
2846 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2847 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2849 /* Cancel the read thread */
2850 if (ripng
->t_read
) {
2851 thread_cancel(ripng
->t_read
);
2852 ripng
->t_read
= NULL
;
2855 /* Close the RIPng socket */
2856 if (ripng
->sock
>= 0) {
2861 /* Static RIPng route configuration. */
2862 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2865 route_unlock_node(rp
);
2868 /* RIPng aggregated prefixes */
2869 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2872 route_unlock_node(rp
);
2875 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2876 if (ripng
->route_map
[i
].name
)
2877 free(ripng
->route_map
[i
].name
);
2879 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2880 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2881 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2883 stream_free(ripng
->ibuf
);
2884 stream_free(ripng
->obuf
);
2886 XFREE(MTYPE_RIPNG
, ripng
);
2890 ripng_clean_network();
2891 ripng_passive_interface_clean();
2892 ripng_offset_clean();
2893 ripng_interface_clean();
2894 ripng_redistribute_clean();
2897 /* Reset all values to the default settings. */
2900 /* Call ripd related reset functions. */
2901 ripng_debug_reset();
2902 ripng_route_map_reset();
2904 /* Call library reset functions. */
2906 access_list_reset();
2907 prefix_list_reset();
2909 distribute_list_reset();
2911 ripng_interface_reset();
2913 ripng_zclient_reset();
2916 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2918 struct interface
*ifp
;
2919 struct ripng_interface
*ri
;
2920 struct route_map
*rmap
;
2922 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2928 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2929 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2931 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2933 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2935 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2937 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2938 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2940 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2942 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2944 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2947 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2949 struct if_rmap
*if_rmap
;
2951 if_rmap
= if_rmap_lookup(ifp
->name
);
2953 ripng_if_rmap_update(if_rmap
);
2956 static void ripng_routemap_update_redistribute(void)
2961 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2962 if (ripng
->route_map
[i
].name
)
2963 ripng
->route_map
[i
].map
=
2964 route_map_lookup_by_name(
2965 ripng
->route_map
[i
].name
);
2970 static void ripng_routemap_update(const char *unused
)
2972 struct interface
*ifp
;
2973 struct listnode
*node
;
2975 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2976 ripng_if_rmap_update_interface(ifp
);
2978 ripng_routemap_update_redistribute();
2981 /* Initialize ripng structure and set commands. */
2984 /* Install RIPNG_NODE. */
2985 install_node(&cmd_ripng_node
, ripng_config_write
);
2987 /* Install ripng commands. */
2988 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2989 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2991 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2993 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2994 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
2996 install_default(RIPNG_NODE
);
2997 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2998 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
2999 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3000 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3002 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3003 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3005 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3006 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3008 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3009 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3010 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3011 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3012 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3013 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3014 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3017 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3018 install_element(RIPNG_NODE
,
3019 &no_ripng_default_information_originate_cmd
);
3021 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3022 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3027 /* Access list install. */
3029 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3030 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3032 /* Prefix list initialize.*/
3034 prefix_list_add_hook(ripng_distribute_update_all
);
3035 prefix_list_delete_hook(ripng_distribute_update_all
);
3037 /* Distribute list install. */
3038 distribute_list_init(RIPNG_NODE
);
3039 distribute_list_add_hook(ripng_distribute_update
);
3040 distribute_list_delete_hook(ripng_distribute_update
);
3042 /* Route-map for interface. */
3043 ripng_route_map_init();
3044 ripng_offset_init();
3046 route_map_add_hook(ripng_routemap_update
);
3047 route_map_delete_hook(ripng_routemap_update
);
3049 if_rmap_init(RIPNG_NODE
);
3050 if_rmap_hook_add(ripng_if_rmap_update
);
3051 if_rmap_hook_delete(ripng_if_rmap_update
);