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
,
54 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
56 int ripng_triggered_update(struct thread
*);
58 /* RIPng next hop specification. */
59 struct ripng_nexthop
{
60 enum ripng_nexthop_type
{
64 struct in6_addr address
;
67 static int ripng_route_rte(struct ripng_info
*rinfo
)
69 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
70 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
73 /* Allocate new ripng information. */
74 struct ripng_info
*ripng_info_new()
76 struct ripng_info
*new;
78 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
82 /* Free ripng information. */
83 void ripng_info_free(struct ripng_info
*rinfo
)
85 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
88 /* Create ripng socket. */
89 static int ripng_make_socket(void)
93 struct sockaddr_in6 ripaddr
;
95 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
97 zlog_err("Can't make ripng socket");
101 setsockopt_so_recvbuf(sock
, 8096);
102 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
105 #ifdef IPTOS_PREC_INTERNETCONTROL
106 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
110 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
113 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
116 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
120 memset(&ripaddr
, 0, sizeof(ripaddr
));
121 ripaddr
.sin6_family
= AF_INET6
;
123 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
124 #endif /* SIN6_LEN */
125 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
127 if (ripngd_privs
.change(ZPRIVS_RAISE
))
128 zlog_err("ripng_make_socket: could not raise privs");
130 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
132 zlog_err("Can't bind ripng socket: %s.", safe_strerror(errno
));
133 if (ripngd_privs
.change(ZPRIVS_LOWER
))
134 zlog_err("ripng_make_socket: could not lower privs");
137 if (ripngd_privs
.change(ZPRIVS_LOWER
))
138 zlog_err("ripng_make_socket: could not lower privs");
146 /* Send RIPng packet. */
147 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
148 struct interface
*ifp
)
153 struct cmsghdr
*cmsgptr
;
155 struct in6_pktinfo
*pkt
;
156 struct sockaddr_in6 addr
;
158 if (IS_RIPNG_DEBUG_SEND
) {
160 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
161 zlog_debug(" send interface %s", ifp
->name
);
162 zlog_debug(" send packet size %d", bufsize
);
165 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
166 addr
.sin6_family
= AF_INET6
;
168 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
169 #endif /* SIN6_LEN */
170 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
172 /* When destination is specified. */
174 addr
.sin6_addr
= to
->sin6_addr
;
175 addr
.sin6_port
= to
->sin6_port
;
177 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
178 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
181 memset(&msg
, 0, sizeof(msg
));
182 msg
.msg_name
= (void *)&addr
;
183 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
186 msg
.msg_control
= (void *)adata
;
187 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
190 iov
.iov_len
= bufsize
;
192 cmsgptr
= (struct cmsghdr
*)adata
;
193 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
194 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
195 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
197 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
198 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
199 pkt
->ipi6_ifindex
= ifp
->ifindex
;
201 ret
= sendmsg(ripng
->sock
, &msg
, 0);
205 zlog_err("RIPng send fail on %s to %s: %s", ifp
->name
,
206 inet6_ntoa(to
->sin6_addr
),
207 safe_strerror(errno
));
209 zlog_err("RIPng send fail on %s: %s", ifp
->name
,
210 safe_strerror(errno
));
216 /* Receive UDP RIPng packet from socket. */
217 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
218 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
224 struct cmsghdr
*cmsgptr
;
225 struct in6_addr dst
= {.s6_addr
= {0}};
227 memset(&dst
, 0, sizeof(struct in6_addr
));
229 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
230 point I can't determine size of cmsghdr */
233 /* Fill in message and iovec. */
234 memset(&msg
, 0, sizeof(msg
));
235 msg
.msg_name
= (void *)from
;
236 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
239 msg
.msg_control
= (void *)adata
;
240 msg
.msg_controllen
= sizeof adata
;
242 iov
.iov_len
= bufsize
;
244 /* If recvmsg fail return minus value. */
245 ret
= recvmsg(sock
, &msg
, 0);
249 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
250 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
251 /* I want interface index which this packet comes from. */
252 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
253 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
254 struct in6_pktinfo
*ptr
;
256 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
257 *ifindex
= ptr
->ipi6_ifindex
;
258 dst
= ptr
->ipi6_addr
;
262 "Interface index returned by IPV6_PKTINFO is zero");
265 /* Incoming packet's multicast hop limit. */
266 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
267 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
268 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
269 *hoplimit
= *phoplimit
;
273 /* Hoplimit check shold be done when destination address is
274 multicast address. */
275 if (!IN6_IS_ADDR_MULTICAST(&dst
))
281 /* Dump rip packet */
282 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
287 const char *command_str
;
289 /* Set command string. */
290 if (packet
->command
== RIPNG_REQUEST
)
291 command_str
= "request";
292 else if (packet
->command
== RIPNG_RESPONSE
)
293 command_str
= "response";
295 command_str
= "unknown";
297 /* Dump packet header. */
298 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
299 packet
->version
, size
);
301 /* Dump each routing table entry. */
304 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
305 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
306 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
309 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
310 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
311 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
315 /* RIPng next hop address RTE (Route Table Entry). */
316 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
317 struct ripng_nexthop
*nexthop
)
319 char buf
[INET6_BUFSIZ
];
321 /* Logging before checking RTE. */
322 if (IS_RIPNG_DEBUG_RECV
)
323 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
325 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
328 /* RFC2080 2.1.1 Next Hop:
329 The route tag and prefix length in the next hop RTE must be
330 set to zero on sending and ignored on receiption. */
331 if (ntohs(rte
->tag
) != 0)
333 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
335 (route_tag_t
)ntohs(rte
->tag
),
336 inet6_ntoa(from
->sin6_addr
));
338 if (rte
->prefixlen
!= 0)
340 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
341 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
343 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
344 next hop RTE indicates that the next hop address should be the
345 originator of the RIPng advertisement. An address specified as a
346 next hop must be a link-local address. */
347 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
348 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
349 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
353 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
354 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
355 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
359 /* The purpose of the next hop RTE is to eliminate packets being
360 routed through extra hops in the system. It is particularly useful
361 when RIPng is not being run on all of the routers on a network.
362 Note that next hop RTE is "advisory". That is, if the provided
363 information is ignored, a possibly sub-optimal, but absolutely
364 valid, route may be taken. If the received next hop address is not
365 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
366 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
367 inet6_ntoa(rte
->addr
),
368 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
370 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
371 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
376 /* If ifp has same link-local address then return 1. */
377 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
379 struct listnode
*node
;
380 struct connected
*connected
;
383 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
384 p
= connected
->address
;
386 if (p
->family
== AF_INET6
387 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
388 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
394 /* RIPng route garbage collect timer. */
395 static int ripng_garbage_collect(struct thread
*t
)
397 struct ripng_info
*rinfo
;
398 struct route_node
*rp
;
400 rinfo
= THREAD_ARG(t
);
401 rinfo
->t_garbage_collect
= NULL
;
403 /* Off timeout timer. */
404 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
406 /* Get route_node pointer. */
409 /* Unlock route_node. */
410 listnode_delete(rp
->info
, rinfo
);
411 if (list_isempty((struct list
*)rp
->info
)) {
412 list_delete_and_null((struct list
**)&rp
->info
);
413 route_unlock_node(rp
);
416 /* Free RIPng routing information. */
417 ripng_info_free(rinfo
);
422 static void ripng_timeout_update(struct ripng_info
*rinfo
);
424 /* Add new route to the ECMP list.
425 * RETURN: the new entry added in the list, or NULL if it is not the first
426 * entry and ECMP is not allowed.
428 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
430 struct route_node
*rp
= rinfo_new
->rp
;
431 struct ripng_info
*rinfo
= NULL
;
432 struct list
*list
= NULL
;
434 if (rp
->info
== NULL
)
435 rp
->info
= list_new();
436 list
= (struct list
*)rp
->info
;
438 /* If ECMP is not allowed and some entry already exists in the list,
440 if (listcount(list
) && !ripng
->ecmp
)
443 rinfo
= ripng_info_new();
444 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
445 listnode_add(list
, rinfo
);
447 if (ripng_route_rte(rinfo
)) {
448 ripng_timeout_update(rinfo
);
449 ripng_zebra_ipv6_add(rp
);
452 ripng_aggregate_increment(rp
, rinfo
);
454 /* Set the route change flag on the first entry. */
455 rinfo
= listgetdata(listhead(list
));
456 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
458 /* Signal the output process to trigger an update. */
459 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
464 /* Replace the ECMP list with the new route.
465 * RETURN: the new entry added in the list
467 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
469 struct route_node
*rp
= rinfo_new
->rp
;
470 struct list
*list
= (struct list
*)rp
->info
;
471 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
472 struct listnode
*node
= NULL
, *nextnode
= NULL
;
474 if (list
== NULL
|| listcount(list
) == 0)
475 return ripng_ecmp_add(rinfo_new
);
477 /* Get the first entry */
478 rinfo
= listgetdata(listhead(list
));
480 /* Learnt route replaced by a local one. Delete it from zebra. */
481 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
482 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
483 ripng_zebra_ipv6_delete(rp
);
485 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
486 ripng_aggregate_decrement_list(rp
, list
);
488 /* Re-use the first entry, and delete the others. */
489 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
490 if (tmp_rinfo
!= rinfo
) {
491 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
492 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
493 list_delete_node(list
, node
);
494 ripng_info_free(tmp_rinfo
);
497 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
498 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
499 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
501 if (ripng_route_rte(rinfo
)) {
502 ripng_timeout_update(rinfo
);
503 /* The ADD message implies an update. */
504 ripng_zebra_ipv6_add(rp
);
507 ripng_aggregate_increment(rp
, rinfo
);
509 /* Set the route change flag. */
510 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
512 /* Signal the output process to trigger an update. */
513 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
518 /* Delete one route from the ECMP list.
520 * null - the entry is freed, and other entries exist in the list
521 * the entry - the entry is the last one in the list; its metric is set
522 * to INFINITY, and the garbage collector is started for it
524 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
526 struct route_node
*rp
= rinfo
->rp
;
527 struct list
*list
= (struct list
*)rp
->info
;
529 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
531 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
532 ripng_aggregate_decrement(rp
, rinfo
);
534 if (listcount(list
) > 1) {
535 /* Some other ECMP entries still exist. Just delete this entry.
537 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
538 listnode_delete(list
, rinfo
);
539 if (ripng_route_rte(rinfo
)
540 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
541 /* The ADD message implies the update. */
542 ripng_zebra_ipv6_add(rp
);
543 ripng_info_free(rinfo
);
546 assert(rinfo
== listgetdata(listhead(list
)));
548 /* This is the only entry left in the list. We must keep it in
549 * the list for garbage collection time, with INFINITY metric.
552 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
553 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
554 ripng
->garbage_time
);
556 if (ripng_route_rte(rinfo
)
557 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
558 ripng_zebra_ipv6_delete(rp
);
561 /* Set the route change flag on the first entry. */
562 rinfo
= listgetdata(listhead(list
));
563 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
565 /* Signal the output process to trigger an update. */
566 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
571 /* Timeout RIPng routes. */
572 static int ripng_timeout(struct thread
*t
)
574 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
578 static void ripng_timeout_update(struct ripng_info
*rinfo
)
580 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
581 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
582 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
583 ripng
->timeout_time
);
587 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
588 struct ripng_interface
*ri
)
590 struct distribute
*dist
;
591 struct access_list
*alist
;
592 struct prefix_list
*plist
;
593 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
596 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
598 /* Input distribute-list filtering. */
599 if (ri
->list
[ripng_distribute
]) {
600 if (access_list_apply(ri
->list
[ripng_distribute
],
603 if (IS_RIPNG_DEBUG_PACKET
)
604 zlog_debug("%s/%d filtered by distribute %s",
605 inet6_ntoa(p
->prefix
), p
->prefixlen
,
610 if (ri
->prefix
[ripng_distribute
]) {
611 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
614 if (IS_RIPNG_DEBUG_PACKET
)
615 zlog_debug("%s/%d filtered by prefix-list %s",
616 inet6_ntoa(p
->prefix
), p
->prefixlen
,
622 /* All interface filter check. */
623 dist
= distribute_lookup(NULL
);
625 if (dist
->list
[distribute
]) {
626 alist
= access_list_lookup(AFI_IP6
,
627 dist
->list
[distribute
]);
630 if (access_list_apply(alist
, (struct prefix
*)p
)
632 if (IS_RIPNG_DEBUG_PACKET
)
634 "%s/%d filtered by distribute %s",
635 inet6_ntoa(p
->prefix
),
636 p
->prefixlen
, inout
);
641 if (dist
->prefix
[distribute
]) {
642 plist
= prefix_list_lookup(AFI_IP6
,
643 dist
->prefix
[distribute
]);
646 if (prefix_list_apply(plist
, (struct prefix
*)p
)
648 if (IS_RIPNG_DEBUG_PACKET
)
650 "%s/%d filtered by prefix-list %s",
651 inet6_ntoa(p
->prefix
),
652 p
->prefixlen
, inout
);
661 /* Process RIPng route according to RFC2080. */
662 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
663 struct ripng_nexthop
*ripng_nexthop
,
664 struct interface
*ifp
)
667 struct prefix_ipv6 p
;
668 struct route_node
*rp
;
669 struct ripng_info
*rinfo
= NULL
, newinfo
;
670 struct ripng_interface
*ri
;
671 struct in6_addr
*nexthop
;
673 struct list
*list
= NULL
;
674 struct listnode
*node
= NULL
;
676 /* Make prefix structure. */
677 memset(&p
, 0, sizeof(struct prefix_ipv6
));
679 /* p.prefix = rte->addr; */
680 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
681 p
.prefixlen
= rte
->prefixlen
;
683 /* Make sure mask is applied. */
684 /* XXX We have to check the prefix is valid or not before call
688 /* Apply input filters. */
691 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
695 memset(&newinfo
, 0, sizeof(newinfo
));
696 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
697 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
698 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
699 newinfo
.nexthop
= ripng_nexthop
->address
;
701 newinfo
.nexthop
= from
->sin6_addr
;
702 newinfo
.from
= from
->sin6_addr
;
703 newinfo
.ifindex
= ifp
->ifindex
;
704 newinfo
.metric
= rte
->metric
;
705 newinfo
.metric_out
= rte
->metric
; /* XXX */
706 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
709 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
712 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
713 (struct prefix
*)&p
, RMAP_RIPNG
,
716 if (ret
== RMAP_DENYMATCH
) {
717 if (IS_RIPNG_DEBUG_PACKET
)
719 "RIPng %s/%d is filtered by route-map in",
720 inet6_ntoa(p
.prefix
), p
.prefixlen
);
724 /* Get back the object */
725 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
726 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
727 &ripng_nexthop
->address
)) {
728 /* the nexthop get changed by the routemap */
729 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
730 ripng_nexthop
->address
=
733 ripng_nexthop
->address
= in6addr_any
;
736 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
738 /* the nexthop get changed by the routemap */
739 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
740 ripng_nexthop
->flag
=
741 RIPNG_NEXTHOP_ADDRESS
;
742 ripng_nexthop
->address
=
747 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
749 newinfo
.metric_out
; /* XXX: the routemap uses the
753 /* Once the entry has been validated, update the metric by
754 * adding the cost of the network on wich the message
755 * arrived. If the result is greater than infinity, use infinity
756 * (RFC2453 Sec. 3.9.2)
759 /* Zebra ripngd can handle offset-list in. */
760 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
762 /* If offset-list does not modify the metric use interface's
765 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
767 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
768 rte
->metric
= RIPNG_METRIC_INFINITY
;
770 /* Set nexthop pointer. */
771 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
772 nexthop
= &ripng_nexthop
->address
;
774 nexthop
= &from
->sin6_addr
;
776 /* Lookup RIPng routing table. */
777 rp
= route_node_get(ripng
->table
, (struct prefix
*)&p
);
780 newinfo
.nexthop
= *nexthop
;
781 newinfo
.metric
= rte
->metric
;
782 newinfo
.tag
= ntohs(rte
->tag
);
784 /* Check to see whether there is already RIPng route on the table. */
785 if ((list
= rp
->info
) != NULL
)
786 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
787 /* Need to compare with redistributed entry or local
789 if (!ripng_route_rte(rinfo
))
792 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
793 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
796 if (!listnextnode(node
)) {
797 /* Not found in the list */
799 if (rte
->metric
> rinfo
->metric
) {
800 /* New route has a greater metric.
802 route_unlock_node(rp
);
806 if (rte
->metric
< rinfo
->metric
)
807 /* New route has a smaller metric.
808 * Replace the ECMP list
809 * with the new one in below. */
812 /* Metrics are same. Unless ECMP is disabled,
813 * keep "rinfo" null and
814 * the new route is added in the ECMP list in
822 /* Redistributed route check. */
823 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
824 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
825 route_unlock_node(rp
);
829 /* Local static route. */
830 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
831 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
832 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
833 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
834 route_unlock_node(rp
);
840 /* Now, check to see whether there is already an explicit route
841 for the destination prefix. If there is no such route, add
842 this route to the routing table, unless the metric is
843 infinity (there is no point in adding a route which
845 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
846 ripng_ecmp_add(&newinfo
);
848 route_unlock_node(rp
);
850 /* If there is an existing route, compare the next hop address
851 to the address of the router from which the datagram came.
852 If this datagram is from the same router as the existing
853 route, reinitialize the timeout. */
854 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
855 && (rinfo
->ifindex
== ifp
->ifindex
));
858 * RFC 2080 - Section 2.4.2:
859 * "If the new metric is the same as the old one, examine the
861 * for the existing route. If it is at least halfway to the
863 * point, switch to the new route. This heuristic is optional,
865 * highly recommended".
867 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
869 && (thread_timer_remain_second(rinfo
->t_timeout
)
870 < (ripng
->timeout_time
/ 2))) {
871 ripng_ecmp_replace(&newinfo
);
873 /* Next, compare the metrics. If the datagram is from the same
874 router as the existing route, and the new metric is different
875 than the old one; or, if the new metric is lower than the old
876 one; do the following actions: */
877 else if ((same
&& rinfo
->metric
!= rte
->metric
)
878 || rte
->metric
< rinfo
->metric
) {
879 if (listcount(list
) == 1) {
880 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
881 ripng_ecmp_replace(&newinfo
);
883 ripng_ecmp_delete(rinfo
);
885 if (newinfo
.metric
< rinfo
->metric
)
886 ripng_ecmp_replace(&newinfo
);
887 else /* newinfo.metric > rinfo->metric */
888 ripng_ecmp_delete(rinfo
);
890 } else /* same & no change */
891 ripng_timeout_update(rinfo
);
893 /* Unlock tempolary lock of the route. */
894 route_unlock_node(rp
);
898 /* Add redistributed route to RIPng table. */
899 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
900 ifindex_t ifindex
, struct in6_addr
*nexthop
,
903 struct route_node
*rp
;
904 struct ripng_info
*rinfo
= NULL
, newinfo
;
905 struct list
*list
= NULL
;
907 /* Redistribute route */
908 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
910 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
913 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
915 memset(&newinfo
, 0, sizeof(struct ripng_info
));
917 newinfo
.sub_type
= sub_type
;
918 newinfo
.ifindex
= ifindex
;
920 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
923 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
924 newinfo
.nexthop
= *nexthop
;
926 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
927 rinfo
= listgetdata(listhead(list
));
929 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
930 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
931 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
932 route_unlock_node(rp
);
936 /* Manually configured RIPng route check.
937 * They have the precedence on all the other entries.
939 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
940 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
941 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
942 if (type
!= ZEBRA_ROUTE_RIPNG
943 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
944 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
945 route_unlock_node(rp
);
950 ripng_ecmp_replace(&newinfo
);
951 route_unlock_node(rp
);
953 ripng_ecmp_add(&newinfo
);
955 if (IS_RIPNG_DEBUG_EVENT
) {
958 "Redistribute new prefix %s/%d on the interface %s",
959 inet6_ntoa(p
->prefix
), p
->prefixlen
,
960 ifindex2ifname(ifindex
, VRF_DEFAULT
));
963 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
964 inet6_ntoa(p
->prefix
), p
->prefixlen
,
965 inet6_ntoa(*nexthop
),
966 ifindex2ifname(ifindex
, VRF_DEFAULT
));
969 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
972 /* Delete redistributed route to RIPng table. */
973 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
976 struct route_node
*rp
;
977 struct ripng_info
*rinfo
;
979 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
981 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
984 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
987 struct list
*list
= rp
->info
;
989 if (list
!= NULL
&& listcount(list
) != 0) {
990 rinfo
= listgetdata(listhead(list
));
991 if (rinfo
!= NULL
&& rinfo
->type
== type
992 && rinfo
->sub_type
== sub_type
993 && rinfo
->ifindex
== ifindex
) {
994 /* Perform poisoned reverse. */
995 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
996 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
997 ripng_garbage_collect
,
998 ripng
->garbage_time
);
999 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1001 /* Aggregate count decrement. */
1002 ripng_aggregate_decrement(rp
, rinfo
);
1004 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1006 if (IS_RIPNG_DEBUG_EVENT
)
1008 "Poisone %s/%d on the interface %s with an "
1009 "infinity metric [delete]",
1010 inet6_ntoa(p
->prefix
),
1012 ifindex2ifname(ifindex
,
1015 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1018 route_unlock_node(rp
);
1022 /* Withdraw redistributed route. */
1023 void ripng_redistribute_withdraw(int type
)
1025 struct route_node
*rp
;
1026 struct ripng_info
*rinfo
= NULL
;
1027 struct list
*list
= NULL
;
1032 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1033 if ((list
= rp
->info
) != NULL
) {
1034 rinfo
= listgetdata(listhead(list
));
1035 if ((rinfo
->type
== type
)
1036 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1037 /* Perform poisoned reverse. */
1038 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1039 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1040 ripng_garbage_collect
,
1041 ripng
->garbage_time
);
1042 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1044 /* Aggregate count decrement. */
1045 ripng_aggregate_decrement(rp
, rinfo
);
1047 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1049 if (IS_RIPNG_DEBUG_EVENT
) {
1050 struct prefix_ipv6
*p
=
1051 (struct prefix_ipv6
*)&rp
->p
;
1054 "Poisone %s/%d on the interface %s [withdraw]",
1055 inet6_ntoa(p
->prefix
),
1057 ifindex2ifname(rinfo
->ifindex
,
1061 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1066 /* RIP routing information. */
1067 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1068 struct sockaddr_in6
*from
,
1069 struct interface
*ifp
, int hoplimit
)
1073 struct ripng_nexthop nexthop
;
1075 /* RFC2080 2.4.2 Response Messages:
1076 The Response must be ignored if it is not from the RIPng port. */
1077 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1078 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1079 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1080 ripng_peer_bad_packet(from
);
1084 /* The datagram's IPv6 source address should be checked to see
1085 whether the datagram is from a valid neighbor; the source of the
1086 datagram must be a link-local address. */
1087 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1088 zlog_warn("RIPng packet comes from non link local address %s",
1089 inet6_ntoa(from
->sin6_addr
));
1090 ripng_peer_bad_packet(from
);
1094 /* It is also worth checking to see whether the response is from one
1095 of the router's own addresses. Interfaces on broadcast networks
1096 may receive copies of their own multicasts immediately. If a
1097 router processes its own output as new input, confusion is likely,
1098 and such datagrams must be ignored. */
1099 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1101 "RIPng packet comes from my own link local address %s",
1102 inet6_ntoa(from
->sin6_addr
));
1103 ripng_peer_bad_packet(from
);
1107 /* As an additional check, periodic advertisements must have their
1108 hop counts set to 255, and inbound, multicast packets sent from the
1109 RIPng port (i.e. periodic advertisement or triggered update
1110 packets) must be examined to ensure that the hop count is 255. */
1111 if (hoplimit
>= 0 && hoplimit
!= 255) {
1113 "RIPng packet comes with non 255 hop count %d from %s",
1114 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1115 ripng_peer_bad_packet(from
);
1119 /* Update RIPng peer. */
1120 ripng_peer_update(from
, packet
->version
);
1122 /* Reset nexthop. */
1123 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1124 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1126 /* Set RTE pointer. */
1129 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1130 /* First of all, we have to check this RTE is next hop RTE or
1131 not. Next hop RTE is completely different with normal RTE so
1132 we need special treatment. */
1133 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1134 ripng_nexthop_rte(rte
, from
, &nexthop
);
1138 /* RTE information validation. */
1140 /* - is the destination prefix valid (e.g., not a multicast
1141 prefix and not a link-local address) A link-local address
1142 should never be present in an RTE. */
1143 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1145 "Destination prefix is a multicast address %s/%d [%d]",
1146 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1148 ripng_peer_bad_route(from
);
1151 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1153 "Destination prefix is a link-local address %s/%d [%d]",
1154 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1156 ripng_peer_bad_route(from
);
1159 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1161 "Destination prefix is a loopback address %s/%d [%d]",
1162 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1164 ripng_peer_bad_route(from
);
1168 /* - is the prefix length valid (i.e., between 0 and 128,
1170 if (rte
->prefixlen
> 128) {
1171 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1172 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1173 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1174 ripng_peer_bad_route(from
);
1178 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1179 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1180 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1181 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1182 ripng_peer_bad_route(from
);
1186 /* Vincent: XXX Should we compute the direclty reachable nexthop
1187 * for our RIPng network ?
1190 /* Routing table updates. */
1191 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1195 /* Response to request message. */
1196 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1197 struct sockaddr_in6
*from
,
1198 struct interface
*ifp
)
1202 struct prefix_ipv6 p
;
1203 struct route_node
*rp
;
1204 struct ripng_info
*rinfo
;
1205 struct ripng_interface
*ri
;
1207 /* Does not reponse to the requests on the loopback interfaces */
1208 if (if_is_loopback(ifp
))
1211 /* Check RIPng process is enabled on this interface. */
1216 /* When passive interface is specified, suppress responses */
1220 /* RIPng peer update. */
1221 ripng_peer_update(from
, packet
->version
);
1223 lim
= ((caddr_t
)packet
) + size
;
1226 /* The Request is processed entry by entry. If there are no
1227 entries, no response is given. */
1228 if (lim
== (caddr_t
)rte
)
1231 /* There is one special case. If there is exactly one entry in the
1232 request, and it has a destination prefix of zero, a prefix length
1233 of zero, and a metric of infinity (i.e., 16), then this is a
1234 request to send the entire routing table. In that case, a call
1235 is made to the output process to send the routing table to the
1236 requesting address/port. */
1237 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1238 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1239 /* All route with split horizon */
1240 ripng_output_process(ifp
, from
, ripng_all_route
);
1242 /* Except for this special case, processing is quite simple.
1243 Examine the list of RTEs in the Request one by one. For each
1244 entry, look up the destination in the router's routing
1245 database and, if there is a route, put that route's metric in
1246 the metric field of the RTE. If there is no explicit route
1247 to the specified destination, put infinity in the metric
1248 field. Once all the entries have been filled in, change the
1249 command from Request to Response and send the datagram back
1250 to the requestor. */
1251 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1252 p
.family
= AF_INET6
;
1254 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1255 p
.prefix
= rte
->addr
;
1256 p
.prefixlen
= rte
->prefixlen
;
1257 apply_mask_ipv6(&p
);
1259 rp
= route_node_lookup(ripng
->table
,
1260 (struct prefix
*)&p
);
1263 rinfo
= listgetdata(
1264 listhead((struct list
*)rp
->info
));
1265 rte
->metric
= rinfo
->metric
;
1266 route_unlock_node(rp
);
1268 rte
->metric
= RIPNG_METRIC_INFINITY
;
1270 packet
->command
= RIPNG_RESPONSE
;
1272 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1276 /* First entry point of reading RIPng packet. */
1277 static int ripng_read(struct thread
*thread
)
1281 struct sockaddr_in6 from
;
1282 struct ripng_packet
*packet
;
1283 ifindex_t ifindex
= 0;
1284 struct interface
*ifp
;
1287 /* Check ripng is active and alive. */
1288 assert(ripng
!= NULL
);
1289 assert(ripng
->sock
>= 0);
1291 /* Fetch thread data and set read pointer to empty for event
1292 managing. `sock' sould be same as ripng->sock. */
1293 sock
= THREAD_FD(thread
);
1294 ripng
->t_read
= NULL
;
1296 /* Add myself to the next event. */
1297 ripng_event(RIPNG_READ
, sock
);
1299 /* Read RIPng packet. */
1300 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1301 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1304 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1308 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1309 (4)) must be multiple size of one RTE size (20). */
1310 if (((len
- 4) % 20) != 0) {
1311 zlog_warn("RIPng invalid packet size %d from %s", len
,
1312 inet6_ntoa(from
.sin6_addr
));
1313 ripng_peer_bad_packet(&from
);
1317 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1318 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1320 /* RIPng packet received. */
1321 if (IS_RIPNG_DEBUG_EVENT
)
1322 zlog_debug("RIPng packet received from %s port %d on %s",
1323 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1324 ifp
? ifp
->name
: "unknown");
1326 /* Logging before packet checking. */
1327 if (IS_RIPNG_DEBUG_RECV
)
1328 ripng_packet_dump(packet
, len
, "RECV");
1330 /* Packet comes from unknown interface. */
1332 zlog_warn("RIPng packet comes from unknown interface %d",
1337 /* Packet version mismatch checking. */
1338 if (packet
->version
!= ripng
->version
) {
1340 "RIPng packet version %d doesn't fit to my version %d",
1341 packet
->version
, ripng
->version
);
1342 ripng_peer_bad_packet(&from
);
1346 /* Process RIPng packet. */
1347 switch (packet
->command
) {
1349 ripng_request_process(packet
, len
, &from
, ifp
);
1351 case RIPNG_RESPONSE
:
1352 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1355 zlog_warn("Invalid RIPng command %d", packet
->command
);
1356 ripng_peer_bad_packet(&from
);
1362 /* Walk down the RIPng routing table then clear changed flag. */
1363 static void ripng_clear_changed_flag(void)
1365 struct route_node
*rp
;
1366 struct ripng_info
*rinfo
= NULL
;
1367 struct list
*list
= NULL
;
1368 struct listnode
*listnode
= NULL
;
1370 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1371 if ((list
= rp
->info
) != NULL
)
1372 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1373 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1374 /* This flag can be set only on the first entry.
1380 /* Regular update of RIPng route. Send all routing formation to RIPng
1381 enabled interface. */
1382 static int ripng_update(struct thread
*t
)
1384 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1385 struct interface
*ifp
;
1386 struct ripng_interface
*ri
;
1388 /* Clear update timer thread. */
1389 ripng
->t_update
= NULL
;
1391 /* Logging update event. */
1392 if (IS_RIPNG_DEBUG_EVENT
)
1393 zlog_debug("RIPng update timer expired!");
1395 /* Supply routes to each interface. */
1396 FOR_ALL_INTERFACES (vrf
, ifp
) {
1399 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1405 /* When passive interface is specified, suppress announce to the
1411 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1412 if (IS_RIPNG_DEBUG_EVENT
)
1414 "[Event] RIPng send to if %d is suppressed by config",
1418 #endif /* RIPNG_ADVANCED */
1420 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1423 /* Triggered updates may be suppressed if a regular update is due by
1424 the time the triggered update would be sent. */
1425 if (ripng
->t_triggered_interval
) {
1426 thread_cancel(ripng
->t_triggered_interval
);
1427 ripng
->t_triggered_interval
= NULL
;
1431 /* Reset flush event. */
1432 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1437 /* Triggered update interval timer. */
1438 static int ripng_triggered_interval(struct thread
*t
)
1440 ripng
->t_triggered_interval
= NULL
;
1442 if (ripng
->trigger
) {
1444 ripng_triggered_update(t
);
1449 /* Execute triggered update. */
1450 int ripng_triggered_update(struct thread
*t
)
1452 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1453 struct interface
*ifp
;
1454 struct ripng_interface
*ri
;
1457 ripng
->t_triggered_update
= NULL
;
1459 /* Cancel interval timer. */
1460 if (ripng
->t_triggered_interval
) {
1461 thread_cancel(ripng
->t_triggered_interval
);
1462 ripng
->t_triggered_interval
= NULL
;
1466 /* Logging triggered update. */
1467 if (IS_RIPNG_DEBUG_EVENT
)
1468 zlog_debug("RIPng triggered update!");
1470 /* Split Horizon processing is done when generating triggered
1471 updates as well as normal updates (see section 2.6). */
1472 FOR_ALL_INTERFACES (vrf
, ifp
) {
1475 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1481 /* When passive interface is specified, suppress announce to the
1486 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1489 /* Once all of the triggered updates have been generated, the route
1490 change flags should be cleared. */
1491 ripng_clear_changed_flag();
1493 /* After a triggered update is sent, a timer should be set for a
1494 random interval between 1 and 5 seconds. If other changes that
1495 would trigger updates occur before the timer expires, a single
1496 update is triggered when the timer expires. */
1497 interval
= (random() % 5) + 1;
1499 ripng
->t_triggered_interval
= NULL
;
1500 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1501 &ripng
->t_triggered_interval
);
1506 /* Write routing table entry to the stream and return next index of
1507 the routing table entry in the stream. */
1508 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1509 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1511 /* RIPng packet header. */
1513 stream_putc(s
, RIPNG_RESPONSE
);
1514 stream_putc(s
, RIPNG_V1
);
1518 /* Write routing table entry. */
1521 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1523 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1524 stream_putw(s
, tag
);
1526 stream_putc(s
, p
->prefixlen
);
1529 stream_putc(s
, metric
);
1534 /* Send RESPONSE message to specified destination. */
1535 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1539 struct route_node
*rp
;
1540 struct ripng_info
*rinfo
;
1541 struct ripng_interface
*ri
;
1542 struct ripng_aggregate
*aggregate
;
1543 struct prefix_ipv6
*p
;
1544 struct list
*ripng_rte_list
;
1545 struct list
*list
= NULL
;
1546 struct listnode
*listnode
= NULL
;
1548 if (IS_RIPNG_DEBUG_EVENT
) {
1550 zlog_debug("RIPng update routes to neighbor %s",
1551 inet6_ntoa(to
->sin6_addr
));
1553 zlog_debug("RIPng update routes on interface %s",
1557 /* Get RIPng interface. */
1560 ripng_rte_list
= ripng_rte_new();
1562 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1563 if ((list
= rp
->info
) != NULL
1564 && (rinfo
= listgetdata(listhead(list
))) != NULL
1565 && rinfo
->suppress
== 0) {
1566 /* If no route-map are applied, the RTE will be these
1570 p
= (struct prefix_ipv6
*)&rp
->p
;
1571 rinfo
->metric_out
= rinfo
->metric
;
1572 rinfo
->tag_out
= rinfo
->tag
;
1573 memset(&rinfo
->nexthop_out
, 0,
1574 sizeof(rinfo
->nexthop_out
));
1575 /* In order to avoid some local loops,
1576 * if the RIPng route has a nexthop via this interface,
1578 * otherwise set it to 0. The nexthop should not be
1580 * beyond the local broadcast/multicast area in order
1581 * to avoid an IGP multi-level recursive look-up.
1583 if (rinfo
->ifindex
== ifp
->ifindex
)
1584 rinfo
->nexthop_out
= rinfo
->nexthop
;
1586 /* Apply output filters. */
1587 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1591 /* Changed route only output. */
1592 if (route_type
== ripng_changed_route
1593 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1596 /* Split horizon. */
1597 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1598 /* We perform split horizon for RIPng routes. */
1600 struct ripng_info
*tmp_rinfo
= NULL
;
1602 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1604 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1605 && tmp_rinfo
->ifindex
1614 /* Preparation for route-map. */
1615 rinfo
->metric_set
= 0;
1618 * and tag_out are already initialized.
1621 /* Interface route-map */
1622 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1625 ret
= route_map_apply(
1626 ri
->routemap
[RIPNG_FILTER_OUT
],
1627 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1629 if (ret
== RMAP_DENYMATCH
) {
1630 if (IS_RIPNG_DEBUG_PACKET
)
1632 "RIPng %s/%d is filtered by route-map out",
1633 inet6_ntoa(p
->prefix
),
1639 /* Redistribute route-map. */
1640 if (ripng
->route_map
[rinfo
->type
].name
) {
1643 ret
= route_map_apply(
1644 ripng
->route_map
[rinfo
->type
].map
,
1645 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1647 if (ret
== RMAP_DENYMATCH
) {
1648 if (IS_RIPNG_DEBUG_PACKET
)
1650 "RIPng %s/%d is filtered by route-map",
1651 inet6_ntoa(p
->prefix
),
1657 /* When the route-map does not set metric. */
1658 if (!rinfo
->metric_set
) {
1659 /* If the redistribute metric is set. */
1660 if (ripng
->route_map
[rinfo
->type
].metric_config
1661 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1663 ripng
->route_map
[rinfo
->type
]
1666 /* If the route is not connected or
1668 one, use default-metric value */
1669 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1671 != ZEBRA_ROUTE_CONNECT
1673 != RIPNG_METRIC_INFINITY
)
1675 ripng
->default_metric
;
1679 /* Apply offset-list */
1680 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1681 ripng_offset_list_apply_out(p
, ifp
,
1682 &rinfo
->metric_out
);
1684 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1685 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1687 /* Perform split-horizon with poisoned reverse
1690 if (ri
->split_horizon
1691 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1692 struct ripng_info
*tmp_rinfo
= NULL
;
1694 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1696 if ((tmp_rinfo
->type
1697 == ZEBRA_ROUTE_RIPNG
)
1698 && tmp_rinfo
->ifindex
1701 RIPNG_METRIC_INFINITY
;
1704 /* Add RTE to the list */
1705 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1708 /* Process the aggregated RTE entry */
1709 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1710 && aggregate
->suppress
== 0) {
1711 /* If no route-map are applied, the RTE will be these
1715 p
= (struct prefix_ipv6
*)&rp
->p
;
1716 aggregate
->metric_set
= 0;
1717 aggregate
->metric_out
= aggregate
->metric
;
1718 aggregate
->tag_out
= aggregate
->tag
;
1719 memset(&aggregate
->nexthop_out
, 0,
1720 sizeof(aggregate
->nexthop_out
));
1722 /* Apply output filters.*/
1723 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1727 /* Interface route-map */
1728 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1730 struct ripng_info newinfo
;
1732 /* let's cast the aggregate structure to
1734 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1735 /* the nexthop is :: */
1736 newinfo
.metric
= aggregate
->metric
;
1737 newinfo
.metric_out
= aggregate
->metric_out
;
1738 newinfo
.tag
= aggregate
->tag
;
1739 newinfo
.tag_out
= aggregate
->tag_out
;
1741 ret
= route_map_apply(
1742 ri
->routemap
[RIPNG_FILTER_OUT
],
1743 (struct prefix
*)p
, RMAP_RIPNG
,
1746 if (ret
== RMAP_DENYMATCH
) {
1747 if (IS_RIPNG_DEBUG_PACKET
)
1749 "RIPng %s/%d is filtered by route-map out",
1750 inet6_ntoa(p
->prefix
),
1755 aggregate
->metric_out
= newinfo
.metric_out
;
1756 aggregate
->tag_out
= newinfo
.tag_out
;
1757 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1758 aggregate
->nexthop_out
=
1759 newinfo
.nexthop_out
;
1762 /* There is no redistribute routemap for the aggregated
1765 /* Changed route only output. */
1766 /* XXX, vincent, in order to increase time convergence,
1767 * it should be announced if a child has changed.
1769 if (route_type
== ripng_changed_route
)
1772 /* Apply offset-list */
1773 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1774 ripng_offset_list_apply_out(
1775 p
, ifp
, &aggregate
->metric_out
);
1777 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1778 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1780 /* Add RTE to the list */
1781 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1785 /* Flush the list */
1786 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1787 ripng_rte_free(ripng_rte_list
);
1790 /* Create new RIPng instance and set it to global variable. */
1791 static int ripng_create(void)
1793 /* ripng should be NULL. */
1794 assert(ripng
== NULL
);
1796 /* Allocaste RIPng instance. */
1797 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1799 /* Default version and timer values. */
1800 ripng
->version
= RIPNG_V1
;
1801 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1802 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1803 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1804 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1807 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1808 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1810 /* Initialize RIPng routig table. */
1811 ripng
->table
= route_table_init();
1812 ripng
->route
= route_table_init();
1813 ripng
->aggregate
= route_table_init();
1816 ripng
->sock
= ripng_make_socket();
1817 if (ripng
->sock
< 0)
1821 ripng_event(RIPNG_READ
, ripng
->sock
);
1822 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1827 /* Send RIPng request to the interface. */
1828 int ripng_request(struct interface
*ifp
)
1831 struct ripng_packet ripng_packet
;
1833 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1835 if (if_is_loopback(ifp
))
1838 /* If interface is down, don't send RIP packet. */
1842 if (IS_RIPNG_DEBUG_EVENT
)
1843 zlog_debug("RIPng send request to %s", ifp
->name
);
1845 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1846 ripng_packet
.command
= RIPNG_REQUEST
;
1847 ripng_packet
.version
= RIPNG_V1
;
1848 rte
= ripng_packet
.rte
;
1849 rte
->metric
= RIPNG_METRIC_INFINITY
;
1851 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1856 static int ripng_update_jitter(int time
)
1858 return ((random() % (time
+ 1)) - (time
/ 2));
1861 void ripng_event(enum ripng_event event
, int sock
)
1867 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1869 case RIPNG_UPDATE_EVENT
:
1870 if (ripng
->t_update
) {
1871 thread_cancel(ripng
->t_update
);
1872 ripng
->t_update
= NULL
;
1874 /* Update timer jitter. */
1875 jitter
= ripng_update_jitter(ripng
->update_time
);
1877 ripng
->t_update
= NULL
;
1878 thread_add_timer(master
, ripng_update
, NULL
,
1879 sock
? 2 : ripng
->update_time
+ jitter
,
1882 case RIPNG_TRIGGERED_UPDATE
:
1883 if (ripng
->t_triggered_interval
)
1886 thread_add_event(master
, ripng_triggered_update
, NULL
,
1887 0, &ripng
->t_triggered_update
);
1895 /* Print out routes update time. */
1896 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1901 char timebuf
[TIME_BUF
];
1902 struct thread
*thread
;
1904 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1905 clock
= thread_timer_remain_second(thread
);
1906 tm
= gmtime(&clock
);
1907 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1908 vty_out(vty
, "%5s", timebuf
);
1909 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1910 clock
= thread_timer_remain_second(thread
);
1911 tm
= gmtime(&clock
);
1912 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1913 vty_out(vty
, "%5s", timebuf
);
1917 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1922 if (rinfo
->suppress
)
1925 switch (rinfo
->sub_type
) {
1926 case RIPNG_ROUTE_RTE
:
1929 case RIPNG_ROUTE_STATIC
:
1932 case RIPNG_ROUTE_DEFAULT
:
1935 case RIPNG_ROUTE_REDISTRIBUTE
:
1938 case RIPNG_ROUTE_INTERFACE
:
1949 DEFUN (show_ipv6_ripng
,
1950 show_ipv6_ripng_cmd
,
1954 "Show RIPng routes\n")
1956 struct route_node
*rp
;
1957 struct ripng_info
*rinfo
;
1958 struct ripng_aggregate
*aggregate
;
1959 struct prefix_ipv6
*p
;
1960 struct list
*list
= NULL
;
1961 struct listnode
*listnode
= NULL
;
1967 /* Header of display. */
1969 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1971 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1972 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1973 " Network Next Hop Via Metric Tag Time\n");
1975 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1976 if ((aggregate
= rp
->aggregate
) != NULL
) {
1977 p
= (struct prefix_ipv6
*)&rp
->p
;
1980 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1981 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1984 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1988 vty_out(vty
, "%*s", 18, " ");
1990 vty_out(vty
, "%*s", 28, " ");
1991 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1992 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1995 if ((list
= rp
->info
) != NULL
)
1996 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1997 p
= (struct prefix_ipv6
*)&rp
->p
;
2000 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2001 zebra_route_char(rinfo
->type
),
2002 ripng_route_subtype_print(rinfo
),
2003 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2006 vty_out(vty
, "%c(%s) %s/%d ",
2007 zebra_route_char(rinfo
->type
),
2008 ripng_route_subtype_print(rinfo
),
2009 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2012 vty_out(vty
, "%*s", 18, " ");
2013 len
= vty_out(vty
, "%s",
2014 inet6_ntoa(rinfo
->nexthop
));
2018 vty_out(vty
, "%*s", len
, " ");
2021 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2022 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2025 ifindex2ifname(rinfo
->ifindex
,
2027 } else if (rinfo
->metric
2028 == RIPNG_METRIC_INFINITY
) {
2029 len
= vty_out(vty
, "kill");
2031 len
= vty_out(vty
, "self");
2035 vty_out(vty
, "%*s", len
, " ");
2037 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2038 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2041 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2042 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2043 /* RTE from remote RIP routers */
2044 ripng_vty_out_uptime(vty
, rinfo
);
2045 } else if (rinfo
->metric
2046 == RIPNG_METRIC_INFINITY
) {
2047 /* poisonous reversed routes (gc) */
2048 ripng_vty_out_uptime(vty
, rinfo
);
2058 DEFUN (show_ipv6_ripng_status
,
2059 show_ipv6_ripng_status_cmd
,
2060 "show ipv6 ripng status",
2063 "Show RIPng routes\n"
2064 "IPv6 routing protocol process parameters and statistics\n")
2066 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2067 struct interface
*ifp
;
2072 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2073 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2074 ripng
->update_time
);
2075 vty_out(vty
, " next due in %lu seconds\n",
2076 thread_timer_remain_second(ripng
->t_update
));
2077 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2078 vty_out(vty
, " garbage collect after %ld seconds\n",
2079 ripng
->garbage_time
);
2081 /* Filtering status show. */
2082 config_show_distribute(vty
);
2084 /* Default metric information. */
2085 vty_out(vty
, " Default redistribution metric is %d\n",
2086 ripng
->default_metric
);
2088 /* Redistribute information. */
2089 vty_out(vty
, " Redistributing:");
2090 ripng_redistribute_write(vty
, 0);
2093 vty_out(vty
, " Default version control: send version %d,",
2095 vty_out(vty
, " receive version %d \n", ripng
->version
);
2097 vty_out(vty
, " Interface Send Recv\n");
2099 FOR_ALL_INTERFACES (vrf
, ifp
) {
2100 struct ripng_interface
*ri
;
2104 if (ri
->enable_network
|| ri
->enable_interface
) {
2106 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2107 ripng
->version
, ripng
->version
);
2111 vty_out(vty
, " Routing for Networks:\n");
2112 ripng_network_write(vty
, 0);
2114 vty_out(vty
, " Routing Information Sources:\n");
2116 " Gateway BadPackets BadRoutes Distance Last Update\n");
2117 ripng_peer_display(vty
);
2122 DEFUN (clear_ipv6_rip
,
2127 "Clear IPv6 RIP database\n")
2129 struct route_node
*rp
;
2130 struct ripng_info
*rinfo
;
2132 struct listnode
*listnode
;
2134 /* Clear received RIPng routes */
2135 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2140 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2141 if (!ripng_route_rte(rinfo
))
2144 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2145 ripng_zebra_ipv6_delete(rp
);
2150 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2151 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2152 listnode_delete(list
, rinfo
);
2153 ripng_info_free(rinfo
);
2156 if (list_isempty(list
)) {
2157 list_delete_and_null(&list
);
2159 route_unlock_node(rp
);
2166 DEFUN_NOSH (router_ripng
,
2169 "Enable a routing process\n"
2170 "Make RIPng instance command\n")
2174 vty
->node
= RIPNG_NODE
;
2177 ret
= ripng_create();
2179 /* Notice to user we couldn't create RIPng. */
2181 zlog_warn("can't create RIPng");
2182 return CMD_WARNING_CONFIG_FAILED
;
2189 DEFUN (no_router_ripng
,
2190 no_router_ripng_cmd
,
2193 "Enable a routing process\n"
2194 "Make RIPng instance command\n")
2204 "Static route setup\n"
2205 "Set static RIPng route announcement\n")
2207 int idx_ipv6addr
= 1;
2209 struct prefix_ipv6 p
;
2210 struct route_node
*rp
;
2212 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2213 (struct prefix_ipv6
*)&p
);
2215 vty_out(vty
, "Malformed address\n");
2216 return CMD_WARNING_CONFIG_FAILED
;
2218 apply_mask_ipv6(&p
);
2220 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2222 vty_out(vty
, "There is already same static route.\n");
2223 route_unlock_node(rp
);
2226 rp
->info
= (void *)1;
2228 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2234 DEFUN (no_ripng_route
,
2236 "no route IPV6ADDR",
2238 "Static route setup\n"
2239 "Delete static RIPng route announcement\n")
2241 int idx_ipv6addr
= 2;
2243 struct prefix_ipv6 p
;
2244 struct route_node
*rp
;
2246 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2247 (struct prefix_ipv6
*)&p
);
2249 vty_out(vty
, "Malformed address\n");
2250 return CMD_WARNING_CONFIG_FAILED
;
2252 apply_mask_ipv6(&p
);
2254 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2256 vty_out(vty
, "Can't find static route.\n");
2257 return CMD_WARNING_CONFIG_FAILED
;
2260 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2261 route_unlock_node(rp
);
2264 route_unlock_node(rp
);
2269 DEFUN (ripng_aggregate_address
,
2270 ripng_aggregate_address_cmd
,
2271 "aggregate-address X:X::X:X/M",
2272 "Set aggregate RIPng route announcement\n"
2273 "Aggregate network\n")
2275 int idx_ipv6_prefixlen
= 1;
2278 struct route_node
*node
;
2280 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2281 (struct prefix_ipv6
*)&p
);
2283 vty_out(vty
, "Malformed address\n");
2284 return CMD_WARNING_CONFIG_FAILED
;
2287 /* Check aggregate alredy exist or not. */
2288 node
= route_node_get(ripng
->aggregate
, &p
);
2290 vty_out(vty
, "There is already same aggregate route.\n");
2291 route_unlock_node(node
);
2294 node
->info
= (void *)1;
2296 ripng_aggregate_add(&p
);
2301 DEFUN (no_ripng_aggregate_address
,
2302 no_ripng_aggregate_address_cmd
,
2303 "no aggregate-address X:X::X:X/M",
2305 "Delete aggregate RIPng route announcement\n"
2306 "Aggregate network\n")
2308 int idx_ipv6_prefixlen
= 2;
2311 struct route_node
*rn
;
2313 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2314 (struct prefix_ipv6
*)&p
);
2316 vty_out(vty
, "Malformed address\n");
2317 return CMD_WARNING_CONFIG_FAILED
;
2320 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2322 vty_out(vty
, "Can't find aggregate route.\n");
2323 return CMD_WARNING_CONFIG_FAILED
;
2325 route_unlock_node(rn
);
2327 route_unlock_node(rn
);
2329 ripng_aggregate_delete(&p
);
2334 DEFUN (ripng_default_metric
,
2335 ripng_default_metric_cmd
,
2336 "default-metric (1-16)",
2337 "Set a metric of redistribute routes\n"
2342 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2347 DEFUN (no_ripng_default_metric
,
2348 no_ripng_default_metric_cmd
,
2349 "no default-metric [(1-16)]",
2351 "Set a metric of redistribute routes\n"
2355 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2362 /* RIPng update timer setup. */
2363 DEFUN (ripng_update_timer
,
2364 ripng_update_timer_cmd
,
2365 "update-timer SECOND",
2366 "Set RIPng update timer in seconds\n"
2369 unsigned long update
;
2370 char *endptr
= NULL
;
2372 update
= strtoul (argv
[0], &endptr
, 10);
2373 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2375 vty_out (vty
, "update timer value error\n");
2376 return CMD_WARNING_CONFIG_FAILED
;
2379 ripng
->update_time
= update
;
2381 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2385 DEFUN (no_ripng_update_timer
,
2386 no_ripng_update_timer_cmd
,
2387 "no update-timer SECOND",
2389 "Unset RIPng update timer in seconds\n"
2392 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2393 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2397 /* RIPng timeout timer setup. */
2398 DEFUN (ripng_timeout_timer
,
2399 ripng_timeout_timer_cmd
,
2400 "timeout-timer SECOND",
2401 "Set RIPng timeout timer in seconds\n"
2404 unsigned long timeout
;
2405 char *endptr
= NULL
;
2407 timeout
= strtoul (argv
[0], &endptr
, 10);
2408 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2410 vty_out (vty
, "timeout timer value error\n");
2411 return CMD_WARNING_CONFIG_FAILED
;
2414 ripng
->timeout_time
= timeout
;
2419 DEFUN (no_ripng_timeout_timer
,
2420 no_ripng_timeout_timer_cmd
,
2421 "no timeout-timer SECOND",
2423 "Unset RIPng timeout timer in seconds\n"
2426 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2430 /* RIPng garbage timer setup. */
2431 DEFUN (ripng_garbage_timer
,
2432 ripng_garbage_timer_cmd
,
2433 "garbage-timer SECOND",
2434 "Set RIPng garbage timer in seconds\n"
2437 unsigned long garbage
;
2438 char *endptr
= NULL
;
2440 garbage
= strtoul (argv
[0], &endptr
, 10);
2441 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2443 vty_out (vty
, "garbage timer value error\n");
2444 return CMD_WARNING_CONFIG_FAILED
;
2447 ripng
->garbage_time
= garbage
;
2452 DEFUN (no_ripng_garbage_timer
,
2453 no_ripng_garbage_timer_cmd
,
2454 "no garbage-timer SECOND",
2456 "Unset RIPng garbage timer in seconds\n"
2459 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2464 DEFUN (ripng_timers
,
2466 "timers basic (0-65535) (0-65535) (0-65535)",
2467 "RIPng timers setup\n"
2469 "Routing table update timer value in second. Default is 30.\n"
2470 "Routing information timeout timer. Default is 180.\n"
2471 "Garbage collection timer. Default is 120.\n")
2474 int idx_number_2
= 3;
2475 int idx_number_3
= 4;
2476 unsigned long update
;
2477 unsigned long timeout
;
2478 unsigned long garbage
;
2480 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2481 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2482 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2484 /* Set each timer value. */
2485 ripng
->update_time
= update
;
2486 ripng
->timeout_time
= timeout
;
2487 ripng
->garbage_time
= garbage
;
2489 /* Reset update timer thread. */
2490 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2495 DEFUN (no_ripng_timers
,
2496 no_ripng_timers_cmd
,
2497 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2499 "RIPng timers setup\n"
2501 "Routing table update timer value in second. Default is 30.\n"
2502 "Routing information timeout timer. Default is 180.\n"
2503 "Garbage collection timer. Default is 120.\n")
2505 /* Set each timer value to the default. */
2506 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2507 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2508 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2510 /* Reset update timer thread. */
2511 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2517 DEFUN (show_ipv6_protocols
,
2518 show_ipv6_protocols_cmd
,
2519 "show ipv6 protocols",
2522 "Routing protocol information\n")
2527 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2529 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2530 ripng
->update_time
, 0);
2532 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2533 ripng
->timeout_time
,
2534 ripng
->garbage_time
);
2536 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2537 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2543 /* Please be carefull to use this command. */
2544 DEFUN (ripng_default_information_originate
,
2545 ripng_default_information_originate_cmd
,
2546 "default-information originate",
2547 "Default route information\n"
2548 "Distribute default route\n")
2550 struct prefix_ipv6 p
;
2552 if (!ripng
->default_information
) {
2553 ripng
->default_information
= 1;
2555 str2prefix_ipv6("::/0", &p
);
2556 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2563 DEFUN (no_ripng_default_information_originate
,
2564 no_ripng_default_information_originate_cmd
,
2565 "no default-information originate",
2567 "Default route information\n"
2568 "Distribute default route\n")
2570 struct prefix_ipv6 p
;
2572 if (ripng
->default_information
) {
2573 ripng
->default_information
= 0;
2575 str2prefix_ipv6("::/0", &p
);
2576 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2577 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2583 /* Update ECMP routes to zebra when ECMP is disabled. */
2584 static void ripng_ecmp_disable(void)
2586 struct route_node
*rp
;
2587 struct ripng_info
*rinfo
, *tmp_rinfo
;
2589 struct listnode
*node
, *nextnode
;
2594 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2595 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2596 rinfo
= listgetdata(listhead(list
));
2597 if (!ripng_route_rte(rinfo
))
2600 /* Drop all other entries, except the first one. */
2601 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2602 if (tmp_rinfo
!= rinfo
) {
2603 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2605 tmp_rinfo
->t_garbage_collect
);
2606 list_delete_node(list
, node
);
2607 ripng_info_free(tmp_rinfo
);
2611 ripng_zebra_ipv6_add(rp
);
2613 /* Set the route change flag. */
2614 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2616 /* Signal the output process to trigger an update. */
2617 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2621 DEFUN (ripng_allow_ecmp
,
2622 ripng_allow_ecmp_cmd
,
2624 "Allow Equal Cost MultiPath\n")
2627 vty_out(vty
, "ECMP is already enabled.\n");
2632 zlog_info("ECMP is enabled.");
2636 DEFUN (no_ripng_allow_ecmp
,
2637 no_ripng_allow_ecmp_cmd
,
2640 "Allow Equal Cost MultiPath\n")
2643 vty_out(vty
, "ECMP is already disabled.\n");
2648 zlog_info("ECMP is disabled.");
2649 ripng_ecmp_disable();
2653 /* RIPng configuration write function. */
2654 static int ripng_config_write(struct vty
*vty
)
2656 int ripng_network_write(struct vty
*, int);
2657 void ripng_redistribute_write(struct vty
*, int);
2659 struct route_node
*rp
;
2664 vty_out(vty
, "router ripng\n");
2666 if (ripng
->default_information
)
2667 vty_out(vty
, " default-information originate\n");
2669 ripng_network_write(vty
, 1);
2671 /* RIPng default metric configuration */
2672 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2673 vty_out(vty
, " default-metric %d\n",
2674 ripng
->default_metric
);
2676 ripng_redistribute_write(vty
, 1);
2678 /* RIP offset-list configuration. */
2679 config_write_ripng_offset_list(vty
);
2681 /* RIPng aggregate routes. */
2682 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2683 if (rp
->info
!= NULL
)
2684 vty_out(vty
, " aggregate-address %s/%d\n",
2685 inet6_ntoa(rp
->p
.u
.prefix6
),
2688 /* ECMP configuration. */
2690 vty_out(vty
, " allow-ecmp\n");
2692 /* RIPng static routes. */
2693 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2694 if (rp
->info
!= NULL
)
2695 vty_out(vty
, " route %s/%d\n",
2696 inet6_ntoa(rp
->p
.u
.prefix6
),
2699 /* RIPng timers configuration. */
2700 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2701 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2702 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2703 vty_out(vty
, " timers basic %ld %ld %ld\n",
2704 ripng
->update_time
, ripng
->timeout_time
,
2705 ripng
->garbage_time
);
2708 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2709 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2710 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2711 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2712 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2713 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2716 write
+= config_write_distribute(vty
);
2718 write
+= config_write_if_rmap(vty
);
2725 /* RIPng node structure. */
2726 static struct cmd_node cmd_ripng_node
= {
2727 RIPNG_NODE
, "%s(config-router)# ", 1,
2730 static void ripng_distribute_update(struct distribute
*dist
)
2732 struct interface
*ifp
;
2733 struct ripng_interface
*ri
;
2734 struct access_list
*alist
;
2735 struct prefix_list
*plist
;
2740 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2746 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2747 alist
= access_list_lookup(AFI_IP6
,
2748 dist
->list
[DISTRIBUTE_V6_IN
]);
2750 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2752 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2754 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2756 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2757 alist
= access_list_lookup(AFI_IP6
,
2758 dist
->list
[DISTRIBUTE_V6_OUT
]);
2760 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2762 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2764 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2766 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2767 plist
= prefix_list_lookup(AFI_IP6
,
2768 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2770 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2772 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2774 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2776 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2777 plist
= prefix_list_lookup(AFI_IP6
,
2778 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2780 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2782 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2784 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2787 void ripng_distribute_update_interface(struct interface
*ifp
)
2789 struct distribute
*dist
;
2791 dist
= distribute_lookup(ifp
->name
);
2793 ripng_distribute_update(dist
);
2796 /* Update all interface's distribute list. */
2797 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2799 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2800 struct interface
*ifp
;
2802 FOR_ALL_INTERFACES (vrf
, ifp
)
2803 ripng_distribute_update_interface(ifp
);
2806 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2808 ripng_distribute_update_all(NULL
);
2811 /* delete all the added ripng routes. */
2815 struct route_node
*rp
;
2816 struct ripng_info
*rinfo
;
2817 struct ripng_aggregate
*aggregate
;
2818 struct list
*list
= NULL
;
2819 struct listnode
*listnode
= NULL
;
2822 /* Clear RIPng routes */
2823 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2824 if ((list
= rp
->info
) != NULL
) {
2825 rinfo
= listgetdata(listhead(list
));
2826 if (ripng_route_rte(rinfo
))
2827 ripng_zebra_ipv6_delete(rp
);
2829 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2831 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2833 rinfo
->t_garbage_collect
);
2834 ripng_info_free(rinfo
);
2836 list_delete_and_null(&list
);
2838 route_unlock_node(rp
);
2841 if ((aggregate
= rp
->aggregate
) != NULL
) {
2842 ripng_aggregate_free(aggregate
);
2843 rp
->aggregate
= NULL
;
2844 route_unlock_node(rp
);
2848 /* Cancel the RIPng timers */
2849 RIPNG_TIMER_OFF(ripng
->t_update
);
2850 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2851 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2853 /* Cancel the read thread */
2854 if (ripng
->t_read
) {
2855 thread_cancel(ripng
->t_read
);
2856 ripng
->t_read
= NULL
;
2859 /* Close the RIPng socket */
2860 if (ripng
->sock
>= 0) {
2865 /* Static RIPng route configuration. */
2866 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2869 route_unlock_node(rp
);
2872 /* RIPng aggregated prefixes */
2873 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2876 route_unlock_node(rp
);
2879 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2880 if (ripng
->route_map
[i
].name
)
2881 free(ripng
->route_map
[i
].name
);
2883 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2884 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2885 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2887 stream_free(ripng
->ibuf
);
2888 stream_free(ripng
->obuf
);
2890 XFREE(MTYPE_RIPNG
, ripng
);
2894 ripng_clean_network();
2895 ripng_passive_interface_clean();
2896 ripng_offset_clean();
2897 ripng_interface_clean();
2898 ripng_redistribute_clean();
2901 /* Reset all values to the default settings. */
2904 /* Call ripd related reset functions. */
2905 ripng_debug_reset();
2906 ripng_route_map_reset();
2908 /* Call library reset functions. */
2910 access_list_reset();
2911 prefix_list_reset();
2913 distribute_list_reset();
2915 ripng_interface_reset();
2917 ripng_zclient_reset();
2920 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2922 struct interface
*ifp
;
2923 struct ripng_interface
*ri
;
2924 struct route_map
*rmap
;
2926 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2932 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2933 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2935 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2937 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2939 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2941 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2942 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2944 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2946 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2948 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2951 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2953 struct if_rmap
*if_rmap
;
2955 if_rmap
= if_rmap_lookup(ifp
->name
);
2957 ripng_if_rmap_update(if_rmap
);
2960 static void ripng_routemap_update_redistribute(void)
2965 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2966 if (ripng
->route_map
[i
].name
)
2967 ripng
->route_map
[i
].map
=
2968 route_map_lookup_by_name(
2969 ripng
->route_map
[i
].name
);
2974 static void ripng_routemap_update(const char *unused
)
2976 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2977 struct interface
*ifp
;
2979 FOR_ALL_INTERFACES (vrf
, ifp
)
2980 ripng_if_rmap_update_interface(ifp
);
2982 ripng_routemap_update_redistribute();
2985 /* Initialize ripng structure and set commands. */
2988 /* Install RIPNG_NODE. */
2989 install_node(&cmd_ripng_node
, ripng_config_write
);
2991 /* Install ripng commands. */
2992 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2993 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2995 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2997 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2998 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
3000 install_default(RIPNG_NODE
);
3001 install_element(RIPNG_NODE
, &ripng_route_cmd
);
3002 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
3003 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3004 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3006 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3007 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3009 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3010 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3012 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3013 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3014 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3015 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3016 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3017 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3018 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3021 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3022 install_element(RIPNG_NODE
,
3023 &no_ripng_default_information_originate_cmd
);
3025 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3026 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3031 /* Access list install. */
3033 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3034 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3036 /* Prefix list initialize.*/
3038 prefix_list_add_hook(ripng_distribute_update_all
);
3039 prefix_list_delete_hook(ripng_distribute_update_all
);
3041 /* Distribute list install. */
3042 distribute_list_init(RIPNG_NODE
);
3043 distribute_list_add_hook(ripng_distribute_update
);
3044 distribute_list_delete_hook(ripng_distribute_update
);
3046 /* Route-map for interface. */
3047 ripng_route_map_init();
3048 ripng_offset_init();
3050 route_map_add_hook(ripng_routemap_update
);
3051 route_map_delete_hook(ripng_routemap_update
);
3053 if_rmap_init(RIPNG_NODE
);
3054 if_rmap_hook_add(ripng_if_rmap_update
);
3055 if_rmap_hook_delete(ripng_if_rmap_update
);