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 msg
.msg_name
= (void *)&addr
;
180 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
183 msg
.msg_control
= (void *)adata
;
184 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
187 iov
.iov_len
= bufsize
;
189 cmsgptr
= (struct cmsghdr
*)adata
;
190 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
191 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
192 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
194 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
195 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
196 pkt
->ipi6_ifindex
= ifp
->ifindex
;
198 ret
= sendmsg(ripng
->sock
, &msg
, 0);
202 zlog_err("RIPng send fail on %s to %s: %s", ifp
->name
,
203 inet6_ntoa(to
->sin6_addr
),
204 safe_strerror(errno
));
206 zlog_err("RIPng send fail on %s: %s", ifp
->name
,
207 safe_strerror(errno
));
213 /* Receive UDP RIPng packet from socket. */
214 static int ripng_recv_packet(int sock
, u_char
*buf
, int bufsize
,
215 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
221 struct cmsghdr
*cmsgptr
;
222 struct in6_addr dst
= {.s6_addr
= {0}};
224 memset(&dst
, 0, sizeof(struct in6_addr
));
226 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
227 point I can't determine size of cmsghdr */
230 /* Fill in message and iovec. */
231 msg
.msg_name
= (void *)from
;
232 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
235 msg
.msg_control
= (void *)adata
;
236 msg
.msg_controllen
= sizeof adata
;
238 iov
.iov_len
= bufsize
;
240 /* If recvmsg fail return minus value. */
241 ret
= recvmsg(sock
, &msg
, 0);
245 for (cmsgptr
= ZCMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
246 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
247 /* I want interface index which this packet comes from. */
248 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
249 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
250 struct in6_pktinfo
*ptr
;
252 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
253 *ifindex
= ptr
->ipi6_ifindex
;
254 dst
= ptr
->ipi6_addr
;
258 "Interface index returned by IPV6_PKTINFO is zero");
261 /* Incoming packet's multicast hop limit. */
262 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
263 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
264 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
265 *hoplimit
= *phoplimit
;
269 /* Hoplimit check shold be done when destination address is
270 multicast address. */
271 if (!IN6_IS_ADDR_MULTICAST(&dst
))
277 /* Dump rip packet */
278 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
283 const char *command_str
;
285 /* Set command string. */
286 if (packet
->command
== RIPNG_REQUEST
)
287 command_str
= "request";
288 else if (packet
->command
== RIPNG_RESPONSE
)
289 command_str
= "response";
291 command_str
= "unknown";
293 /* Dump packet header. */
294 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
295 packet
->version
, size
);
297 /* Dump each routing table entry. */
300 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
301 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
302 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
305 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
306 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
307 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
311 /* RIPng next hop address RTE (Route Table Entry). */
312 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
313 struct ripng_nexthop
*nexthop
)
315 char buf
[INET6_BUFSIZ
];
317 /* Logging before checking RTE. */
318 if (IS_RIPNG_DEBUG_RECV
)
319 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
321 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
324 /* RFC2080 2.1.1 Next Hop:
325 The route tag and prefix length in the next hop RTE must be
326 set to zero on sending and ignored on receiption. */
327 if (ntohs(rte
->tag
) != 0)
329 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
331 (route_tag_t
)ntohs(rte
->tag
),
332 inet6_ntoa(from
->sin6_addr
));
334 if (rte
->prefixlen
!= 0)
336 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
337 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
339 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
340 next hop RTE indicates that the next hop address should be the
341 originator of the RIPng advertisement. An address specified as a
342 next hop must be a link-local address. */
343 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
344 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
345 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
349 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
350 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
351 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
355 /* The purpose of the next hop RTE is to eliminate packets being
356 routed through extra hops in the system. It is particularly useful
357 when RIPng is not being run on all of the routers on a network.
358 Note that next hop RTE is "advisory". That is, if the provided
359 information is ignored, a possibly sub-optimal, but absolutely
360 valid, route may be taken. If the received next hop address is not
361 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
362 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
363 inet6_ntoa(rte
->addr
),
364 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
366 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
367 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
372 /* If ifp has same link-local address then return 1. */
373 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
375 struct listnode
*node
;
376 struct connected
*connected
;
379 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
380 p
= connected
->address
;
382 if (p
->family
== AF_INET6
383 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
384 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
390 /* RIPng route garbage collect timer. */
391 static int ripng_garbage_collect(struct thread
*t
)
393 struct ripng_info
*rinfo
;
394 struct route_node
*rp
;
396 rinfo
= THREAD_ARG(t
);
397 rinfo
->t_garbage_collect
= NULL
;
399 /* Off timeout timer. */
400 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
402 /* Get route_node pointer. */
405 /* Unlock route_node. */
406 listnode_delete(rp
->info
, rinfo
);
407 if (list_isempty((struct list
*)rp
->info
)) {
410 route_unlock_node(rp
);
413 /* Free RIPng routing information. */
414 ripng_info_free(rinfo
);
419 static void ripng_timeout_update(struct ripng_info
*rinfo
);
421 /* Add new route to the ECMP list.
422 * RETURN: the new entry added in the list, or NULL if it is not the first
423 * entry and ECMP is not allowed.
425 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
427 struct route_node
*rp
= rinfo_new
->rp
;
428 struct ripng_info
*rinfo
= NULL
;
429 struct list
*list
= NULL
;
431 if (rp
->info
== NULL
)
432 rp
->info
= list_new();
433 list
= (struct list
*)rp
->info
;
435 /* If ECMP is not allowed and some entry already exists in the list,
437 if (listcount(list
) && !ripng
->ecmp
)
440 rinfo
= ripng_info_new();
441 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
442 listnode_add(list
, rinfo
);
444 if (ripng_route_rte(rinfo
)) {
445 ripng_timeout_update(rinfo
);
446 ripng_zebra_ipv6_add(rp
);
449 ripng_aggregate_increment(rp
, rinfo
);
451 /* Set the route change flag on the first entry. */
452 rinfo
= listgetdata(listhead(list
));
453 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
455 /* Signal the output process to trigger an update. */
456 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
461 /* Replace the ECMP list with the new route.
462 * RETURN: the new entry added in the list
464 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
466 struct route_node
*rp
= rinfo_new
->rp
;
467 struct list
*list
= (struct list
*)rp
->info
;
468 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
469 struct listnode
*node
= NULL
, *nextnode
= NULL
;
471 if (list
== NULL
|| listcount(list
) == 0)
472 return ripng_ecmp_add(rinfo_new
);
474 /* Get the first entry */
475 rinfo
= listgetdata(listhead(list
));
477 /* Learnt route replaced by a local one. Delete it from zebra. */
478 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
479 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
480 ripng_zebra_ipv6_delete(rp
);
482 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
483 ripng_aggregate_decrement_list(rp
, list
);
485 /* Re-use the first entry, and delete the others. */
486 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
487 if (tmp_rinfo
!= rinfo
) {
488 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
489 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
490 list_delete_node(list
, node
);
491 ripng_info_free(tmp_rinfo
);
494 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
495 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
496 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
498 if (ripng_route_rte(rinfo
)) {
499 ripng_timeout_update(rinfo
);
500 /* The ADD message implies an update. */
501 ripng_zebra_ipv6_add(rp
);
504 ripng_aggregate_increment(rp
, rinfo
);
506 /* Set the route change flag. */
507 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
509 /* Signal the output process to trigger an update. */
510 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
515 /* Delete one route from the ECMP list.
517 * null - the entry is freed, and other entries exist in the list
518 * the entry - the entry is the last one in the list; its metric is set
519 * to INFINITY, and the garbage collector is started for it
521 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
523 struct route_node
*rp
= rinfo
->rp
;
524 struct list
*list
= (struct list
*)rp
->info
;
526 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
528 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
529 ripng_aggregate_decrement(rp
, rinfo
);
531 if (listcount(list
) > 1) {
532 /* Some other ECMP entries still exist. Just delete this entry.
534 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
535 listnode_delete(list
, rinfo
);
536 if (ripng_route_rte(rinfo
)
537 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
538 /* The ADD message implies the update. */
539 ripng_zebra_ipv6_add(rp
);
540 ripng_info_free(rinfo
);
543 assert(rinfo
== listgetdata(listhead(list
)));
545 /* This is the only entry left in the list. We must keep it in
546 * the list for garbage collection time, with INFINITY metric.
549 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
550 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
551 ripng
->garbage_time
);
553 if (ripng_route_rte(rinfo
)
554 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
555 ripng_zebra_ipv6_delete(rp
);
558 /* Set the route change flag on the first entry. */
559 rinfo
= listgetdata(listhead(list
));
560 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
562 /* Signal the output process to trigger an update. */
563 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
568 /* Timeout RIPng routes. */
569 static int ripng_timeout(struct thread
*t
)
571 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
575 static void ripng_timeout_update(struct ripng_info
*rinfo
)
577 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
578 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
579 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
580 ripng
->timeout_time
);
584 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
585 struct ripng_interface
*ri
)
587 struct distribute
*dist
;
588 struct access_list
*alist
;
589 struct prefix_list
*plist
;
590 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
593 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
595 /* Input distribute-list filtering. */
596 if (ri
->list
[ripng_distribute
]) {
597 if (access_list_apply(ri
->list
[ripng_distribute
],
600 if (IS_RIPNG_DEBUG_PACKET
)
601 zlog_debug("%s/%d filtered by distribute %s",
602 inet6_ntoa(p
->prefix
), p
->prefixlen
,
607 if (ri
->prefix
[ripng_distribute
]) {
608 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
611 if (IS_RIPNG_DEBUG_PACKET
)
612 zlog_debug("%s/%d filtered by prefix-list %s",
613 inet6_ntoa(p
->prefix
), p
->prefixlen
,
619 /* All interface filter check. */
620 dist
= distribute_lookup(NULL
);
622 if (dist
->list
[distribute
]) {
623 alist
= access_list_lookup(AFI_IP6
,
624 dist
->list
[distribute
]);
627 if (access_list_apply(alist
, (struct prefix
*)p
)
629 if (IS_RIPNG_DEBUG_PACKET
)
631 "%s/%d filtered by distribute %s",
632 inet6_ntoa(p
->prefix
),
633 p
->prefixlen
, inout
);
638 if (dist
->prefix
[distribute
]) {
639 plist
= prefix_list_lookup(AFI_IP6
,
640 dist
->prefix
[distribute
]);
643 if (prefix_list_apply(plist
, (struct prefix
*)p
)
645 if (IS_RIPNG_DEBUG_PACKET
)
647 "%s/%d filtered by prefix-list %s",
648 inet6_ntoa(p
->prefix
),
649 p
->prefixlen
, inout
);
658 /* Process RIPng route according to RFC2080. */
659 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
660 struct ripng_nexthop
*ripng_nexthop
,
661 struct interface
*ifp
)
664 struct prefix_ipv6 p
;
665 struct route_node
*rp
;
666 struct ripng_info
*rinfo
= NULL
, newinfo
;
667 struct ripng_interface
*ri
;
668 struct in6_addr
*nexthop
;
670 struct list
*list
= NULL
;
671 struct listnode
*node
= NULL
;
673 /* Make prefix structure. */
674 memset(&p
, 0, sizeof(struct prefix_ipv6
));
676 /* p.prefix = rte->addr; */
677 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
678 p
.prefixlen
= rte
->prefixlen
;
680 /* Make sure mask is applied. */
681 /* XXX We have to check the prefix is valid or not before call
685 /* Apply input filters. */
688 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
692 memset(&newinfo
, 0, sizeof(newinfo
));
693 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
694 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
695 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
696 newinfo
.nexthop
= ripng_nexthop
->address
;
698 newinfo
.nexthop
= from
->sin6_addr
;
699 newinfo
.from
= from
->sin6_addr
;
700 newinfo
.ifindex
= ifp
->ifindex
;
701 newinfo
.metric
= rte
->metric
;
702 newinfo
.metric_out
= rte
->metric
; /* XXX */
703 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
706 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
709 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
710 (struct prefix
*)&p
, RMAP_RIPNG
,
713 if (ret
== RMAP_DENYMATCH
) {
714 if (IS_RIPNG_DEBUG_PACKET
)
716 "RIPng %s/%d is filtered by route-map in",
717 inet6_ntoa(p
.prefix
), p
.prefixlen
);
721 /* Get back the object */
722 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
723 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
724 &ripng_nexthop
->address
)) {
725 /* the nexthop get changed by the routemap */
726 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
727 ripng_nexthop
->address
=
730 ripng_nexthop
->address
= in6addr_any
;
733 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
735 /* the nexthop get changed by the routemap */
736 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
737 ripng_nexthop
->flag
=
738 RIPNG_NEXTHOP_ADDRESS
;
739 ripng_nexthop
->address
=
744 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
746 newinfo
.metric_out
; /* XXX: the routemap uses the
750 /* Once the entry has been validated, update the metric by
751 * adding the cost of the network on wich the message
752 * arrived. If the result is greater than infinity, use infinity
753 * (RFC2453 Sec. 3.9.2)
756 /* Zebra ripngd can handle offset-list in. */
757 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
759 /* If offset-list does not modify the metric use interface's
762 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
764 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
765 rte
->metric
= RIPNG_METRIC_INFINITY
;
767 /* Set nexthop pointer. */
768 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
769 nexthop
= &ripng_nexthop
->address
;
771 nexthop
= &from
->sin6_addr
;
773 /* Lookup RIPng routing table. */
774 rp
= route_node_get(ripng
->table
, (struct prefix
*)&p
);
777 newinfo
.nexthop
= *nexthop
;
778 newinfo
.metric
= rte
->metric
;
779 newinfo
.tag
= ntohs(rte
->tag
);
781 /* Check to see whether there is already RIPng route on the table. */
782 if ((list
= rp
->info
) != NULL
)
783 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
784 /* Need to compare with redistributed entry or local
786 if (!ripng_route_rte(rinfo
))
789 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
790 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
793 if (!listnextnode(node
)) {
794 /* Not found in the list */
796 if (rte
->metric
> rinfo
->metric
) {
797 /* New route has a greater metric.
799 route_unlock_node(rp
);
803 if (rte
->metric
< rinfo
->metric
)
804 /* New route has a smaller metric.
805 * Replace the ECMP list
806 * with the new one in below. */
809 /* Metrics are same. Unless ECMP is disabled,
810 * keep "rinfo" null and
811 * the new route is added in the ECMP list in
819 /* Redistributed route check. */
820 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
821 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
822 route_unlock_node(rp
);
826 /* Local static route. */
827 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
828 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
829 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
830 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
831 route_unlock_node(rp
);
837 /* Now, check to see whether there is already an explicit route
838 for the destination prefix. If there is no such route, add
839 this route to the routing table, unless the metric is
840 infinity (there is no point in adding a route which
842 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
843 ripng_ecmp_add(&newinfo
);
845 /* If there is an existing route, compare the next hop address
846 to the address of the router from which the datagram came.
847 If this datagram is from the same router as the existing
848 route, reinitialize the timeout. */
849 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
850 && (rinfo
->ifindex
== ifp
->ifindex
));
853 * RFC 2080 - Section 2.4.2:
854 * "If the new metric is the same as the old one, examine the
856 * for the existing route. If it is at least halfway to the
858 * point, switch to the new route. This heuristic is optional,
860 * highly recommended".
862 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
864 && (thread_timer_remain_second(rinfo
->t_timeout
)
865 < (ripng
->timeout_time
/ 2))) {
866 ripng_ecmp_replace(&newinfo
);
868 /* Next, compare the metrics. If the datagram is from the same
869 router as the existing route, and the new metric is different
870 than the old one; or, if the new metric is lower than the old
871 one; do the following actions: */
872 else if ((same
&& rinfo
->metric
!= rte
->metric
)
873 || rte
->metric
< rinfo
->metric
) {
874 if (listcount(list
) == 1) {
875 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
876 ripng_ecmp_replace(&newinfo
);
878 ripng_ecmp_delete(rinfo
);
880 if (newinfo
.metric
< rinfo
->metric
)
881 ripng_ecmp_replace(&newinfo
);
882 else /* newinfo.metric > rinfo->metric */
883 ripng_ecmp_delete(rinfo
);
885 } else /* same & no change */
886 ripng_timeout_update(rinfo
);
888 /* Unlock tempolary lock of the route. */
889 route_unlock_node(rp
);
893 /* Add redistributed route to RIPng table. */
894 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
895 ifindex_t ifindex
, struct in6_addr
*nexthop
,
898 struct route_node
*rp
;
899 struct ripng_info
*rinfo
= NULL
, newinfo
;
900 struct list
*list
= NULL
;
902 /* Redistribute route */
903 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
905 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
908 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
910 memset(&newinfo
, 0, sizeof(struct ripng_info
));
912 newinfo
.sub_type
= sub_type
;
913 newinfo
.ifindex
= ifindex
;
915 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
918 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
919 newinfo
.nexthop
= *nexthop
;
921 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
922 rinfo
= listgetdata(listhead(list
));
924 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
925 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
926 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
927 route_unlock_node(rp
);
931 /* Manually configured RIPng route check.
932 * They have the precedence on all the other entries.
934 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
935 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
936 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
937 if (type
!= ZEBRA_ROUTE_RIPNG
938 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
939 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
940 route_unlock_node(rp
);
945 ripng_ecmp_replace(&newinfo
);
946 route_unlock_node(rp
);
948 ripng_ecmp_add(&newinfo
);
950 if (IS_RIPNG_DEBUG_EVENT
) {
953 "Redistribute new prefix %s/%d on the interface %s",
954 inet6_ntoa(p
->prefix
), p
->prefixlen
,
955 ifindex2ifname(ifindex
, VRF_DEFAULT
));
958 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
959 inet6_ntoa(p
->prefix
), p
->prefixlen
,
960 inet6_ntoa(*nexthop
),
961 ifindex2ifname(ifindex
, VRF_DEFAULT
));
964 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
967 /* Delete redistributed route to RIPng table. */
968 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
971 struct route_node
*rp
;
972 struct ripng_info
*rinfo
;
974 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
976 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
979 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
982 struct list
*list
= rp
->info
;
984 if (list
!= NULL
&& listcount(list
) != 0) {
985 rinfo
= listgetdata(listhead(list
));
986 if (rinfo
!= NULL
&& rinfo
->type
== type
987 && rinfo
->sub_type
== sub_type
988 && rinfo
->ifindex
== ifindex
) {
989 /* Perform poisoned reverse. */
990 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
991 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
992 ripng_garbage_collect
,
993 ripng
->garbage_time
);
994 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
996 /* Aggregate count decrement. */
997 ripng_aggregate_decrement(rp
, rinfo
);
999 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1001 if (IS_RIPNG_DEBUG_EVENT
)
1003 "Poisone %s/%d on the interface %s with an "
1004 "infinity metric [delete]",
1005 inet6_ntoa(p
->prefix
),
1007 ifindex2ifname(ifindex
,
1010 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1013 route_unlock_node(rp
);
1017 /* Withdraw redistributed route. */
1018 void ripng_redistribute_withdraw(int type
)
1020 struct route_node
*rp
;
1021 struct ripng_info
*rinfo
= NULL
;
1022 struct list
*list
= NULL
;
1027 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1028 if ((list
= rp
->info
) != NULL
) {
1029 rinfo
= listgetdata(listhead(list
));
1030 if ((rinfo
->type
== type
)
1031 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1032 /* Perform poisoned reverse. */
1033 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1034 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1035 ripng_garbage_collect
,
1036 ripng
->garbage_time
);
1037 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1039 /* Aggregate count decrement. */
1040 ripng_aggregate_decrement(rp
, rinfo
);
1042 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1044 if (IS_RIPNG_DEBUG_EVENT
) {
1045 struct prefix_ipv6
*p
=
1046 (struct prefix_ipv6
*)&rp
->p
;
1049 "Poisone %s/%d on the interface %s [withdraw]",
1050 inet6_ntoa(p
->prefix
),
1052 ifindex2ifname(rinfo
->ifindex
,
1056 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1061 /* RIP routing information. */
1062 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1063 struct sockaddr_in6
*from
,
1064 struct interface
*ifp
, int hoplimit
)
1068 struct ripng_nexthop nexthop
;
1070 /* RFC2080 2.4.2 Response Messages:
1071 The Response must be ignored if it is not from the RIPng port. */
1072 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1073 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1074 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1075 ripng_peer_bad_packet(from
);
1079 /* The datagram's IPv6 source address should be checked to see
1080 whether the datagram is from a valid neighbor; the source of the
1081 datagram must be a link-local address. */
1082 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1083 zlog_warn("RIPng packet comes from non link local address %s",
1084 inet6_ntoa(from
->sin6_addr
));
1085 ripng_peer_bad_packet(from
);
1089 /* It is also worth checking to see whether the response is from one
1090 of the router's own addresses. Interfaces on broadcast networks
1091 may receive copies of their own multicasts immediately. If a
1092 router processes its own output as new input, confusion is likely,
1093 and such datagrams must be ignored. */
1094 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1096 "RIPng packet comes from my own link local address %s",
1097 inet6_ntoa(from
->sin6_addr
));
1098 ripng_peer_bad_packet(from
);
1102 /* As an additional check, periodic advertisements must have their
1103 hop counts set to 255, and inbound, multicast packets sent from the
1104 RIPng port (i.e. periodic advertisement or triggered update
1105 packets) must be examined to ensure that the hop count is 255. */
1106 if (hoplimit
>= 0 && hoplimit
!= 255) {
1108 "RIPng packet comes with non 255 hop count %d from %s",
1109 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1110 ripng_peer_bad_packet(from
);
1114 /* Update RIPng peer. */
1115 ripng_peer_update(from
, packet
->version
);
1117 /* Reset nexthop. */
1118 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1119 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1121 /* Set RTE pointer. */
1124 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1125 /* First of all, we have to check this RTE is next hop RTE or
1126 not. Next hop RTE is completely different with normal RTE so
1127 we need special treatment. */
1128 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1129 ripng_nexthop_rte(rte
, from
, &nexthop
);
1133 /* RTE information validation. */
1135 /* - is the destination prefix valid (e.g., not a multicast
1136 prefix and not a link-local address) A link-local address
1137 should never be present in an RTE. */
1138 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1140 "Destination prefix is a multicast address %s/%d [%d]",
1141 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1143 ripng_peer_bad_route(from
);
1146 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1148 "Destination prefix is a link-local address %s/%d [%d]",
1149 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1151 ripng_peer_bad_route(from
);
1154 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1156 "Destination prefix is a loopback address %s/%d [%d]",
1157 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1159 ripng_peer_bad_route(from
);
1163 /* - is the prefix length valid (i.e., between 0 and 128,
1165 if (rte
->prefixlen
> 128) {
1166 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1167 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1168 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1169 ripng_peer_bad_route(from
);
1173 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1174 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1175 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1176 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1177 ripng_peer_bad_route(from
);
1181 /* Vincent: XXX Should we compute the direclty reachable nexthop
1182 * for our RIPng network ?
1185 /* Routing table updates. */
1186 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1190 /* Response to request message. */
1191 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1192 struct sockaddr_in6
*from
,
1193 struct interface
*ifp
)
1197 struct prefix_ipv6 p
;
1198 struct route_node
*rp
;
1199 struct ripng_info
*rinfo
;
1200 struct ripng_interface
*ri
;
1202 /* Does not reponse to the requests on the loopback interfaces */
1203 if (if_is_loopback(ifp
))
1206 /* Check RIPng process is enabled on this interface. */
1211 /* When passive interface is specified, suppress responses */
1215 /* RIPng peer update. */
1216 ripng_peer_update(from
, packet
->version
);
1218 lim
= ((caddr_t
)packet
) + size
;
1221 /* The Request is processed entry by entry. If there are no
1222 entries, no response is given. */
1223 if (lim
== (caddr_t
)rte
)
1226 /* There is one special case. If there is exactly one entry in the
1227 request, and it has a destination prefix of zero, a prefix length
1228 of zero, and a metric of infinity (i.e., 16), then this is a
1229 request to send the entire routing table. In that case, a call
1230 is made to the output process to send the routing table to the
1231 requesting address/port. */
1232 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1233 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1234 /* All route with split horizon */
1235 ripng_output_process(ifp
, from
, ripng_all_route
);
1237 /* Except for this special case, processing is quite simple.
1238 Examine the list of RTEs in the Request one by one. For each
1239 entry, look up the destination in the router's routing
1240 database and, if there is a route, put that route's metric in
1241 the metric field of the RTE. If there is no explicit route
1242 to the specified destination, put infinity in the metric
1243 field. Once all the entries have been filled in, change the
1244 command from Request to Response and send the datagram back
1245 to the requestor. */
1246 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1247 p
.family
= AF_INET6
;
1249 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1250 p
.prefix
= rte
->addr
;
1251 p
.prefixlen
= rte
->prefixlen
;
1252 apply_mask_ipv6(&p
);
1254 rp
= route_node_lookup(ripng
->table
,
1255 (struct prefix
*)&p
);
1258 rinfo
= listgetdata(
1259 listhead((struct list
*)rp
->info
));
1260 rte
->metric
= rinfo
->metric
;
1261 route_unlock_node(rp
);
1263 rte
->metric
= RIPNG_METRIC_INFINITY
;
1265 packet
->command
= RIPNG_RESPONSE
;
1267 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1271 /* First entry point of reading RIPng packet. */
1272 static int ripng_read(struct thread
*thread
)
1276 struct sockaddr_in6 from
;
1277 struct ripng_packet
*packet
;
1278 ifindex_t ifindex
= 0;
1279 struct interface
*ifp
;
1282 /* Check ripng is active and alive. */
1283 assert(ripng
!= NULL
);
1284 assert(ripng
->sock
>= 0);
1286 /* Fetch thread data and set read pointer to empty for event
1287 managing. `sock' sould be same as ripng->sock. */
1288 sock
= THREAD_FD(thread
);
1289 ripng
->t_read
= NULL
;
1291 /* Add myself to the next event. */
1292 ripng_event(RIPNG_READ
, sock
);
1294 /* Read RIPng packet. */
1295 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1296 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1299 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1303 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1304 (4)) must be multiple size of one RTE size (20). */
1305 if (((len
- 4) % 20) != 0) {
1306 zlog_warn("RIPng invalid packet size %d from %s", len
,
1307 inet6_ntoa(from
.sin6_addr
));
1308 ripng_peer_bad_packet(&from
);
1312 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1313 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1315 /* RIPng packet received. */
1316 if (IS_RIPNG_DEBUG_EVENT
)
1317 zlog_debug("RIPng packet received from %s port %d on %s",
1318 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1319 ifp
? ifp
->name
: "unknown");
1321 /* Logging before packet checking. */
1322 if (IS_RIPNG_DEBUG_RECV
)
1323 ripng_packet_dump(packet
, len
, "RECV");
1325 /* Packet comes from unknown interface. */
1327 zlog_warn("RIPng packet comes from unknown interface %d",
1332 /* Packet version mismatch checking. */
1333 if (packet
->version
!= ripng
->version
) {
1335 "RIPng packet version %d doesn't fit to my version %d",
1336 packet
->version
, ripng
->version
);
1337 ripng_peer_bad_packet(&from
);
1341 /* Process RIPng packet. */
1342 switch (packet
->command
) {
1344 ripng_request_process(packet
, len
, &from
, ifp
);
1346 case RIPNG_RESPONSE
:
1347 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1350 zlog_warn("Invalid RIPng command %d", packet
->command
);
1351 ripng_peer_bad_packet(&from
);
1357 /* Walk down the RIPng routing table then clear changed flag. */
1358 static void ripng_clear_changed_flag(void)
1360 struct route_node
*rp
;
1361 struct ripng_info
*rinfo
= NULL
;
1362 struct list
*list
= NULL
;
1363 struct listnode
*listnode
= NULL
;
1365 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1366 if ((list
= rp
->info
) != NULL
)
1367 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1368 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1369 /* This flag can be set only on the first entry.
1375 /* Regular update of RIPng route. Send all routing formation to RIPng
1376 enabled interface. */
1377 static int ripng_update(struct thread
*t
)
1379 struct listnode
*node
;
1380 struct interface
*ifp
;
1381 struct ripng_interface
*ri
;
1383 /* Clear update timer thread. */
1384 ripng
->t_update
= NULL
;
1386 /* Logging update event. */
1387 if (IS_RIPNG_DEBUG_EVENT
)
1388 zlog_debug("RIPng update timer expired!");
1390 /* Supply routes to each interface. */
1391 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1394 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1400 /* When passive interface is specified, suppress announce to the
1406 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1407 if (IS_RIPNG_DEBUG_EVENT
)
1409 "[Event] RIPng send to if %d is suppressed by config",
1413 #endif /* RIPNG_ADVANCED */
1415 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1418 /* Triggered updates may be suppressed if a regular update is due by
1419 the time the triggered update would be sent. */
1420 if (ripng
->t_triggered_interval
) {
1421 thread_cancel(ripng
->t_triggered_interval
);
1422 ripng
->t_triggered_interval
= NULL
;
1426 /* Reset flush event. */
1427 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1432 /* Triggered update interval timer. */
1433 static int ripng_triggered_interval(struct thread
*t
)
1435 ripng
->t_triggered_interval
= NULL
;
1437 if (ripng
->trigger
) {
1439 ripng_triggered_update(t
);
1444 /* Execute triggered update. */
1445 int ripng_triggered_update(struct thread
*t
)
1447 struct listnode
*node
;
1448 struct interface
*ifp
;
1449 struct ripng_interface
*ri
;
1452 ripng
->t_triggered_update
= NULL
;
1454 /* Cancel interval timer. */
1455 if (ripng
->t_triggered_interval
) {
1456 thread_cancel(ripng
->t_triggered_interval
);
1457 ripng
->t_triggered_interval
= NULL
;
1461 /* Logging triggered update. */
1462 if (IS_RIPNG_DEBUG_EVENT
)
1463 zlog_debug("RIPng triggered update!");
1465 /* Split Horizon processing is done when generating triggered
1466 updates as well as normal updates (see section 2.6). */
1467 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
1470 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1476 /* When passive interface is specified, suppress announce to the
1481 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1484 /* Once all of the triggered updates have been generated, the route
1485 change flags should be cleared. */
1486 ripng_clear_changed_flag();
1488 /* After a triggered update is sent, a timer should be set for a
1489 random interval between 1 and 5 seconds. If other changes that
1490 would trigger updates occur before the timer expires, a single
1491 update is triggered when the timer expires. */
1492 interval
= (random() % 5) + 1;
1494 ripng
->t_triggered_interval
= NULL
;
1495 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1496 &ripng
->t_triggered_interval
);
1501 /* Write routing table entry to the stream and return next index of
1502 the routing table entry in the stream. */
1503 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1504 struct in6_addr
*nexthop
, u_int16_t tag
, u_char metric
)
1506 /* RIPng packet header. */
1508 stream_putc(s
, RIPNG_RESPONSE
);
1509 stream_putc(s
, RIPNG_V1
);
1513 /* Write routing table entry. */
1515 stream_write(s
, (u_char
*)&p
->prefix
, sizeof(struct in6_addr
));
1517 stream_write(s
, (u_char
*)nexthop
, sizeof(struct in6_addr
));
1518 stream_putw(s
, tag
);
1520 stream_putc(s
, p
->prefixlen
);
1523 stream_putc(s
, metric
);
1528 /* Send RESPONSE message to specified destination. */
1529 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1533 struct route_node
*rp
;
1534 struct ripng_info
*rinfo
;
1535 struct ripng_interface
*ri
;
1536 struct ripng_aggregate
*aggregate
;
1537 struct prefix_ipv6
*p
;
1538 struct list
*ripng_rte_list
;
1539 struct list
*list
= NULL
;
1540 struct listnode
*listnode
= NULL
;
1542 if (IS_RIPNG_DEBUG_EVENT
) {
1544 zlog_debug("RIPng update routes to neighbor %s",
1545 inet6_ntoa(to
->sin6_addr
));
1547 zlog_debug("RIPng update routes on interface %s",
1551 /* Get RIPng interface. */
1554 ripng_rte_list
= ripng_rte_new();
1556 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1557 if ((list
= rp
->info
) != NULL
1558 && (rinfo
= listgetdata(listhead(list
))) != NULL
1559 && rinfo
->suppress
== 0) {
1560 /* If no route-map are applied, the RTE will be these
1564 p
= (struct prefix_ipv6
*)&rp
->p
;
1565 rinfo
->metric_out
= rinfo
->metric
;
1566 rinfo
->tag_out
= rinfo
->tag
;
1567 memset(&rinfo
->nexthop_out
, 0,
1568 sizeof(rinfo
->nexthop_out
));
1569 /* In order to avoid some local loops,
1570 * if the RIPng route has a nexthop via this interface,
1572 * otherwise set it to 0. The nexthop should not be
1574 * beyond the local broadcast/multicast area in order
1575 * to avoid an IGP multi-level recursive look-up.
1577 if (rinfo
->ifindex
== ifp
->ifindex
)
1578 rinfo
->nexthop_out
= rinfo
->nexthop
;
1580 /* Apply output filters. */
1581 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1585 /* Changed route only output. */
1586 if (route_type
== ripng_changed_route
1587 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1590 /* Split horizon. */
1591 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1592 /* We perform split horizon for RIPng routes. */
1594 struct ripng_info
*tmp_rinfo
= NULL
;
1596 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1598 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1599 && tmp_rinfo
->ifindex
1608 /* Preparation for route-map. */
1609 rinfo
->metric_set
= 0;
1612 * and tag_out are already initialized.
1615 /* Interface route-map */
1616 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1619 ret
= route_map_apply(
1620 ri
->routemap
[RIPNG_FILTER_OUT
],
1621 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1623 if (ret
== RMAP_DENYMATCH
) {
1624 if (IS_RIPNG_DEBUG_PACKET
)
1626 "RIPng %s/%d is filtered by route-map out",
1627 inet6_ntoa(p
->prefix
),
1633 /* Redistribute route-map. */
1634 if (ripng
->route_map
[rinfo
->type
].name
) {
1637 ret
= route_map_apply(
1638 ripng
->route_map
[rinfo
->type
].map
,
1639 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1641 if (ret
== RMAP_DENYMATCH
) {
1642 if (IS_RIPNG_DEBUG_PACKET
)
1644 "RIPng %s/%d is filtered by route-map",
1645 inet6_ntoa(p
->prefix
),
1651 /* When the route-map does not set metric. */
1652 if (!rinfo
->metric_set
) {
1653 /* If the redistribute metric is set. */
1654 if (ripng
->route_map
[rinfo
->type
].metric_config
1655 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1657 ripng
->route_map
[rinfo
->type
]
1660 /* If the route is not connected or
1662 one, use default-metric value */
1663 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1665 != ZEBRA_ROUTE_CONNECT
1667 != RIPNG_METRIC_INFINITY
)
1669 ripng
->default_metric
;
1673 /* Apply offset-list */
1674 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1675 ripng_offset_list_apply_out(p
, ifp
,
1676 &rinfo
->metric_out
);
1678 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1679 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1681 /* Perform split-horizon with poisoned reverse
1684 if (ri
->split_horizon
1685 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1686 struct ripng_info
*tmp_rinfo
= NULL
;
1688 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1690 if ((tmp_rinfo
->type
1691 == ZEBRA_ROUTE_RIPNG
)
1692 && tmp_rinfo
->ifindex
1695 RIPNG_METRIC_INFINITY
;
1698 /* Add RTE to the list */
1699 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1702 /* Process the aggregated RTE entry */
1703 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1704 && aggregate
->suppress
== 0) {
1705 /* If no route-map are applied, the RTE will be these
1709 p
= (struct prefix_ipv6
*)&rp
->p
;
1710 aggregate
->metric_set
= 0;
1711 aggregate
->metric_out
= aggregate
->metric
;
1712 aggregate
->tag_out
= aggregate
->tag
;
1713 memset(&aggregate
->nexthop_out
, 0,
1714 sizeof(aggregate
->nexthop_out
));
1716 /* Apply output filters.*/
1717 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1721 /* Interface route-map */
1722 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1724 struct ripng_info newinfo
;
1726 /* let's cast the aggregate structure to
1728 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1729 /* the nexthop is :: */
1730 newinfo
.metric
= aggregate
->metric
;
1731 newinfo
.metric_out
= aggregate
->metric_out
;
1732 newinfo
.tag
= aggregate
->tag
;
1733 newinfo
.tag_out
= aggregate
->tag_out
;
1735 ret
= route_map_apply(
1736 ri
->routemap
[RIPNG_FILTER_OUT
],
1737 (struct prefix
*)p
, RMAP_RIPNG
,
1740 if (ret
== RMAP_DENYMATCH
) {
1741 if (IS_RIPNG_DEBUG_PACKET
)
1743 "RIPng %s/%d is filtered by route-map out",
1744 inet6_ntoa(p
->prefix
),
1749 aggregate
->metric_out
= newinfo
.metric_out
;
1750 aggregate
->tag_out
= newinfo
.tag_out
;
1751 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1752 aggregate
->nexthop_out
=
1753 newinfo
.nexthop_out
;
1756 /* There is no redistribute routemap for the aggregated
1759 /* Changed route only output. */
1760 /* XXX, vincent, in order to increase time convergence,
1761 * it should be announced if a child has changed.
1763 if (route_type
== ripng_changed_route
)
1766 /* Apply offset-list */
1767 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1768 ripng_offset_list_apply_out(
1769 p
, ifp
, &aggregate
->metric_out
);
1771 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1772 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1774 /* Add RTE to the list */
1775 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1779 /* Flush the list */
1780 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1781 ripng_rte_free(ripng_rte_list
);
1784 /* Create new RIPng instance and set it to global variable. */
1785 static int ripng_create(void)
1787 /* ripng should be NULL. */
1788 assert(ripng
== NULL
);
1790 /* Allocaste RIPng instance. */
1791 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1793 /* Default version and timer values. */
1794 ripng
->version
= RIPNG_V1
;
1795 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1796 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1797 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1798 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1801 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1802 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1804 /* Initialize RIPng routig table. */
1805 ripng
->table
= route_table_init();
1806 ripng
->route
= route_table_init();
1807 ripng
->aggregate
= route_table_init();
1810 ripng
->sock
= ripng_make_socket();
1811 if (ripng
->sock
< 0)
1815 ripng_event(RIPNG_READ
, ripng
->sock
);
1816 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1821 /* Send RIPng request to the interface. */
1822 int ripng_request(struct interface
*ifp
)
1825 struct ripng_packet ripng_packet
;
1827 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1829 if (if_is_loopback(ifp
))
1832 /* If interface is down, don't send RIP packet. */
1836 if (IS_RIPNG_DEBUG_EVENT
)
1837 zlog_debug("RIPng send request to %s", ifp
->name
);
1839 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1840 ripng_packet
.command
= RIPNG_REQUEST
;
1841 ripng_packet
.version
= RIPNG_V1
;
1842 rte
= ripng_packet
.rte
;
1843 rte
->metric
= RIPNG_METRIC_INFINITY
;
1845 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1850 static int ripng_update_jitter(int time
)
1852 return ((random() % (time
+ 1)) - (time
/ 2));
1855 void ripng_event(enum ripng_event event
, int sock
)
1861 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1863 case RIPNG_UPDATE_EVENT
:
1864 if (ripng
->t_update
) {
1865 thread_cancel(ripng
->t_update
);
1866 ripng
->t_update
= NULL
;
1868 /* Update timer jitter. */
1869 jitter
= ripng_update_jitter(ripng
->update_time
);
1871 ripng
->t_update
= NULL
;
1872 thread_add_timer(master
, ripng_update
, NULL
,
1873 sock
? 2 : ripng
->update_time
+ jitter
,
1876 case RIPNG_TRIGGERED_UPDATE
:
1877 if (ripng
->t_triggered_interval
)
1880 thread_add_event(master
, ripng_triggered_update
, NULL
,
1881 0, &ripng
->t_triggered_update
);
1889 /* Print out routes update time. */
1890 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1895 char timebuf
[TIME_BUF
];
1896 struct thread
*thread
;
1898 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1899 clock
= thread_timer_remain_second(thread
);
1900 tm
= gmtime(&clock
);
1901 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1902 vty_out(vty
, "%5s", timebuf
);
1903 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1904 clock
= thread_timer_remain_second(thread
);
1905 tm
= gmtime(&clock
);
1906 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1907 vty_out(vty
, "%5s", timebuf
);
1911 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1916 if (rinfo
->suppress
)
1919 switch (rinfo
->sub_type
) {
1920 case RIPNG_ROUTE_RTE
:
1923 case RIPNG_ROUTE_STATIC
:
1926 case RIPNG_ROUTE_DEFAULT
:
1929 case RIPNG_ROUTE_REDISTRIBUTE
:
1932 case RIPNG_ROUTE_INTERFACE
:
1943 DEFUN (show_ipv6_ripng
,
1944 show_ipv6_ripng_cmd
,
1948 "Show RIPng routes\n")
1950 struct route_node
*rp
;
1951 struct ripng_info
*rinfo
;
1952 struct ripng_aggregate
*aggregate
;
1953 struct prefix_ipv6
*p
;
1954 struct list
*list
= NULL
;
1955 struct listnode
*listnode
= NULL
;
1961 /* Header of display. */
1963 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1965 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1966 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1967 " Network Next Hop Via Metric Tag Time\n");
1969 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1970 if ((aggregate
= rp
->aggregate
) != NULL
) {
1971 p
= (struct prefix_ipv6
*)&rp
->p
;
1974 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1975 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1978 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1982 vty_out(vty
, "%*s", 18, " ");
1984 vty_out(vty
, "%*s", 28, " ");
1985 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1986 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1989 if ((list
= rp
->info
) != NULL
)
1990 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1991 p
= (struct prefix_ipv6
*)&rp
->p
;
1994 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1995 zebra_route_char(rinfo
->type
),
1996 ripng_route_subtype_print(rinfo
),
1997 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2000 vty_out(vty
, "%c(%s) %s/%d ",
2001 zebra_route_char(rinfo
->type
),
2002 ripng_route_subtype_print(rinfo
),
2003 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2006 vty_out(vty
, "%*s", 18, " ");
2007 len
= vty_out(vty
, "%s",
2008 inet6_ntoa(rinfo
->nexthop
));
2012 len
= vty_out(vty
, "%*s", len
, " ");
2015 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2016 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2019 ifindex2ifname(rinfo
->ifindex
,
2021 } else if (rinfo
->metric
2022 == RIPNG_METRIC_INFINITY
) {
2023 len
= vty_out(vty
, "kill");
2025 len
= vty_out(vty
, "self");
2029 vty_out(vty
, "%*s", len
, " ");
2031 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2032 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2035 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2036 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2037 /* RTE from remote RIP routers */
2038 ripng_vty_out_uptime(vty
, rinfo
);
2039 } else if (rinfo
->metric
2040 == RIPNG_METRIC_INFINITY
) {
2041 /* poisonous reversed routes (gc) */
2042 ripng_vty_out_uptime(vty
, rinfo
);
2052 DEFUN (show_ipv6_ripng_status
,
2053 show_ipv6_ripng_status_cmd
,
2054 "show ipv6 ripng status",
2057 "Show RIPng routes\n"
2058 "IPv6 routing protocol process parameters and statistics\n")
2060 struct listnode
*node
;
2061 struct interface
*ifp
;
2066 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2067 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2068 ripng
->update_time
);
2069 vty_out(vty
, " next due in %lu seconds\n",
2070 thread_timer_remain_second(ripng
->t_update
));
2071 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2072 vty_out(vty
, " garbage collect after %ld seconds\n",
2073 ripng
->garbage_time
);
2075 /* Filtering status show. */
2076 config_show_distribute(vty
);
2078 /* Default metric information. */
2079 vty_out(vty
, " Default redistribution metric is %d\n",
2080 ripng
->default_metric
);
2082 /* Redistribute information. */
2083 vty_out(vty
, " Redistributing:");
2084 ripng_redistribute_write(vty
, 0);
2087 vty_out(vty
, " Default version control: send version %d,",
2089 vty_out(vty
, " receive version %d \n", ripng
->version
);
2091 vty_out(vty
, " Interface Send Recv\n");
2093 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
)) {
2094 struct ripng_interface
*ri
;
2098 if (ri
->enable_network
|| ri
->enable_interface
) {
2100 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2101 ripng
->version
, ripng
->version
);
2105 vty_out(vty
, " Routing for Networks:\n");
2106 ripng_network_write(vty
, 0);
2108 vty_out(vty
, " Routing Information Sources:\n");
2110 " Gateway BadPackets BadRoutes Distance Last Update\n");
2111 ripng_peer_display(vty
);
2116 DEFUN (clear_ipv6_rip
,
2121 "Clear IPv6 RIP database\n")
2123 struct route_node
*rp
;
2124 struct ripng_info
*rinfo
;
2126 struct listnode
*listnode
;
2128 /* Clear received RIPng routes */
2129 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2134 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2135 if (!ripng_route_rte(rinfo
))
2138 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2139 ripng_zebra_ipv6_delete(rp
);
2144 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2145 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2146 listnode_delete(list
, rinfo
);
2147 ripng_info_free(rinfo
);
2150 if (list_isempty(list
)) {
2153 route_unlock_node(rp
);
2160 DEFUN_NOSH (router_ripng
,
2163 "Enable a routing process\n"
2164 "Make RIPng instance command\n")
2168 vty
->node
= RIPNG_NODE
;
2171 ret
= ripng_create();
2173 /* Notice to user we couldn't create RIPng. */
2175 zlog_warn("can't create RIPng");
2176 return CMD_WARNING_CONFIG_FAILED
;
2183 DEFUN (no_router_ripng
,
2184 no_router_ripng_cmd
,
2187 "Enable a routing process\n"
2188 "Make RIPng instance command\n")
2198 "Static route setup\n"
2199 "Set static RIPng route announcement\n")
2201 int idx_ipv6addr
= 1;
2203 struct prefix_ipv6 p
;
2204 struct route_node
*rp
;
2206 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2207 (struct prefix_ipv6
*)&p
);
2209 vty_out(vty
, "Malformed address\n");
2210 return CMD_WARNING_CONFIG_FAILED
;
2212 apply_mask_ipv6(&p
);
2214 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2216 vty_out(vty
, "There is already same static route.\n");
2217 route_unlock_node(rp
);
2218 return CMD_WARNING_CONFIG_FAILED
;
2220 rp
->info
= (void *)1;
2222 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2228 DEFUN (no_ripng_route
,
2230 "no route IPV6ADDR",
2232 "Static route setup\n"
2233 "Delete static RIPng route announcement\n")
2235 int idx_ipv6addr
= 2;
2237 struct prefix_ipv6 p
;
2238 struct route_node
*rp
;
2240 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2241 (struct prefix_ipv6
*)&p
);
2243 vty_out(vty
, "Malformed address\n");
2244 return CMD_WARNING_CONFIG_FAILED
;
2246 apply_mask_ipv6(&p
);
2248 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2250 vty_out(vty
, "Can't find static route.\n");
2251 return CMD_WARNING_CONFIG_FAILED
;
2254 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2255 route_unlock_node(rp
);
2258 route_unlock_node(rp
);
2263 DEFUN (ripng_aggregate_address
,
2264 ripng_aggregate_address_cmd
,
2265 "aggregate-address X:X::X:X/M",
2266 "Set aggregate RIPng route announcement\n"
2267 "Aggregate network\n")
2269 int idx_ipv6_prefixlen
= 1;
2272 struct route_node
*node
;
2274 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2275 (struct prefix_ipv6
*)&p
);
2277 vty_out(vty
, "Malformed address\n");
2278 return CMD_WARNING_CONFIG_FAILED
;
2281 /* Check aggregate alredy exist or not. */
2282 node
= route_node_get(ripng
->aggregate
, &p
);
2284 vty_out(vty
, "There is already same aggregate route.\n");
2285 route_unlock_node(node
);
2286 return CMD_WARNING_CONFIG_FAILED
;
2288 node
->info
= (void *)1;
2290 ripng_aggregate_add(&p
);
2295 DEFUN (no_ripng_aggregate_address
,
2296 no_ripng_aggregate_address_cmd
,
2297 "no aggregate-address X:X::X:X/M",
2299 "Delete aggregate RIPng route announcement\n"
2300 "Aggregate network\n")
2302 int idx_ipv6_prefixlen
= 2;
2305 struct route_node
*rn
;
2307 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2308 (struct prefix_ipv6
*)&p
);
2310 vty_out(vty
, "Malformed address\n");
2311 return CMD_WARNING_CONFIG_FAILED
;
2314 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2316 vty_out(vty
, "Can't find aggregate route.\n");
2317 return CMD_WARNING_CONFIG_FAILED
;
2319 route_unlock_node(rn
);
2321 route_unlock_node(rn
);
2323 ripng_aggregate_delete(&p
);
2328 DEFUN (ripng_default_metric
,
2329 ripng_default_metric_cmd
,
2330 "default-metric (1-16)",
2331 "Set a metric of redistribute routes\n"
2336 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2341 DEFUN (no_ripng_default_metric
,
2342 no_ripng_default_metric_cmd
,
2343 "no default-metric [(1-16)]",
2345 "Set a metric of redistribute routes\n"
2349 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2356 /* RIPng update timer setup. */
2357 DEFUN (ripng_update_timer
,
2358 ripng_update_timer_cmd
,
2359 "update-timer SECOND",
2360 "Set RIPng update timer in seconds\n"
2363 unsigned long update
;
2364 char *endptr
= NULL
;
2366 update
= strtoul (argv
[0], &endptr
, 10);
2367 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2369 vty_out (vty
, "update timer value error\n");
2370 return CMD_WARNING_CONFIG_FAILED
;
2373 ripng
->update_time
= update
;
2375 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2379 DEFUN (no_ripng_update_timer
,
2380 no_ripng_update_timer_cmd
,
2381 "no update-timer SECOND",
2383 "Unset RIPng update timer in seconds\n"
2386 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2387 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2391 /* RIPng timeout timer setup. */
2392 DEFUN (ripng_timeout_timer
,
2393 ripng_timeout_timer_cmd
,
2394 "timeout-timer SECOND",
2395 "Set RIPng timeout timer in seconds\n"
2398 unsigned long timeout
;
2399 char *endptr
= NULL
;
2401 timeout
= strtoul (argv
[0], &endptr
, 10);
2402 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2404 vty_out (vty
, "timeout timer value error\n");
2405 return CMD_WARNING_CONFIG_FAILED
;
2408 ripng
->timeout_time
= timeout
;
2413 DEFUN (no_ripng_timeout_timer
,
2414 no_ripng_timeout_timer_cmd
,
2415 "no timeout-timer SECOND",
2417 "Unset RIPng timeout timer in seconds\n"
2420 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2424 /* RIPng garbage timer setup. */
2425 DEFUN (ripng_garbage_timer
,
2426 ripng_garbage_timer_cmd
,
2427 "garbage-timer SECOND",
2428 "Set RIPng garbage timer in seconds\n"
2431 unsigned long garbage
;
2432 char *endptr
= NULL
;
2434 garbage
= strtoul (argv
[0], &endptr
, 10);
2435 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2437 vty_out (vty
, "garbage timer value error\n");
2438 return CMD_WARNING_CONFIG_FAILED
;
2441 ripng
->garbage_time
= garbage
;
2446 DEFUN (no_ripng_garbage_timer
,
2447 no_ripng_garbage_timer_cmd
,
2448 "no garbage-timer SECOND",
2450 "Unset RIPng garbage timer in seconds\n"
2453 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2458 DEFUN (ripng_timers
,
2460 "timers basic (0-65535) (0-65535) (0-65535)",
2461 "RIPng timers setup\n"
2463 "Routing table update timer value in second. Default is 30.\n"
2464 "Routing information timeout timer. Default is 180.\n"
2465 "Garbage collection timer. Default is 120.\n")
2468 int idx_number_2
= 3;
2469 int idx_number_3
= 4;
2470 unsigned long update
;
2471 unsigned long timeout
;
2472 unsigned long garbage
;
2474 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2475 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2476 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2478 /* Set each timer value. */
2479 ripng
->update_time
= update
;
2480 ripng
->timeout_time
= timeout
;
2481 ripng
->garbage_time
= garbage
;
2483 /* Reset update timer thread. */
2484 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2489 DEFUN (no_ripng_timers
,
2490 no_ripng_timers_cmd
,
2491 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2493 "RIPng timers setup\n"
2495 "Routing table update timer value in second. Default is 30.\n"
2496 "Routing information timeout timer. Default is 180.\n"
2497 "Garbage collection timer. Default is 120.\n")
2499 /* Set each timer value to the default. */
2500 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2501 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2502 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2504 /* Reset update timer thread. */
2505 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2511 DEFUN (show_ipv6_protocols
,
2512 show_ipv6_protocols_cmd
,
2513 "show ipv6 protocols",
2516 "Routing protocol information\n")
2521 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2523 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2524 ripng
->update_time
, 0);
2526 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2527 ripng
->timeout_time
,
2528 ripng
->garbage_time
);
2530 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2531 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2537 /* Please be carefull to use this command. */
2538 DEFUN (ripng_default_information_originate
,
2539 ripng_default_information_originate_cmd
,
2540 "default-information originate",
2541 "Default route information\n"
2542 "Distribute default route\n")
2544 struct prefix_ipv6 p
;
2546 if (!ripng
->default_information
) {
2547 ripng
->default_information
= 1;
2549 str2prefix_ipv6("::/0", &p
);
2550 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2557 DEFUN (no_ripng_default_information_originate
,
2558 no_ripng_default_information_originate_cmd
,
2559 "no default-information originate",
2561 "Default route information\n"
2562 "Distribute default route\n")
2564 struct prefix_ipv6 p
;
2566 if (ripng
->default_information
) {
2567 ripng
->default_information
= 0;
2569 str2prefix_ipv6("::/0", &p
);
2570 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2571 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2577 /* Update ECMP routes to zebra when ECMP is disabled. */
2578 static void ripng_ecmp_disable(void)
2580 struct route_node
*rp
;
2581 struct ripng_info
*rinfo
, *tmp_rinfo
;
2583 struct listnode
*node
, *nextnode
;
2588 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2589 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2590 rinfo
= listgetdata(listhead(list
));
2591 if (!ripng_route_rte(rinfo
))
2594 /* Drop all other entries, except the first one. */
2595 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2596 if (tmp_rinfo
!= rinfo
) {
2597 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2599 tmp_rinfo
->t_garbage_collect
);
2600 list_delete_node(list
, node
);
2601 ripng_info_free(tmp_rinfo
);
2605 ripng_zebra_ipv6_add(rp
);
2607 /* Set the route change flag. */
2608 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2610 /* Signal the output process to trigger an update. */
2611 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2615 DEFUN (ripng_allow_ecmp
,
2616 ripng_allow_ecmp_cmd
,
2618 "Allow Equal Cost MultiPath\n")
2621 vty_out(vty
, "ECMP is already enabled.\n");
2622 return CMD_WARNING_CONFIG_FAILED
;
2626 zlog_info("ECMP is enabled.");
2630 DEFUN (no_ripng_allow_ecmp
,
2631 no_ripng_allow_ecmp_cmd
,
2634 "Allow Equal Cost MultiPath\n")
2637 vty_out(vty
, "ECMP is already disabled.\n");
2638 return CMD_WARNING_CONFIG_FAILED
;
2642 zlog_info("ECMP is disabled.");
2643 ripng_ecmp_disable();
2647 /* RIPng configuration write function. */
2648 static int ripng_config_write(struct vty
*vty
)
2650 int ripng_network_write(struct vty
*, int);
2651 void ripng_redistribute_write(struct vty
*, int);
2653 struct route_node
*rp
;
2658 vty_out(vty
, "router ripng\n");
2660 if (ripng
->default_information
)
2661 vty_out(vty
, " default-information originate\n");
2663 ripng_network_write(vty
, 1);
2665 /* RIPng default metric configuration */
2666 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2667 vty_out(vty
, " default-metric %d\n",
2668 ripng
->default_metric
);
2670 ripng_redistribute_write(vty
, 1);
2672 /* RIP offset-list configuration. */
2673 config_write_ripng_offset_list(vty
);
2675 /* RIPng aggregate routes. */
2676 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2677 if (rp
->info
!= NULL
)
2678 vty_out(vty
, " aggregate-address %s/%d\n",
2679 inet6_ntoa(rp
->p
.u
.prefix6
),
2682 /* ECMP configuration. */
2684 vty_out(vty
, " allow-ecmp\n");
2686 /* RIPng static routes. */
2687 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2688 if (rp
->info
!= NULL
)
2689 vty_out(vty
, " route %s/%d\n",
2690 inet6_ntoa(rp
->p
.u
.prefix6
),
2693 /* RIPng timers configuration. */
2694 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2695 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2696 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2697 vty_out(vty
, " timers basic %ld %ld %ld\n",
2698 ripng
->update_time
, ripng
->timeout_time
,
2699 ripng
->garbage_time
);
2702 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2703 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2704 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2705 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2706 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2707 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2710 write
+= config_write_distribute(vty
);
2712 write
+= config_write_if_rmap(vty
);
2719 /* RIPng node structure. */
2720 static struct cmd_node cmd_ripng_node
= {
2721 RIPNG_NODE
, "%s(config-router)# ", 1,
2724 static void ripng_distribute_update(struct distribute
*dist
)
2726 struct interface
*ifp
;
2727 struct ripng_interface
*ri
;
2728 struct access_list
*alist
;
2729 struct prefix_list
*plist
;
2734 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2740 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2741 alist
= access_list_lookup(AFI_IP6
,
2742 dist
->list
[DISTRIBUTE_V6_IN
]);
2744 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2746 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2748 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2750 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2751 alist
= access_list_lookup(AFI_IP6
,
2752 dist
->list
[DISTRIBUTE_V6_OUT
]);
2754 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2756 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2758 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2760 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2761 plist
= prefix_list_lookup(AFI_IP6
,
2762 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2764 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2766 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2768 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2770 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2771 plist
= prefix_list_lookup(AFI_IP6
,
2772 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2774 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2776 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2778 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2781 void ripng_distribute_update_interface(struct interface
*ifp
)
2783 struct distribute
*dist
;
2785 dist
= distribute_lookup(ifp
->name
);
2787 ripng_distribute_update(dist
);
2790 /* Update all interface's distribute list. */
2791 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2793 struct interface
*ifp
;
2794 struct listnode
*node
;
2796 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2797 ripng_distribute_update_interface(ifp
);
2800 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2802 ripng_distribute_update_all(NULL
);
2805 /* delete all the added ripng routes. */
2809 struct route_node
*rp
;
2810 struct ripng_info
*rinfo
;
2811 struct ripng_aggregate
*aggregate
;
2812 struct list
*list
= NULL
;
2813 struct listnode
*listnode
= NULL
;
2816 /* Clear RIPng routes */
2817 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2818 if ((list
= rp
->info
) != NULL
) {
2819 rinfo
= listgetdata(listhead(list
));
2820 if (ripng_route_rte(rinfo
))
2821 ripng_zebra_ipv6_delete(rp
);
2823 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2825 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2827 rinfo
->t_garbage_collect
);
2828 ripng_info_free(rinfo
);
2832 route_unlock_node(rp
);
2835 if ((aggregate
= rp
->aggregate
) != NULL
) {
2836 ripng_aggregate_free(aggregate
);
2837 rp
->aggregate
= NULL
;
2838 route_unlock_node(rp
);
2842 /* Cancel the RIPng timers */
2843 RIPNG_TIMER_OFF(ripng
->t_update
);
2844 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2845 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2847 /* Cancel the read thread */
2848 if (ripng
->t_read
) {
2849 thread_cancel(ripng
->t_read
);
2850 ripng
->t_read
= NULL
;
2853 /* Close the RIPng socket */
2854 if (ripng
->sock
>= 0) {
2859 /* Static RIPng route configuration. */
2860 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2863 route_unlock_node(rp
);
2866 /* RIPng aggregated prefixes */
2867 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2870 route_unlock_node(rp
);
2873 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2874 if (ripng
->route_map
[i
].name
)
2875 free(ripng
->route_map
[i
].name
);
2877 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2878 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2879 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2881 stream_free(ripng
->ibuf
);
2882 stream_free(ripng
->obuf
);
2884 XFREE(MTYPE_RIPNG
, ripng
);
2888 ripng_clean_network();
2889 ripng_passive_interface_clean();
2890 ripng_offset_clean();
2891 ripng_interface_clean();
2892 ripng_redistribute_clean();
2895 /* Reset all values to the default settings. */
2898 /* Call ripd related reset functions. */
2899 ripng_debug_reset();
2900 ripng_route_map_reset();
2902 /* Call library reset functions. */
2904 access_list_reset();
2905 prefix_list_reset();
2907 distribute_list_reset();
2909 ripng_interface_reset();
2911 ripng_zclient_reset();
2914 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2916 struct interface
*ifp
;
2917 struct ripng_interface
*ri
;
2918 struct route_map
*rmap
;
2920 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2926 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2927 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2929 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2931 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2933 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2935 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2936 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2938 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2940 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2942 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2945 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2947 struct if_rmap
*if_rmap
;
2949 if_rmap
= if_rmap_lookup(ifp
->name
);
2951 ripng_if_rmap_update(if_rmap
);
2954 static void ripng_routemap_update_redistribute(void)
2959 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2960 if (ripng
->route_map
[i
].name
)
2961 ripng
->route_map
[i
].map
=
2962 route_map_lookup_by_name(
2963 ripng
->route_map
[i
].name
);
2968 static void ripng_routemap_update(const char *unused
)
2970 struct interface
*ifp
;
2971 struct listnode
*node
;
2973 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
2974 ripng_if_rmap_update_interface(ifp
);
2976 ripng_routemap_update_redistribute();
2979 /* Initialize ripng structure and set commands. */
2982 /* Install RIPNG_NODE. */
2983 install_node(&cmd_ripng_node
, ripng_config_write
);
2985 /* Install ripng commands. */
2986 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2987 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2989 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2991 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2992 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
2994 install_default(RIPNG_NODE
);
2995 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2996 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
2997 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
2998 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3000 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3001 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3003 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3004 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3006 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3007 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3008 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3009 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3010 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3011 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3012 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3015 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3016 install_element(RIPNG_NODE
,
3017 &no_ripng_default_information_originate_cmd
);
3019 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3020 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3025 /* Access list install. */
3027 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3028 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3030 /* Prefix list initialize.*/
3032 prefix_list_add_hook(ripng_distribute_update_all
);
3033 prefix_list_delete_hook(ripng_distribute_update_all
);
3035 /* Distribute list install. */
3036 distribute_list_init(RIPNG_NODE
);
3037 distribute_list_add_hook(ripng_distribute_update
);
3038 distribute_list_delete_hook(ripng_distribute_update
);
3040 /* Route-map for interface. */
3041 ripng_route_map_init();
3042 ripng_offset_init();
3044 route_map_add_hook(ripng_routemap_update
);
3045 route_map_delete_hook(ripng_routemap_update
);
3047 if_rmap_init(RIPNG_NODE
);
3048 if_rmap_hook_add(ripng_if_rmap_update
);
3049 if_rmap_hook_delete(ripng_if_rmap_update
);