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
)) {
410 list_delete_and_null((struct list
**)&rp
->info
);
411 route_unlock_node(rp
);
414 /* Free RIPng routing information. */
415 ripng_info_free(rinfo
);
420 static void ripng_timeout_update(struct ripng_info
*rinfo
);
422 /* Add new route to the ECMP list.
423 * RETURN: the new entry added in the list, or NULL if it is not the first
424 * entry and ECMP is not allowed.
426 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
428 struct route_node
*rp
= rinfo_new
->rp
;
429 struct ripng_info
*rinfo
= NULL
;
430 struct list
*list
= NULL
;
432 if (rp
->info
== NULL
)
433 rp
->info
= list_new();
434 list
= (struct list
*)rp
->info
;
436 /* If ECMP is not allowed and some entry already exists in the list,
438 if (listcount(list
) && !ripng
->ecmp
)
441 rinfo
= ripng_info_new();
442 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
443 listnode_add(list
, rinfo
);
445 if (ripng_route_rte(rinfo
)) {
446 ripng_timeout_update(rinfo
);
447 ripng_zebra_ipv6_add(rp
);
450 ripng_aggregate_increment(rp
, rinfo
);
452 /* Set the route change flag on the first entry. */
453 rinfo
= listgetdata(listhead(list
));
454 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
456 /* Signal the output process to trigger an update. */
457 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
462 /* Replace the ECMP list with the new route.
463 * RETURN: the new entry added in the list
465 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
467 struct route_node
*rp
= rinfo_new
->rp
;
468 struct list
*list
= (struct list
*)rp
->info
;
469 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
470 struct listnode
*node
= NULL
, *nextnode
= NULL
;
472 if (list
== NULL
|| listcount(list
) == 0)
473 return ripng_ecmp_add(rinfo_new
);
475 /* Get the first entry */
476 rinfo
= listgetdata(listhead(list
));
478 /* Learnt route replaced by a local one. Delete it from zebra. */
479 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
480 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
481 ripng_zebra_ipv6_delete(rp
);
483 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
484 ripng_aggregate_decrement_list(rp
, list
);
486 /* Re-use the first entry, and delete the others. */
487 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
488 if (tmp_rinfo
!= rinfo
) {
489 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
490 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
491 list_delete_node(list
, node
);
492 ripng_info_free(tmp_rinfo
);
495 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
496 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
497 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
499 if (ripng_route_rte(rinfo
)) {
500 ripng_timeout_update(rinfo
);
501 /* The ADD message implies an update. */
502 ripng_zebra_ipv6_add(rp
);
505 ripng_aggregate_increment(rp
, rinfo
);
507 /* Set the route change flag. */
508 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
510 /* Signal the output process to trigger an update. */
511 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
516 /* Delete one route from the ECMP list.
518 * null - the entry is freed, and other entries exist in the list
519 * the entry - the entry is the last one in the list; its metric is set
520 * to INFINITY, and the garbage collector is started for it
522 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
524 struct route_node
*rp
= rinfo
->rp
;
525 struct list
*list
= (struct list
*)rp
->info
;
527 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
529 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
530 ripng_aggregate_decrement(rp
, rinfo
);
532 if (listcount(list
) > 1) {
533 /* Some other ECMP entries still exist. Just delete this entry.
535 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
536 listnode_delete(list
, rinfo
);
537 if (ripng_route_rte(rinfo
)
538 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
539 /* The ADD message implies the update. */
540 ripng_zebra_ipv6_add(rp
);
541 ripng_info_free(rinfo
);
544 assert(rinfo
== listgetdata(listhead(list
)));
546 /* This is the only entry left in the list. We must keep it in
547 * the list for garbage collection time, with INFINITY metric.
550 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
551 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
552 ripng
->garbage_time
);
554 if (ripng_route_rte(rinfo
)
555 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
556 ripng_zebra_ipv6_delete(rp
);
559 /* Set the route change flag on the first entry. */
560 rinfo
= listgetdata(listhead(list
));
561 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
563 /* Signal the output process to trigger an update. */
564 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
569 /* Timeout RIPng routes. */
570 static int ripng_timeout(struct thread
*t
)
572 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
576 static void ripng_timeout_update(struct ripng_info
*rinfo
)
578 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
579 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
580 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
581 ripng
->timeout_time
);
585 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
586 struct ripng_interface
*ri
)
588 struct distribute
*dist
;
589 struct access_list
*alist
;
590 struct prefix_list
*plist
;
591 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
594 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
596 /* Input distribute-list filtering. */
597 if (ri
->list
[ripng_distribute
]) {
598 if (access_list_apply(ri
->list
[ripng_distribute
],
601 if (IS_RIPNG_DEBUG_PACKET
)
602 zlog_debug("%s/%d filtered by distribute %s",
603 inet6_ntoa(p
->prefix
), p
->prefixlen
,
608 if (ri
->prefix
[ripng_distribute
]) {
609 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
612 if (IS_RIPNG_DEBUG_PACKET
)
613 zlog_debug("%s/%d filtered by prefix-list %s",
614 inet6_ntoa(p
->prefix
), p
->prefixlen
,
620 /* All interface filter check. */
621 dist
= distribute_lookup(NULL
);
623 if (dist
->list
[distribute
]) {
624 alist
= access_list_lookup(AFI_IP6
,
625 dist
->list
[distribute
]);
628 if (access_list_apply(alist
, (struct prefix
*)p
)
630 if (IS_RIPNG_DEBUG_PACKET
)
632 "%s/%d filtered by distribute %s",
633 inet6_ntoa(p
->prefix
),
634 p
->prefixlen
, inout
);
639 if (dist
->prefix
[distribute
]) {
640 plist
= prefix_list_lookup(AFI_IP6
,
641 dist
->prefix
[distribute
]);
644 if (prefix_list_apply(plist
, (struct prefix
*)p
)
646 if (IS_RIPNG_DEBUG_PACKET
)
648 "%s/%d filtered by prefix-list %s",
649 inet6_ntoa(p
->prefix
),
650 p
->prefixlen
, inout
);
659 /* Process RIPng route according to RFC2080. */
660 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
661 struct ripng_nexthop
*ripng_nexthop
,
662 struct interface
*ifp
)
665 struct prefix_ipv6 p
;
666 struct route_node
*rp
;
667 struct ripng_info
*rinfo
= NULL
, newinfo
;
668 struct ripng_interface
*ri
;
669 struct in6_addr
*nexthop
;
671 struct list
*list
= NULL
;
672 struct listnode
*node
= NULL
;
674 /* Make prefix structure. */
675 memset(&p
, 0, sizeof(struct prefix_ipv6
));
677 /* p.prefix = rte->addr; */
678 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
679 p
.prefixlen
= rte
->prefixlen
;
681 /* Make sure mask is applied. */
682 /* XXX We have to check the prefix is valid or not before call
686 /* Apply input filters. */
689 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
693 memset(&newinfo
, 0, sizeof(newinfo
));
694 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
695 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
696 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
697 newinfo
.nexthop
= ripng_nexthop
->address
;
699 newinfo
.nexthop
= from
->sin6_addr
;
700 newinfo
.from
= from
->sin6_addr
;
701 newinfo
.ifindex
= ifp
->ifindex
;
702 newinfo
.metric
= rte
->metric
;
703 newinfo
.metric_out
= rte
->metric
; /* XXX */
704 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
707 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
710 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
711 (struct prefix
*)&p
, RMAP_RIPNG
,
714 if (ret
== RMAP_DENYMATCH
) {
715 if (IS_RIPNG_DEBUG_PACKET
)
717 "RIPng %s/%d is filtered by route-map in",
718 inet6_ntoa(p
.prefix
), p
.prefixlen
);
722 /* Get back the object */
723 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
724 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
725 &ripng_nexthop
->address
)) {
726 /* the nexthop get changed by the routemap */
727 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
728 ripng_nexthop
->address
=
731 ripng_nexthop
->address
= in6addr_any
;
734 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
736 /* the nexthop get changed by the routemap */
737 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
738 ripng_nexthop
->flag
=
739 RIPNG_NEXTHOP_ADDRESS
;
740 ripng_nexthop
->address
=
745 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
747 newinfo
.metric_out
; /* XXX: the routemap uses the
751 /* Once the entry has been validated, update the metric by
752 * adding the cost of the network on wich the message
753 * arrived. If the result is greater than infinity, use infinity
754 * (RFC2453 Sec. 3.9.2)
757 /* Zebra ripngd can handle offset-list in. */
758 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
760 /* If offset-list does not modify the metric use interface's
763 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
765 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
766 rte
->metric
= RIPNG_METRIC_INFINITY
;
768 /* Set nexthop pointer. */
769 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
770 nexthop
= &ripng_nexthop
->address
;
772 nexthop
= &from
->sin6_addr
;
774 /* Lookup RIPng routing table. */
775 rp
= route_node_get(ripng
->table
, (struct prefix
*)&p
);
778 newinfo
.nexthop
= *nexthop
;
779 newinfo
.metric
= rte
->metric
;
780 newinfo
.tag
= ntohs(rte
->tag
);
782 /* Check to see whether there is already RIPng route on the table. */
783 if ((list
= rp
->info
) != NULL
)
784 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
785 /* Need to compare with redistributed entry or local
787 if (!ripng_route_rte(rinfo
))
790 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
791 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
794 if (!listnextnode(node
)) {
795 /* Not found in the list */
797 if (rte
->metric
> rinfo
->metric
) {
798 /* New route has a greater metric.
800 route_unlock_node(rp
);
804 if (rte
->metric
< rinfo
->metric
)
805 /* New route has a smaller metric.
806 * Replace the ECMP list
807 * with the new one in below. */
810 /* Metrics are same. Unless ECMP is disabled,
811 * keep "rinfo" null and
812 * the new route is added in the ECMP list in
820 /* Redistributed route check. */
821 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
822 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
823 route_unlock_node(rp
);
827 /* Local static route. */
828 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
829 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
830 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
831 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
832 route_unlock_node(rp
);
838 /* Now, check to see whether there is already an explicit route
839 for the destination prefix. If there is no such route, add
840 this route to the routing table, unless the metric is
841 infinity (there is no point in adding a route which
843 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
844 ripng_ecmp_add(&newinfo
);
846 route_unlock_node(rp
);
848 /* If there is an existing route, compare the next hop address
849 to the address of the router from which the datagram came.
850 If this datagram is from the same router as the existing
851 route, reinitialize the timeout. */
852 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
853 && (rinfo
->ifindex
== ifp
->ifindex
));
856 * RFC 2080 - Section 2.4.2:
857 * "If the new metric is the same as the old one, examine the
859 * for the existing route. If it is at least halfway to the
861 * point, switch to the new route. This heuristic is optional,
863 * highly recommended".
865 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
867 && (thread_timer_remain_second(rinfo
->t_timeout
)
868 < (ripng
->timeout_time
/ 2))) {
869 ripng_ecmp_replace(&newinfo
);
871 /* Next, compare the metrics. If the datagram is from the same
872 router as the existing route, and the new metric is different
873 than the old one; or, if the new metric is lower than the old
874 one; do the following actions: */
875 else if ((same
&& rinfo
->metric
!= rte
->metric
)
876 || rte
->metric
< rinfo
->metric
) {
877 if (listcount(list
) == 1) {
878 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
879 ripng_ecmp_replace(&newinfo
);
881 ripng_ecmp_delete(rinfo
);
883 if (newinfo
.metric
< rinfo
->metric
)
884 ripng_ecmp_replace(&newinfo
);
885 else /* newinfo.metric > rinfo->metric */
886 ripng_ecmp_delete(rinfo
);
888 } else /* same & no change */
889 ripng_timeout_update(rinfo
);
891 /* Unlock tempolary lock of the route. */
892 route_unlock_node(rp
);
896 /* Add redistributed route to RIPng table. */
897 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
898 ifindex_t ifindex
, struct in6_addr
*nexthop
,
901 struct route_node
*rp
;
902 struct ripng_info
*rinfo
= NULL
, newinfo
;
903 struct list
*list
= NULL
;
905 /* Redistribute route */
906 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
908 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
911 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
913 memset(&newinfo
, 0, sizeof(struct ripng_info
));
915 newinfo
.sub_type
= sub_type
;
916 newinfo
.ifindex
= ifindex
;
918 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
921 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
922 newinfo
.nexthop
= *nexthop
;
924 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
925 rinfo
= listgetdata(listhead(list
));
927 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
928 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
929 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
930 route_unlock_node(rp
);
934 /* Manually configured RIPng route check.
935 * They have the precedence on all the other entries.
937 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
938 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
939 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
940 if (type
!= ZEBRA_ROUTE_RIPNG
941 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
942 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
943 route_unlock_node(rp
);
948 ripng_ecmp_replace(&newinfo
);
949 route_unlock_node(rp
);
951 ripng_ecmp_add(&newinfo
);
953 if (IS_RIPNG_DEBUG_EVENT
) {
956 "Redistribute new prefix %s/%d on the interface %s",
957 inet6_ntoa(p
->prefix
), p
->prefixlen
,
958 ifindex2ifname(ifindex
, VRF_DEFAULT
));
961 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
962 inet6_ntoa(p
->prefix
), p
->prefixlen
,
963 inet6_ntoa(*nexthop
),
964 ifindex2ifname(ifindex
, VRF_DEFAULT
));
967 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
970 /* Delete redistributed route to RIPng table. */
971 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
974 struct route_node
*rp
;
975 struct ripng_info
*rinfo
;
977 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
979 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
982 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
985 struct list
*list
= rp
->info
;
987 if (list
!= NULL
&& listcount(list
) != 0) {
988 rinfo
= listgetdata(listhead(list
));
989 if (rinfo
!= NULL
&& rinfo
->type
== type
990 && rinfo
->sub_type
== sub_type
991 && rinfo
->ifindex
== ifindex
) {
992 /* Perform poisoned reverse. */
993 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
994 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
995 ripng_garbage_collect
,
996 ripng
->garbage_time
);
997 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
999 /* Aggregate count decrement. */
1000 ripng_aggregate_decrement(rp
, rinfo
);
1002 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1004 if (IS_RIPNG_DEBUG_EVENT
)
1006 "Poisone %s/%d on the interface %s with an "
1007 "infinity metric [delete]",
1008 inet6_ntoa(p
->prefix
),
1010 ifindex2ifname(ifindex
,
1013 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1016 route_unlock_node(rp
);
1020 /* Withdraw redistributed route. */
1021 void ripng_redistribute_withdraw(int type
)
1023 struct route_node
*rp
;
1024 struct ripng_info
*rinfo
= NULL
;
1025 struct list
*list
= NULL
;
1030 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1031 if ((list
= rp
->info
) != NULL
) {
1032 rinfo
= listgetdata(listhead(list
));
1033 if ((rinfo
->type
== type
)
1034 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1035 /* Perform poisoned reverse. */
1036 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1037 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1038 ripng_garbage_collect
,
1039 ripng
->garbage_time
);
1040 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1042 /* Aggregate count decrement. */
1043 ripng_aggregate_decrement(rp
, rinfo
);
1045 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1047 if (IS_RIPNG_DEBUG_EVENT
) {
1048 struct prefix_ipv6
*p
=
1049 (struct prefix_ipv6
*)&rp
->p
;
1052 "Poisone %s/%d on the interface %s [withdraw]",
1053 inet6_ntoa(p
->prefix
),
1055 ifindex2ifname(rinfo
->ifindex
,
1059 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1064 /* RIP routing information. */
1065 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1066 struct sockaddr_in6
*from
,
1067 struct interface
*ifp
, int hoplimit
)
1071 struct ripng_nexthop nexthop
;
1073 /* RFC2080 2.4.2 Response Messages:
1074 The Response must be ignored if it is not from the RIPng port. */
1075 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1076 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1077 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1078 ripng_peer_bad_packet(from
);
1082 /* The datagram's IPv6 source address should be checked to see
1083 whether the datagram is from a valid neighbor; the source of the
1084 datagram must be a link-local address. */
1085 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1086 zlog_warn("RIPng packet comes from non link local address %s",
1087 inet6_ntoa(from
->sin6_addr
));
1088 ripng_peer_bad_packet(from
);
1092 /* It is also worth checking to see whether the response is from one
1093 of the router's own addresses. Interfaces on broadcast networks
1094 may receive copies of their own multicasts immediately. If a
1095 router processes its own output as new input, confusion is likely,
1096 and such datagrams must be ignored. */
1097 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1099 "RIPng packet comes from my own link local address %s",
1100 inet6_ntoa(from
->sin6_addr
));
1101 ripng_peer_bad_packet(from
);
1105 /* As an additional check, periodic advertisements must have their
1106 hop counts set to 255, and inbound, multicast packets sent from the
1107 RIPng port (i.e. periodic advertisement or triggered update
1108 packets) must be examined to ensure that the hop count is 255. */
1109 if (hoplimit
>= 0 && hoplimit
!= 255) {
1111 "RIPng packet comes with non 255 hop count %d from %s",
1112 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1113 ripng_peer_bad_packet(from
);
1117 /* Update RIPng peer. */
1118 ripng_peer_update(from
, packet
->version
);
1120 /* Reset nexthop. */
1121 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1122 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1124 /* Set RTE pointer. */
1127 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1128 /* First of all, we have to check this RTE is next hop RTE or
1129 not. Next hop RTE is completely different with normal RTE so
1130 we need special treatment. */
1131 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1132 ripng_nexthop_rte(rte
, from
, &nexthop
);
1136 /* RTE information validation. */
1138 /* - is the destination prefix valid (e.g., not a multicast
1139 prefix and not a link-local address) A link-local address
1140 should never be present in an RTE. */
1141 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1143 "Destination prefix is a multicast address %s/%d [%d]",
1144 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1146 ripng_peer_bad_route(from
);
1149 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1151 "Destination prefix is a link-local address %s/%d [%d]",
1152 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1154 ripng_peer_bad_route(from
);
1157 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1159 "Destination prefix is a loopback address %s/%d [%d]",
1160 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1162 ripng_peer_bad_route(from
);
1166 /* - is the prefix length valid (i.e., between 0 and 128,
1168 if (rte
->prefixlen
> 128) {
1169 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1170 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1171 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1172 ripng_peer_bad_route(from
);
1176 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1177 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1178 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1179 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1180 ripng_peer_bad_route(from
);
1184 /* Vincent: XXX Should we compute the direclty reachable nexthop
1185 * for our RIPng network ?
1188 /* Routing table updates. */
1189 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1193 /* Response to request message. */
1194 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1195 struct sockaddr_in6
*from
,
1196 struct interface
*ifp
)
1200 struct prefix_ipv6 p
;
1201 struct route_node
*rp
;
1202 struct ripng_info
*rinfo
;
1203 struct ripng_interface
*ri
;
1205 /* Does not reponse to the requests on the loopback interfaces */
1206 if (if_is_loopback(ifp
))
1209 /* Check RIPng process is enabled on this interface. */
1214 /* When passive interface is specified, suppress responses */
1218 /* RIPng peer update. */
1219 ripng_peer_update(from
, packet
->version
);
1221 lim
= ((caddr_t
)packet
) + size
;
1224 /* The Request is processed entry by entry. If there are no
1225 entries, no response is given. */
1226 if (lim
== (caddr_t
)rte
)
1229 /* There is one special case. If there is exactly one entry in the
1230 request, and it has a destination prefix of zero, a prefix length
1231 of zero, and a metric of infinity (i.e., 16), then this is a
1232 request to send the entire routing table. In that case, a call
1233 is made to the output process to send the routing table to the
1234 requesting address/port. */
1235 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1236 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1237 /* All route with split horizon */
1238 ripng_output_process(ifp
, from
, ripng_all_route
);
1240 /* Except for this special case, processing is quite simple.
1241 Examine the list of RTEs in the Request one by one. For each
1242 entry, look up the destination in the router's routing
1243 database and, if there is a route, put that route's metric in
1244 the metric field of the RTE. If there is no explicit route
1245 to the specified destination, put infinity in the metric
1246 field. Once all the entries have been filled in, change the
1247 command from Request to Response and send the datagram back
1248 to the requestor. */
1249 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1250 p
.family
= AF_INET6
;
1252 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1253 p
.prefix
= rte
->addr
;
1254 p
.prefixlen
= rte
->prefixlen
;
1255 apply_mask_ipv6(&p
);
1257 rp
= route_node_lookup(ripng
->table
,
1258 (struct prefix
*)&p
);
1261 rinfo
= listgetdata(
1262 listhead((struct list
*)rp
->info
));
1263 rte
->metric
= rinfo
->metric
;
1264 route_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 route_node
*rp
;
1364 struct ripng_info
*rinfo
= NULL
;
1365 struct list
*list
= NULL
;
1366 struct listnode
*listnode
= NULL
;
1368 for (rp
= route_top(ripng
->table
); rp
; rp
= 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 listnode
*node
;
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_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, 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 listnode
*node
;
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_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, 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
, u_int16_t tag
, u_char metric
)
1509 /* RIPng packet header. */
1511 stream_putc(s
, RIPNG_RESPONSE
);
1512 stream_putc(s
, RIPNG_V1
);
1516 /* Write routing table entry. */
1518 stream_write(s
, (u_char
*)&p
->prefix
, sizeof(struct in6_addr
));
1520 stream_write(s
, (u_char
*)nexthop
, sizeof(struct in6_addr
));
1521 stream_putw(s
, tag
);
1523 stream_putc(s
, p
->prefixlen
);
1526 stream_putc(s
, metric
);
1531 /* Send RESPONSE message to specified destination. */
1532 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1536 struct route_node
*rp
;
1537 struct ripng_info
*rinfo
;
1538 struct ripng_interface
*ri
;
1539 struct ripng_aggregate
*aggregate
;
1540 struct prefix_ipv6
*p
;
1541 struct list
*ripng_rte_list
;
1542 struct list
*list
= NULL
;
1543 struct listnode
*listnode
= NULL
;
1545 if (IS_RIPNG_DEBUG_EVENT
) {
1547 zlog_debug("RIPng update routes to neighbor %s",
1548 inet6_ntoa(to
->sin6_addr
));
1550 zlog_debug("RIPng update routes on interface %s",
1554 /* Get RIPng interface. */
1557 ripng_rte_list
= ripng_rte_new();
1559 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1560 if ((list
= rp
->info
) != NULL
1561 && (rinfo
= listgetdata(listhead(list
))) != NULL
1562 && rinfo
->suppress
== 0) {
1563 /* If no route-map are applied, the RTE will be these
1567 p
= (struct prefix_ipv6
*)&rp
->p
;
1568 rinfo
->metric_out
= rinfo
->metric
;
1569 rinfo
->tag_out
= rinfo
->tag
;
1570 memset(&rinfo
->nexthop_out
, 0,
1571 sizeof(rinfo
->nexthop_out
));
1572 /* In order to avoid some local loops,
1573 * if the RIPng route has a nexthop via this interface,
1575 * otherwise set it to 0. The nexthop should not be
1577 * beyond the local broadcast/multicast area in order
1578 * to avoid an IGP multi-level recursive look-up.
1580 if (rinfo
->ifindex
== ifp
->ifindex
)
1581 rinfo
->nexthop_out
= rinfo
->nexthop
;
1583 /* Apply output filters. */
1584 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1588 /* Changed route only output. */
1589 if (route_type
== ripng_changed_route
1590 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1593 /* Split horizon. */
1594 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1595 /* We perform split horizon for RIPng routes. */
1597 struct ripng_info
*tmp_rinfo
= NULL
;
1599 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1601 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1602 && tmp_rinfo
->ifindex
1611 /* Preparation for route-map. */
1612 rinfo
->metric_set
= 0;
1615 * and tag_out are already initialized.
1618 /* Interface route-map */
1619 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1622 ret
= route_map_apply(
1623 ri
->routemap
[RIPNG_FILTER_OUT
],
1624 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1626 if (ret
== RMAP_DENYMATCH
) {
1627 if (IS_RIPNG_DEBUG_PACKET
)
1629 "RIPng %s/%d is filtered by route-map out",
1630 inet6_ntoa(p
->prefix
),
1636 /* Redistribute route-map. */
1637 if (ripng
->route_map
[rinfo
->type
].name
) {
1640 ret
= route_map_apply(
1641 ripng
->route_map
[rinfo
->type
].map
,
1642 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1644 if (ret
== RMAP_DENYMATCH
) {
1645 if (IS_RIPNG_DEBUG_PACKET
)
1647 "RIPng %s/%d is filtered by route-map",
1648 inet6_ntoa(p
->prefix
),
1654 /* When the route-map does not set metric. */
1655 if (!rinfo
->metric_set
) {
1656 /* If the redistribute metric is set. */
1657 if (ripng
->route_map
[rinfo
->type
].metric_config
1658 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1660 ripng
->route_map
[rinfo
->type
]
1663 /* If the route is not connected or
1665 one, use default-metric value */
1666 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1668 != ZEBRA_ROUTE_CONNECT
1670 != RIPNG_METRIC_INFINITY
)
1672 ripng
->default_metric
;
1676 /* Apply offset-list */
1677 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1678 ripng_offset_list_apply_out(p
, ifp
,
1679 &rinfo
->metric_out
);
1681 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1682 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1684 /* Perform split-horizon with poisoned reverse
1687 if (ri
->split_horizon
1688 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1689 struct ripng_info
*tmp_rinfo
= NULL
;
1691 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1693 if ((tmp_rinfo
->type
1694 == ZEBRA_ROUTE_RIPNG
)
1695 && tmp_rinfo
->ifindex
1698 RIPNG_METRIC_INFINITY
;
1701 /* Add RTE to the list */
1702 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1705 /* Process the aggregated RTE entry */
1706 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1707 && aggregate
->suppress
== 0) {
1708 /* If no route-map are applied, the RTE will be these
1712 p
= (struct prefix_ipv6
*)&rp
->p
;
1713 aggregate
->metric_set
= 0;
1714 aggregate
->metric_out
= aggregate
->metric
;
1715 aggregate
->tag_out
= aggregate
->tag
;
1716 memset(&aggregate
->nexthop_out
, 0,
1717 sizeof(aggregate
->nexthop_out
));
1719 /* Apply output filters.*/
1720 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1724 /* Interface route-map */
1725 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1727 struct ripng_info newinfo
;
1729 /* let's cast the aggregate structure to
1731 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1732 /* the nexthop is :: */
1733 newinfo
.metric
= aggregate
->metric
;
1734 newinfo
.metric_out
= aggregate
->metric_out
;
1735 newinfo
.tag
= aggregate
->tag
;
1736 newinfo
.tag_out
= aggregate
->tag_out
;
1738 ret
= route_map_apply(
1739 ri
->routemap
[RIPNG_FILTER_OUT
],
1740 (struct prefix
*)p
, RMAP_RIPNG
,
1743 if (ret
== RMAP_DENYMATCH
) {
1744 if (IS_RIPNG_DEBUG_PACKET
)
1746 "RIPng %s/%d is filtered by route-map out",
1747 inet6_ntoa(p
->prefix
),
1752 aggregate
->metric_out
= newinfo
.metric_out
;
1753 aggregate
->tag_out
= newinfo
.tag_out
;
1754 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1755 aggregate
->nexthop_out
=
1756 newinfo
.nexthop_out
;
1759 /* There is no redistribute routemap for the aggregated
1762 /* Changed route only output. */
1763 /* XXX, vincent, in order to increase time convergence,
1764 * it should be announced if a child has changed.
1766 if (route_type
== ripng_changed_route
)
1769 /* Apply offset-list */
1770 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1771 ripng_offset_list_apply_out(
1772 p
, ifp
, &aggregate
->metric_out
);
1774 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1775 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1777 /* Add RTE to the list */
1778 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1782 /* Flush the list */
1783 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1784 ripng_rte_free(ripng_rte_list
);
1787 /* Create new RIPng instance and set it to global variable. */
1788 static int ripng_create(void)
1790 /* ripng should be NULL. */
1791 assert(ripng
== NULL
);
1793 /* Allocaste RIPng instance. */
1794 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1796 /* Default version and timer values. */
1797 ripng
->version
= RIPNG_V1
;
1798 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1799 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1800 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1801 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1804 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1805 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1807 /* Initialize RIPng routig table. */
1808 ripng
->table
= route_table_init();
1809 ripng
->route
= route_table_init();
1810 ripng
->aggregate
= route_table_init();
1813 ripng
->sock
= ripng_make_socket();
1814 if (ripng
->sock
< 0)
1818 ripng_event(RIPNG_READ
, ripng
->sock
);
1819 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1824 /* Send RIPng request to the interface. */
1825 int ripng_request(struct interface
*ifp
)
1828 struct ripng_packet ripng_packet
;
1830 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1832 if (if_is_loopback(ifp
))
1835 /* If interface is down, don't send RIP packet. */
1839 if (IS_RIPNG_DEBUG_EVENT
)
1840 zlog_debug("RIPng send request to %s", ifp
->name
);
1842 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1843 ripng_packet
.command
= RIPNG_REQUEST
;
1844 ripng_packet
.version
= RIPNG_V1
;
1845 rte
= ripng_packet
.rte
;
1846 rte
->metric
= RIPNG_METRIC_INFINITY
;
1848 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1853 static int ripng_update_jitter(int time
)
1855 return ((random() % (time
+ 1)) - (time
/ 2));
1858 void ripng_event(enum ripng_event event
, int sock
)
1864 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1866 case RIPNG_UPDATE_EVENT
:
1867 if (ripng
->t_update
) {
1868 thread_cancel(ripng
->t_update
);
1869 ripng
->t_update
= NULL
;
1871 /* Update timer jitter. */
1872 jitter
= ripng_update_jitter(ripng
->update_time
);
1874 ripng
->t_update
= NULL
;
1875 thread_add_timer(master
, ripng_update
, NULL
,
1876 sock
? 2 : ripng
->update_time
+ jitter
,
1879 case RIPNG_TRIGGERED_UPDATE
:
1880 if (ripng
->t_triggered_interval
)
1883 thread_add_event(master
, ripng_triggered_update
, NULL
,
1884 0, &ripng
->t_triggered_update
);
1892 /* Print out routes update time. */
1893 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1898 char timebuf
[TIME_BUF
];
1899 struct thread
*thread
;
1901 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1902 clock
= thread_timer_remain_second(thread
);
1903 tm
= gmtime(&clock
);
1904 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1905 vty_out(vty
, "%5s", timebuf
);
1906 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1907 clock
= thread_timer_remain_second(thread
);
1908 tm
= gmtime(&clock
);
1909 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1910 vty_out(vty
, "%5s", timebuf
);
1914 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1919 if (rinfo
->suppress
)
1922 switch (rinfo
->sub_type
) {
1923 case RIPNG_ROUTE_RTE
:
1926 case RIPNG_ROUTE_STATIC
:
1929 case RIPNG_ROUTE_DEFAULT
:
1932 case RIPNG_ROUTE_REDISTRIBUTE
:
1935 case RIPNG_ROUTE_INTERFACE
:
1946 DEFUN (show_ipv6_ripng
,
1947 show_ipv6_ripng_cmd
,
1951 "Show RIPng routes\n")
1953 struct route_node
*rp
;
1954 struct ripng_info
*rinfo
;
1955 struct ripng_aggregate
*aggregate
;
1956 struct prefix_ipv6
*p
;
1957 struct list
*list
= NULL
;
1958 struct listnode
*listnode
= NULL
;
1964 /* Header of display. */
1966 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1968 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1969 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1970 " Network Next Hop Via Metric Tag Time\n");
1972 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1973 if ((aggregate
= rp
->aggregate
) != NULL
) {
1974 p
= (struct prefix_ipv6
*)&rp
->p
;
1977 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1978 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1981 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1985 vty_out(vty
, "%*s", 18, " ");
1987 vty_out(vty
, "%*s", 28, " ");
1988 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1989 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1992 if ((list
= rp
->info
) != NULL
)
1993 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1994 p
= (struct prefix_ipv6
*)&rp
->p
;
1997 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1998 zebra_route_char(rinfo
->type
),
1999 ripng_route_subtype_print(rinfo
),
2000 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2003 vty_out(vty
, "%c(%s) %s/%d ",
2004 zebra_route_char(rinfo
->type
),
2005 ripng_route_subtype_print(rinfo
),
2006 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2009 vty_out(vty
, "%*s", 18, " ");
2010 len
= vty_out(vty
, "%s",
2011 inet6_ntoa(rinfo
->nexthop
));
2015 vty_out(vty
, "%*s", len
, " ");
2018 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2019 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2022 ifindex2ifname(rinfo
->ifindex
,
2024 } else if (rinfo
->metric
2025 == RIPNG_METRIC_INFINITY
) {
2026 len
= vty_out(vty
, "kill");
2028 len
= vty_out(vty
, "self");
2032 vty_out(vty
, "%*s", len
, " ");
2034 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2035 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2038 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2039 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2040 /* RTE from remote RIP routers */
2041 ripng_vty_out_uptime(vty
, rinfo
);
2042 } else if (rinfo
->metric
2043 == RIPNG_METRIC_INFINITY
) {
2044 /* poisonous reversed routes (gc) */
2045 ripng_vty_out_uptime(vty
, rinfo
);
2055 DEFUN (show_ipv6_ripng_status
,
2056 show_ipv6_ripng_status_cmd
,
2057 "show ipv6 ripng status",
2060 "Show RIPng routes\n"
2061 "IPv6 routing protocol process parameters and statistics\n")
2063 struct listnode
*node
;
2064 struct interface
*ifp
;
2069 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2070 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2071 ripng
->update_time
);
2072 vty_out(vty
, " next due in %lu seconds\n",
2073 thread_timer_remain_second(ripng
->t_update
));
2074 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2075 vty_out(vty
, " garbage collect after %ld seconds\n",
2076 ripng
->garbage_time
);
2078 /* Filtering status show. */
2079 config_show_distribute(vty
);
2081 /* Default metric information. */
2082 vty_out(vty
, " Default redistribution metric is %d\n",
2083 ripng
->default_metric
);
2085 /* Redistribute information. */
2086 vty_out(vty
, " Redistributing:");
2087 ripng_redistribute_write(vty
, 0);
2090 vty_out(vty
, " Default version control: send version %d,",
2092 vty_out(vty
, " receive version %d \n", ripng
->version
);
2094 vty_out(vty
, " Interface Send Recv\n");
2096 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
2097 struct ripng_interface
*ri
;
2101 if (ri
->enable_network
|| ri
->enable_interface
) {
2103 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2104 ripng
->version
, ripng
->version
);
2108 vty_out(vty
, " Routing for Networks:\n");
2109 ripng_network_write(vty
, 0);
2111 vty_out(vty
, " Routing Information Sources:\n");
2113 " Gateway BadPackets BadRoutes Distance Last Update\n");
2114 ripng_peer_display(vty
);
2119 DEFUN (clear_ipv6_rip
,
2124 "Clear IPv6 RIP database\n")
2126 struct route_node
*rp
;
2127 struct ripng_info
*rinfo
;
2129 struct listnode
*listnode
;
2131 /* Clear received RIPng routes */
2132 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2137 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2138 if (!ripng_route_rte(rinfo
))
2141 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2142 ripng_zebra_ipv6_delete(rp
);
2147 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2148 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2149 listnode_delete(list
, rinfo
);
2150 ripng_info_free(rinfo
);
2153 if (list_isempty(list
)) {
2154 list_delete_and_null(&list
);
2156 route_unlock_node(rp
);
2163 DEFUN_NOSH (router_ripng
,
2166 "Enable a routing process\n"
2167 "Make RIPng instance command\n")
2171 vty
->node
= RIPNG_NODE
;
2174 ret
= ripng_create();
2176 /* Notice to user we couldn't create RIPng. */
2178 zlog_warn("can't create RIPng");
2179 return CMD_WARNING_CONFIG_FAILED
;
2186 DEFUN (no_router_ripng
,
2187 no_router_ripng_cmd
,
2190 "Enable a routing process\n"
2191 "Make RIPng instance command\n")
2201 "Static route setup\n"
2202 "Set static RIPng route announcement\n")
2204 int idx_ipv6addr
= 1;
2206 struct prefix_ipv6 p
;
2207 struct route_node
*rp
;
2209 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2210 (struct prefix_ipv6
*)&p
);
2212 vty_out(vty
, "Malformed address\n");
2213 return CMD_WARNING_CONFIG_FAILED
;
2215 apply_mask_ipv6(&p
);
2217 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2219 vty_out(vty
, "There is already same static route.\n");
2220 route_unlock_node(rp
);
2223 rp
->info
= (void *)1;
2225 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2231 DEFUN (no_ripng_route
,
2233 "no route IPV6ADDR",
2235 "Static route setup\n"
2236 "Delete static RIPng route announcement\n")
2238 int idx_ipv6addr
= 2;
2240 struct prefix_ipv6 p
;
2241 struct route_node
*rp
;
2243 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2244 (struct prefix_ipv6
*)&p
);
2246 vty_out(vty
, "Malformed address\n");
2247 return CMD_WARNING_CONFIG_FAILED
;
2249 apply_mask_ipv6(&p
);
2251 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2253 vty_out(vty
, "Can't find static route.\n");
2254 return CMD_WARNING_CONFIG_FAILED
;
2257 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2258 route_unlock_node(rp
);
2261 route_unlock_node(rp
);
2266 DEFUN (ripng_aggregate_address
,
2267 ripng_aggregate_address_cmd
,
2268 "aggregate-address X:X::X:X/M",
2269 "Set aggregate RIPng route announcement\n"
2270 "Aggregate network\n")
2272 int idx_ipv6_prefixlen
= 1;
2275 struct route_node
*node
;
2277 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2278 (struct prefix_ipv6
*)&p
);
2280 vty_out(vty
, "Malformed address\n");
2281 return CMD_WARNING_CONFIG_FAILED
;
2284 /* Check aggregate alredy exist or not. */
2285 node
= route_node_get(ripng
->aggregate
, &p
);
2287 vty_out(vty
, "There is already same aggregate route.\n");
2288 route_unlock_node(node
);
2291 node
->info
= (void *)1;
2293 ripng_aggregate_add(&p
);
2298 DEFUN (no_ripng_aggregate_address
,
2299 no_ripng_aggregate_address_cmd
,
2300 "no aggregate-address X:X::X:X/M",
2302 "Delete aggregate RIPng route announcement\n"
2303 "Aggregate network\n")
2305 int idx_ipv6_prefixlen
= 2;
2308 struct route_node
*rn
;
2310 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2311 (struct prefix_ipv6
*)&p
);
2313 vty_out(vty
, "Malformed address\n");
2314 return CMD_WARNING_CONFIG_FAILED
;
2317 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2319 vty_out(vty
, "Can't find aggregate route.\n");
2320 return CMD_WARNING_CONFIG_FAILED
;
2322 route_unlock_node(rn
);
2324 route_unlock_node(rn
);
2326 ripng_aggregate_delete(&p
);
2331 DEFUN (ripng_default_metric
,
2332 ripng_default_metric_cmd
,
2333 "default-metric (1-16)",
2334 "Set a metric of redistribute routes\n"
2339 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2344 DEFUN (no_ripng_default_metric
,
2345 no_ripng_default_metric_cmd
,
2346 "no default-metric [(1-16)]",
2348 "Set a metric of redistribute routes\n"
2352 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2359 /* RIPng update timer setup. */
2360 DEFUN (ripng_update_timer
,
2361 ripng_update_timer_cmd
,
2362 "update-timer SECOND",
2363 "Set RIPng update timer in seconds\n"
2366 unsigned long update
;
2367 char *endptr
= NULL
;
2369 update
= strtoul (argv
[0], &endptr
, 10);
2370 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2372 vty_out (vty
, "update timer value error\n");
2373 return CMD_WARNING_CONFIG_FAILED
;
2376 ripng
->update_time
= update
;
2378 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2382 DEFUN (no_ripng_update_timer
,
2383 no_ripng_update_timer_cmd
,
2384 "no update-timer SECOND",
2386 "Unset RIPng update timer in seconds\n"
2389 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2390 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2394 /* RIPng timeout timer setup. */
2395 DEFUN (ripng_timeout_timer
,
2396 ripng_timeout_timer_cmd
,
2397 "timeout-timer SECOND",
2398 "Set RIPng timeout timer in seconds\n"
2401 unsigned long timeout
;
2402 char *endptr
= NULL
;
2404 timeout
= strtoul (argv
[0], &endptr
, 10);
2405 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2407 vty_out (vty
, "timeout timer value error\n");
2408 return CMD_WARNING_CONFIG_FAILED
;
2411 ripng
->timeout_time
= timeout
;
2416 DEFUN (no_ripng_timeout_timer
,
2417 no_ripng_timeout_timer_cmd
,
2418 "no timeout-timer SECOND",
2420 "Unset RIPng timeout timer in seconds\n"
2423 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2427 /* RIPng garbage timer setup. */
2428 DEFUN (ripng_garbage_timer
,
2429 ripng_garbage_timer_cmd
,
2430 "garbage-timer SECOND",
2431 "Set RIPng garbage timer in seconds\n"
2434 unsigned long garbage
;
2435 char *endptr
= NULL
;
2437 garbage
= strtoul (argv
[0], &endptr
, 10);
2438 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2440 vty_out (vty
, "garbage timer value error\n");
2441 return CMD_WARNING_CONFIG_FAILED
;
2444 ripng
->garbage_time
= garbage
;
2449 DEFUN (no_ripng_garbage_timer
,
2450 no_ripng_garbage_timer_cmd
,
2451 "no garbage-timer SECOND",
2453 "Unset RIPng garbage timer in seconds\n"
2456 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2461 DEFUN (ripng_timers
,
2463 "timers basic (0-65535) (0-65535) (0-65535)",
2464 "RIPng timers setup\n"
2466 "Routing table update timer value in second. Default is 30.\n"
2467 "Routing information timeout timer. Default is 180.\n"
2468 "Garbage collection timer. Default is 120.\n")
2471 int idx_number_2
= 3;
2472 int idx_number_3
= 4;
2473 unsigned long update
;
2474 unsigned long timeout
;
2475 unsigned long garbage
;
2477 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2478 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2479 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2481 /* Set each timer value. */
2482 ripng
->update_time
= update
;
2483 ripng
->timeout_time
= timeout
;
2484 ripng
->garbage_time
= garbage
;
2486 /* Reset update timer thread. */
2487 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2492 DEFUN (no_ripng_timers
,
2493 no_ripng_timers_cmd
,
2494 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2496 "RIPng timers setup\n"
2498 "Routing table update timer value in second. Default is 30.\n"
2499 "Routing information timeout timer. Default is 180.\n"
2500 "Garbage collection timer. Default is 120.\n")
2502 /* Set each timer value to the default. */
2503 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2504 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2505 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2507 /* Reset update timer thread. */
2508 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2514 DEFUN (show_ipv6_protocols
,
2515 show_ipv6_protocols_cmd
,
2516 "show ipv6 protocols",
2519 "Routing protocol information\n")
2524 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2526 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2527 ripng
->update_time
, 0);
2529 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2530 ripng
->timeout_time
,
2531 ripng
->garbage_time
);
2533 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2534 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2540 /* Please be carefull to use this command. */
2541 DEFUN (ripng_default_information_originate
,
2542 ripng_default_information_originate_cmd
,
2543 "default-information originate",
2544 "Default route information\n"
2545 "Distribute default route\n")
2547 struct prefix_ipv6 p
;
2549 if (!ripng
->default_information
) {
2550 ripng
->default_information
= 1;
2552 str2prefix_ipv6("::/0", &p
);
2553 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2560 DEFUN (no_ripng_default_information_originate
,
2561 no_ripng_default_information_originate_cmd
,
2562 "no default-information originate",
2564 "Default route information\n"
2565 "Distribute default route\n")
2567 struct prefix_ipv6 p
;
2569 if (ripng
->default_information
) {
2570 ripng
->default_information
= 0;
2572 str2prefix_ipv6("::/0", &p
);
2573 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2574 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2580 /* Update ECMP routes to zebra when ECMP is disabled. */
2581 static void ripng_ecmp_disable(void)
2583 struct route_node
*rp
;
2584 struct ripng_info
*rinfo
, *tmp_rinfo
;
2586 struct listnode
*node
, *nextnode
;
2591 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2592 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2593 rinfo
= listgetdata(listhead(list
));
2594 if (!ripng_route_rte(rinfo
))
2597 /* Drop all other entries, except the first one. */
2598 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2599 if (tmp_rinfo
!= rinfo
) {
2600 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2602 tmp_rinfo
->t_garbage_collect
);
2603 list_delete_node(list
, node
);
2604 ripng_info_free(tmp_rinfo
);
2608 ripng_zebra_ipv6_add(rp
);
2610 /* Set the route change flag. */
2611 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2613 /* Signal the output process to trigger an update. */
2614 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2618 DEFUN (ripng_allow_ecmp
,
2619 ripng_allow_ecmp_cmd
,
2621 "Allow Equal Cost MultiPath\n")
2624 vty_out(vty
, "ECMP is already enabled.\n");
2629 zlog_info("ECMP is enabled.");
2633 DEFUN (no_ripng_allow_ecmp
,
2634 no_ripng_allow_ecmp_cmd
,
2637 "Allow Equal Cost MultiPath\n")
2640 vty_out(vty
, "ECMP is already disabled.\n");
2645 zlog_info("ECMP is disabled.");
2646 ripng_ecmp_disable();
2650 /* RIPng configuration write function. */
2651 static int ripng_config_write(struct vty
*vty
)
2653 int ripng_network_write(struct vty
*, int);
2654 void ripng_redistribute_write(struct vty
*, int);
2656 struct route_node
*rp
;
2661 vty_out(vty
, "router ripng\n");
2663 if (ripng
->default_information
)
2664 vty_out(vty
, " default-information originate\n");
2666 ripng_network_write(vty
, 1);
2668 /* RIPng default metric configuration */
2669 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2670 vty_out(vty
, " default-metric %d\n",
2671 ripng
->default_metric
);
2673 ripng_redistribute_write(vty
, 1);
2675 /* RIP offset-list configuration. */
2676 config_write_ripng_offset_list(vty
);
2678 /* RIPng aggregate routes. */
2679 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2680 if (rp
->info
!= NULL
)
2681 vty_out(vty
, " aggregate-address %s/%d\n",
2682 inet6_ntoa(rp
->p
.u
.prefix6
),
2685 /* ECMP configuration. */
2687 vty_out(vty
, " allow-ecmp\n");
2689 /* RIPng static routes. */
2690 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2691 if (rp
->info
!= NULL
)
2692 vty_out(vty
, " route %s/%d\n",
2693 inet6_ntoa(rp
->p
.u
.prefix6
),
2696 /* RIPng timers configuration. */
2697 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2698 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2699 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2700 vty_out(vty
, " timers basic %ld %ld %ld\n",
2701 ripng
->update_time
, ripng
->timeout_time
,
2702 ripng
->garbage_time
);
2705 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2706 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2707 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2708 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2709 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2710 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2713 write
+= config_write_distribute(vty
);
2715 write
+= config_write_if_rmap(vty
);
2722 /* RIPng node structure. */
2723 static struct cmd_node cmd_ripng_node
= {
2724 RIPNG_NODE
, "%s(config-router)# ", 1,
2727 static void ripng_distribute_update(struct distribute
*dist
)
2729 struct interface
*ifp
;
2730 struct ripng_interface
*ri
;
2731 struct access_list
*alist
;
2732 struct prefix_list
*plist
;
2737 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2743 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2744 alist
= access_list_lookup(AFI_IP6
,
2745 dist
->list
[DISTRIBUTE_V6_IN
]);
2747 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2749 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2751 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2753 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2754 alist
= access_list_lookup(AFI_IP6
,
2755 dist
->list
[DISTRIBUTE_V6_OUT
]);
2757 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2759 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2761 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2763 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2764 plist
= prefix_list_lookup(AFI_IP6
,
2765 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2767 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2769 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2771 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2773 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2774 plist
= prefix_list_lookup(AFI_IP6
,
2775 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2777 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2779 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2781 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2784 void ripng_distribute_update_interface(struct interface
*ifp
)
2786 struct distribute
*dist
;
2788 dist
= distribute_lookup(ifp
->name
);
2790 ripng_distribute_update(dist
);
2793 /* Update all interface's distribute list. */
2794 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2796 struct interface
*ifp
;
2797 struct listnode
*node
;
2799 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2800 ripng_distribute_update_interface(ifp
);
2803 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2805 ripng_distribute_update_all(NULL
);
2808 /* delete all the added ripng routes. */
2812 struct route_node
*rp
;
2813 struct ripng_info
*rinfo
;
2814 struct ripng_aggregate
*aggregate
;
2815 struct list
*list
= NULL
;
2816 struct listnode
*listnode
= NULL
;
2819 /* Clear RIPng routes */
2820 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2821 if ((list
= rp
->info
) != NULL
) {
2822 rinfo
= listgetdata(listhead(list
));
2823 if (ripng_route_rte(rinfo
))
2824 ripng_zebra_ipv6_delete(rp
);
2826 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2828 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2830 rinfo
->t_garbage_collect
);
2831 ripng_info_free(rinfo
);
2833 list_delete_and_null(&list
);
2835 route_unlock_node(rp
);
2838 if ((aggregate
= rp
->aggregate
) != NULL
) {
2839 ripng_aggregate_free(aggregate
);
2840 rp
->aggregate
= NULL
;
2841 route_unlock_node(rp
);
2845 /* Cancel the RIPng timers */
2846 RIPNG_TIMER_OFF(ripng
->t_update
);
2847 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2848 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2850 /* Cancel the read thread */
2851 if (ripng
->t_read
) {
2852 thread_cancel(ripng
->t_read
);
2853 ripng
->t_read
= NULL
;
2856 /* Close the RIPng socket */
2857 if (ripng
->sock
>= 0) {
2862 /* Static RIPng route configuration. */
2863 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2866 route_unlock_node(rp
);
2869 /* RIPng aggregated prefixes */
2870 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2873 route_unlock_node(rp
);
2876 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2877 if (ripng
->route_map
[i
].name
)
2878 free(ripng
->route_map
[i
].name
);
2880 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2881 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2882 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2884 stream_free(ripng
->ibuf
);
2885 stream_free(ripng
->obuf
);
2887 XFREE(MTYPE_RIPNG
, ripng
);
2891 ripng_clean_network();
2892 ripng_passive_interface_clean();
2893 ripng_offset_clean();
2894 ripng_interface_clean();
2895 ripng_redistribute_clean();
2898 /* Reset all values to the default settings. */
2901 /* Call ripd related reset functions. */
2902 ripng_debug_reset();
2903 ripng_route_map_reset();
2905 /* Call library reset functions. */
2907 access_list_reset();
2908 prefix_list_reset();
2910 distribute_list_reset();
2912 ripng_interface_reset();
2914 ripng_zclient_reset();
2917 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2919 struct interface
*ifp
;
2920 struct ripng_interface
*ri
;
2921 struct route_map
*rmap
;
2923 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2929 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2930 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2932 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2934 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2936 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2938 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2939 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2941 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2943 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2945 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2948 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2950 struct if_rmap
*if_rmap
;
2952 if_rmap
= if_rmap_lookup(ifp
->name
);
2954 ripng_if_rmap_update(if_rmap
);
2957 static void ripng_routemap_update_redistribute(void)
2962 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2963 if (ripng
->route_map
[i
].name
)
2964 ripng
->route_map
[i
].map
=
2965 route_map_lookup_by_name(
2966 ripng
->route_map
[i
].name
);
2971 static void ripng_routemap_update(const char *unused
)
2973 struct interface
*ifp
;
2974 struct listnode
*node
;
2976 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2977 ripng_if_rmap_update_interface(ifp
);
2979 ripng_routemap_update_redistribute();
2982 /* Initialize ripng structure and set commands. */
2985 /* Install RIPNG_NODE. */
2986 install_node(&cmd_ripng_node
, ripng_config_write
);
2988 /* Install ripng commands. */
2989 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2990 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2992 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2994 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2995 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
2997 install_default(RIPNG_NODE
);
2998 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2999 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
3000 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3001 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3003 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3004 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3006 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3007 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3009 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3010 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3011 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3012 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3013 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3014 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3015 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3018 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3019 install_element(RIPNG_NODE
,
3020 &no_ripng_default_information_originate_cmd
);
3022 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3023 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3028 /* Access list install. */
3030 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3031 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3033 /* Prefix list initialize.*/
3035 prefix_list_add_hook(ripng_distribute_update_all
);
3036 prefix_list_delete_hook(ripng_distribute_update_all
);
3038 /* Distribute list install. */
3039 distribute_list_init(RIPNG_NODE
);
3040 distribute_list_add_hook(ripng_distribute_update
);
3041 distribute_list_delete_hook(ripng_distribute_update
);
3043 /* Route-map for interface. */
3044 ripng_route_map_init();
3045 ripng_offset_init();
3047 route_map_add_hook(ripng_routemap_update
);
3048 route_map_delete_hook(ripng_routemap_update
);
3050 if_rmap_init(RIPNG_NODE
);
3051 if_rmap_hook_add(ripng_if_rmap_update
);
3052 if_rmap_hook_delete(ripng_if_rmap_update
);