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 /* If there is an existing route, compare the next hop address
847 to the address of the router from which the datagram came.
848 If this datagram is from the same router as the existing
849 route, reinitialize the timeout. */
850 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
851 && (rinfo
->ifindex
== ifp
->ifindex
));
854 * RFC 2080 - Section 2.4.2:
855 * "If the new metric is the same as the old one, examine the
857 * for the existing route. If it is at least halfway to the
859 * point, switch to the new route. This heuristic is optional,
861 * highly recommended".
863 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
865 && (thread_timer_remain_second(rinfo
->t_timeout
)
866 < (ripng
->timeout_time
/ 2))) {
867 ripng_ecmp_replace(&newinfo
);
869 /* Next, compare the metrics. If the datagram is from the same
870 router as the existing route, and the new metric is different
871 than the old one; or, if the new metric is lower than the old
872 one; do the following actions: */
873 else if ((same
&& rinfo
->metric
!= rte
->metric
)
874 || rte
->metric
< rinfo
->metric
) {
875 if (listcount(list
) == 1) {
876 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
877 ripng_ecmp_replace(&newinfo
);
879 ripng_ecmp_delete(rinfo
);
881 if (newinfo
.metric
< rinfo
->metric
)
882 ripng_ecmp_replace(&newinfo
);
883 else /* newinfo.metric > rinfo->metric */
884 ripng_ecmp_delete(rinfo
);
886 } else /* same & no change */
887 ripng_timeout_update(rinfo
);
889 /* Unlock tempolary lock of the route. */
890 route_unlock_node(rp
);
894 /* Add redistributed route to RIPng table. */
895 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
896 ifindex_t ifindex
, struct in6_addr
*nexthop
,
899 struct route_node
*rp
;
900 struct ripng_info
*rinfo
= NULL
, newinfo
;
901 struct list
*list
= NULL
;
903 /* Redistribute route */
904 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
906 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
909 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
911 memset(&newinfo
, 0, sizeof(struct ripng_info
));
913 newinfo
.sub_type
= sub_type
;
914 newinfo
.ifindex
= ifindex
;
916 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
919 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
920 newinfo
.nexthop
= *nexthop
;
922 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
923 rinfo
= listgetdata(listhead(list
));
925 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
926 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
927 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
928 route_unlock_node(rp
);
932 /* Manually configured RIPng route check.
933 * They have the precedence on all the other entries.
935 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
936 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
937 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
938 if (type
!= ZEBRA_ROUTE_RIPNG
939 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
940 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
941 route_unlock_node(rp
);
946 ripng_ecmp_replace(&newinfo
);
947 route_unlock_node(rp
);
949 ripng_ecmp_add(&newinfo
);
951 if (IS_RIPNG_DEBUG_EVENT
) {
954 "Redistribute new prefix %s/%d on the interface %s",
955 inet6_ntoa(p
->prefix
), p
->prefixlen
,
956 ifindex2ifname(ifindex
, VRF_DEFAULT
));
959 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
960 inet6_ntoa(p
->prefix
), p
->prefixlen
,
961 inet6_ntoa(*nexthop
),
962 ifindex2ifname(ifindex
, VRF_DEFAULT
));
965 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
968 /* Delete redistributed route to RIPng table. */
969 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
972 struct route_node
*rp
;
973 struct ripng_info
*rinfo
;
975 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
977 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
980 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
983 struct list
*list
= rp
->info
;
985 if (list
!= NULL
&& listcount(list
) != 0) {
986 rinfo
= listgetdata(listhead(list
));
987 if (rinfo
!= NULL
&& rinfo
->type
== type
988 && rinfo
->sub_type
== sub_type
989 && rinfo
->ifindex
== ifindex
) {
990 /* Perform poisoned reverse. */
991 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
992 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
993 ripng_garbage_collect
,
994 ripng
->garbage_time
);
995 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
997 /* Aggregate count decrement. */
998 ripng_aggregate_decrement(rp
, rinfo
);
1000 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1002 if (IS_RIPNG_DEBUG_EVENT
)
1004 "Poisone %s/%d on the interface %s with an "
1005 "infinity metric [delete]",
1006 inet6_ntoa(p
->prefix
),
1008 ifindex2ifname(ifindex
,
1011 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1014 route_unlock_node(rp
);
1018 /* Withdraw redistributed route. */
1019 void ripng_redistribute_withdraw(int type
)
1021 struct route_node
*rp
;
1022 struct ripng_info
*rinfo
= NULL
;
1023 struct list
*list
= NULL
;
1028 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1029 if ((list
= rp
->info
) != NULL
) {
1030 rinfo
= listgetdata(listhead(list
));
1031 if ((rinfo
->type
== type
)
1032 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1033 /* Perform poisoned reverse. */
1034 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1035 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1036 ripng_garbage_collect
,
1037 ripng
->garbage_time
);
1038 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1040 /* Aggregate count decrement. */
1041 ripng_aggregate_decrement(rp
, rinfo
);
1043 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1045 if (IS_RIPNG_DEBUG_EVENT
) {
1046 struct prefix_ipv6
*p
=
1047 (struct prefix_ipv6
*)&rp
->p
;
1050 "Poisone %s/%d on the interface %s [withdraw]",
1051 inet6_ntoa(p
->prefix
),
1053 ifindex2ifname(rinfo
->ifindex
,
1057 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1062 /* RIP routing information. */
1063 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1064 struct sockaddr_in6
*from
,
1065 struct interface
*ifp
, int hoplimit
)
1069 struct ripng_nexthop nexthop
;
1071 /* RFC2080 2.4.2 Response Messages:
1072 The Response must be ignored if it is not from the RIPng port. */
1073 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1074 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1075 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1076 ripng_peer_bad_packet(from
);
1080 /* The datagram's IPv6 source address should be checked to see
1081 whether the datagram is from a valid neighbor; the source of the
1082 datagram must be a link-local address. */
1083 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1084 zlog_warn("RIPng packet comes from non link local address %s",
1085 inet6_ntoa(from
->sin6_addr
));
1086 ripng_peer_bad_packet(from
);
1090 /* It is also worth checking to see whether the response is from one
1091 of the router's own addresses. Interfaces on broadcast networks
1092 may receive copies of their own multicasts immediately. If a
1093 router processes its own output as new input, confusion is likely,
1094 and such datagrams must be ignored. */
1095 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1097 "RIPng packet comes from my own link local address %s",
1098 inet6_ntoa(from
->sin6_addr
));
1099 ripng_peer_bad_packet(from
);
1103 /* As an additional check, periodic advertisements must have their
1104 hop counts set to 255, and inbound, multicast packets sent from the
1105 RIPng port (i.e. periodic advertisement or triggered update
1106 packets) must be examined to ensure that the hop count is 255. */
1107 if (hoplimit
>= 0 && hoplimit
!= 255) {
1109 "RIPng packet comes with non 255 hop count %d from %s",
1110 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1111 ripng_peer_bad_packet(from
);
1115 /* Update RIPng peer. */
1116 ripng_peer_update(from
, packet
->version
);
1118 /* Reset nexthop. */
1119 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1120 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1122 /* Set RTE pointer. */
1125 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1126 /* First of all, we have to check this RTE is next hop RTE or
1127 not. Next hop RTE is completely different with normal RTE so
1128 we need special treatment. */
1129 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1130 ripng_nexthop_rte(rte
, from
, &nexthop
);
1134 /* RTE information validation. */
1136 /* - is the destination prefix valid (e.g., not a multicast
1137 prefix and not a link-local address) A link-local address
1138 should never be present in an RTE. */
1139 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1141 "Destination prefix is a multicast address %s/%d [%d]",
1142 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1144 ripng_peer_bad_route(from
);
1147 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1149 "Destination prefix is a link-local address %s/%d [%d]",
1150 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1152 ripng_peer_bad_route(from
);
1155 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1157 "Destination prefix is a loopback address %s/%d [%d]",
1158 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1160 ripng_peer_bad_route(from
);
1164 /* - is the prefix length valid (i.e., between 0 and 128,
1166 if (rte
->prefixlen
> 128) {
1167 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1168 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1169 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1170 ripng_peer_bad_route(from
);
1174 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1175 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1176 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1177 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1178 ripng_peer_bad_route(from
);
1182 /* Vincent: XXX Should we compute the direclty reachable nexthop
1183 * for our RIPng network ?
1186 /* Routing table updates. */
1187 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1191 /* Response to request message. */
1192 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1193 struct sockaddr_in6
*from
,
1194 struct interface
*ifp
)
1198 struct prefix_ipv6 p
;
1199 struct route_node
*rp
;
1200 struct ripng_info
*rinfo
;
1201 struct ripng_interface
*ri
;
1203 /* Does not reponse to the requests on the loopback interfaces */
1204 if (if_is_loopback(ifp
))
1207 /* Check RIPng process is enabled on this interface. */
1212 /* When passive interface is specified, suppress responses */
1216 /* RIPng peer update. */
1217 ripng_peer_update(from
, packet
->version
);
1219 lim
= ((caddr_t
)packet
) + size
;
1222 /* The Request is processed entry by entry. If there are no
1223 entries, no response is given. */
1224 if (lim
== (caddr_t
)rte
)
1227 /* There is one special case. If there is exactly one entry in the
1228 request, and it has a destination prefix of zero, a prefix length
1229 of zero, and a metric of infinity (i.e., 16), then this is a
1230 request to send the entire routing table. In that case, a call
1231 is made to the output process to send the routing table to the
1232 requesting address/port. */
1233 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1234 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1235 /* All route with split horizon */
1236 ripng_output_process(ifp
, from
, ripng_all_route
);
1238 /* Except for this special case, processing is quite simple.
1239 Examine the list of RTEs in the Request one by one. For each
1240 entry, look up the destination in the router's routing
1241 database and, if there is a route, put that route's metric in
1242 the metric field of the RTE. If there is no explicit route
1243 to the specified destination, put infinity in the metric
1244 field. Once all the entries have been filled in, change the
1245 command from Request to Response and send the datagram back
1246 to the requestor. */
1247 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1248 p
.family
= AF_INET6
;
1250 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1251 p
.prefix
= rte
->addr
;
1252 p
.prefixlen
= rte
->prefixlen
;
1253 apply_mask_ipv6(&p
);
1255 rp
= route_node_lookup(ripng
->table
,
1256 (struct prefix
*)&p
);
1259 rinfo
= listgetdata(
1260 listhead((struct list
*)rp
->info
));
1261 rte
->metric
= rinfo
->metric
;
1262 route_unlock_node(rp
);
1264 rte
->metric
= RIPNG_METRIC_INFINITY
;
1266 packet
->command
= RIPNG_RESPONSE
;
1268 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1272 /* First entry point of reading RIPng packet. */
1273 static int ripng_read(struct thread
*thread
)
1277 struct sockaddr_in6 from
;
1278 struct ripng_packet
*packet
;
1279 ifindex_t ifindex
= 0;
1280 struct interface
*ifp
;
1283 /* Check ripng is active and alive. */
1284 assert(ripng
!= NULL
);
1285 assert(ripng
->sock
>= 0);
1287 /* Fetch thread data and set read pointer to empty for event
1288 managing. `sock' sould be same as ripng->sock. */
1289 sock
= THREAD_FD(thread
);
1290 ripng
->t_read
= NULL
;
1292 /* Add myself to the next event. */
1293 ripng_event(RIPNG_READ
, sock
);
1295 /* Read RIPng packet. */
1296 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1297 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1300 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1304 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1305 (4)) must be multiple size of one RTE size (20). */
1306 if (((len
- 4) % 20) != 0) {
1307 zlog_warn("RIPng invalid packet size %d from %s", len
,
1308 inet6_ntoa(from
.sin6_addr
));
1309 ripng_peer_bad_packet(&from
);
1313 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1314 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1316 /* RIPng packet received. */
1317 if (IS_RIPNG_DEBUG_EVENT
)
1318 zlog_debug("RIPng packet received from %s port %d on %s",
1319 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1320 ifp
? ifp
->name
: "unknown");
1322 /* Logging before packet checking. */
1323 if (IS_RIPNG_DEBUG_RECV
)
1324 ripng_packet_dump(packet
, len
, "RECV");
1326 /* Packet comes from unknown interface. */
1328 zlog_warn("RIPng packet comes from unknown interface %d",
1333 /* Packet version mismatch checking. */
1334 if (packet
->version
!= ripng
->version
) {
1336 "RIPng packet version %d doesn't fit to my version %d",
1337 packet
->version
, ripng
->version
);
1338 ripng_peer_bad_packet(&from
);
1342 /* Process RIPng packet. */
1343 switch (packet
->command
) {
1345 ripng_request_process(packet
, len
, &from
, ifp
);
1347 case RIPNG_RESPONSE
:
1348 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1351 zlog_warn("Invalid RIPng command %d", packet
->command
);
1352 ripng_peer_bad_packet(&from
);
1358 /* Walk down the RIPng routing table then clear changed flag. */
1359 static void ripng_clear_changed_flag(void)
1361 struct route_node
*rp
;
1362 struct ripng_info
*rinfo
= NULL
;
1363 struct list
*list
= NULL
;
1364 struct listnode
*listnode
= NULL
;
1366 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1367 if ((list
= rp
->info
) != NULL
)
1368 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1369 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1370 /* This flag can be set only on the first entry.
1376 /* Regular update of RIPng route. Send all routing formation to RIPng
1377 enabled interface. */
1378 static int ripng_update(struct thread
*t
)
1380 struct listnode
*node
;
1381 struct interface
*ifp
;
1382 struct ripng_interface
*ri
;
1384 /* Clear update timer thread. */
1385 ripng
->t_update
= NULL
;
1387 /* Logging update event. */
1388 if (IS_RIPNG_DEBUG_EVENT
)
1389 zlog_debug("RIPng update timer expired!");
1391 /* Supply routes to each interface. */
1392 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1395 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1401 /* When passive interface is specified, suppress announce to the
1407 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1408 if (IS_RIPNG_DEBUG_EVENT
)
1410 "[Event] RIPng send to if %d is suppressed by config",
1414 #endif /* RIPNG_ADVANCED */
1416 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1419 /* Triggered updates may be suppressed if a regular update is due by
1420 the time the triggered update would be sent. */
1421 if (ripng
->t_triggered_interval
) {
1422 thread_cancel(ripng
->t_triggered_interval
);
1423 ripng
->t_triggered_interval
= NULL
;
1427 /* Reset flush event. */
1428 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1433 /* Triggered update interval timer. */
1434 static int ripng_triggered_interval(struct thread
*t
)
1436 ripng
->t_triggered_interval
= NULL
;
1438 if (ripng
->trigger
) {
1440 ripng_triggered_update(t
);
1445 /* Execute triggered update. */
1446 int ripng_triggered_update(struct thread
*t
)
1448 struct listnode
*node
;
1449 struct interface
*ifp
;
1450 struct ripng_interface
*ri
;
1453 ripng
->t_triggered_update
= NULL
;
1455 /* Cancel interval timer. */
1456 if (ripng
->t_triggered_interval
) {
1457 thread_cancel(ripng
->t_triggered_interval
);
1458 ripng
->t_triggered_interval
= NULL
;
1462 /* Logging triggered update. */
1463 if (IS_RIPNG_DEBUG_EVENT
)
1464 zlog_debug("RIPng triggered update!");
1466 /* Split Horizon processing is done when generating triggered
1467 updates as well as normal updates (see section 2.6). */
1468 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1471 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1477 /* When passive interface is specified, suppress announce to the
1482 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1485 /* Once all of the triggered updates have been generated, the route
1486 change flags should be cleared. */
1487 ripng_clear_changed_flag();
1489 /* After a triggered update is sent, a timer should be set for a
1490 random interval between 1 and 5 seconds. If other changes that
1491 would trigger updates occur before the timer expires, a single
1492 update is triggered when the timer expires. */
1493 interval
= (random() % 5) + 1;
1495 ripng
->t_triggered_interval
= NULL
;
1496 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1497 &ripng
->t_triggered_interval
);
1502 /* Write routing table entry to the stream and return next index of
1503 the routing table entry in the stream. */
1504 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1505 struct in6_addr
*nexthop
, u_int16_t tag
, u_char metric
)
1507 /* RIPng packet header. */
1509 stream_putc(s
, RIPNG_RESPONSE
);
1510 stream_putc(s
, RIPNG_V1
);
1514 /* Write routing table entry. */
1516 stream_write(s
, (u_char
*)&p
->prefix
, sizeof(struct in6_addr
));
1518 stream_write(s
, (u_char
*)nexthop
, sizeof(struct in6_addr
));
1519 stream_putw(s
, tag
);
1521 stream_putc(s
, p
->prefixlen
);
1524 stream_putc(s
, metric
);
1529 /* Send RESPONSE message to specified destination. */
1530 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1534 struct route_node
*rp
;
1535 struct ripng_info
*rinfo
;
1536 struct ripng_interface
*ri
;
1537 struct ripng_aggregate
*aggregate
;
1538 struct prefix_ipv6
*p
;
1539 struct list
*ripng_rte_list
;
1540 struct list
*list
= NULL
;
1541 struct listnode
*listnode
= NULL
;
1543 if (IS_RIPNG_DEBUG_EVENT
) {
1545 zlog_debug("RIPng update routes to neighbor %s",
1546 inet6_ntoa(to
->sin6_addr
));
1548 zlog_debug("RIPng update routes on interface %s",
1552 /* Get RIPng interface. */
1555 ripng_rte_list
= ripng_rte_new();
1557 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1558 if ((list
= rp
->info
) != NULL
1559 && (rinfo
= listgetdata(listhead(list
))) != NULL
1560 && rinfo
->suppress
== 0) {
1561 /* If no route-map are applied, the RTE will be these
1565 p
= (struct prefix_ipv6
*)&rp
->p
;
1566 rinfo
->metric_out
= rinfo
->metric
;
1567 rinfo
->tag_out
= rinfo
->tag
;
1568 memset(&rinfo
->nexthop_out
, 0,
1569 sizeof(rinfo
->nexthop_out
));
1570 /* In order to avoid some local loops,
1571 * if the RIPng route has a nexthop via this interface,
1573 * otherwise set it to 0. The nexthop should not be
1575 * beyond the local broadcast/multicast area in order
1576 * to avoid an IGP multi-level recursive look-up.
1578 if (rinfo
->ifindex
== ifp
->ifindex
)
1579 rinfo
->nexthop_out
= rinfo
->nexthop
;
1581 /* Apply output filters. */
1582 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1586 /* Changed route only output. */
1587 if (route_type
== ripng_changed_route
1588 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1591 /* Split horizon. */
1592 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1593 /* We perform split horizon for RIPng routes. */
1595 struct ripng_info
*tmp_rinfo
= NULL
;
1597 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1599 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1600 && tmp_rinfo
->ifindex
1609 /* Preparation for route-map. */
1610 rinfo
->metric_set
= 0;
1613 * and tag_out are already initialized.
1616 /* Interface route-map */
1617 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1620 ret
= route_map_apply(
1621 ri
->routemap
[RIPNG_FILTER_OUT
],
1622 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1624 if (ret
== RMAP_DENYMATCH
) {
1625 if (IS_RIPNG_DEBUG_PACKET
)
1627 "RIPng %s/%d is filtered by route-map out",
1628 inet6_ntoa(p
->prefix
),
1634 /* Redistribute route-map. */
1635 if (ripng
->route_map
[rinfo
->type
].name
) {
1638 ret
= route_map_apply(
1639 ripng
->route_map
[rinfo
->type
].map
,
1640 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1642 if (ret
== RMAP_DENYMATCH
) {
1643 if (IS_RIPNG_DEBUG_PACKET
)
1645 "RIPng %s/%d is filtered by route-map",
1646 inet6_ntoa(p
->prefix
),
1652 /* When the route-map does not set metric. */
1653 if (!rinfo
->metric_set
) {
1654 /* If the redistribute metric is set. */
1655 if (ripng
->route_map
[rinfo
->type
].metric_config
1656 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1658 ripng
->route_map
[rinfo
->type
]
1661 /* If the route is not connected or
1663 one, use default-metric value */
1664 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1666 != ZEBRA_ROUTE_CONNECT
1668 != RIPNG_METRIC_INFINITY
)
1670 ripng
->default_metric
;
1674 /* Apply offset-list */
1675 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1676 ripng_offset_list_apply_out(p
, ifp
,
1677 &rinfo
->metric_out
);
1679 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1680 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1682 /* Perform split-horizon with poisoned reverse
1685 if (ri
->split_horizon
1686 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1687 struct ripng_info
*tmp_rinfo
= NULL
;
1689 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1691 if ((tmp_rinfo
->type
1692 == ZEBRA_ROUTE_RIPNG
)
1693 && tmp_rinfo
->ifindex
1696 RIPNG_METRIC_INFINITY
;
1699 /* Add RTE to the list */
1700 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1703 /* Process the aggregated RTE entry */
1704 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1705 && aggregate
->suppress
== 0) {
1706 /* If no route-map are applied, the RTE will be these
1710 p
= (struct prefix_ipv6
*)&rp
->p
;
1711 aggregate
->metric_set
= 0;
1712 aggregate
->metric_out
= aggregate
->metric
;
1713 aggregate
->tag_out
= aggregate
->tag
;
1714 memset(&aggregate
->nexthop_out
, 0,
1715 sizeof(aggregate
->nexthop_out
));
1717 /* Apply output filters.*/
1718 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1722 /* Interface route-map */
1723 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1725 struct ripng_info newinfo
;
1727 /* let's cast the aggregate structure to
1729 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1730 /* the nexthop is :: */
1731 newinfo
.metric
= aggregate
->metric
;
1732 newinfo
.metric_out
= aggregate
->metric_out
;
1733 newinfo
.tag
= aggregate
->tag
;
1734 newinfo
.tag_out
= aggregate
->tag_out
;
1736 ret
= route_map_apply(
1737 ri
->routemap
[RIPNG_FILTER_OUT
],
1738 (struct prefix
*)p
, RMAP_RIPNG
,
1741 if (ret
== RMAP_DENYMATCH
) {
1742 if (IS_RIPNG_DEBUG_PACKET
)
1744 "RIPng %s/%d is filtered by route-map out",
1745 inet6_ntoa(p
->prefix
),
1750 aggregate
->metric_out
= newinfo
.metric_out
;
1751 aggregate
->tag_out
= newinfo
.tag_out
;
1752 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1753 aggregate
->nexthop_out
=
1754 newinfo
.nexthop_out
;
1757 /* There is no redistribute routemap for the aggregated
1760 /* Changed route only output. */
1761 /* XXX, vincent, in order to increase time convergence,
1762 * it should be announced if a child has changed.
1764 if (route_type
== ripng_changed_route
)
1767 /* Apply offset-list */
1768 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1769 ripng_offset_list_apply_out(
1770 p
, ifp
, &aggregate
->metric_out
);
1772 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1773 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1775 /* Add RTE to the list */
1776 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1780 /* Flush the list */
1781 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1782 ripng_rte_free(ripng_rte_list
);
1785 /* Create new RIPng instance and set it to global variable. */
1786 static int ripng_create(void)
1788 /* ripng should be NULL. */
1789 assert(ripng
== NULL
);
1791 /* Allocaste RIPng instance. */
1792 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1794 /* Default version and timer values. */
1795 ripng
->version
= RIPNG_V1
;
1796 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1797 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1798 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1799 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1802 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1803 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1805 /* Initialize RIPng routig table. */
1806 ripng
->table
= route_table_init();
1807 ripng
->route
= route_table_init();
1808 ripng
->aggregate
= route_table_init();
1811 ripng
->sock
= ripng_make_socket();
1812 if (ripng
->sock
< 0)
1816 ripng_event(RIPNG_READ
, ripng
->sock
);
1817 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1822 /* Send RIPng request to the interface. */
1823 int ripng_request(struct interface
*ifp
)
1826 struct ripng_packet ripng_packet
;
1828 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1830 if (if_is_loopback(ifp
))
1833 /* If interface is down, don't send RIP packet. */
1837 if (IS_RIPNG_DEBUG_EVENT
)
1838 zlog_debug("RIPng send request to %s", ifp
->name
);
1840 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1841 ripng_packet
.command
= RIPNG_REQUEST
;
1842 ripng_packet
.version
= RIPNG_V1
;
1843 rte
= ripng_packet
.rte
;
1844 rte
->metric
= RIPNG_METRIC_INFINITY
;
1846 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1851 static int ripng_update_jitter(int time
)
1853 return ((random() % (time
+ 1)) - (time
/ 2));
1856 void ripng_event(enum ripng_event event
, int sock
)
1862 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1864 case RIPNG_UPDATE_EVENT
:
1865 if (ripng
->t_update
) {
1866 thread_cancel(ripng
->t_update
);
1867 ripng
->t_update
= NULL
;
1869 /* Update timer jitter. */
1870 jitter
= ripng_update_jitter(ripng
->update_time
);
1872 ripng
->t_update
= NULL
;
1873 thread_add_timer(master
, ripng_update
, NULL
,
1874 sock
? 2 : ripng
->update_time
+ jitter
,
1877 case RIPNG_TRIGGERED_UPDATE
:
1878 if (ripng
->t_triggered_interval
)
1881 thread_add_event(master
, ripng_triggered_update
, NULL
,
1882 0, &ripng
->t_triggered_update
);
1890 /* Print out routes update time. */
1891 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1896 char timebuf
[TIME_BUF
];
1897 struct thread
*thread
;
1899 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1900 clock
= thread_timer_remain_second(thread
);
1901 tm
= gmtime(&clock
);
1902 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1903 vty_out(vty
, "%5s", timebuf
);
1904 } else if ((thread
= rinfo
->t_garbage_collect
) != 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
);
1912 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1917 if (rinfo
->suppress
)
1920 switch (rinfo
->sub_type
) {
1921 case RIPNG_ROUTE_RTE
:
1924 case RIPNG_ROUTE_STATIC
:
1927 case RIPNG_ROUTE_DEFAULT
:
1930 case RIPNG_ROUTE_REDISTRIBUTE
:
1933 case RIPNG_ROUTE_INTERFACE
:
1944 DEFUN (show_ipv6_ripng
,
1945 show_ipv6_ripng_cmd
,
1949 "Show RIPng routes\n")
1951 struct route_node
*rp
;
1952 struct ripng_info
*rinfo
;
1953 struct ripng_aggregate
*aggregate
;
1954 struct prefix_ipv6
*p
;
1955 struct list
*list
= NULL
;
1956 struct listnode
*listnode
= NULL
;
1962 /* Header of display. */
1964 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1966 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1967 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1968 " Network Next Hop Via Metric Tag Time\n");
1970 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1971 if ((aggregate
= rp
->aggregate
) != NULL
) {
1972 p
= (struct prefix_ipv6
*)&rp
->p
;
1975 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1976 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1979 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1983 vty_out(vty
, "%*s", 18, " ");
1985 vty_out(vty
, "%*s", 28, " ");
1986 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1987 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1990 if ((list
= rp
->info
) != NULL
)
1991 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1992 p
= (struct prefix_ipv6
*)&rp
->p
;
1995 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1996 zebra_route_char(rinfo
->type
),
1997 ripng_route_subtype_print(rinfo
),
1998 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2001 vty_out(vty
, "%c(%s) %s/%d ",
2002 zebra_route_char(rinfo
->type
),
2003 ripng_route_subtype_print(rinfo
),
2004 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2007 vty_out(vty
, "%*s", 18, " ");
2008 len
= vty_out(vty
, "%s",
2009 inet6_ntoa(rinfo
->nexthop
));
2013 vty_out(vty
, "%*s", len
, " ");
2016 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2017 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2020 ifindex2ifname(rinfo
->ifindex
,
2022 } else if (rinfo
->metric
2023 == RIPNG_METRIC_INFINITY
) {
2024 len
= vty_out(vty
, "kill");
2026 len
= vty_out(vty
, "self");
2030 vty_out(vty
, "%*s", len
, " ");
2032 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2033 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2036 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2037 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2038 /* RTE from remote RIP routers */
2039 ripng_vty_out_uptime(vty
, rinfo
);
2040 } else if (rinfo
->metric
2041 == RIPNG_METRIC_INFINITY
) {
2042 /* poisonous reversed routes (gc) */
2043 ripng_vty_out_uptime(vty
, rinfo
);
2053 DEFUN (show_ipv6_ripng_status
,
2054 show_ipv6_ripng_status_cmd
,
2055 "show ipv6 ripng status",
2058 "Show RIPng routes\n"
2059 "IPv6 routing protocol process parameters and statistics\n")
2061 struct listnode
*node
;
2062 struct interface
*ifp
;
2067 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2068 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2069 ripng
->update_time
);
2070 vty_out(vty
, " next due in %lu seconds\n",
2071 thread_timer_remain_second(ripng
->t_update
));
2072 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2073 vty_out(vty
, " garbage collect after %ld seconds\n",
2074 ripng
->garbage_time
);
2076 /* Filtering status show. */
2077 config_show_distribute(vty
);
2079 /* Default metric information. */
2080 vty_out(vty
, " Default redistribution metric is %d\n",
2081 ripng
->default_metric
);
2083 /* Redistribute information. */
2084 vty_out(vty
, " Redistributing:");
2085 ripng_redistribute_write(vty
, 0);
2088 vty_out(vty
, " Default version control: send version %d,",
2090 vty_out(vty
, " receive version %d \n", ripng
->version
);
2092 vty_out(vty
, " Interface Send Recv\n");
2094 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
2095 struct ripng_interface
*ri
;
2099 if (ri
->enable_network
|| ri
->enable_interface
) {
2101 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2102 ripng
->version
, ripng
->version
);
2106 vty_out(vty
, " Routing for Networks:\n");
2107 ripng_network_write(vty
, 0);
2109 vty_out(vty
, " Routing Information Sources:\n");
2111 " Gateway BadPackets BadRoutes Distance Last Update\n");
2112 ripng_peer_display(vty
);
2117 DEFUN (clear_ipv6_rip
,
2122 "Clear IPv6 RIP database\n")
2124 struct route_node
*rp
;
2125 struct ripng_info
*rinfo
;
2127 struct listnode
*listnode
;
2129 /* Clear received RIPng routes */
2130 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2135 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2136 if (!ripng_route_rte(rinfo
))
2139 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2140 ripng_zebra_ipv6_delete(rp
);
2145 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2146 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2147 listnode_delete(list
, rinfo
);
2148 ripng_info_free(rinfo
);
2151 if (list_isempty(list
)) {
2152 list_delete_and_null(&list
);
2154 route_unlock_node(rp
);
2161 DEFUN_NOSH (router_ripng
,
2164 "Enable a routing process\n"
2165 "Make RIPng instance command\n")
2169 vty
->node
= RIPNG_NODE
;
2172 ret
= ripng_create();
2174 /* Notice to user we couldn't create RIPng. */
2176 zlog_warn("can't create RIPng");
2177 return CMD_WARNING_CONFIG_FAILED
;
2184 DEFUN (no_router_ripng
,
2185 no_router_ripng_cmd
,
2188 "Enable a routing process\n"
2189 "Make RIPng instance command\n")
2199 "Static route setup\n"
2200 "Set static RIPng route announcement\n")
2202 int idx_ipv6addr
= 1;
2204 struct prefix_ipv6 p
;
2205 struct route_node
*rp
;
2207 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2208 (struct prefix_ipv6
*)&p
);
2210 vty_out(vty
, "Malformed address\n");
2211 return CMD_WARNING_CONFIG_FAILED
;
2213 apply_mask_ipv6(&p
);
2215 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2217 vty_out(vty
, "There is already same static route.\n");
2218 route_unlock_node(rp
);
2221 rp
->info
= (void *)1;
2223 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2229 DEFUN (no_ripng_route
,
2231 "no route IPV6ADDR",
2233 "Static route setup\n"
2234 "Delete static RIPng route announcement\n")
2236 int idx_ipv6addr
= 2;
2238 struct prefix_ipv6 p
;
2239 struct route_node
*rp
;
2241 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2242 (struct prefix_ipv6
*)&p
);
2244 vty_out(vty
, "Malformed address\n");
2245 return CMD_WARNING_CONFIG_FAILED
;
2247 apply_mask_ipv6(&p
);
2249 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2251 vty_out(vty
, "Can't find static route.\n");
2252 return CMD_WARNING_CONFIG_FAILED
;
2255 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2256 route_unlock_node(rp
);
2259 route_unlock_node(rp
);
2264 DEFUN (ripng_aggregate_address
,
2265 ripng_aggregate_address_cmd
,
2266 "aggregate-address X:X::X:X/M",
2267 "Set aggregate RIPng route announcement\n"
2268 "Aggregate network\n")
2270 int idx_ipv6_prefixlen
= 1;
2273 struct route_node
*node
;
2275 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2276 (struct prefix_ipv6
*)&p
);
2278 vty_out(vty
, "Malformed address\n");
2279 return CMD_WARNING_CONFIG_FAILED
;
2282 /* Check aggregate alredy exist or not. */
2283 node
= route_node_get(ripng
->aggregate
, &p
);
2285 vty_out(vty
, "There is already same aggregate route.\n");
2286 route_unlock_node(node
);
2289 node
->info
= (void *)1;
2291 ripng_aggregate_add(&p
);
2296 DEFUN (no_ripng_aggregate_address
,
2297 no_ripng_aggregate_address_cmd
,
2298 "no aggregate-address X:X::X:X/M",
2300 "Delete aggregate RIPng route announcement\n"
2301 "Aggregate network\n")
2303 int idx_ipv6_prefixlen
= 2;
2306 struct route_node
*rn
;
2308 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2309 (struct prefix_ipv6
*)&p
);
2311 vty_out(vty
, "Malformed address\n");
2312 return CMD_WARNING_CONFIG_FAILED
;
2315 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2317 vty_out(vty
, "Can't find aggregate route.\n");
2318 return CMD_WARNING_CONFIG_FAILED
;
2320 route_unlock_node(rn
);
2322 route_unlock_node(rn
);
2324 ripng_aggregate_delete(&p
);
2329 DEFUN (ripng_default_metric
,
2330 ripng_default_metric_cmd
,
2331 "default-metric (1-16)",
2332 "Set a metric of redistribute routes\n"
2337 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2342 DEFUN (no_ripng_default_metric
,
2343 no_ripng_default_metric_cmd
,
2344 "no default-metric [(1-16)]",
2346 "Set a metric of redistribute routes\n"
2350 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2357 /* RIPng update timer setup. */
2358 DEFUN (ripng_update_timer
,
2359 ripng_update_timer_cmd
,
2360 "update-timer SECOND",
2361 "Set RIPng update timer in seconds\n"
2364 unsigned long update
;
2365 char *endptr
= NULL
;
2367 update
= strtoul (argv
[0], &endptr
, 10);
2368 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2370 vty_out (vty
, "update timer value error\n");
2371 return CMD_WARNING_CONFIG_FAILED
;
2374 ripng
->update_time
= update
;
2376 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2380 DEFUN (no_ripng_update_timer
,
2381 no_ripng_update_timer_cmd
,
2382 "no update-timer SECOND",
2384 "Unset RIPng update timer in seconds\n"
2387 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2388 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2392 /* RIPng timeout timer setup. */
2393 DEFUN (ripng_timeout_timer
,
2394 ripng_timeout_timer_cmd
,
2395 "timeout-timer SECOND",
2396 "Set RIPng timeout timer in seconds\n"
2399 unsigned long timeout
;
2400 char *endptr
= NULL
;
2402 timeout
= strtoul (argv
[0], &endptr
, 10);
2403 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2405 vty_out (vty
, "timeout timer value error\n");
2406 return CMD_WARNING_CONFIG_FAILED
;
2409 ripng
->timeout_time
= timeout
;
2414 DEFUN (no_ripng_timeout_timer
,
2415 no_ripng_timeout_timer_cmd
,
2416 "no timeout-timer SECOND",
2418 "Unset RIPng timeout timer in seconds\n"
2421 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2425 /* RIPng garbage timer setup. */
2426 DEFUN (ripng_garbage_timer
,
2427 ripng_garbage_timer_cmd
,
2428 "garbage-timer SECOND",
2429 "Set RIPng garbage timer in seconds\n"
2432 unsigned long garbage
;
2433 char *endptr
= NULL
;
2435 garbage
= strtoul (argv
[0], &endptr
, 10);
2436 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2438 vty_out (vty
, "garbage timer value error\n");
2439 return CMD_WARNING_CONFIG_FAILED
;
2442 ripng
->garbage_time
= garbage
;
2447 DEFUN (no_ripng_garbage_timer
,
2448 no_ripng_garbage_timer_cmd
,
2449 "no garbage-timer SECOND",
2451 "Unset RIPng garbage timer in seconds\n"
2454 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2459 DEFUN (ripng_timers
,
2461 "timers basic (0-65535) (0-65535) (0-65535)",
2462 "RIPng timers setup\n"
2464 "Routing table update timer value in second. Default is 30.\n"
2465 "Routing information timeout timer. Default is 180.\n"
2466 "Garbage collection timer. Default is 120.\n")
2469 int idx_number_2
= 3;
2470 int idx_number_3
= 4;
2471 unsigned long update
;
2472 unsigned long timeout
;
2473 unsigned long garbage
;
2475 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2476 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2477 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2479 /* Set each timer value. */
2480 ripng
->update_time
= update
;
2481 ripng
->timeout_time
= timeout
;
2482 ripng
->garbage_time
= garbage
;
2484 /* Reset update timer thread. */
2485 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2490 DEFUN (no_ripng_timers
,
2491 no_ripng_timers_cmd
,
2492 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2494 "RIPng timers setup\n"
2496 "Routing table update timer value in second. Default is 30.\n"
2497 "Routing information timeout timer. Default is 180.\n"
2498 "Garbage collection timer. Default is 120.\n")
2500 /* Set each timer value to the default. */
2501 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2502 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2503 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2505 /* Reset update timer thread. */
2506 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2512 DEFUN (show_ipv6_protocols
,
2513 show_ipv6_protocols_cmd
,
2514 "show ipv6 protocols",
2517 "Routing protocol information\n")
2522 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2524 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2525 ripng
->update_time
, 0);
2527 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2528 ripng
->timeout_time
,
2529 ripng
->garbage_time
);
2531 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2532 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2538 /* Please be carefull to use this command. */
2539 DEFUN (ripng_default_information_originate
,
2540 ripng_default_information_originate_cmd
,
2541 "default-information originate",
2542 "Default route information\n"
2543 "Distribute default route\n")
2545 struct prefix_ipv6 p
;
2547 if (!ripng
->default_information
) {
2548 ripng
->default_information
= 1;
2550 str2prefix_ipv6("::/0", &p
);
2551 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2558 DEFUN (no_ripng_default_information_originate
,
2559 no_ripng_default_information_originate_cmd
,
2560 "no default-information originate",
2562 "Default route information\n"
2563 "Distribute default route\n")
2565 struct prefix_ipv6 p
;
2567 if (ripng
->default_information
) {
2568 ripng
->default_information
= 0;
2570 str2prefix_ipv6("::/0", &p
);
2571 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2572 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2578 /* Update ECMP routes to zebra when ECMP is disabled. */
2579 static void ripng_ecmp_disable(void)
2581 struct route_node
*rp
;
2582 struct ripng_info
*rinfo
, *tmp_rinfo
;
2584 struct listnode
*node
, *nextnode
;
2589 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2590 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2591 rinfo
= listgetdata(listhead(list
));
2592 if (!ripng_route_rte(rinfo
))
2595 /* Drop all other entries, except the first one. */
2596 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2597 if (tmp_rinfo
!= rinfo
) {
2598 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2600 tmp_rinfo
->t_garbage_collect
);
2601 list_delete_node(list
, node
);
2602 ripng_info_free(tmp_rinfo
);
2606 ripng_zebra_ipv6_add(rp
);
2608 /* Set the route change flag. */
2609 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2611 /* Signal the output process to trigger an update. */
2612 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2616 DEFUN (ripng_allow_ecmp
,
2617 ripng_allow_ecmp_cmd
,
2619 "Allow Equal Cost MultiPath\n")
2622 vty_out(vty
, "ECMP is already enabled.\n");
2627 zlog_info("ECMP is enabled.");
2631 DEFUN (no_ripng_allow_ecmp
,
2632 no_ripng_allow_ecmp_cmd
,
2635 "Allow Equal Cost MultiPath\n")
2638 vty_out(vty
, "ECMP is already disabled.\n");
2643 zlog_info("ECMP is disabled.");
2644 ripng_ecmp_disable();
2648 /* RIPng configuration write function. */
2649 static int ripng_config_write(struct vty
*vty
)
2651 int ripng_network_write(struct vty
*, int);
2652 void ripng_redistribute_write(struct vty
*, int);
2654 struct route_node
*rp
;
2659 vty_out(vty
, "router ripng\n");
2661 if (ripng
->default_information
)
2662 vty_out(vty
, " default-information originate\n");
2664 ripng_network_write(vty
, 1);
2666 /* RIPng default metric configuration */
2667 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2668 vty_out(vty
, " default-metric %d\n",
2669 ripng
->default_metric
);
2671 ripng_redistribute_write(vty
, 1);
2673 /* RIP offset-list configuration. */
2674 config_write_ripng_offset_list(vty
);
2676 /* RIPng aggregate routes. */
2677 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2678 if (rp
->info
!= NULL
)
2679 vty_out(vty
, " aggregate-address %s/%d\n",
2680 inet6_ntoa(rp
->p
.u
.prefix6
),
2683 /* ECMP configuration. */
2685 vty_out(vty
, " allow-ecmp\n");
2687 /* RIPng static routes. */
2688 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2689 if (rp
->info
!= NULL
)
2690 vty_out(vty
, " route %s/%d\n",
2691 inet6_ntoa(rp
->p
.u
.prefix6
),
2694 /* RIPng timers configuration. */
2695 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2696 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2697 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2698 vty_out(vty
, " timers basic %ld %ld %ld\n",
2699 ripng
->update_time
, ripng
->timeout_time
,
2700 ripng
->garbage_time
);
2703 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2704 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2705 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2706 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2707 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2708 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2711 write
+= config_write_distribute(vty
);
2713 write
+= config_write_if_rmap(vty
);
2720 /* RIPng node structure. */
2721 static struct cmd_node cmd_ripng_node
= {
2722 RIPNG_NODE
, "%s(config-router)# ", 1,
2725 static void ripng_distribute_update(struct distribute
*dist
)
2727 struct interface
*ifp
;
2728 struct ripng_interface
*ri
;
2729 struct access_list
*alist
;
2730 struct prefix_list
*plist
;
2735 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2741 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2742 alist
= access_list_lookup(AFI_IP6
,
2743 dist
->list
[DISTRIBUTE_V6_IN
]);
2745 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2747 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2749 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2751 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2752 alist
= access_list_lookup(AFI_IP6
,
2753 dist
->list
[DISTRIBUTE_V6_OUT
]);
2755 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2757 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2759 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2761 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2762 plist
= prefix_list_lookup(AFI_IP6
,
2763 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2765 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2767 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2769 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2771 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2772 plist
= prefix_list_lookup(AFI_IP6
,
2773 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2775 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2777 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2779 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2782 void ripng_distribute_update_interface(struct interface
*ifp
)
2784 struct distribute
*dist
;
2786 dist
= distribute_lookup(ifp
->name
);
2788 ripng_distribute_update(dist
);
2791 /* Update all interface's distribute list. */
2792 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2794 struct interface
*ifp
;
2795 struct listnode
*node
;
2797 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2798 ripng_distribute_update_interface(ifp
);
2801 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2803 ripng_distribute_update_all(NULL
);
2806 /* delete all the added ripng routes. */
2810 struct route_node
*rp
;
2811 struct ripng_info
*rinfo
;
2812 struct ripng_aggregate
*aggregate
;
2813 struct list
*list
= NULL
;
2814 struct listnode
*listnode
= NULL
;
2817 /* Clear RIPng routes */
2818 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2819 if ((list
= rp
->info
) != NULL
) {
2820 rinfo
= listgetdata(listhead(list
));
2821 if (ripng_route_rte(rinfo
))
2822 ripng_zebra_ipv6_delete(rp
);
2824 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2826 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2828 rinfo
->t_garbage_collect
);
2829 ripng_info_free(rinfo
);
2831 list_delete_and_null(&list
);
2833 route_unlock_node(rp
);
2836 if ((aggregate
= rp
->aggregate
) != NULL
) {
2837 ripng_aggregate_free(aggregate
);
2838 rp
->aggregate
= NULL
;
2839 route_unlock_node(rp
);
2843 /* Cancel the RIPng timers */
2844 RIPNG_TIMER_OFF(ripng
->t_update
);
2845 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2846 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2848 /* Cancel the read thread */
2849 if (ripng
->t_read
) {
2850 thread_cancel(ripng
->t_read
);
2851 ripng
->t_read
= NULL
;
2854 /* Close the RIPng socket */
2855 if (ripng
->sock
>= 0) {
2860 /* Static RIPng route configuration. */
2861 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2864 route_unlock_node(rp
);
2867 /* RIPng aggregated prefixes */
2868 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2871 route_unlock_node(rp
);
2874 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2875 if (ripng
->route_map
[i
].name
)
2876 free(ripng
->route_map
[i
].name
);
2878 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2879 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2880 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2882 stream_free(ripng
->ibuf
);
2883 stream_free(ripng
->obuf
);
2885 XFREE(MTYPE_RIPNG
, ripng
);
2889 ripng_clean_network();
2890 ripng_passive_interface_clean();
2891 ripng_offset_clean();
2892 ripng_interface_clean();
2893 ripng_redistribute_clean();
2896 /* Reset all values to the default settings. */
2899 /* Call ripd related reset functions. */
2900 ripng_debug_reset();
2901 ripng_route_map_reset();
2903 /* Call library reset functions. */
2905 access_list_reset();
2906 prefix_list_reset();
2908 distribute_list_reset();
2910 ripng_interface_reset();
2912 ripng_zclient_reset();
2915 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2917 struct interface
*ifp
;
2918 struct ripng_interface
*ri
;
2919 struct route_map
*rmap
;
2921 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2927 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2928 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2930 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2932 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2934 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2936 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2937 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2939 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2941 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2943 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2946 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2948 struct if_rmap
*if_rmap
;
2950 if_rmap
= if_rmap_lookup(ifp
->name
);
2952 ripng_if_rmap_update(if_rmap
);
2955 static void ripng_routemap_update_redistribute(void)
2960 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2961 if (ripng
->route_map
[i
].name
)
2962 ripng
->route_map
[i
].map
=
2963 route_map_lookup_by_name(
2964 ripng
->route_map
[i
].name
);
2969 static void ripng_routemap_update(const char *unused
)
2971 struct interface
*ifp
;
2972 struct listnode
*node
;
2974 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2975 ripng_if_rmap_update_interface(ifp
);
2977 ripng_routemap_update_redistribute();
2980 /* Initialize ripng structure and set commands. */
2983 /* Install RIPNG_NODE. */
2984 install_node(&cmd_ripng_node
, ripng_config_write
);
2986 /* Install ripng commands. */
2987 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2988 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2990 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2992 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2993 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
2995 install_default(RIPNG_NODE
);
2996 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2997 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
2998 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
2999 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3001 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3002 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3004 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3005 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3007 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3008 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3009 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3010 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3011 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3012 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3013 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3016 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3017 install_element(RIPNG_NODE
,
3018 &no_ripng_default_information_originate_cmd
);
3020 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3021 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3026 /* Access list install. */
3028 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3029 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3031 /* Prefix list initialize.*/
3033 prefix_list_add_hook(ripng_distribute_update_all
);
3034 prefix_list_delete_hook(ripng_distribute_update_all
);
3036 /* Distribute list install. */
3037 distribute_list_init(RIPNG_NODE
);
3038 distribute_list_add_hook(ripng_distribute_update
);
3039 distribute_list_delete_hook(ripng_distribute_update
);
3041 /* Route-map for interface. */
3042 ripng_route_map_init();
3043 ripng_offset_init();
3045 route_map_add_hook(ripng_routemap_update
);
3046 route_map_delete_hook(ripng_routemap_update
);
3048 if_rmap_init(RIPNG_NODE
);
3049 if_rmap_hook_add(ripng_if_rmap_update
);
3050 if_rmap_hook_delete(ripng_if_rmap_update
);