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"
38 #include "lib_errors.h"
40 #include "ripngd/ripngd.h"
41 #include "ripngd/ripng_route.h"
42 #include "ripngd/ripng_debug.h"
43 #include "ripngd/ripng_nexthop.h"
45 /* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48 struct ripng
*ripng
= NULL
;
50 enum { ripng_all_route
,
55 void ripng_output_process(struct interface
*, struct sockaddr_in6
*, int);
57 int ripng_triggered_update(struct thread
*);
59 /* RIPng next hop specification. */
60 struct ripng_nexthop
{
61 enum ripng_nexthop_type
{
65 struct in6_addr address
;
68 static int ripng_route_rte(struct ripng_info
*rinfo
)
70 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
71 && rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
74 /* Allocate new ripng information. */
75 struct ripng_info
*ripng_info_new()
77 struct ripng_info
*new;
79 new = XCALLOC(MTYPE_RIPNG_ROUTE
, sizeof(struct ripng_info
));
83 /* Free ripng information. */
84 void ripng_info_free(struct ripng_info
*rinfo
)
86 XFREE(MTYPE_RIPNG_ROUTE
, rinfo
);
89 /* Create ripng socket. */
90 static int ripng_make_socket(void)
94 struct sockaddr_in6 ripaddr
;
96 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
98 flog_err_sys(LIB_ERR_SOCKET
, "Can't make ripng socket");
102 setsockopt_so_recvbuf(sock
, 8096);
103 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
106 #ifdef IPTOS_PREC_INTERNETCONTROL
107 ret
= setsockopt_ipv6_tclass(sock
, IPTOS_PREC_INTERNETCONTROL
);
111 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
114 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
117 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
121 memset(&ripaddr
, 0, sizeof(ripaddr
));
122 ripaddr
.sin6_family
= AF_INET6
;
124 ripaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
125 #endif /* SIN6_LEN */
126 ripaddr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
128 if (ripngd_privs
.change(ZPRIVS_RAISE
))
129 flog_err(LIB_ERR_PRIVILEGES
,
130 "ripng_make_socket: could not raise privs");
132 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
134 flog_err_sys(LIB_ERR_SOCKET
, "Can't bind ripng socket: %s.",
135 safe_strerror(errno
));
136 if (ripngd_privs
.change(ZPRIVS_LOWER
))
137 flog_err(LIB_ERR_PRIVILEGES
,
138 "ripng_make_socket: could not lower privs");
141 if (ripngd_privs
.change(ZPRIVS_LOWER
))
142 flog_err(LIB_ERR_PRIVILEGES
,
143 "ripng_make_socket: could not lower privs");
151 /* Send RIPng packet. */
152 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
153 struct interface
*ifp
)
158 struct cmsghdr
*cmsgptr
;
160 struct in6_pktinfo
*pkt
;
161 struct sockaddr_in6 addr
;
163 if (IS_RIPNG_DEBUG_SEND
) {
165 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
166 zlog_debug(" send interface %s", ifp
->name
);
167 zlog_debug(" send packet size %d", bufsize
);
170 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
171 addr
.sin6_family
= AF_INET6
;
173 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
174 #endif /* SIN6_LEN */
175 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
177 /* When destination is specified. */
179 addr
.sin6_addr
= to
->sin6_addr
;
180 addr
.sin6_port
= to
->sin6_port
;
182 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
183 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
186 memset(&msg
, 0, sizeof(msg
));
187 msg
.msg_name
= (void *)&addr
;
188 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
191 msg
.msg_control
= (void *)adata
;
192 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
195 iov
.iov_len
= bufsize
;
197 cmsgptr
= (struct cmsghdr
*)adata
;
198 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
199 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
200 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
202 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
203 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
204 pkt
->ipi6_ifindex
= ifp
->ifindex
;
206 ret
= sendmsg(ripng
->sock
, &msg
, 0);
210 flog_err_sys(LIB_ERR_SOCKET
,
211 "RIPng send fail on %s to %s: %s",
212 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
213 safe_strerror(errno
));
215 flog_err_sys(LIB_ERR_SOCKET
,
216 "RIPng send fail on %s: %s", ifp
->name
,
217 safe_strerror(errno
));
223 /* Receive UDP RIPng packet from socket. */
224 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
225 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
231 struct cmsghdr
*cmsgptr
;
232 struct in6_addr dst
= {.s6_addr
= {0}};
234 memset(&dst
, 0, sizeof(struct in6_addr
));
236 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
237 point I can't determine size of cmsghdr */
240 /* Fill in message and iovec. */
241 memset(&msg
, 0, sizeof(msg
));
242 msg
.msg_name
= (void *)from
;
243 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
246 msg
.msg_control
= (void *)adata
;
247 msg
.msg_controllen
= sizeof adata
;
249 iov
.iov_len
= bufsize
;
251 /* If recvmsg fail return minus value. */
252 ret
= recvmsg(sock
, &msg
, 0);
256 for (cmsgptr
= ZCMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
257 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
258 /* I want interface index which this packet comes from. */
259 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
260 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
261 struct in6_pktinfo
*ptr
;
263 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
264 *ifindex
= ptr
->ipi6_ifindex
;
265 dst
= ptr
->ipi6_addr
;
269 "Interface index returned by IPV6_PKTINFO is zero");
272 /* Incoming packet's multicast hop limit. */
273 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
274 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
275 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
276 *hoplimit
= *phoplimit
;
280 /* Hoplimit check shold be done when destination address is
281 multicast address. */
282 if (!IN6_IS_ADDR_MULTICAST(&dst
))
288 /* Dump rip packet */
289 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
294 const char *command_str
;
296 /* Set command string. */
297 if (packet
->command
== RIPNG_REQUEST
)
298 command_str
= "request";
299 else if (packet
->command
== RIPNG_RESPONSE
)
300 command_str
= "response";
302 command_str
= "unknown";
304 /* Dump packet header. */
305 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
306 packet
->version
, size
);
308 /* Dump each routing table entry. */
311 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
312 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
313 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
316 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
317 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
318 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
322 /* RIPng next hop address RTE (Route Table Entry). */
323 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
324 struct ripng_nexthop
*nexthop
)
326 char buf
[INET6_BUFSIZ
];
328 /* Logging before checking RTE. */
329 if (IS_RIPNG_DEBUG_RECV
)
330 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
332 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
335 /* RFC2080 2.1.1 Next Hop:
336 The route tag and prefix length in the next hop RTE must be
337 set to zero on sending and ignored on receiption. */
338 if (ntohs(rte
->tag
) != 0)
340 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
342 (route_tag_t
)ntohs(rte
->tag
),
343 inet6_ntoa(from
->sin6_addr
));
345 if (rte
->prefixlen
!= 0)
347 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
348 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
350 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
351 next hop RTE indicates that the next hop address should be the
352 originator of the RIPng advertisement. An address specified as a
353 next hop must be a link-local address. */
354 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
355 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
356 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
360 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
361 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
362 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
366 /* The purpose of the next hop RTE is to eliminate packets being
367 routed through extra hops in the system. It is particularly useful
368 when RIPng is not being run on all of the routers on a network.
369 Note that next hop RTE is "advisory". That is, if the provided
370 information is ignored, a possibly sub-optimal, but absolutely
371 valid, route may be taken. If the received next hop address is not
372 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
373 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
374 inet6_ntoa(rte
->addr
),
375 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
377 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
378 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
383 /* If ifp has same link-local address then return 1. */
384 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
386 struct listnode
*node
;
387 struct connected
*connected
;
390 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
391 p
= connected
->address
;
393 if (p
->family
== AF_INET6
394 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
395 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
401 /* RIPng route garbage collect timer. */
402 static int ripng_garbage_collect(struct thread
*t
)
404 struct ripng_info
*rinfo
;
405 struct route_node
*rp
;
407 rinfo
= THREAD_ARG(t
);
408 rinfo
->t_garbage_collect
= NULL
;
410 /* Off timeout timer. */
411 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
413 /* Get route_node pointer. */
416 /* Unlock route_node. */
417 listnode_delete(rp
->info
, rinfo
);
418 if (list_isempty((struct list
*)rp
->info
)) {
419 list_delete_and_null((struct list
**)&rp
->info
);
420 route_unlock_node(rp
);
423 /* Free RIPng routing information. */
424 ripng_info_free(rinfo
);
429 static void ripng_timeout_update(struct ripng_info
*rinfo
);
431 /* Add new route to the ECMP list.
432 * RETURN: the new entry added in the list, or NULL if it is not the first
433 * entry and ECMP is not allowed.
435 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
437 struct route_node
*rp
= rinfo_new
->rp
;
438 struct ripng_info
*rinfo
= NULL
;
439 struct list
*list
= NULL
;
441 if (rp
->info
== NULL
)
442 rp
->info
= list_new();
443 list
= (struct list
*)rp
->info
;
445 /* If ECMP is not allowed and some entry already exists in the list,
447 if (listcount(list
) && !ripng
->ecmp
)
450 rinfo
= ripng_info_new();
451 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
452 listnode_add(list
, rinfo
);
454 if (ripng_route_rte(rinfo
)) {
455 ripng_timeout_update(rinfo
);
456 ripng_zebra_ipv6_add(rp
);
459 ripng_aggregate_increment(rp
, rinfo
);
461 /* Set the route change flag on the first entry. */
462 rinfo
= listgetdata(listhead(list
));
463 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
465 /* Signal the output process to trigger an update. */
466 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
471 /* Replace the ECMP list with the new route.
472 * RETURN: the new entry added in the list
474 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
476 struct route_node
*rp
= rinfo_new
->rp
;
477 struct list
*list
= (struct list
*)rp
->info
;
478 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
479 struct listnode
*node
= NULL
, *nextnode
= NULL
;
481 if (list
== NULL
|| listcount(list
) == 0)
482 return ripng_ecmp_add(rinfo_new
);
484 /* Get the first entry */
485 rinfo
= listgetdata(listhead(list
));
487 /* Learnt route replaced by a local one. Delete it from zebra. */
488 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
489 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
490 ripng_zebra_ipv6_delete(rp
);
492 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
493 ripng_aggregate_decrement_list(rp
, list
);
495 /* Re-use the first entry, and delete the others. */
496 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
497 if (tmp_rinfo
!= rinfo
) {
498 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
499 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
500 list_delete_node(list
, node
);
501 ripng_info_free(tmp_rinfo
);
504 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
505 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
506 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
508 if (ripng_route_rte(rinfo
)) {
509 ripng_timeout_update(rinfo
);
510 /* The ADD message implies an update. */
511 ripng_zebra_ipv6_add(rp
);
514 ripng_aggregate_increment(rp
, rinfo
);
516 /* Set the route change flag. */
517 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
519 /* Signal the output process to trigger an update. */
520 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
525 /* Delete one route from the ECMP list.
527 * null - the entry is freed, and other entries exist in the list
528 * the entry - the entry is the last one in the list; its metric is set
529 * to INFINITY, and the garbage collector is started for it
531 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
533 struct route_node
*rp
= rinfo
->rp
;
534 struct list
*list
= (struct list
*)rp
->info
;
536 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
538 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
539 ripng_aggregate_decrement(rp
, rinfo
);
541 if (listcount(list
) > 1) {
542 /* Some other ECMP entries still exist. Just delete this entry.
544 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
545 listnode_delete(list
, rinfo
);
546 if (ripng_route_rte(rinfo
)
547 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
548 /* The ADD message implies the update. */
549 ripng_zebra_ipv6_add(rp
);
550 ripng_info_free(rinfo
);
553 assert(rinfo
== listgetdata(listhead(list
)));
555 /* This is the only entry left in the list. We must keep it in
556 * the list for garbage collection time, with INFINITY metric.
559 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
560 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
561 ripng
->garbage_time
);
563 if (ripng_route_rte(rinfo
)
564 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
565 ripng_zebra_ipv6_delete(rp
);
568 /* Set the route change flag on the first entry. */
569 rinfo
= listgetdata(listhead(list
));
570 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
572 /* Signal the output process to trigger an update. */
573 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
578 /* Timeout RIPng routes. */
579 static int ripng_timeout(struct thread
*t
)
581 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
585 static void ripng_timeout_update(struct ripng_info
*rinfo
)
587 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
588 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
589 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
590 ripng
->timeout_time
);
594 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
595 struct ripng_interface
*ri
)
597 struct distribute
*dist
;
598 struct access_list
*alist
;
599 struct prefix_list
*plist
;
600 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
603 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
605 /* Input distribute-list filtering. */
606 if (ri
->list
[ripng_distribute
]) {
607 if (access_list_apply(ri
->list
[ripng_distribute
],
610 if (IS_RIPNG_DEBUG_PACKET
)
611 zlog_debug("%s/%d filtered by distribute %s",
612 inet6_ntoa(p
->prefix
), p
->prefixlen
,
617 if (ri
->prefix
[ripng_distribute
]) {
618 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
621 if (IS_RIPNG_DEBUG_PACKET
)
622 zlog_debug("%s/%d filtered by prefix-list %s",
623 inet6_ntoa(p
->prefix
), p
->prefixlen
,
629 /* All interface filter check. */
630 dist
= distribute_lookup(NULL
);
632 if (dist
->list
[distribute
]) {
633 alist
= access_list_lookup(AFI_IP6
,
634 dist
->list
[distribute
]);
637 if (access_list_apply(alist
, (struct prefix
*)p
)
639 if (IS_RIPNG_DEBUG_PACKET
)
641 "%s/%d filtered by distribute %s",
642 inet6_ntoa(p
->prefix
),
643 p
->prefixlen
, inout
);
648 if (dist
->prefix
[distribute
]) {
649 plist
= prefix_list_lookup(AFI_IP6
,
650 dist
->prefix
[distribute
]);
653 if (prefix_list_apply(plist
, (struct prefix
*)p
)
655 if (IS_RIPNG_DEBUG_PACKET
)
657 "%s/%d filtered by prefix-list %s",
658 inet6_ntoa(p
->prefix
),
659 p
->prefixlen
, inout
);
668 /* Process RIPng route according to RFC2080. */
669 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
670 struct ripng_nexthop
*ripng_nexthop
,
671 struct interface
*ifp
)
674 struct prefix_ipv6 p
;
675 struct route_node
*rp
;
676 struct ripng_info
*rinfo
= NULL
, newinfo
;
677 struct ripng_interface
*ri
;
678 struct in6_addr
*nexthop
;
680 struct list
*list
= NULL
;
681 struct listnode
*node
= NULL
;
683 /* Make prefix structure. */
684 memset(&p
, 0, sizeof(struct prefix_ipv6
));
686 /* p.prefix = rte->addr; */
687 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
688 p
.prefixlen
= rte
->prefixlen
;
690 /* Make sure mask is applied. */
691 /* XXX We have to check the prefix is valid or not before call
695 /* Apply input filters. */
698 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
702 memset(&newinfo
, 0, sizeof(newinfo
));
703 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
704 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
705 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
706 newinfo
.nexthop
= ripng_nexthop
->address
;
708 newinfo
.nexthop
= from
->sin6_addr
;
709 newinfo
.from
= from
->sin6_addr
;
710 newinfo
.ifindex
= ifp
->ifindex
;
711 newinfo
.metric
= rte
->metric
;
712 newinfo
.metric_out
= rte
->metric
; /* XXX */
713 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
716 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
719 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
720 (struct prefix
*)&p
, RMAP_RIPNG
,
723 if (ret
== RMAP_DENYMATCH
) {
724 if (IS_RIPNG_DEBUG_PACKET
)
726 "RIPng %s/%d is filtered by route-map in",
727 inet6_ntoa(p
.prefix
), p
.prefixlen
);
731 /* Get back the object */
732 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
733 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
734 &ripng_nexthop
->address
)) {
735 /* the nexthop get changed by the routemap */
736 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
737 ripng_nexthop
->address
=
740 ripng_nexthop
->address
= in6addr_any
;
743 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
745 /* the nexthop get changed by the routemap */
746 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
747 ripng_nexthop
->flag
=
748 RIPNG_NEXTHOP_ADDRESS
;
749 ripng_nexthop
->address
=
754 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
756 newinfo
.metric_out
; /* XXX: the routemap uses the
760 /* Once the entry has been validated, update the metric by
761 * adding the cost of the network on wich the message
762 * arrived. If the result is greater than infinity, use infinity
763 * (RFC2453 Sec. 3.9.2)
766 /* Zebra ripngd can handle offset-list in. */
767 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
769 /* If offset-list does not modify the metric use interface's
772 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
774 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
775 rte
->metric
= RIPNG_METRIC_INFINITY
;
777 /* Set nexthop pointer. */
778 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
779 nexthop
= &ripng_nexthop
->address
;
781 nexthop
= &from
->sin6_addr
;
783 /* Lookup RIPng routing table. */
784 rp
= route_node_get(ripng
->table
, (struct prefix
*)&p
);
787 newinfo
.nexthop
= *nexthop
;
788 newinfo
.metric
= rte
->metric
;
789 newinfo
.tag
= ntohs(rte
->tag
);
791 /* Check to see whether there is already RIPng route on the table. */
792 if ((list
= rp
->info
) != NULL
)
793 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
794 /* Need to compare with redistributed entry or local
796 if (!ripng_route_rte(rinfo
))
799 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
800 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
803 if (!listnextnode(node
)) {
804 /* Not found in the list */
806 if (rte
->metric
> rinfo
->metric
) {
807 /* New route has a greater metric.
809 route_unlock_node(rp
);
813 if (rte
->metric
< rinfo
->metric
)
814 /* New route has a smaller metric.
815 * Replace the ECMP list
816 * with the new one in below. */
819 /* Metrics are same. Unless ECMP is disabled,
820 * keep "rinfo" null and
821 * the new route is added in the ECMP list in
829 /* Redistributed route check. */
830 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
831 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
832 route_unlock_node(rp
);
836 /* Local static route. */
837 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
838 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
839 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
840 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
841 route_unlock_node(rp
);
847 /* Now, check to see whether there is already an explicit route
848 for the destination prefix. If there is no such route, add
849 this route to the routing table, unless the metric is
850 infinity (there is no point in adding a route which
852 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
853 ripng_ecmp_add(&newinfo
);
855 route_unlock_node(rp
);
857 /* If there is an existing route, compare the next hop address
858 to the address of the router from which the datagram came.
859 If this datagram is from the same router as the existing
860 route, reinitialize the timeout. */
861 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
862 && (rinfo
->ifindex
== ifp
->ifindex
));
865 * RFC 2080 - Section 2.4.2:
866 * "If the new metric is the same as the old one, examine the
868 * for the existing route. If it is at least halfway to the
870 * point, switch to the new route. This heuristic is optional,
872 * highly recommended".
874 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
876 && (thread_timer_remain_second(rinfo
->t_timeout
)
877 < (ripng
->timeout_time
/ 2))) {
878 ripng_ecmp_replace(&newinfo
);
880 /* Next, compare the metrics. If the datagram is from the same
881 router as the existing route, and the new metric is different
882 than the old one; or, if the new metric is lower than the old
883 one; do the following actions: */
884 else if ((same
&& rinfo
->metric
!= rte
->metric
)
885 || rte
->metric
< rinfo
->metric
) {
886 if (listcount(list
) == 1) {
887 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
888 ripng_ecmp_replace(&newinfo
);
890 ripng_ecmp_delete(rinfo
);
892 if (newinfo
.metric
< rinfo
->metric
)
893 ripng_ecmp_replace(&newinfo
);
894 else /* newinfo.metric > rinfo->metric */
895 ripng_ecmp_delete(rinfo
);
897 } else /* same & no change */
898 ripng_timeout_update(rinfo
);
900 /* Unlock tempolary lock of the route. */
901 route_unlock_node(rp
);
905 /* Add redistributed route to RIPng table. */
906 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
907 ifindex_t ifindex
, struct in6_addr
*nexthop
,
910 struct route_node
*rp
;
911 struct ripng_info
*rinfo
= NULL
, newinfo
;
912 struct list
*list
= NULL
;
914 /* Redistribute route */
915 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
917 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
920 rp
= route_node_get(ripng
->table
, (struct prefix
*)p
);
922 memset(&newinfo
, 0, sizeof(struct ripng_info
));
924 newinfo
.sub_type
= sub_type
;
925 newinfo
.ifindex
= ifindex
;
927 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
930 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
931 newinfo
.nexthop
= *nexthop
;
933 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
934 rinfo
= listgetdata(listhead(list
));
936 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
937 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
938 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
939 route_unlock_node(rp
);
943 /* Manually configured RIPng route check.
944 * They have the precedence on all the other entries.
946 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
947 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
948 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
949 if (type
!= ZEBRA_ROUTE_RIPNG
950 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
951 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
952 route_unlock_node(rp
);
957 ripng_ecmp_replace(&newinfo
);
958 route_unlock_node(rp
);
960 ripng_ecmp_add(&newinfo
);
962 if (IS_RIPNG_DEBUG_EVENT
) {
965 "Redistribute new prefix %s/%d on the interface %s",
966 inet6_ntoa(p
->prefix
), p
->prefixlen
,
967 ifindex2ifname(ifindex
, VRF_DEFAULT
));
970 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
971 inet6_ntoa(p
->prefix
), p
->prefixlen
,
972 inet6_ntoa(*nexthop
),
973 ifindex2ifname(ifindex
, VRF_DEFAULT
));
976 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
979 /* Delete redistributed route to RIPng table. */
980 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
983 struct route_node
*rp
;
984 struct ripng_info
*rinfo
;
986 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
988 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
991 rp
= route_node_lookup(ripng
->table
, (struct prefix
*)p
);
994 struct list
*list
= rp
->info
;
996 if (list
!= NULL
&& listcount(list
) != 0) {
997 rinfo
= listgetdata(listhead(list
));
998 if (rinfo
!= NULL
&& rinfo
->type
== type
999 && rinfo
->sub_type
== sub_type
1000 && rinfo
->ifindex
== ifindex
) {
1001 /* Perform poisoned reverse. */
1002 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1003 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1004 ripng_garbage_collect
,
1005 ripng
->garbage_time
);
1006 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1008 /* Aggregate count decrement. */
1009 ripng_aggregate_decrement(rp
, rinfo
);
1011 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1013 if (IS_RIPNG_DEBUG_EVENT
)
1015 "Poisone %s/%d on the interface %s with an "
1016 "infinity metric [delete]",
1017 inet6_ntoa(p
->prefix
),
1019 ifindex2ifname(ifindex
,
1022 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1025 route_unlock_node(rp
);
1029 /* Withdraw redistributed route. */
1030 void ripng_redistribute_withdraw(int type
)
1032 struct route_node
*rp
;
1033 struct ripng_info
*rinfo
= NULL
;
1034 struct list
*list
= NULL
;
1039 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1040 if ((list
= rp
->info
) != NULL
) {
1041 rinfo
= listgetdata(listhead(list
));
1042 if ((rinfo
->type
== type
)
1043 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1044 /* Perform poisoned reverse. */
1045 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1046 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1047 ripng_garbage_collect
,
1048 ripng
->garbage_time
);
1049 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1051 /* Aggregate count decrement. */
1052 ripng_aggregate_decrement(rp
, rinfo
);
1054 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1056 if (IS_RIPNG_DEBUG_EVENT
) {
1057 struct prefix_ipv6
*p
=
1058 (struct prefix_ipv6
*)&rp
->p
;
1061 "Poisone %s/%d on the interface %s [withdraw]",
1062 inet6_ntoa(p
->prefix
),
1064 ifindex2ifname(rinfo
->ifindex
,
1068 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1073 /* RIP routing information. */
1074 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1075 struct sockaddr_in6
*from
,
1076 struct interface
*ifp
, int hoplimit
)
1080 struct ripng_nexthop nexthop
;
1082 /* RFC2080 2.4.2 Response Messages:
1083 The Response must be ignored if it is not from the RIPng port. */
1084 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1085 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1086 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1087 ripng_peer_bad_packet(from
);
1091 /* The datagram's IPv6 source address should be checked to see
1092 whether the datagram is from a valid neighbor; the source of the
1093 datagram must be a link-local address. */
1094 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1095 zlog_warn("RIPng packet comes from non link local address %s",
1096 inet6_ntoa(from
->sin6_addr
));
1097 ripng_peer_bad_packet(from
);
1101 /* It is also worth checking to see whether the response is from one
1102 of the router's own addresses. Interfaces on broadcast networks
1103 may receive copies of their own multicasts immediately. If a
1104 router processes its own output as new input, confusion is likely,
1105 and such datagrams must be ignored. */
1106 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1108 "RIPng packet comes from my own link local address %s",
1109 inet6_ntoa(from
->sin6_addr
));
1110 ripng_peer_bad_packet(from
);
1114 /* As an additional check, periodic advertisements must have their
1115 hop counts set to 255, and inbound, multicast packets sent from the
1116 RIPng port (i.e. periodic advertisement or triggered update
1117 packets) must be examined to ensure that the hop count is 255. */
1118 if (hoplimit
>= 0 && hoplimit
!= 255) {
1120 "RIPng packet comes with non 255 hop count %d from %s",
1121 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1122 ripng_peer_bad_packet(from
);
1126 /* Update RIPng peer. */
1127 ripng_peer_update(from
, packet
->version
);
1129 /* Reset nexthop. */
1130 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1131 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1133 /* Set RTE pointer. */
1136 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1137 /* First of all, we have to check this RTE is next hop RTE or
1138 not. Next hop RTE is completely different with normal RTE so
1139 we need special treatment. */
1140 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1141 ripng_nexthop_rte(rte
, from
, &nexthop
);
1145 /* RTE information validation. */
1147 /* - is the destination prefix valid (e.g., not a multicast
1148 prefix and not a link-local address) A link-local address
1149 should never be present in an RTE. */
1150 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1152 "Destination prefix is a multicast address %s/%d [%d]",
1153 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1155 ripng_peer_bad_route(from
);
1158 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1160 "Destination prefix is a link-local address %s/%d [%d]",
1161 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1163 ripng_peer_bad_route(from
);
1166 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1168 "Destination prefix is a loopback address %s/%d [%d]",
1169 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1171 ripng_peer_bad_route(from
);
1175 /* - is the prefix length valid (i.e., between 0 and 128,
1177 if (rte
->prefixlen
> 128) {
1178 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1179 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1180 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1181 ripng_peer_bad_route(from
);
1185 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1186 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1187 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1188 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1189 ripng_peer_bad_route(from
);
1193 /* Vincent: XXX Should we compute the direclty reachable nexthop
1194 * for our RIPng network ?
1197 /* Routing table updates. */
1198 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1202 /* Response to request message. */
1203 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1204 struct sockaddr_in6
*from
,
1205 struct interface
*ifp
)
1209 struct prefix_ipv6 p
;
1210 struct route_node
*rp
;
1211 struct ripng_info
*rinfo
;
1212 struct ripng_interface
*ri
;
1214 /* Does not reponse to the requests on the loopback interfaces */
1215 if (if_is_loopback(ifp
))
1218 /* Check RIPng process is enabled on this interface. */
1223 /* When passive interface is specified, suppress responses */
1227 /* RIPng peer update. */
1228 ripng_peer_update(from
, packet
->version
);
1230 lim
= ((caddr_t
)packet
) + size
;
1233 /* The Request is processed entry by entry. If there are no
1234 entries, no response is given. */
1235 if (lim
== (caddr_t
)rte
)
1238 /* There is one special case. If there is exactly one entry in the
1239 request, and it has a destination prefix of zero, a prefix length
1240 of zero, and a metric of infinity (i.e., 16), then this is a
1241 request to send the entire routing table. In that case, a call
1242 is made to the output process to send the routing table to the
1243 requesting address/port. */
1244 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1245 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1246 /* All route with split horizon */
1247 ripng_output_process(ifp
, from
, ripng_all_route
);
1249 /* Except for this special case, processing is quite simple.
1250 Examine the list of RTEs in the Request one by one. For each
1251 entry, look up the destination in the router's routing
1252 database and, if there is a route, put that route's metric in
1253 the metric field of the RTE. If there is no explicit route
1254 to the specified destination, put infinity in the metric
1255 field. Once all the entries have been filled in, change the
1256 command from Request to Response and send the datagram back
1257 to the requestor. */
1258 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1259 p
.family
= AF_INET6
;
1261 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1262 p
.prefix
= rte
->addr
;
1263 p
.prefixlen
= rte
->prefixlen
;
1264 apply_mask_ipv6(&p
);
1266 rp
= route_node_lookup(ripng
->table
,
1267 (struct prefix
*)&p
);
1270 rinfo
= listgetdata(
1271 listhead((struct list
*)rp
->info
));
1272 rte
->metric
= rinfo
->metric
;
1273 route_unlock_node(rp
);
1275 rte
->metric
= RIPNG_METRIC_INFINITY
;
1277 packet
->command
= RIPNG_RESPONSE
;
1279 ripng_send_packet((caddr_t
)packet
, size
, from
, ifp
);
1283 /* First entry point of reading RIPng packet. */
1284 static int ripng_read(struct thread
*thread
)
1288 struct sockaddr_in6 from
;
1289 struct ripng_packet
*packet
;
1290 ifindex_t ifindex
= 0;
1291 struct interface
*ifp
;
1294 /* Check ripng is active and alive. */
1295 assert(ripng
!= NULL
);
1296 assert(ripng
->sock
>= 0);
1298 /* Fetch thread data and set read pointer to empty for event
1299 managing. `sock' sould be same as ripng->sock. */
1300 sock
= THREAD_FD(thread
);
1301 ripng
->t_read
= NULL
;
1303 /* Add myself to the next event. */
1304 ripng_event(RIPNG_READ
, sock
);
1306 /* Read RIPng packet. */
1307 len
= ripng_recv_packet(sock
, STREAM_DATA(ripng
->ibuf
),
1308 STREAM_SIZE(ripng
->ibuf
), &from
, &ifindex
,
1311 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno
));
1315 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1316 (4)) must be multiple size of one RTE size (20). */
1317 if (((len
- 4) % 20) != 0) {
1318 zlog_warn("RIPng invalid packet size %d from %s", len
,
1319 inet6_ntoa(from
.sin6_addr
));
1320 ripng_peer_bad_packet(&from
);
1324 packet
= (struct ripng_packet
*)STREAM_DATA(ripng
->ibuf
);
1325 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
1327 /* RIPng packet received. */
1328 if (IS_RIPNG_DEBUG_EVENT
)
1329 zlog_debug("RIPng packet received from %s port %d on %s",
1330 inet6_ntoa(from
.sin6_addr
), ntohs(from
.sin6_port
),
1331 ifp
? ifp
->name
: "unknown");
1333 /* Logging before packet checking. */
1334 if (IS_RIPNG_DEBUG_RECV
)
1335 ripng_packet_dump(packet
, len
, "RECV");
1337 /* Packet comes from unknown interface. */
1339 zlog_warn("RIPng packet comes from unknown interface %d",
1344 /* Packet version mismatch checking. */
1345 if (packet
->version
!= ripng
->version
) {
1347 "RIPng packet version %d doesn't fit to my version %d",
1348 packet
->version
, ripng
->version
);
1349 ripng_peer_bad_packet(&from
);
1353 /* Process RIPng packet. */
1354 switch (packet
->command
) {
1356 ripng_request_process(packet
, len
, &from
, ifp
);
1358 case RIPNG_RESPONSE
:
1359 ripng_response_process(packet
, len
, &from
, ifp
, hoplimit
);
1362 zlog_warn("Invalid RIPng command %d", packet
->command
);
1363 ripng_peer_bad_packet(&from
);
1369 /* Walk down the RIPng routing table then clear changed flag. */
1370 static void ripng_clear_changed_flag(void)
1372 struct route_node
*rp
;
1373 struct ripng_info
*rinfo
= NULL
;
1374 struct list
*list
= NULL
;
1375 struct listnode
*listnode
= NULL
;
1377 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
1378 if ((list
= rp
->info
) != NULL
)
1379 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1380 UNSET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
1381 /* This flag can be set only on the first entry.
1387 /* Regular update of RIPng route. Send all routing formation to RIPng
1388 enabled interface. */
1389 static int ripng_update(struct thread
*t
)
1391 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1392 struct interface
*ifp
;
1393 struct ripng_interface
*ri
;
1395 /* Clear update timer thread. */
1396 ripng
->t_update
= NULL
;
1398 /* Logging update event. */
1399 if (IS_RIPNG_DEBUG_EVENT
)
1400 zlog_debug("RIPng update timer expired!");
1402 /* Supply routes to each interface. */
1403 FOR_ALL_INTERFACES (vrf
, ifp
) {
1406 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1412 /* When passive interface is specified, suppress announce to the
1418 if (ri
->ri_send
== RIPNG_SEND_OFF
) {
1419 if (IS_RIPNG_DEBUG_EVENT
)
1421 "[Event] RIPng send to if %d is suppressed by config",
1425 #endif /* RIPNG_ADVANCED */
1427 ripng_output_process(ifp
, NULL
, ripng_all_route
);
1430 /* Triggered updates may be suppressed if a regular update is due by
1431 the time the triggered update would be sent. */
1432 if (ripng
->t_triggered_interval
) {
1433 thread_cancel(ripng
->t_triggered_interval
);
1434 ripng
->t_triggered_interval
= NULL
;
1438 /* Reset flush event. */
1439 ripng_event(RIPNG_UPDATE_EVENT
, 0);
1444 /* Triggered update interval timer. */
1445 static int ripng_triggered_interval(struct thread
*t
)
1447 ripng
->t_triggered_interval
= NULL
;
1449 if (ripng
->trigger
) {
1451 ripng_triggered_update(t
);
1456 /* Execute triggered update. */
1457 int ripng_triggered_update(struct thread
*t
)
1459 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1460 struct interface
*ifp
;
1461 struct ripng_interface
*ri
;
1464 ripng
->t_triggered_update
= NULL
;
1466 /* Cancel interval timer. */
1467 if (ripng
->t_triggered_interval
) {
1468 thread_cancel(ripng
->t_triggered_interval
);
1469 ripng
->t_triggered_interval
= NULL
;
1473 /* Logging triggered update. */
1474 if (IS_RIPNG_DEBUG_EVENT
)
1475 zlog_debug("RIPng triggered update!");
1477 /* Split Horizon processing is done when generating triggered
1478 updates as well as normal updates (see section 2.6). */
1479 FOR_ALL_INTERFACES (vrf
, ifp
) {
1482 if (if_is_loopback(ifp
) || !if_is_up(ifp
))
1488 /* When passive interface is specified, suppress announce to the
1493 ripng_output_process(ifp
, NULL
, ripng_changed_route
);
1496 /* Once all of the triggered updates have been generated, the route
1497 change flags should be cleared. */
1498 ripng_clear_changed_flag();
1500 /* After a triggered update is sent, a timer should be set for a
1501 random interval between 1 and 5 seconds. If other changes that
1502 would trigger updates occur before the timer expires, a single
1503 update is triggered when the timer expires. */
1504 interval
= (random() % 5) + 1;
1506 ripng
->t_triggered_interval
= NULL
;
1507 thread_add_timer(master
, ripng_triggered_interval
, NULL
, interval
,
1508 &ripng
->t_triggered_interval
);
1513 /* Write routing table entry to the stream and return next index of
1514 the routing table entry in the stream. */
1515 int ripng_write_rte(int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1516 struct in6_addr
*nexthop
, uint16_t tag
, uint8_t metric
)
1518 /* RIPng packet header. */
1520 stream_putc(s
, RIPNG_RESPONSE
);
1521 stream_putc(s
, RIPNG_V1
);
1525 /* Write routing table entry. */
1528 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1530 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1531 stream_putw(s
, tag
);
1533 stream_putc(s
, p
->prefixlen
);
1536 stream_putc(s
, metric
);
1541 /* Send RESPONSE message to specified destination. */
1542 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1546 struct route_node
*rp
;
1547 struct ripng_info
*rinfo
;
1548 struct ripng_interface
*ri
;
1549 struct ripng_aggregate
*aggregate
;
1550 struct prefix_ipv6
*p
;
1551 struct list
*ripng_rte_list
;
1552 struct list
*list
= NULL
;
1553 struct listnode
*listnode
= NULL
;
1555 if (IS_RIPNG_DEBUG_EVENT
) {
1557 zlog_debug("RIPng update routes to neighbor %s",
1558 inet6_ntoa(to
->sin6_addr
));
1560 zlog_debug("RIPng update routes on interface %s",
1564 /* Get RIPng interface. */
1567 ripng_rte_list
= ripng_rte_new();
1569 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1570 if ((list
= rp
->info
) != NULL
1571 && (rinfo
= listgetdata(listhead(list
))) != NULL
1572 && rinfo
->suppress
== 0) {
1573 /* If no route-map are applied, the RTE will be these
1577 p
= (struct prefix_ipv6
*)&rp
->p
;
1578 rinfo
->metric_out
= rinfo
->metric
;
1579 rinfo
->tag_out
= rinfo
->tag
;
1580 memset(&rinfo
->nexthop_out
, 0,
1581 sizeof(rinfo
->nexthop_out
));
1582 /* In order to avoid some local loops,
1583 * if the RIPng route has a nexthop via this interface,
1585 * otherwise set it to 0. The nexthop should not be
1587 * beyond the local broadcast/multicast area in order
1588 * to avoid an IGP multi-level recursive look-up.
1590 if (rinfo
->ifindex
== ifp
->ifindex
)
1591 rinfo
->nexthop_out
= rinfo
->nexthop
;
1593 /* Apply output filters. */
1594 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1598 /* Changed route only output. */
1599 if (route_type
== ripng_changed_route
1600 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1603 /* Split horizon. */
1604 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1605 /* We perform split horizon for RIPng routes. */
1607 struct ripng_info
*tmp_rinfo
= NULL
;
1609 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1611 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1612 && tmp_rinfo
->ifindex
1621 /* Preparation for route-map. */
1622 rinfo
->metric_set
= 0;
1625 * and tag_out are already initialized.
1628 /* Interface route-map */
1629 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1632 ret
= route_map_apply(
1633 ri
->routemap
[RIPNG_FILTER_OUT
],
1634 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1636 if (ret
== RMAP_DENYMATCH
) {
1637 if (IS_RIPNG_DEBUG_PACKET
)
1639 "RIPng %s/%d is filtered by route-map out",
1640 inet6_ntoa(p
->prefix
),
1646 /* Redistribute route-map. */
1647 if (ripng
->route_map
[rinfo
->type
].name
) {
1650 ret
= route_map_apply(
1651 ripng
->route_map
[rinfo
->type
].map
,
1652 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1654 if (ret
== RMAP_DENYMATCH
) {
1655 if (IS_RIPNG_DEBUG_PACKET
)
1657 "RIPng %s/%d is filtered by route-map",
1658 inet6_ntoa(p
->prefix
),
1664 /* When the route-map does not set metric. */
1665 if (!rinfo
->metric_set
) {
1666 /* If the redistribute metric is set. */
1667 if (ripng
->route_map
[rinfo
->type
].metric_config
1668 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1670 ripng
->route_map
[rinfo
->type
]
1673 /* If the route is not connected or
1675 one, use default-metric value */
1676 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1678 != ZEBRA_ROUTE_CONNECT
1680 != RIPNG_METRIC_INFINITY
)
1682 ripng
->default_metric
;
1686 /* Apply offset-list */
1687 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1688 ripng_offset_list_apply_out(p
, ifp
,
1689 &rinfo
->metric_out
);
1691 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1692 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1694 /* Perform split-horizon with poisoned reverse
1697 if (ri
->split_horizon
1698 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1699 struct ripng_info
*tmp_rinfo
= NULL
;
1701 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1703 if ((tmp_rinfo
->type
1704 == ZEBRA_ROUTE_RIPNG
)
1705 && tmp_rinfo
->ifindex
1708 RIPNG_METRIC_INFINITY
;
1711 /* Add RTE to the list */
1712 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1715 /* Process the aggregated RTE entry */
1716 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1717 && aggregate
->suppress
== 0) {
1718 /* If no route-map are applied, the RTE will be these
1722 p
= (struct prefix_ipv6
*)&rp
->p
;
1723 aggregate
->metric_set
= 0;
1724 aggregate
->metric_out
= aggregate
->metric
;
1725 aggregate
->tag_out
= aggregate
->tag
;
1726 memset(&aggregate
->nexthop_out
, 0,
1727 sizeof(aggregate
->nexthop_out
));
1729 /* Apply output filters.*/
1730 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1734 /* Interface route-map */
1735 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1737 struct ripng_info newinfo
;
1739 /* let's cast the aggregate structure to
1741 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1742 /* the nexthop is :: */
1743 newinfo
.metric
= aggregate
->metric
;
1744 newinfo
.metric_out
= aggregate
->metric_out
;
1745 newinfo
.tag
= aggregate
->tag
;
1746 newinfo
.tag_out
= aggregate
->tag_out
;
1748 ret
= route_map_apply(
1749 ri
->routemap
[RIPNG_FILTER_OUT
],
1750 (struct prefix
*)p
, RMAP_RIPNG
,
1753 if (ret
== RMAP_DENYMATCH
) {
1754 if (IS_RIPNG_DEBUG_PACKET
)
1756 "RIPng %s/%d is filtered by route-map out",
1757 inet6_ntoa(p
->prefix
),
1762 aggregate
->metric_out
= newinfo
.metric_out
;
1763 aggregate
->tag_out
= newinfo
.tag_out
;
1764 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1765 aggregate
->nexthop_out
=
1766 newinfo
.nexthop_out
;
1769 /* There is no redistribute routemap for the aggregated
1772 /* Changed route only output. */
1773 /* XXX, vincent, in order to increase time convergence,
1774 * it should be announced if a child has changed.
1776 if (route_type
== ripng_changed_route
)
1779 /* Apply offset-list */
1780 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1781 ripng_offset_list_apply_out(
1782 p
, ifp
, &aggregate
->metric_out
);
1784 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1785 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1787 /* Add RTE to the list */
1788 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1792 /* Flush the list */
1793 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1794 ripng_rte_free(ripng_rte_list
);
1797 /* Create new RIPng instance and set it to global variable. */
1798 static int ripng_create(void)
1800 /* ripng should be NULL. */
1801 assert(ripng
== NULL
);
1803 /* Allocaste RIPng instance. */
1804 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1806 /* Default version and timer values. */
1807 ripng
->version
= RIPNG_V1
;
1808 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1809 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1810 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1811 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1814 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1815 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1817 /* Initialize RIPng routig table. */
1818 ripng
->table
= route_table_init();
1819 ripng
->route
= route_table_init();
1820 ripng
->aggregate
= route_table_init();
1823 ripng
->sock
= ripng_make_socket();
1824 if (ripng
->sock
< 0)
1828 ripng_event(RIPNG_READ
, ripng
->sock
);
1829 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1834 /* Send RIPng request to the interface. */
1835 int ripng_request(struct interface
*ifp
)
1838 struct ripng_packet ripng_packet
;
1840 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1842 if (if_is_loopback(ifp
))
1845 /* If interface is down, don't send RIP packet. */
1849 if (IS_RIPNG_DEBUG_EVENT
)
1850 zlog_debug("RIPng send request to %s", ifp
->name
);
1852 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1853 ripng_packet
.command
= RIPNG_REQUEST
;
1854 ripng_packet
.version
= RIPNG_V1
;
1855 rte
= ripng_packet
.rte
;
1856 rte
->metric
= RIPNG_METRIC_INFINITY
;
1858 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1863 static int ripng_update_jitter(int time
)
1865 return ((random() % (time
+ 1)) - (time
/ 2));
1868 void ripng_event(enum ripng_event event
, int sock
)
1874 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1876 case RIPNG_UPDATE_EVENT
:
1877 if (ripng
->t_update
) {
1878 thread_cancel(ripng
->t_update
);
1879 ripng
->t_update
= NULL
;
1881 /* Update timer jitter. */
1882 jitter
= ripng_update_jitter(ripng
->update_time
);
1884 ripng
->t_update
= NULL
;
1885 thread_add_timer(master
, ripng_update
, NULL
,
1886 sock
? 2 : ripng
->update_time
+ jitter
,
1889 case RIPNG_TRIGGERED_UPDATE
:
1890 if (ripng
->t_triggered_interval
)
1893 thread_add_event(master
, ripng_triggered_update
, NULL
,
1894 0, &ripng
->t_triggered_update
);
1902 /* Print out routes update time. */
1903 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1908 char timebuf
[TIME_BUF
];
1909 struct thread
*thread
;
1911 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1912 clock
= thread_timer_remain_second(thread
);
1913 tm
= gmtime(&clock
);
1914 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1915 vty_out(vty
, "%5s", timebuf
);
1916 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1917 clock
= thread_timer_remain_second(thread
);
1918 tm
= gmtime(&clock
);
1919 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1920 vty_out(vty
, "%5s", timebuf
);
1924 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1929 if (rinfo
->suppress
)
1932 switch (rinfo
->sub_type
) {
1933 case RIPNG_ROUTE_RTE
:
1936 case RIPNG_ROUTE_STATIC
:
1939 case RIPNG_ROUTE_DEFAULT
:
1942 case RIPNG_ROUTE_REDISTRIBUTE
:
1945 case RIPNG_ROUTE_INTERFACE
:
1956 DEFUN (show_ipv6_ripng
,
1957 show_ipv6_ripng_cmd
,
1961 "Show RIPng routes\n")
1963 struct route_node
*rp
;
1964 struct ripng_info
*rinfo
;
1965 struct ripng_aggregate
*aggregate
;
1966 struct prefix_ipv6
*p
;
1967 struct list
*list
= NULL
;
1968 struct listnode
*listnode
= NULL
;
1974 /* Header of display. */
1976 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1978 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1979 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1980 " Network Next Hop Via Metric Tag Time\n");
1982 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
1983 if ((aggregate
= rp
->aggregate
) != NULL
) {
1984 p
= (struct prefix_ipv6
*)&rp
->p
;
1987 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1988 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1991 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1995 vty_out(vty
, "%*s", 18, " ");
1997 vty_out(vty
, "%*s", 28, " ");
1998 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1999 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
2002 if ((list
= rp
->info
) != NULL
)
2003 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2004 p
= (struct prefix_ipv6
*)&rp
->p
;
2007 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
2008 zebra_route_char(rinfo
->type
),
2009 ripng_route_subtype_print(rinfo
),
2010 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
2013 vty_out(vty
, "%c(%s) %s/%d ",
2014 zebra_route_char(rinfo
->type
),
2015 ripng_route_subtype_print(rinfo
),
2016 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2019 vty_out(vty
, "%*s", 18, " ");
2020 len
= vty_out(vty
, "%s",
2021 inet6_ntoa(rinfo
->nexthop
));
2025 vty_out(vty
, "%*s", len
, " ");
2028 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2029 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2032 ifindex2ifname(rinfo
->ifindex
,
2034 } else if (rinfo
->metric
2035 == RIPNG_METRIC_INFINITY
) {
2036 len
= vty_out(vty
, "kill");
2038 len
= vty_out(vty
, "self");
2042 vty_out(vty
, "%*s", len
, " ");
2044 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2045 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2048 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2049 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2050 /* RTE from remote RIP routers */
2051 ripng_vty_out_uptime(vty
, rinfo
);
2052 } else if (rinfo
->metric
2053 == RIPNG_METRIC_INFINITY
) {
2054 /* poisonous reversed routes (gc) */
2055 ripng_vty_out_uptime(vty
, rinfo
);
2065 DEFUN (show_ipv6_ripng_status
,
2066 show_ipv6_ripng_status_cmd
,
2067 "show ipv6 ripng status",
2070 "Show RIPng routes\n"
2071 "IPv6 routing protocol process parameters and statistics\n")
2073 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2074 struct interface
*ifp
;
2079 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2080 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2081 ripng
->update_time
);
2082 vty_out(vty
, " next due in %lu seconds\n",
2083 thread_timer_remain_second(ripng
->t_update
));
2084 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2085 vty_out(vty
, " garbage collect after %ld seconds\n",
2086 ripng
->garbage_time
);
2088 /* Filtering status show. */
2089 config_show_distribute(vty
);
2091 /* Default metric information. */
2092 vty_out(vty
, " Default redistribution metric is %d\n",
2093 ripng
->default_metric
);
2095 /* Redistribute information. */
2096 vty_out(vty
, " Redistributing:");
2097 ripng_redistribute_write(vty
, 0);
2100 vty_out(vty
, " Default version control: send version %d,",
2102 vty_out(vty
, " receive version %d \n", ripng
->version
);
2104 vty_out(vty
, " Interface Send Recv\n");
2106 FOR_ALL_INTERFACES (vrf
, ifp
) {
2107 struct ripng_interface
*ri
;
2111 if (ri
->enable_network
|| ri
->enable_interface
) {
2113 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2114 ripng
->version
, ripng
->version
);
2118 vty_out(vty
, " Routing for Networks:\n");
2119 ripng_network_write(vty
, 0);
2121 vty_out(vty
, " Routing Information Sources:\n");
2123 " Gateway BadPackets BadRoutes Distance Last Update\n");
2124 ripng_peer_display(vty
);
2129 DEFUN (clear_ipv6_rip
,
2134 "Clear IPv6 RIP database\n")
2136 struct route_node
*rp
;
2137 struct ripng_info
*rinfo
;
2139 struct listnode
*listnode
;
2141 /* Clear received RIPng routes */
2142 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2147 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2148 if (!ripng_route_rte(rinfo
))
2151 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2152 ripng_zebra_ipv6_delete(rp
);
2157 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2158 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2159 listnode_delete(list
, rinfo
);
2160 ripng_info_free(rinfo
);
2163 if (list_isempty(list
)) {
2164 list_delete_and_null(&list
);
2166 route_unlock_node(rp
);
2173 DEFUN_NOSH (router_ripng
,
2176 "Enable a routing process\n"
2177 "Make RIPng instance command\n")
2181 vty
->node
= RIPNG_NODE
;
2184 ret
= ripng_create();
2186 /* Notice to user we couldn't create RIPng. */
2188 zlog_warn("can't create RIPng");
2189 return CMD_WARNING_CONFIG_FAILED
;
2196 DEFUN (no_router_ripng
,
2197 no_router_ripng_cmd
,
2200 "Enable a routing process\n"
2201 "Make RIPng instance command\n")
2211 "Static route setup\n"
2212 "Set static RIPng route announcement\n")
2214 int idx_ipv6addr
= 1;
2216 struct prefix_ipv6 p
;
2217 struct route_node
*rp
;
2219 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2220 (struct prefix_ipv6
*)&p
);
2222 vty_out(vty
, "Malformed address\n");
2223 return CMD_WARNING_CONFIG_FAILED
;
2225 apply_mask_ipv6(&p
);
2227 rp
= route_node_get(ripng
->route
, (struct prefix
*)&p
);
2229 vty_out(vty
, "There is already same static route.\n");
2230 route_unlock_node(rp
);
2233 rp
->info
= (void *)1;
2235 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2241 DEFUN (no_ripng_route
,
2243 "no route IPV6ADDR",
2245 "Static route setup\n"
2246 "Delete static RIPng route announcement\n")
2248 int idx_ipv6addr
= 2;
2250 struct prefix_ipv6 p
;
2251 struct route_node
*rp
;
2253 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2254 (struct prefix_ipv6
*)&p
);
2256 vty_out(vty
, "Malformed address\n");
2257 return CMD_WARNING_CONFIG_FAILED
;
2259 apply_mask_ipv6(&p
);
2261 rp
= route_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2263 vty_out(vty
, "Can't find static route.\n");
2264 return CMD_WARNING_CONFIG_FAILED
;
2267 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2268 route_unlock_node(rp
);
2271 route_unlock_node(rp
);
2276 DEFUN (ripng_aggregate_address
,
2277 ripng_aggregate_address_cmd
,
2278 "aggregate-address X:X::X:X/M",
2279 "Set aggregate RIPng route announcement\n"
2280 "Aggregate network\n")
2282 int idx_ipv6_prefixlen
= 1;
2285 struct route_node
*node
;
2287 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2288 (struct prefix_ipv6
*)&p
);
2290 vty_out(vty
, "Malformed address\n");
2291 return CMD_WARNING_CONFIG_FAILED
;
2294 /* Check aggregate alredy exist or not. */
2295 node
= route_node_get(ripng
->aggregate
, &p
);
2297 vty_out(vty
, "There is already same aggregate route.\n");
2298 route_unlock_node(node
);
2301 node
->info
= (void *)1;
2303 ripng_aggregate_add(&p
);
2308 DEFUN (no_ripng_aggregate_address
,
2309 no_ripng_aggregate_address_cmd
,
2310 "no aggregate-address X:X::X:X/M",
2312 "Delete aggregate RIPng route announcement\n"
2313 "Aggregate network\n")
2315 int idx_ipv6_prefixlen
= 2;
2318 struct route_node
*rn
;
2320 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2321 (struct prefix_ipv6
*)&p
);
2323 vty_out(vty
, "Malformed address\n");
2324 return CMD_WARNING_CONFIG_FAILED
;
2327 rn
= route_node_lookup(ripng
->aggregate
, &p
);
2329 vty_out(vty
, "Can't find aggregate route.\n");
2330 return CMD_WARNING_CONFIG_FAILED
;
2332 route_unlock_node(rn
);
2334 route_unlock_node(rn
);
2336 ripng_aggregate_delete(&p
);
2341 DEFUN (ripng_default_metric
,
2342 ripng_default_metric_cmd
,
2343 "default-metric (1-16)",
2344 "Set a metric of redistribute routes\n"
2349 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2354 DEFUN (no_ripng_default_metric
,
2355 no_ripng_default_metric_cmd
,
2356 "no default-metric [(1-16)]",
2358 "Set a metric of redistribute routes\n"
2362 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2369 /* RIPng update timer setup. */
2370 DEFUN (ripng_update_timer
,
2371 ripng_update_timer_cmd
,
2372 "update-timer SECOND",
2373 "Set RIPng update timer in seconds\n"
2376 unsigned long update
;
2377 char *endptr
= NULL
;
2379 update
= strtoul (argv
[0], &endptr
, 10);
2380 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2382 vty_out (vty
, "update timer value error\n");
2383 return CMD_WARNING_CONFIG_FAILED
;
2386 ripng
->update_time
= update
;
2388 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2392 DEFUN (no_ripng_update_timer
,
2393 no_ripng_update_timer_cmd
,
2394 "no update-timer SECOND",
2396 "Unset RIPng update timer in seconds\n"
2399 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2400 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2404 /* RIPng timeout timer setup. */
2405 DEFUN (ripng_timeout_timer
,
2406 ripng_timeout_timer_cmd
,
2407 "timeout-timer SECOND",
2408 "Set RIPng timeout timer in seconds\n"
2411 unsigned long timeout
;
2412 char *endptr
= NULL
;
2414 timeout
= strtoul (argv
[0], &endptr
, 10);
2415 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2417 vty_out (vty
, "timeout timer value error\n");
2418 return CMD_WARNING_CONFIG_FAILED
;
2421 ripng
->timeout_time
= timeout
;
2426 DEFUN (no_ripng_timeout_timer
,
2427 no_ripng_timeout_timer_cmd
,
2428 "no timeout-timer SECOND",
2430 "Unset RIPng timeout timer in seconds\n"
2433 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2437 /* RIPng garbage timer setup. */
2438 DEFUN (ripng_garbage_timer
,
2439 ripng_garbage_timer_cmd
,
2440 "garbage-timer SECOND",
2441 "Set RIPng garbage timer in seconds\n"
2444 unsigned long garbage
;
2445 char *endptr
= NULL
;
2447 garbage
= strtoul (argv
[0], &endptr
, 10);
2448 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2450 vty_out (vty
, "garbage timer value error\n");
2451 return CMD_WARNING_CONFIG_FAILED
;
2454 ripng
->garbage_time
= garbage
;
2459 DEFUN (no_ripng_garbage_timer
,
2460 no_ripng_garbage_timer_cmd
,
2461 "no garbage-timer SECOND",
2463 "Unset RIPng garbage timer in seconds\n"
2466 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2471 DEFUN (ripng_timers
,
2473 "timers basic (0-65535) (0-65535) (0-65535)",
2474 "RIPng timers setup\n"
2476 "Routing table update timer value in second. Default is 30.\n"
2477 "Routing information timeout timer. Default is 180.\n"
2478 "Garbage collection timer. Default is 120.\n")
2481 int idx_number_2
= 3;
2482 int idx_number_3
= 4;
2483 unsigned long update
;
2484 unsigned long timeout
;
2485 unsigned long garbage
;
2487 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2488 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2489 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2491 /* Set each timer value. */
2492 ripng
->update_time
= update
;
2493 ripng
->timeout_time
= timeout
;
2494 ripng
->garbage_time
= garbage
;
2496 /* Reset update timer thread. */
2497 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2502 DEFUN (no_ripng_timers
,
2503 no_ripng_timers_cmd
,
2504 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2506 "RIPng timers setup\n"
2508 "Routing table update timer value in second. Default is 30.\n"
2509 "Routing information timeout timer. Default is 180.\n"
2510 "Garbage collection timer. Default is 120.\n")
2512 /* Set each timer value to the default. */
2513 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2514 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2515 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2517 /* Reset update timer thread. */
2518 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2524 DEFUN (show_ipv6_protocols
,
2525 show_ipv6_protocols_cmd
,
2526 "show ipv6 protocols",
2529 "Routing protocol information\n")
2534 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2536 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2537 ripng
->update_time
, 0);
2539 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2540 ripng
->timeout_time
,
2541 ripng
->garbage_time
);
2543 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2544 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2550 /* Please be carefull to use this command. */
2551 DEFUN (ripng_default_information_originate
,
2552 ripng_default_information_originate_cmd
,
2553 "default-information originate",
2554 "Default route information\n"
2555 "Distribute default route\n")
2557 struct prefix_ipv6 p
;
2559 if (!ripng
->default_information
) {
2560 ripng
->default_information
= 1;
2562 str2prefix_ipv6("::/0", &p
);
2563 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2570 DEFUN (no_ripng_default_information_originate
,
2571 no_ripng_default_information_originate_cmd
,
2572 "no default-information originate",
2574 "Default route information\n"
2575 "Distribute default route\n")
2577 struct prefix_ipv6 p
;
2579 if (ripng
->default_information
) {
2580 ripng
->default_information
= 0;
2582 str2prefix_ipv6("::/0", &p
);
2583 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2584 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2590 /* Update ECMP routes to zebra when ECMP is disabled. */
2591 static void ripng_ecmp_disable(void)
2593 struct route_node
*rp
;
2594 struct ripng_info
*rinfo
, *tmp_rinfo
;
2596 struct listnode
*node
, *nextnode
;
2601 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
))
2602 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2603 rinfo
= listgetdata(listhead(list
));
2604 if (!ripng_route_rte(rinfo
))
2607 /* Drop all other entries, except the first one. */
2608 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2609 if (tmp_rinfo
!= rinfo
) {
2610 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2612 tmp_rinfo
->t_garbage_collect
);
2613 list_delete_node(list
, node
);
2614 ripng_info_free(tmp_rinfo
);
2618 ripng_zebra_ipv6_add(rp
);
2620 /* Set the route change flag. */
2621 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2623 /* Signal the output process to trigger an update. */
2624 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2628 DEFUN (ripng_allow_ecmp
,
2629 ripng_allow_ecmp_cmd
,
2631 "Allow Equal Cost MultiPath\n")
2634 vty_out(vty
, "ECMP is already enabled.\n");
2639 zlog_info("ECMP is enabled.");
2643 DEFUN (no_ripng_allow_ecmp
,
2644 no_ripng_allow_ecmp_cmd
,
2647 "Allow Equal Cost MultiPath\n")
2650 vty_out(vty
, "ECMP is already disabled.\n");
2655 zlog_info("ECMP is disabled.");
2656 ripng_ecmp_disable();
2660 /* RIPng configuration write function. */
2661 static int ripng_config_write(struct vty
*vty
)
2663 int ripng_network_write(struct vty
*, int);
2664 void ripng_redistribute_write(struct vty
*, int);
2666 struct route_node
*rp
;
2671 vty_out(vty
, "router ripng\n");
2673 if (ripng
->default_information
)
2674 vty_out(vty
, " default-information originate\n");
2676 ripng_network_write(vty
, 1);
2678 /* RIPng default metric configuration */
2679 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2680 vty_out(vty
, " default-metric %d\n",
2681 ripng
->default_metric
);
2683 ripng_redistribute_write(vty
, 1);
2685 /* RIP offset-list configuration. */
2686 config_write_ripng_offset_list(vty
);
2688 /* RIPng aggregate routes. */
2689 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2690 if (rp
->info
!= NULL
)
2691 vty_out(vty
, " aggregate-address %s/%d\n",
2692 inet6_ntoa(rp
->p
.u
.prefix6
),
2695 /* ECMP configuration. */
2697 vty_out(vty
, " allow-ecmp\n");
2699 /* RIPng static routes. */
2700 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2701 if (rp
->info
!= NULL
)
2702 vty_out(vty
, " route %s/%d\n",
2703 inet6_ntoa(rp
->p
.u
.prefix6
),
2706 /* RIPng timers configuration. */
2707 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2708 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2709 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2710 vty_out(vty
, " timers basic %ld %ld %ld\n",
2711 ripng
->update_time
, ripng
->timeout_time
,
2712 ripng
->garbage_time
);
2715 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2716 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2717 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2718 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2719 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2720 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2723 write
+= config_write_distribute(vty
);
2725 write
+= config_write_if_rmap(vty
);
2732 /* RIPng node structure. */
2733 static struct cmd_node cmd_ripng_node
= {
2734 RIPNG_NODE
, "%s(config-router)# ", 1,
2737 static void ripng_distribute_update(struct distribute
*dist
)
2739 struct interface
*ifp
;
2740 struct ripng_interface
*ri
;
2741 struct access_list
*alist
;
2742 struct prefix_list
*plist
;
2747 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2753 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2754 alist
= access_list_lookup(AFI_IP6
,
2755 dist
->list
[DISTRIBUTE_V6_IN
]);
2757 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2759 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2761 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2763 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2764 alist
= access_list_lookup(AFI_IP6
,
2765 dist
->list
[DISTRIBUTE_V6_OUT
]);
2767 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2769 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2771 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2773 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2774 plist
= prefix_list_lookup(AFI_IP6
,
2775 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2777 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2779 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2781 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2783 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2784 plist
= prefix_list_lookup(AFI_IP6
,
2785 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2787 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2789 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2791 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2794 void ripng_distribute_update_interface(struct interface
*ifp
)
2796 struct distribute
*dist
;
2798 dist
= distribute_lookup(ifp
->name
);
2800 ripng_distribute_update(dist
);
2803 /* Update all interface's distribute list. */
2804 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2806 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2807 struct interface
*ifp
;
2809 FOR_ALL_INTERFACES (vrf
, ifp
)
2810 ripng_distribute_update_interface(ifp
);
2813 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2815 ripng_distribute_update_all(NULL
);
2818 /* delete all the added ripng routes. */
2822 struct route_node
*rp
;
2823 struct ripng_info
*rinfo
;
2824 struct ripng_aggregate
*aggregate
;
2825 struct list
*list
= NULL
;
2826 struct listnode
*listnode
= NULL
;
2829 /* Clear RIPng routes */
2830 for (rp
= route_top(ripng
->table
); rp
; rp
= route_next(rp
)) {
2831 if ((list
= rp
->info
) != NULL
) {
2832 rinfo
= listgetdata(listhead(list
));
2833 if (ripng_route_rte(rinfo
))
2834 ripng_zebra_ipv6_delete(rp
);
2836 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2838 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2840 rinfo
->t_garbage_collect
);
2841 ripng_info_free(rinfo
);
2843 list_delete_and_null(&list
);
2845 route_unlock_node(rp
);
2848 if ((aggregate
= rp
->aggregate
) != NULL
) {
2849 ripng_aggregate_free(aggregate
);
2850 rp
->aggregate
= NULL
;
2851 route_unlock_node(rp
);
2855 /* Cancel the RIPng timers */
2856 RIPNG_TIMER_OFF(ripng
->t_update
);
2857 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2858 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2860 /* Cancel the read thread */
2861 if (ripng
->t_read
) {
2862 thread_cancel(ripng
->t_read
);
2863 ripng
->t_read
= NULL
;
2866 /* Close the RIPng socket */
2867 if (ripng
->sock
>= 0) {
2872 /* Static RIPng route configuration. */
2873 for (rp
= route_top(ripng
->route
); rp
; rp
= route_next(rp
))
2876 route_unlock_node(rp
);
2879 /* RIPng aggregated prefixes */
2880 for (rp
= route_top(ripng
->aggregate
); rp
; rp
= route_next(rp
))
2883 route_unlock_node(rp
);
2886 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2887 if (ripng
->route_map
[i
].name
)
2888 free(ripng
->route_map
[i
].name
);
2890 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2891 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2892 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2894 stream_free(ripng
->ibuf
);
2895 stream_free(ripng
->obuf
);
2897 XFREE(MTYPE_RIPNG
, ripng
);
2901 ripng_clean_network();
2902 ripng_passive_interface_clean();
2903 ripng_offset_clean();
2904 ripng_interface_clean();
2905 ripng_redistribute_clean();
2908 /* Reset all values to the default settings. */
2911 /* Call ripd related reset functions. */
2912 ripng_debug_reset();
2913 ripng_route_map_reset();
2915 /* Call library reset functions. */
2917 access_list_reset();
2918 prefix_list_reset();
2920 distribute_list_reset();
2922 ripng_interface_reset();
2924 ripng_zclient_reset();
2927 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2929 struct interface
*ifp
;
2930 struct ripng_interface
*ri
;
2931 struct route_map
*rmap
;
2933 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2939 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2940 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2942 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2944 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2946 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2948 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2949 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2951 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2953 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2955 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2958 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2960 struct if_rmap
*if_rmap
;
2962 if_rmap
= if_rmap_lookup(ifp
->name
);
2964 ripng_if_rmap_update(if_rmap
);
2967 static void ripng_routemap_update_redistribute(void)
2972 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2973 if (ripng
->route_map
[i
].name
)
2974 ripng
->route_map
[i
].map
=
2975 route_map_lookup_by_name(
2976 ripng
->route_map
[i
].name
);
2981 static void ripng_routemap_update(const char *unused
)
2983 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2984 struct interface
*ifp
;
2986 FOR_ALL_INTERFACES (vrf
, ifp
)
2987 ripng_if_rmap_update_interface(ifp
);
2989 ripng_routemap_update_redistribute();
2992 /* Initialize ripng structure and set commands. */
2995 /* Install RIPNG_NODE. */
2996 install_node(&cmd_ripng_node
, ripng_config_write
);
2998 /* Install ripng commands. */
2999 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
3000 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
3002 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
3004 install_element(CONFIG_NODE
, &router_ripng_cmd
);
3005 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
3007 install_default(RIPNG_NODE
);
3008 install_element(RIPNG_NODE
, &ripng_route_cmd
);
3009 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
3010 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3011 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3013 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3014 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3016 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3017 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3019 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3020 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3021 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3022 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3023 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3024 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3025 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3028 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3029 install_element(RIPNG_NODE
,
3030 &no_ripng_default_information_originate_cmd
);
3032 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3033 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3038 /* Access list install. */
3040 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3041 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3043 /* Prefix list initialize.*/
3045 prefix_list_add_hook(ripng_distribute_update_all
);
3046 prefix_list_delete_hook(ripng_distribute_update_all
);
3048 /* Distribute list install. */
3049 distribute_list_init(RIPNG_NODE
);
3050 distribute_list_add_hook(ripng_distribute_update
);
3051 distribute_list_delete_hook(ripng_distribute_update
);
3053 /* Route-map for interface. */
3054 ripng_route_map_init();
3055 ripng_offset_init();
3057 route_map_add_hook(ripng_routemap_update
);
3058 route_map_delete_hook(ripng_routemap_update
);
3060 if_rmap_init(RIPNG_NODE
);
3061 if_rmap_hook_add(ripng_if_rmap_update
);
3062 if_rmap_hook_delete(ripng_if_rmap_update
);