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
30 #include "agg_table.h"
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(EC_LIB_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 frr_elevate_privs(&ripngd_privs
) {
129 ret
= bind(sock
, (struct sockaddr
*)&ripaddr
, sizeof(ripaddr
));
131 zlog_err("Can't bind ripng socket: %s.",
132 safe_strerror(errno
));
143 /* Send RIPng packet. */
144 int ripng_send_packet(caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
145 struct interface
*ifp
)
150 struct cmsghdr
*cmsgptr
;
152 struct in6_pktinfo
*pkt
;
153 struct sockaddr_in6 addr
;
155 if (IS_RIPNG_DEBUG_SEND
) {
157 zlog_debug("send to %s", inet6_ntoa(to
->sin6_addr
));
158 zlog_debug(" send interface %s", ifp
->name
);
159 zlog_debug(" send packet size %d", bufsize
);
162 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
163 addr
.sin6_family
= AF_INET6
;
165 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
166 #endif /* SIN6_LEN */
167 addr
.sin6_flowinfo
= htonl(RIPNG_PRIORITY_DEFAULT
);
169 /* When destination is specified. */
171 addr
.sin6_addr
= to
->sin6_addr
;
172 addr
.sin6_port
= to
->sin6_port
;
174 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
175 addr
.sin6_port
= htons(RIPNG_PORT_DEFAULT
);
178 memset(&msg
, 0, sizeof(msg
));
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 flog_err_sys(EC_LIB_SOCKET
,
203 "RIPng send fail on %s to %s: %s",
204 ifp
->name
, inet6_ntoa(to
->sin6_addr
),
205 safe_strerror(errno
));
207 flog_err_sys(EC_LIB_SOCKET
, "RIPng send fail on %s: %s",
208 ifp
->name
, safe_strerror(errno
));
214 /* Receive UDP RIPng packet from socket. */
215 static int ripng_recv_packet(int sock
, uint8_t *buf
, int bufsize
,
216 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
222 struct cmsghdr
*cmsgptr
;
223 struct in6_addr dst
= {.s6_addr
= {0}};
225 memset(&dst
, 0, sizeof(struct in6_addr
));
227 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
228 point I can't determine size of cmsghdr */
231 /* Fill in message and iovec. */
232 memset(&msg
, 0, sizeof(msg
));
233 msg
.msg_name
= (void *)from
;
234 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
237 msg
.msg_control
= (void *)adata
;
238 msg
.msg_controllen
= sizeof adata
;
240 iov
.iov_len
= bufsize
;
242 /* If recvmsg fail return minus value. */
243 ret
= recvmsg(sock
, &msg
, 0);
247 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
248 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
249 /* I want interface index which this packet comes from. */
250 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
251 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
252 struct in6_pktinfo
*ptr
;
254 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
255 *ifindex
= ptr
->ipi6_ifindex
;
256 dst
= ptr
->ipi6_addr
;
260 "Interface index returned by IPV6_PKTINFO is zero");
263 /* Incoming packet's multicast hop limit. */
264 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
265 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
266 int *phoplimit
= (int *)CMSG_DATA(cmsgptr
);
267 *hoplimit
= *phoplimit
;
271 /* Hoplimit check shold be done when destination address is
272 multicast address. */
273 if (!IN6_IS_ADDR_MULTICAST(&dst
))
279 /* Dump rip packet */
280 void ripng_packet_dump(struct ripng_packet
*packet
, int size
,
285 const char *command_str
;
287 /* Set command string. */
288 if (packet
->command
== RIPNG_REQUEST
)
289 command_str
= "request";
290 else if (packet
->command
== RIPNG_RESPONSE
)
291 command_str
= "response";
293 command_str
= "unknown";
295 /* Dump packet header. */
296 zlog_debug("%s %s version %d packet size %d", sndrcv
, command_str
,
297 packet
->version
, size
);
299 /* Dump each routing table entry. */
302 for (lim
= (caddr_t
)packet
+ size
; (caddr_t
)rte
< lim
; rte
++) {
303 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
304 zlog_debug(" nexthop %s/%d", inet6_ntoa(rte
->addr
),
307 zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI
,
308 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
309 rte
->metric
, (route_tag_t
)ntohs(rte
->tag
));
313 /* RIPng next hop address RTE (Route Table Entry). */
314 static void ripng_nexthop_rte(struct rte
*rte
, struct sockaddr_in6
*from
,
315 struct ripng_nexthop
*nexthop
)
317 char buf
[INET6_BUFSIZ
];
319 /* Logging before checking RTE. */
320 if (IS_RIPNG_DEBUG_RECV
)
321 zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI
323 inet6_ntoa(rte
->addr
), (route_tag_t
)ntohs(rte
->tag
),
326 /* RFC2080 2.1.1 Next Hop:
327 The route tag and prefix length in the next hop RTE must be
328 set to zero on sending and ignored on receiption. */
329 if (ntohs(rte
->tag
) != 0)
331 "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
333 (route_tag_t
)ntohs(rte
->tag
),
334 inet6_ntoa(from
->sin6_addr
));
336 if (rte
->prefixlen
!= 0)
338 "RIPng nexthop RTE with non zero prefixlen value %d from %s",
339 rte
->prefixlen
, inet6_ntoa(from
->sin6_addr
));
341 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
342 next hop RTE indicates that the next hop address should be the
343 originator of the RIPng advertisement. An address specified as a
344 next hop must be a link-local address. */
345 if (IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)) {
346 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
347 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
351 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
352 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
353 IPV6_ADDR_COPY(&nexthop
->address
, &rte
->addr
);
357 /* The purpose of the next hop RTE is to eliminate packets being
358 routed through extra hops in the system. It is particularly useful
359 when RIPng is not being run on all of the routers on a network.
360 Note that next hop RTE is "advisory". That is, if the provided
361 information is ignored, a possibly sub-optimal, but absolutely
362 valid, route may be taken. If the received next hop address is not
363 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
364 zlog_warn("RIPng nexthop RTE with non link-local address %s from %s",
365 inet6_ntoa(rte
->addr
),
366 inet_ntop(AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
368 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
369 memset(&nexthop
->address
, 0, sizeof(struct in6_addr
));
374 /* If ifp has same link-local address then return 1. */
375 static int ripng_lladdr_check(struct interface
*ifp
, struct in6_addr
*addr
)
377 struct listnode
*node
;
378 struct connected
*connected
;
381 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
382 p
= connected
->address
;
384 if (p
->family
== AF_INET6
385 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
)
386 && IN6_ARE_ADDR_EQUAL(&p
->u
.prefix6
, addr
))
392 /* RIPng route garbage collect timer. */
393 static int ripng_garbage_collect(struct thread
*t
)
395 struct ripng_info
*rinfo
;
398 rinfo
= THREAD_ARG(t
);
399 rinfo
->t_garbage_collect
= NULL
;
401 /* Off timeout timer. */
402 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
404 /* Get route_node pointer. */
407 /* Unlock route_node. */
408 listnode_delete(rp
->info
, rinfo
);
409 if (list_isempty((struct list
*)rp
->info
)) {
410 list_delete((struct list
**)&rp
->info
);
414 /* Free RIPng routing information. */
415 ripng_info_free(rinfo
);
420 static void ripng_timeout_update(struct ripng_info
*rinfo
);
422 /* Add new route to the ECMP list.
423 * RETURN: the new entry added in the list, or NULL if it is not the first
424 * entry and ECMP is not allowed.
426 struct ripng_info
*ripng_ecmp_add(struct ripng_info
*rinfo_new
)
428 struct agg_node
*rp
= rinfo_new
->rp
;
429 struct ripng_info
*rinfo
= NULL
;
430 struct list
*list
= NULL
;
432 if (rp
->info
== NULL
)
433 rp
->info
= list_new();
434 list
= (struct list
*)rp
->info
;
436 /* If ECMP is not allowed and some entry already exists in the list,
438 if (listcount(list
) && !ripng
->ecmp
)
441 rinfo
= ripng_info_new();
442 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
443 listnode_add(list
, rinfo
);
445 if (ripng_route_rte(rinfo
)) {
446 ripng_timeout_update(rinfo
);
447 ripng_zebra_ipv6_add(rp
);
450 ripng_aggregate_increment(rp
, rinfo
);
452 /* Set the route change flag on the first entry. */
453 rinfo
= listgetdata(listhead(list
));
454 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
456 /* Signal the output process to trigger an update. */
457 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
462 /* Replace the ECMP list with the new route.
463 * RETURN: the new entry added in the list
465 struct ripng_info
*ripng_ecmp_replace(struct ripng_info
*rinfo_new
)
467 struct agg_node
*rp
= rinfo_new
->rp
;
468 struct list
*list
= (struct list
*)rp
->info
;
469 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
470 struct listnode
*node
= NULL
, *nextnode
= NULL
;
472 if (list
== NULL
|| listcount(list
) == 0)
473 return ripng_ecmp_add(rinfo_new
);
475 /* Get the first entry */
476 rinfo
= listgetdata(listhead(list
));
478 /* Learnt route replaced by a local one. Delete it from zebra. */
479 if (ripng_route_rte(rinfo
) && !ripng_route_rte(rinfo_new
))
480 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
481 ripng_zebra_ipv6_delete(rp
);
483 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
484 ripng_aggregate_decrement_list(rp
, list
);
486 /* Re-use the first entry, and delete the others. */
487 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
488 if (tmp_rinfo
!= rinfo
) {
489 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
490 RIPNG_TIMER_OFF(tmp_rinfo
->t_garbage_collect
);
491 list_delete_node(list
, node
);
492 ripng_info_free(tmp_rinfo
);
495 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
496 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
497 memcpy(rinfo
, rinfo_new
, sizeof(struct ripng_info
));
499 if (ripng_route_rte(rinfo
)) {
500 ripng_timeout_update(rinfo
);
501 /* The ADD message implies an update. */
502 ripng_zebra_ipv6_add(rp
);
505 ripng_aggregate_increment(rp
, rinfo
);
507 /* Set the route change flag. */
508 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
510 /* Signal the output process to trigger an update. */
511 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
516 /* Delete one route from the ECMP list.
518 * null - the entry is freed, and other entries exist in the list
519 * the entry - the entry is the last one in the list; its metric is set
520 * to INFINITY, and the garbage collector is started for it
522 struct ripng_info
*ripng_ecmp_delete(struct ripng_info
*rinfo
)
524 struct agg_node
*rp
= rinfo
->rp
;
525 struct list
*list
= (struct list
*)rp
->info
;
527 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
529 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
530 ripng_aggregate_decrement(rp
, rinfo
);
532 if (listcount(list
) > 1) {
533 /* Some other ECMP entries still exist. Just delete this entry.
535 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
536 listnode_delete(list
, rinfo
);
537 if (ripng_route_rte(rinfo
)
538 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
539 /* The ADD message implies the update. */
540 ripng_zebra_ipv6_add(rp
);
541 ripng_info_free(rinfo
);
544 assert(rinfo
== listgetdata(listhead(list
)));
546 /* This is the only entry left in the list. We must keep it in
547 * the list for garbage collection time, with INFINITY metric.
550 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
551 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
, ripng_garbage_collect
,
552 ripng
->garbage_time
);
554 if (ripng_route_rte(rinfo
)
555 && CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
556 ripng_zebra_ipv6_delete(rp
);
559 /* Set the route change flag on the first entry. */
560 rinfo
= listgetdata(listhead(list
));
561 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
563 /* Signal the output process to trigger an update. */
564 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
569 /* Timeout RIPng routes. */
570 static int ripng_timeout(struct thread
*t
)
572 ripng_ecmp_delete((struct ripng_info
*)THREAD_ARG(t
));
576 static void ripng_timeout_update(struct ripng_info
*rinfo
)
578 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
579 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
580 RIPNG_TIMER_ON(rinfo
->t_timeout
, ripng_timeout
,
581 ripng
->timeout_time
);
585 static int ripng_filter(int ripng_distribute
, struct prefix_ipv6
*p
,
586 struct ripng_interface
*ri
)
588 struct distribute
*dist
;
589 struct access_list
*alist
;
590 struct prefix_list
*plist
;
591 int distribute
= ripng_distribute
== RIPNG_FILTER_OUT
594 const char *inout
= ripng_distribute
== RIPNG_FILTER_OUT
? "out" : "in";
596 /* Input distribute-list filtering. */
597 if (ri
->list
[ripng_distribute
]) {
598 if (access_list_apply(ri
->list
[ripng_distribute
],
601 if (IS_RIPNG_DEBUG_PACKET
)
602 zlog_debug("%s/%d filtered by distribute %s",
603 inet6_ntoa(p
->prefix
), p
->prefixlen
,
608 if (ri
->prefix
[ripng_distribute
]) {
609 if (prefix_list_apply(ri
->prefix
[ripng_distribute
],
612 if (IS_RIPNG_DEBUG_PACKET
)
613 zlog_debug("%s/%d filtered by prefix-list %s",
614 inet6_ntoa(p
->prefix
), p
->prefixlen
,
620 /* All interface filter check. */
621 dist
= distribute_lookup(NULL
);
623 if (dist
->list
[distribute
]) {
624 alist
= access_list_lookup(AFI_IP6
,
625 dist
->list
[distribute
]);
628 if (access_list_apply(alist
, (struct prefix
*)p
)
630 if (IS_RIPNG_DEBUG_PACKET
)
632 "%s/%d filtered by distribute %s",
633 inet6_ntoa(p
->prefix
),
634 p
->prefixlen
, inout
);
639 if (dist
->prefix
[distribute
]) {
640 plist
= prefix_list_lookup(AFI_IP6
,
641 dist
->prefix
[distribute
]);
644 if (prefix_list_apply(plist
, (struct prefix
*)p
)
646 if (IS_RIPNG_DEBUG_PACKET
)
648 "%s/%d filtered by prefix-list %s",
649 inet6_ntoa(p
->prefix
),
650 p
->prefixlen
, inout
);
659 /* Process RIPng route according to RFC2080. */
660 static void ripng_route_process(struct rte
*rte
, struct sockaddr_in6
*from
,
661 struct ripng_nexthop
*ripng_nexthop
,
662 struct interface
*ifp
)
665 struct prefix_ipv6 p
;
667 struct ripng_info
*rinfo
= NULL
, newinfo
;
668 struct ripng_interface
*ri
;
669 struct in6_addr
*nexthop
;
671 struct list
*list
= NULL
;
672 struct listnode
*node
= NULL
;
674 /* Make prefix structure. */
675 memset(&p
, 0, sizeof(struct prefix_ipv6
));
677 /* p.prefix = rte->addr; */
678 IPV6_ADDR_COPY(&p
.prefix
, &rte
->addr
);
679 p
.prefixlen
= rte
->prefixlen
;
681 /* Make sure mask is applied. */
682 /* XXX We have to check the prefix is valid or not before call
686 /* Apply input filters. */
689 ret
= ripng_filter(RIPNG_FILTER_IN
, &p
, ri
);
693 memset(&newinfo
, 0, sizeof(newinfo
));
694 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
695 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
696 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
697 newinfo
.nexthop
= ripng_nexthop
->address
;
699 newinfo
.nexthop
= from
->sin6_addr
;
700 newinfo
.from
= from
->sin6_addr
;
701 newinfo
.ifindex
= ifp
->ifindex
;
702 newinfo
.metric
= rte
->metric
;
703 newinfo
.metric_out
= rte
->metric
; /* XXX */
704 newinfo
.tag
= ntohs(rte
->tag
); /* XXX */
707 if (ri
->routemap
[RIPNG_FILTER_IN
]) {
708 ret
= route_map_apply(ri
->routemap
[RIPNG_FILTER_IN
],
709 (struct prefix
*)&p
, RMAP_RIPNG
,
712 if (ret
== RMAP_DENYMATCH
) {
713 if (IS_RIPNG_DEBUG_PACKET
)
715 "RIPng %s/%d is filtered by route-map in",
716 inet6_ntoa(p
.prefix
), p
.prefixlen
);
720 /* Get back the object */
721 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
722 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
723 &ripng_nexthop
->address
)) {
724 /* the nexthop get changed by the routemap */
725 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
726 ripng_nexthop
->address
=
729 ripng_nexthop
->address
= in6addr_any
;
732 if (!IPV6_ADDR_SAME(&newinfo
.nexthop
,
734 /* the nexthop get changed by the routemap */
735 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
736 ripng_nexthop
->flag
=
737 RIPNG_NEXTHOP_ADDRESS
;
738 ripng_nexthop
->address
=
743 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
745 newinfo
.metric_out
; /* XXX: the routemap uses the
749 /* Once the entry has been validated, update the metric by
750 * adding the cost of the network on wich the message
751 * arrived. If the result is greater than infinity, use infinity
752 * (RFC2453 Sec. 3.9.2)
755 /* Zebra ripngd can handle offset-list in. */
756 ret
= ripng_offset_list_apply_in(&p
, ifp
, &rte
->metric
);
758 /* If offset-list does not modify the metric use interface's
761 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
763 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
764 rte
->metric
= RIPNG_METRIC_INFINITY
;
766 /* Set nexthop pointer. */
767 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
768 nexthop
= &ripng_nexthop
->address
;
770 nexthop
= &from
->sin6_addr
;
772 /* Lookup RIPng routing table. */
773 rp
= agg_node_get(ripng
->table
, (struct prefix
*)&p
);
776 newinfo
.nexthop
= *nexthop
;
777 newinfo
.metric
= rte
->metric
;
778 newinfo
.tag
= ntohs(rte
->tag
);
780 /* Check to see whether there is already RIPng route on the table. */
781 if ((list
= rp
->info
) != NULL
)
782 for (ALL_LIST_ELEMENTS_RO(list
, node
, rinfo
)) {
783 /* Need to compare with redistributed entry or local
785 if (!ripng_route_rte(rinfo
))
788 if (IPV6_ADDR_SAME(&rinfo
->from
, &from
->sin6_addr
)
789 && IPV6_ADDR_SAME(&rinfo
->nexthop
, nexthop
))
792 if (!listnextnode(node
)) {
793 /* Not found in the list */
795 if (rte
->metric
> rinfo
->metric
) {
796 /* New route has a greater metric.
802 if (rte
->metric
< rinfo
->metric
)
803 /* New route has a smaller metric.
804 * Replace the ECMP list
805 * with the new one in below. */
808 /* Metrics are same. Unless ECMP is disabled,
809 * keep "rinfo" null and
810 * the new route is added in the ECMP list in
818 /* Redistributed route check. */
819 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
820 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
825 /* Local static route. */
826 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
827 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
828 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
829 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
836 /* Now, check to see whether there is already an explicit route
837 for the destination prefix. If there is no such route, add
838 this route to the routing table, unless the metric is
839 infinity (there is no point in adding a route which
841 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
842 ripng_ecmp_add(&newinfo
);
846 /* If there is an existing route, compare the next hop address
847 to the address of the router from which the datagram came.
848 If this datagram is from the same router as the existing
849 route, reinitialize the timeout. */
850 same
= (IN6_ARE_ADDR_EQUAL(&rinfo
->from
, &from
->sin6_addr
)
851 && (rinfo
->ifindex
== ifp
->ifindex
));
854 * RFC 2080 - Section 2.4.2:
855 * "If the new metric is the same as the old one, examine the
857 * for the existing route. If it is at least halfway to the
859 * point, switch to the new route. This heuristic is optional,
861 * highly recommended".
863 if (!ripng
->ecmp
&& !same
&& rinfo
->metric
== rte
->metric
865 && (thread_timer_remain_second(rinfo
->t_timeout
)
866 < (ripng
->timeout_time
/ 2))) {
867 ripng_ecmp_replace(&newinfo
);
869 /* Next, compare the metrics. If the datagram is from the same
870 router as the existing route, and the new metric is different
871 than the old one; or, if the new metric is lower than the old
872 one; do the following actions: */
873 else if ((same
&& rinfo
->metric
!= rte
->metric
)
874 || rte
->metric
< rinfo
->metric
) {
875 if (listcount(list
) == 1) {
876 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
877 ripng_ecmp_replace(&newinfo
);
879 ripng_ecmp_delete(rinfo
);
881 if (newinfo
.metric
< rinfo
->metric
)
882 ripng_ecmp_replace(&newinfo
);
883 else /* newinfo.metric > rinfo->metric */
884 ripng_ecmp_delete(rinfo
);
886 } else /* same & no change */
887 ripng_timeout_update(rinfo
);
889 /* Unlock tempolary lock of the route. */
894 /* Add redistributed route to RIPng table. */
895 void ripng_redistribute_add(int type
, int sub_type
, struct prefix_ipv6
*p
,
896 ifindex_t ifindex
, struct in6_addr
*nexthop
,
900 struct ripng_info
*rinfo
= NULL
, newinfo
;
901 struct list
*list
= NULL
;
903 /* Redistribute route */
904 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
906 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
909 rp
= agg_node_get(ripng
->table
, (struct prefix
*)p
);
911 memset(&newinfo
, 0, sizeof(struct ripng_info
));
913 newinfo
.sub_type
= sub_type
;
914 newinfo
.ifindex
= ifindex
;
916 if (tag
<= UINT16_MAX
) /* RIPng only supports 16 bit tags */
919 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
920 newinfo
.nexthop
= *nexthop
;
922 if ((list
= rp
->info
) != NULL
&& listcount(list
) != 0) {
923 rinfo
= listgetdata(listhead(list
));
925 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
926 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
927 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
932 /* Manually configured RIPng route check.
933 * They have the precedence on all the other entries.
935 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
936 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
)
937 || (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))) {
938 if (type
!= ZEBRA_ROUTE_RIPNG
939 || ((sub_type
!= RIPNG_ROUTE_STATIC
)
940 && (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
946 ripng_ecmp_replace(&newinfo
);
949 ripng_ecmp_add(&newinfo
);
951 if (IS_RIPNG_DEBUG_EVENT
) {
954 "Redistribute new prefix %s/%d on the interface %s",
955 inet6_ntoa(p
->prefix
), p
->prefixlen
,
956 ifindex2ifname(ifindex
, VRF_DEFAULT
));
959 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
960 inet6_ntoa(p
->prefix
), p
->prefixlen
,
961 inet6_ntoa(*nexthop
),
962 ifindex2ifname(ifindex
, VRF_DEFAULT
));
965 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
968 /* Delete redistributed route to RIPng table. */
969 void ripng_redistribute_delete(int type
, int sub_type
, struct prefix_ipv6
*p
,
973 struct ripng_info
*rinfo
;
975 if (IN6_IS_ADDR_LINKLOCAL(&p
->prefix
))
977 if (IN6_IS_ADDR_LOOPBACK(&p
->prefix
))
980 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)p
);
983 struct list
*list
= rp
->info
;
985 if (list
!= NULL
&& listcount(list
) != 0) {
986 rinfo
= listgetdata(listhead(list
));
987 if (rinfo
!= NULL
&& rinfo
->type
== type
988 && rinfo
->sub_type
== sub_type
989 && rinfo
->ifindex
== ifindex
) {
990 /* Perform poisoned reverse. */
991 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
992 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
993 ripng_garbage_collect
,
994 ripng
->garbage_time
);
995 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
997 /* Aggregate count decrement. */
998 ripng_aggregate_decrement(rp
, rinfo
);
1000 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1002 if (IS_RIPNG_DEBUG_EVENT
)
1004 "Poisone %s/%d on the interface %s with an "
1005 "infinity metric [delete]",
1006 inet6_ntoa(p
->prefix
),
1008 ifindex2ifname(ifindex
,
1011 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1014 agg_unlock_node(rp
);
1018 /* Withdraw redistributed route. */
1019 void ripng_redistribute_withdraw(int type
)
1021 struct agg_node
*rp
;
1022 struct ripng_info
*rinfo
= NULL
;
1023 struct list
*list
= NULL
;
1028 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
1029 if ((list
= rp
->info
) != NULL
) {
1030 rinfo
= listgetdata(listhead(list
));
1031 if ((rinfo
->type
== type
)
1032 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
)) {
1033 /* Perform poisoned reverse. */
1034 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1035 RIPNG_TIMER_ON(rinfo
->t_garbage_collect
,
1036 ripng_garbage_collect
,
1037 ripng
->garbage_time
);
1038 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
1040 /* Aggregate count decrement. */
1041 ripng_aggregate_decrement(rp
, rinfo
);
1043 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1045 if (IS_RIPNG_DEBUG_EVENT
) {
1046 struct prefix_ipv6
*p
=
1047 (struct prefix_ipv6
*)&rp
->p
;
1050 "Poisone %s/%d on the interface %s [withdraw]",
1051 inet6_ntoa(p
->prefix
),
1053 ifindex2ifname(rinfo
->ifindex
,
1057 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
1062 /* RIP routing information. */
1063 static void ripng_response_process(struct ripng_packet
*packet
, int size
,
1064 struct sockaddr_in6
*from
,
1065 struct interface
*ifp
, int hoplimit
)
1069 struct ripng_nexthop nexthop
;
1071 /* RFC2080 2.4.2 Response Messages:
1072 The Response must be ignored if it is not from the RIPng port. */
1073 if (ntohs(from
->sin6_port
) != RIPNG_PORT_DEFAULT
) {
1074 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1075 ntohs(from
->sin6_port
), inet6_ntoa(from
->sin6_addr
));
1076 ripng_peer_bad_packet(from
);
1080 /* The datagram's IPv6 source address should be checked to see
1081 whether the datagram is from a valid neighbor; the source of the
1082 datagram must be a link-local address. */
1083 if (!IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
)) {
1084 zlog_warn("RIPng packet comes from non link local address %s",
1085 inet6_ntoa(from
->sin6_addr
));
1086 ripng_peer_bad_packet(from
);
1090 /* It is also worth checking to see whether the response is from one
1091 of the router's own addresses. Interfaces on broadcast networks
1092 may receive copies of their own multicasts immediately. If a
1093 router processes its own output as new input, confusion is likely,
1094 and such datagrams must be ignored. */
1095 if (ripng_lladdr_check(ifp
, &from
->sin6_addr
)) {
1097 "RIPng packet comes from my own link local address %s",
1098 inet6_ntoa(from
->sin6_addr
));
1099 ripng_peer_bad_packet(from
);
1103 /* As an additional check, periodic advertisements must have their
1104 hop counts set to 255, and inbound, multicast packets sent from the
1105 RIPng port (i.e. periodic advertisement or triggered update
1106 packets) must be examined to ensure that the hop count is 255. */
1107 if (hoplimit
>= 0 && hoplimit
!= 255) {
1109 "RIPng packet comes with non 255 hop count %d from %s",
1110 hoplimit
, inet6_ntoa(from
->sin6_addr
));
1111 ripng_peer_bad_packet(from
);
1115 /* Update RIPng peer. */
1116 ripng_peer_update(from
, packet
->version
);
1118 /* Reset nexthop. */
1119 memset(&nexthop
, 0, sizeof(struct ripng_nexthop
));
1120 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1122 /* Set RTE pointer. */
1125 for (lim
= ((caddr_t
)packet
) + size
; (caddr_t
)rte
< lim
; rte
++) {
1126 /* First of all, we have to check this RTE is next hop RTE or
1127 not. Next hop RTE is completely different with normal RTE so
1128 we need special treatment. */
1129 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
) {
1130 ripng_nexthop_rte(rte
, from
, &nexthop
);
1134 /* RTE information validation. */
1136 /* - is the destination prefix valid (e.g., not a multicast
1137 prefix and not a link-local address) A link-local address
1138 should never be present in an RTE. */
1139 if (IN6_IS_ADDR_MULTICAST(&rte
->addr
)) {
1141 "Destination prefix is a multicast address %s/%d [%d]",
1142 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1144 ripng_peer_bad_route(from
);
1147 if (IN6_IS_ADDR_LINKLOCAL(&rte
->addr
)) {
1149 "Destination prefix is a link-local address %s/%d [%d]",
1150 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1152 ripng_peer_bad_route(from
);
1155 if (IN6_IS_ADDR_LOOPBACK(&rte
->addr
)) {
1157 "Destination prefix is a loopback address %s/%d [%d]",
1158 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1160 ripng_peer_bad_route(from
);
1164 /* - is the prefix length valid (i.e., between 0 and 128,
1166 if (rte
->prefixlen
> 128) {
1167 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1168 inet6_ntoa(rte
->addr
), rte
->prefixlen
,
1169 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1170 ripng_peer_bad_route(from
);
1174 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1175 if (!(rte
->metric
>= 1 && rte
->metric
<= 16)) {
1176 zlog_warn("Invalid metric %d from %s%%%s", rte
->metric
,
1177 inet6_ntoa(from
->sin6_addr
), ifp
->name
);
1178 ripng_peer_bad_route(from
);
1182 /* Vincent: XXX Should we compute the direclty reachable nexthop
1183 * for our RIPng network ?
1186 /* Routing table updates. */
1187 ripng_route_process(rte
, from
, &nexthop
, ifp
);
1191 /* Response to request message. */
1192 static void ripng_request_process(struct ripng_packet
*packet
, int size
,
1193 struct sockaddr_in6
*from
,
1194 struct interface
*ifp
)
1198 struct prefix_ipv6 p
;
1199 struct agg_node
*rp
;
1200 struct ripng_info
*rinfo
;
1201 struct ripng_interface
*ri
;
1203 /* Does not reponse to the requests on the loopback interfaces */
1204 if (if_is_loopback(ifp
))
1207 /* Check RIPng process is enabled on this interface. */
1212 /* When passive interface is specified, suppress responses */
1216 /* RIPng peer update. */
1217 ripng_peer_update(from
, packet
->version
);
1219 lim
= ((caddr_t
)packet
) + size
;
1222 /* The Request is processed entry by entry. If there are no
1223 entries, no response is given. */
1224 if (lim
== (caddr_t
)rte
)
1227 /* There is one special case. If there is exactly one entry in the
1228 request, and it has a destination prefix of zero, a prefix length
1229 of zero, and a metric of infinity (i.e., 16), then this is a
1230 request to send the entire routing table. In that case, a call
1231 is made to the output process to send the routing table to the
1232 requesting address/port. */
1233 if (lim
== ((caddr_t
)(rte
+ 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte
->addr
)
1234 && rte
->prefixlen
== 0 && rte
->metric
== RIPNG_METRIC_INFINITY
) {
1235 /* All route with split horizon */
1236 ripng_output_process(ifp
, from
, ripng_all_route
);
1238 /* Except for this special case, processing is quite simple.
1239 Examine the list of RTEs in the Request one by one. For each
1240 entry, look up the destination in the router's routing
1241 database and, if there is a route, put that route's metric in
1242 the metric field of the RTE. If there is no explicit route
1243 to the specified destination, put infinity in the metric
1244 field. Once all the entries have been filled in, change the
1245 command from Request to Response and send the datagram back
1246 to the requestor. */
1247 memset(&p
, 0, sizeof(struct prefix_ipv6
));
1248 p
.family
= AF_INET6
;
1250 for (; ((caddr_t
)rte
) < lim
; rte
++) {
1251 p
.prefix
= rte
->addr
;
1252 p
.prefixlen
= rte
->prefixlen
;
1253 apply_mask_ipv6(&p
);
1255 rp
= agg_node_lookup(ripng
->table
, (struct prefix
*)&p
);
1258 rinfo
= listgetdata(
1259 listhead((struct list
*)rp
->info
));
1260 rte
->metric
= rinfo
->metric
;
1261 agg_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 agg_node
*rp
;
1361 struct ripng_info
*rinfo
= NULL
;
1362 struct list
*list
= NULL
;
1363 struct listnode
*listnode
= NULL
;
1365 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_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 vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
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_INTERFACES (vrf
, 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 vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
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_INTERFACES (vrf
, 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
, uint16_t tag
, uint8_t metric
)
1506 /* RIPng packet header. */
1508 stream_putc(s
, RIPNG_RESPONSE
);
1509 stream_putc(s
, RIPNG_V1
);
1513 /* Write routing table entry. */
1516 stream_write(s
, (uint8_t *)&p
->prefix
, sizeof(struct in6_addr
));
1518 stream_write(s
, (uint8_t *)nexthop
, sizeof(struct in6_addr
));
1519 stream_putw(s
, tag
);
1521 stream_putc(s
, p
->prefixlen
);
1524 stream_putc(s
, metric
);
1529 /* Send RESPONSE message to specified destination. */
1530 void ripng_output_process(struct interface
*ifp
, struct sockaddr_in6
*to
,
1534 struct agg_node
*rp
;
1535 struct ripng_info
*rinfo
;
1536 struct ripng_interface
*ri
;
1537 struct ripng_aggregate
*aggregate
;
1538 struct prefix_ipv6
*p
;
1539 struct list
*ripng_rte_list
;
1540 struct list
*list
= NULL
;
1541 struct listnode
*listnode
= NULL
;
1543 if (IS_RIPNG_DEBUG_EVENT
) {
1545 zlog_debug("RIPng update routes to neighbor %s",
1546 inet6_ntoa(to
->sin6_addr
));
1548 zlog_debug("RIPng update routes on interface %s",
1552 /* Get RIPng interface. */
1555 ripng_rte_list
= ripng_rte_new();
1557 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1558 if ((list
= rp
->info
) != NULL
1559 && (rinfo
= listgetdata(listhead(list
))) != NULL
1560 && rinfo
->suppress
== 0) {
1561 /* If no route-map are applied, the RTE will be these
1565 p
= (struct prefix_ipv6
*)&rp
->p
;
1566 rinfo
->metric_out
= rinfo
->metric
;
1567 rinfo
->tag_out
= rinfo
->tag
;
1568 memset(&rinfo
->nexthop_out
, 0,
1569 sizeof(rinfo
->nexthop_out
));
1570 /* In order to avoid some local loops,
1571 * if the RIPng route has a nexthop via this interface,
1573 * otherwise set it to 0. The nexthop should not be
1575 * beyond the local broadcast/multicast area in order
1576 * to avoid an IGP multi-level recursive look-up.
1578 if (rinfo
->ifindex
== ifp
->ifindex
)
1579 rinfo
->nexthop_out
= rinfo
->nexthop
;
1581 /* Apply output filters. */
1582 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1586 /* Changed route only output. */
1587 if (route_type
== ripng_changed_route
1588 && (!(rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1591 /* Split horizon. */
1592 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
) {
1593 /* We perform split horizon for RIPng routes. */
1595 struct ripng_info
*tmp_rinfo
= NULL
;
1597 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1599 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
1600 && tmp_rinfo
->ifindex
1609 /* Preparation for route-map. */
1610 rinfo
->metric_set
= 0;
1613 * and tag_out are already initialized.
1616 /* Interface route-map */
1617 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1618 ret
= route_map_apply(
1619 ri
->routemap
[RIPNG_FILTER_OUT
],
1620 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1622 if (ret
== RMAP_DENYMATCH
) {
1623 if (IS_RIPNG_DEBUG_PACKET
)
1625 "RIPng %s/%d is filtered by route-map out",
1626 inet6_ntoa(p
->prefix
),
1632 /* Redistribute route-map. */
1633 if (ripng
->route_map
[rinfo
->type
].name
) {
1634 ret
= route_map_apply(
1635 ripng
->route_map
[rinfo
->type
].map
,
1636 (struct prefix
*)p
, RMAP_RIPNG
, rinfo
);
1638 if (ret
== RMAP_DENYMATCH
) {
1639 if (IS_RIPNG_DEBUG_PACKET
)
1641 "RIPng %s/%d is filtered by route-map",
1642 inet6_ntoa(p
->prefix
),
1648 /* When the route-map does not set metric. */
1649 if (!rinfo
->metric_set
) {
1650 /* If the redistribute metric is set. */
1651 if (ripng
->route_map
[rinfo
->type
].metric_config
1652 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1654 ripng
->route_map
[rinfo
->type
]
1657 /* If the route is not connected or
1659 one, use default-metric value */
1660 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1662 != ZEBRA_ROUTE_CONNECT
1664 != RIPNG_METRIC_INFINITY
)
1666 ripng
->default_metric
;
1670 /* Apply offset-list */
1671 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1672 ripng_offset_list_apply_out(p
, ifp
,
1673 &rinfo
->metric_out
);
1675 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1676 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1678 /* Perform split-horizon with poisoned reverse
1681 if (ri
->split_horizon
1682 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1683 struct ripng_info
*tmp_rinfo
= NULL
;
1685 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
1687 if ((tmp_rinfo
->type
1688 == ZEBRA_ROUTE_RIPNG
)
1689 && tmp_rinfo
->ifindex
1692 RIPNG_METRIC_INFINITY
;
1695 /* Add RTE to the list */
1696 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1699 /* Process the aggregated RTE entry */
1700 if ((aggregate
= rp
->aggregate
) != NULL
&& aggregate
->count
> 0
1701 && aggregate
->suppress
== 0) {
1702 /* If no route-map are applied, the RTE will be these
1706 p
= (struct prefix_ipv6
*)&rp
->p
;
1707 aggregate
->metric_set
= 0;
1708 aggregate
->metric_out
= aggregate
->metric
;
1709 aggregate
->tag_out
= aggregate
->tag
;
1710 memset(&aggregate
->nexthop_out
, 0,
1711 sizeof(aggregate
->nexthop_out
));
1713 /* Apply output filters.*/
1714 ret
= ripng_filter(RIPNG_FILTER_OUT
, p
, ri
);
1718 /* Interface route-map */
1719 if (ri
->routemap
[RIPNG_FILTER_OUT
]) {
1720 struct ripng_info newinfo
;
1722 /* let's cast the aggregate structure to
1724 memset(&newinfo
, 0, sizeof(struct ripng_info
));
1725 /* the nexthop is :: */
1726 newinfo
.metric
= aggregate
->metric
;
1727 newinfo
.metric_out
= aggregate
->metric_out
;
1728 newinfo
.tag
= aggregate
->tag
;
1729 newinfo
.tag_out
= aggregate
->tag_out
;
1731 ret
= route_map_apply(
1732 ri
->routemap
[RIPNG_FILTER_OUT
],
1733 (struct prefix
*)p
, RMAP_RIPNG
,
1736 if (ret
== RMAP_DENYMATCH
) {
1737 if (IS_RIPNG_DEBUG_PACKET
)
1739 "RIPng %s/%d is filtered by route-map out",
1740 inet6_ntoa(p
->prefix
),
1745 aggregate
->metric_out
= newinfo
.metric_out
;
1746 aggregate
->tag_out
= newinfo
.tag_out
;
1747 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1748 aggregate
->nexthop_out
=
1749 newinfo
.nexthop_out
;
1752 /* There is no redistribute routemap for the aggregated
1755 /* Changed route only output. */
1756 /* XXX, vincent, in order to increase time convergence,
1757 * it should be announced if a child has changed.
1759 if (route_type
== ripng_changed_route
)
1762 /* Apply offset-list */
1763 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1764 ripng_offset_list_apply_out(
1765 p
, ifp
, &aggregate
->metric_out
);
1767 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1768 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1770 /* Add RTE to the list */
1771 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1775 /* Flush the list */
1776 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1777 ripng_rte_free(ripng_rte_list
);
1780 /* Create new RIPng instance and set it to global variable. */
1781 static int ripng_create(void)
1783 /* ripng should be NULL. */
1784 assert(ripng
== NULL
);
1786 /* Allocaste RIPng instance. */
1787 ripng
= XCALLOC(MTYPE_RIPNG
, sizeof(struct ripng
));
1789 /* Default version and timer values. */
1790 ripng
->version
= RIPNG_V1
;
1791 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1792 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1793 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1794 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1797 ripng
->ibuf
= stream_new(RIPNG_MAX_PACKET_SIZE
* 5);
1798 ripng
->obuf
= stream_new(RIPNG_MAX_PACKET_SIZE
);
1800 /* Initialize RIPng routig table. */
1801 ripng
->table
= agg_table_init();
1802 ripng
->route
= agg_table_init();
1803 ripng
->aggregate
= agg_table_init();
1806 ripng
->sock
= ripng_make_socket();
1807 if (ripng
->sock
< 0)
1811 ripng_event(RIPNG_READ
, ripng
->sock
);
1812 ripng_event(RIPNG_UPDATE_EVENT
, 1);
1817 /* Send RIPng request to the interface. */
1818 int ripng_request(struct interface
*ifp
)
1821 struct ripng_packet ripng_packet
;
1823 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1825 if (if_is_loopback(ifp
))
1828 /* If interface is down, don't send RIP packet. */
1832 if (IS_RIPNG_DEBUG_EVENT
)
1833 zlog_debug("RIPng send request to %s", ifp
->name
);
1835 memset(&ripng_packet
, 0, sizeof(ripng_packet
));
1836 ripng_packet
.command
= RIPNG_REQUEST
;
1837 ripng_packet
.version
= RIPNG_V1
;
1838 rte
= ripng_packet
.rte
;
1839 rte
->metric
= RIPNG_METRIC_INFINITY
;
1841 return ripng_send_packet((caddr_t
)&ripng_packet
, sizeof(ripng_packet
),
1846 static int ripng_update_jitter(int time
)
1848 return ((random() % (time
+ 1)) - (time
/ 2));
1851 void ripng_event(enum ripng_event event
, int sock
)
1857 thread_add_read(master
, ripng_read
, NULL
, sock
, &ripng
->t_read
);
1859 case RIPNG_UPDATE_EVENT
:
1860 if (ripng
->t_update
) {
1861 thread_cancel(ripng
->t_update
);
1862 ripng
->t_update
= NULL
;
1864 /* Update timer jitter. */
1865 jitter
= ripng_update_jitter(ripng
->update_time
);
1867 ripng
->t_update
= NULL
;
1868 thread_add_timer(master
, ripng_update
, NULL
,
1869 sock
? 2 : ripng
->update_time
+ jitter
,
1872 case RIPNG_TRIGGERED_UPDATE
:
1873 if (ripng
->t_triggered_interval
)
1876 thread_add_event(master
, ripng_triggered_update
, NULL
,
1877 0, &ripng
->t_triggered_update
);
1885 /* Print out routes update time. */
1886 static void ripng_vty_out_uptime(struct vty
*vty
, struct ripng_info
*rinfo
)
1891 char timebuf
[TIME_BUF
];
1892 struct thread
*thread
;
1894 if ((thread
= rinfo
->t_timeout
) != NULL
) {
1895 clock
= thread_timer_remain_second(thread
);
1896 tm
= gmtime(&clock
);
1897 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1898 vty_out(vty
, "%5s", timebuf
);
1899 } else if ((thread
= rinfo
->t_garbage_collect
) != NULL
) {
1900 clock
= thread_timer_remain_second(thread
);
1901 tm
= gmtime(&clock
);
1902 strftime(timebuf
, TIME_BUF
, "%M:%S", tm
);
1903 vty_out(vty
, "%5s", timebuf
);
1907 static char *ripng_route_subtype_print(struct ripng_info
*rinfo
)
1912 if (rinfo
->suppress
)
1915 switch (rinfo
->sub_type
) {
1916 case RIPNG_ROUTE_RTE
:
1919 case RIPNG_ROUTE_STATIC
:
1922 case RIPNG_ROUTE_DEFAULT
:
1925 case RIPNG_ROUTE_REDISTRIBUTE
:
1928 case RIPNG_ROUTE_INTERFACE
:
1939 DEFUN (show_ipv6_ripng
,
1940 show_ipv6_ripng_cmd
,
1944 "Show RIPng routes\n")
1946 struct agg_node
*rp
;
1947 struct ripng_info
*rinfo
;
1948 struct ripng_aggregate
*aggregate
;
1949 struct prefix_ipv6
*p
;
1950 struct list
*list
= NULL
;
1951 struct listnode
*listnode
= NULL
;
1957 /* Header of display. */
1959 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
1961 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
1962 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
1963 " Network Next Hop Via Metric Tag Time\n");
1965 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
1966 if ((aggregate
= rp
->aggregate
) != NULL
) {
1967 p
= (struct prefix_ipv6
*)&rp
->p
;
1970 vty_out(vty
, "R(a) %d/%d %s/%d ", aggregate
->count
,
1971 aggregate
->suppress
, inet6_ntoa(p
->prefix
),
1974 vty_out(vty
, "R(a) %s/%d ", inet6_ntoa(p
->prefix
),
1978 vty_out(vty
, "%*s", 18, " ");
1980 vty_out(vty
, "%*s", 28, " ");
1981 vty_out(vty
, "self %2d %3" ROUTE_TAG_PRI
"\n",
1982 aggregate
->metric
, (route_tag_t
)aggregate
->tag
);
1985 if ((list
= rp
->info
) != NULL
)
1986 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
1987 p
= (struct prefix_ipv6
*)&rp
->p
;
1990 vty_out(vty
, "%c(%s) 0/%d %s/%d ",
1991 zebra_route_char(rinfo
->type
),
1992 ripng_route_subtype_print(rinfo
),
1993 rinfo
->suppress
, inet6_ntoa(p
->prefix
),
1996 vty_out(vty
, "%c(%s) %s/%d ",
1997 zebra_route_char(rinfo
->type
),
1998 ripng_route_subtype_print(rinfo
),
1999 inet6_ntoa(p
->prefix
), p
->prefixlen
);
2002 vty_out(vty
, "%*s", 18, " ");
2003 len
= vty_out(vty
, "%s",
2004 inet6_ntoa(rinfo
->nexthop
));
2008 vty_out(vty
, "%*s", len
, " ");
2011 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2012 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2015 ifindex2ifname(rinfo
->ifindex
,
2017 } else if (rinfo
->metric
2018 == RIPNG_METRIC_INFINITY
) {
2019 len
= vty_out(vty
, "kill");
2021 len
= vty_out(vty
, "self");
2025 vty_out(vty
, "%*s", len
, " ");
2027 vty_out(vty
, " %2d %3" ROUTE_TAG_PRI
" ",
2028 rinfo
->metric
, (route_tag_t
)rinfo
->tag
);
2031 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
)
2032 && (rinfo
->sub_type
== RIPNG_ROUTE_RTE
)) {
2033 /* RTE from remote RIP routers */
2034 ripng_vty_out_uptime(vty
, rinfo
);
2035 } else if (rinfo
->metric
2036 == RIPNG_METRIC_INFINITY
) {
2037 /* poisonous reversed routes (gc) */
2038 ripng_vty_out_uptime(vty
, rinfo
);
2048 DEFUN (show_ipv6_ripng_status
,
2049 show_ipv6_ripng_status_cmd
,
2050 "show ipv6 ripng status",
2053 "Show RIPng routes\n"
2054 "IPv6 routing protocol process parameters and statistics\n")
2056 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2057 struct interface
*ifp
;
2062 vty_out(vty
, "Routing Protocol is \"RIPng\"\n");
2063 vty_out(vty
, " Sending updates every %ld seconds with +/-50%%,",
2064 ripng
->update_time
);
2065 vty_out(vty
, " next due in %lu seconds\n",
2066 thread_timer_remain_second(ripng
->t_update
));
2067 vty_out(vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2068 vty_out(vty
, " garbage collect after %ld seconds\n",
2069 ripng
->garbage_time
);
2071 /* Filtering status show. */
2072 config_show_distribute(vty
);
2074 /* Default metric information. */
2075 vty_out(vty
, " Default redistribution metric is %d\n",
2076 ripng
->default_metric
);
2078 /* Redistribute information. */
2079 vty_out(vty
, " Redistributing:");
2080 ripng_redistribute_write(vty
, 0);
2083 vty_out(vty
, " Default version control: send version %d,",
2085 vty_out(vty
, " receive version %d \n", ripng
->version
);
2087 vty_out(vty
, " Interface Send Recv\n");
2089 FOR_ALL_INTERFACES (vrf
, ifp
) {
2090 struct ripng_interface
*ri
;
2094 if (ri
->enable_network
|| ri
->enable_interface
) {
2096 vty_out(vty
, " %-17s%-3d %-3d\n", ifp
->name
,
2097 ripng
->version
, ripng
->version
);
2101 vty_out(vty
, " Routing for Networks:\n");
2102 ripng_network_write(vty
, 0);
2104 vty_out(vty
, " Routing Information Sources:\n");
2106 " Gateway BadPackets BadRoutes Distance Last Update\n");
2107 ripng_peer_display(vty
);
2112 DEFUN (clear_ipv6_rip
,
2117 "Clear IPv6 RIP database\n")
2119 struct agg_node
*rp
;
2120 struct ripng_info
*rinfo
;
2122 struct listnode
*listnode
;
2124 /* Clear received RIPng routes */
2125 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
)) {
2130 for (ALL_LIST_ELEMENTS_RO(list
, listnode
, rinfo
)) {
2131 if (!ripng_route_rte(rinfo
))
2134 if (CHECK_FLAG(rinfo
->flags
, RIPNG_RTF_FIB
))
2135 ripng_zebra_ipv6_delete(rp
);
2140 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2141 RIPNG_TIMER_OFF(rinfo
->t_garbage_collect
);
2142 listnode_delete(list
, rinfo
);
2143 ripng_info_free(rinfo
);
2146 if (list_isempty(list
)) {
2149 agg_unlock_node(rp
);
2156 DEFUN_NOSH (router_ripng
,
2159 "Enable a routing process\n"
2160 "Make RIPng instance command\n")
2164 vty
->node
= RIPNG_NODE
;
2167 ret
= ripng_create();
2169 /* Notice to user we couldn't create RIPng. */
2171 zlog_warn("can't create RIPng");
2172 return CMD_WARNING_CONFIG_FAILED
;
2179 DEFUN (no_router_ripng
,
2180 no_router_ripng_cmd
,
2183 "Enable a routing process\n"
2184 "Make RIPng instance command\n")
2194 "Static route setup\n"
2195 "Set static RIPng route announcement\n")
2197 int idx_ipv6addr
= 1;
2199 struct prefix_ipv6 p
;
2200 struct agg_node
*rp
;
2202 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2203 (struct prefix_ipv6
*)&p
);
2205 vty_out(vty
, "Malformed address\n");
2206 return CMD_WARNING_CONFIG_FAILED
;
2208 apply_mask_ipv6(&p
);
2210 rp
= agg_node_get(ripng
->route
, (struct prefix
*)&p
);
2212 vty_out(vty
, "There is already same static route.\n");
2213 agg_unlock_node(rp
);
2216 rp
->info
= (void *)1;
2218 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0,
2224 DEFUN (no_ripng_route
,
2226 "no route IPV6ADDR",
2228 "Static route setup\n"
2229 "Delete static RIPng route announcement\n")
2231 int idx_ipv6addr
= 2;
2233 struct prefix_ipv6 p
;
2234 struct agg_node
*rp
;
2236 ret
= str2prefix_ipv6(argv
[idx_ipv6addr
]->arg
,
2237 (struct prefix_ipv6
*)&p
);
2239 vty_out(vty
, "Malformed address\n");
2240 return CMD_WARNING_CONFIG_FAILED
;
2242 apply_mask_ipv6(&p
);
2244 rp
= agg_node_lookup(ripng
->route
, (struct prefix
*)&p
);
2246 vty_out(vty
, "Can't find static route.\n");
2247 return CMD_WARNING_CONFIG_FAILED
;
2250 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2251 agg_unlock_node(rp
);
2254 agg_unlock_node(rp
);
2259 DEFUN (ripng_aggregate_address
,
2260 ripng_aggregate_address_cmd
,
2261 "aggregate-address X:X::X:X/M",
2262 "Set aggregate RIPng route announcement\n"
2263 "Aggregate network\n")
2265 int idx_ipv6_prefixlen
= 1;
2268 struct agg_node
*node
;
2270 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2271 (struct prefix_ipv6
*)&p
);
2273 vty_out(vty
, "Malformed address\n");
2274 return CMD_WARNING_CONFIG_FAILED
;
2277 /* Check aggregate alredy exist or not. */
2278 node
= agg_node_get(ripng
->aggregate
, &p
);
2280 vty_out(vty
, "There is already same aggregate route.\n");
2281 agg_unlock_node(node
);
2284 node
->info
= (void *)1;
2286 ripng_aggregate_add(&p
);
2291 DEFUN (no_ripng_aggregate_address
,
2292 no_ripng_aggregate_address_cmd
,
2293 "no aggregate-address X:X::X:X/M",
2295 "Delete aggregate RIPng route announcement\n"
2296 "Aggregate network\n")
2298 int idx_ipv6_prefixlen
= 2;
2301 struct agg_node
*rn
;
2303 ret
= str2prefix_ipv6(argv
[idx_ipv6_prefixlen
]->arg
,
2304 (struct prefix_ipv6
*)&p
);
2306 vty_out(vty
, "Malformed address\n");
2307 return CMD_WARNING_CONFIG_FAILED
;
2310 rn
= agg_node_lookup(ripng
->aggregate
, &p
);
2312 vty_out(vty
, "Can't find aggregate route.\n");
2313 return CMD_WARNING_CONFIG_FAILED
;
2315 agg_unlock_node(rn
);
2317 agg_unlock_node(rn
);
2319 ripng_aggregate_delete(&p
);
2324 DEFUN (ripng_default_metric
,
2325 ripng_default_metric_cmd
,
2326 "default-metric (1-16)",
2327 "Set a metric of redistribute routes\n"
2332 ripng
->default_metric
= atoi(argv
[idx_number
]->arg
);
2337 DEFUN (no_ripng_default_metric
,
2338 no_ripng_default_metric_cmd
,
2339 "no default-metric [(1-16)]",
2341 "Set a metric of redistribute routes\n"
2345 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2352 /* RIPng update timer setup. */
2353 DEFUN (ripng_update_timer
,
2354 ripng_update_timer_cmd
,
2355 "update-timer SECOND",
2356 "Set RIPng update timer in seconds\n"
2359 unsigned long update
;
2360 char *endptr
= NULL
;
2362 update
= strtoul (argv
[0], &endptr
, 10);
2363 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2365 vty_out (vty
, "update timer value error\n");
2366 return CMD_WARNING_CONFIG_FAILED
;
2369 ripng
->update_time
= update
;
2371 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2375 DEFUN (no_ripng_update_timer
,
2376 no_ripng_update_timer_cmd
,
2377 "no update-timer SECOND",
2379 "Unset RIPng update timer in seconds\n"
2382 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2383 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2387 /* RIPng timeout timer setup. */
2388 DEFUN (ripng_timeout_timer
,
2389 ripng_timeout_timer_cmd
,
2390 "timeout-timer SECOND",
2391 "Set RIPng timeout timer in seconds\n"
2394 unsigned long timeout
;
2395 char *endptr
= NULL
;
2397 timeout
= strtoul (argv
[0], &endptr
, 10);
2398 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2400 vty_out (vty
, "timeout timer value error\n");
2401 return CMD_WARNING_CONFIG_FAILED
;
2404 ripng
->timeout_time
= timeout
;
2409 DEFUN (no_ripng_timeout_timer
,
2410 no_ripng_timeout_timer_cmd
,
2411 "no timeout-timer SECOND",
2413 "Unset RIPng timeout timer in seconds\n"
2416 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2420 /* RIPng garbage timer setup. */
2421 DEFUN (ripng_garbage_timer
,
2422 ripng_garbage_timer_cmd
,
2423 "garbage-timer SECOND",
2424 "Set RIPng garbage timer in seconds\n"
2427 unsigned long garbage
;
2428 char *endptr
= NULL
;
2430 garbage
= strtoul (argv
[0], &endptr
, 10);
2431 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2433 vty_out (vty
, "garbage timer value error\n");
2434 return CMD_WARNING_CONFIG_FAILED
;
2437 ripng
->garbage_time
= garbage
;
2442 DEFUN (no_ripng_garbage_timer
,
2443 no_ripng_garbage_timer_cmd
,
2444 "no garbage-timer SECOND",
2446 "Unset RIPng garbage timer in seconds\n"
2449 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2454 DEFUN (ripng_timers
,
2456 "timers basic (0-65535) (0-65535) (0-65535)",
2457 "RIPng timers setup\n"
2459 "Routing table update timer value in second. Default is 30.\n"
2460 "Routing information timeout timer. Default is 180.\n"
2461 "Garbage collection timer. Default is 120.\n")
2464 int idx_number_2
= 3;
2465 int idx_number_3
= 4;
2466 unsigned long update
;
2467 unsigned long timeout
;
2468 unsigned long garbage
;
2470 update
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2471 timeout
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
2472 garbage
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
2474 /* Set each timer value. */
2475 ripng
->update_time
= update
;
2476 ripng
->timeout_time
= timeout
;
2477 ripng
->garbage_time
= garbage
;
2479 /* Reset update timer thread. */
2480 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2485 DEFUN (no_ripng_timers
,
2486 no_ripng_timers_cmd
,
2487 "no timers basic [(0-65535) (0-65535) (0-65535)]",
2489 "RIPng timers setup\n"
2491 "Routing table update timer value in second. Default is 30.\n"
2492 "Routing information timeout timer. Default is 180.\n"
2493 "Garbage collection timer. Default is 120.\n")
2495 /* Set each timer value to the default. */
2496 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2497 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2498 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2500 /* Reset update timer thread. */
2501 ripng_event(RIPNG_UPDATE_EVENT
, 0);
2507 DEFUN (show_ipv6_protocols
,
2508 show_ipv6_protocols_cmd
,
2509 "show ipv6 protocols",
2512 "Routing protocol information\n")
2517 vty_out (vty
, "Routing Protocol is \"ripng\"\n");
2519 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds\n",
2520 ripng
->update_time
, 0);
2522 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld\n",
2523 ripng
->timeout_time
,
2524 ripng
->garbage_time
);
2526 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2527 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2533 /* Please be carefull to use this command. */
2534 DEFUN (ripng_default_information_originate
,
2535 ripng_default_information_originate_cmd
,
2536 "default-information originate",
2537 "Default route information\n"
2538 "Distribute default route\n")
2540 struct prefix_ipv6 p
;
2542 if (!ripng
->default_information
) {
2543 ripng
->default_information
= 1;
2545 str2prefix_ipv6("::/0", &p
);
2546 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
,
2553 DEFUN (no_ripng_default_information_originate
,
2554 no_ripng_default_information_originate_cmd
,
2555 "no default-information originate",
2557 "Default route information\n"
2558 "Distribute default route\n")
2560 struct prefix_ipv6 p
;
2562 if (ripng
->default_information
) {
2563 ripng
->default_information
= 0;
2565 str2prefix_ipv6("::/0", &p
);
2566 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG
,
2567 RIPNG_ROUTE_DEFAULT
, &p
, 0);
2573 /* Update ECMP routes to zebra when ECMP is disabled. */
2574 static void ripng_ecmp_disable(void)
2576 struct agg_node
*rp
;
2577 struct ripng_info
*rinfo
, *tmp_rinfo
;
2579 struct listnode
*node
, *nextnode
;
2584 for (rp
= agg_route_top(ripng
->table
); rp
; rp
= agg_route_next(rp
))
2585 if ((list
= rp
->info
) != NULL
&& listcount(list
) > 1) {
2586 rinfo
= listgetdata(listhead(list
));
2587 if (!ripng_route_rte(rinfo
))
2590 /* Drop all other entries, except the first one. */
2591 for (ALL_LIST_ELEMENTS(list
, node
, nextnode
, tmp_rinfo
))
2592 if (tmp_rinfo
!= rinfo
) {
2593 RIPNG_TIMER_OFF(tmp_rinfo
->t_timeout
);
2595 tmp_rinfo
->t_garbage_collect
);
2596 list_delete_node(list
, node
);
2597 ripng_info_free(tmp_rinfo
);
2601 ripng_zebra_ipv6_add(rp
);
2603 /* Set the route change flag. */
2604 SET_FLAG(rinfo
->flags
, RIPNG_RTF_CHANGED
);
2606 /* Signal the output process to trigger an update. */
2607 ripng_event(RIPNG_TRIGGERED_UPDATE
, 0);
2611 DEFUN (ripng_allow_ecmp
,
2612 ripng_allow_ecmp_cmd
,
2614 "Allow Equal Cost MultiPath\n")
2617 vty_out(vty
, "ECMP is already enabled.\n");
2622 zlog_info("ECMP is enabled.");
2626 DEFUN (no_ripng_allow_ecmp
,
2627 no_ripng_allow_ecmp_cmd
,
2630 "Allow Equal Cost MultiPath\n")
2633 vty_out(vty
, "ECMP is already disabled.\n");
2638 zlog_info("ECMP is disabled.");
2639 ripng_ecmp_disable();
2643 /* RIPng configuration write function. */
2644 static int ripng_config_write(struct vty
*vty
)
2646 int ripng_network_write(struct vty
*, int);
2647 void ripng_redistribute_write(struct vty
*, int);
2649 struct agg_node
*rp
;
2654 vty_out(vty
, "router ripng\n");
2656 if (ripng
->default_information
)
2657 vty_out(vty
, " default-information originate\n");
2659 ripng_network_write(vty
, 1);
2661 /* RIPng default metric configuration */
2662 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2663 vty_out(vty
, " default-metric %d\n",
2664 ripng
->default_metric
);
2666 ripng_redistribute_write(vty
, 1);
2668 /* RIP offset-list configuration. */
2669 config_write_ripng_offset_list(vty
);
2671 /* RIPng aggregate routes. */
2672 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2673 rp
= agg_route_next(rp
))
2674 if (rp
->info
!= NULL
)
2675 vty_out(vty
, " aggregate-address %s/%d\n",
2676 inet6_ntoa(rp
->p
.u
.prefix6
),
2679 /* ECMP configuration. */
2681 vty_out(vty
, " allow-ecmp\n");
2683 /* RIPng static routes. */
2684 for (rp
= agg_route_top(ripng
->route
); rp
;
2685 rp
= agg_route_next(rp
))
2686 if (rp
->info
!= NULL
)
2687 vty_out(vty
, " route %s/%d\n",
2688 inet6_ntoa(rp
->p
.u
.prefix6
),
2691 /* RIPng timers configuration. */
2692 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
2693 || ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
2694 || ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
) {
2695 vty_out(vty
, " timers basic %ld %ld %ld\n",
2696 ripng
->update_time
, ripng
->timeout_time
,
2697 ripng
->garbage_time
);
2700 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2701 vty_out (vty
, " update-timer %d\n", ripng
->update_time
);
2702 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2703 vty_out (vty
, " timeout-timer %d\n", ripng
->timeout_time
);
2704 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2705 vty_out (vty
, " garbage-timer %d\n", ripng
->garbage_time
);
2708 write
+= config_write_distribute(vty
);
2710 write
+= config_write_if_rmap(vty
);
2717 /* RIPng node structure. */
2718 static struct cmd_node cmd_ripng_node
= {
2719 RIPNG_NODE
, "%s(config-router)# ", 1,
2722 static void ripng_distribute_update(struct distribute
*dist
)
2724 struct interface
*ifp
;
2725 struct ripng_interface
*ri
;
2726 struct access_list
*alist
;
2727 struct prefix_list
*plist
;
2732 ifp
= if_lookup_by_name(dist
->ifname
, VRF_DEFAULT
);
2738 if (dist
->list
[DISTRIBUTE_V6_IN
]) {
2739 alist
= access_list_lookup(AFI_IP6
,
2740 dist
->list
[DISTRIBUTE_V6_IN
]);
2742 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2744 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2746 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2748 if (dist
->list
[DISTRIBUTE_V6_OUT
]) {
2749 alist
= access_list_lookup(AFI_IP6
,
2750 dist
->list
[DISTRIBUTE_V6_OUT
]);
2752 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2754 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2756 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2758 if (dist
->prefix
[DISTRIBUTE_V6_IN
]) {
2759 plist
= prefix_list_lookup(AFI_IP6
,
2760 dist
->prefix
[DISTRIBUTE_V6_IN
]);
2762 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2764 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2766 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2768 if (dist
->prefix
[DISTRIBUTE_V6_OUT
]) {
2769 plist
= prefix_list_lookup(AFI_IP6
,
2770 dist
->prefix
[DISTRIBUTE_V6_OUT
]);
2772 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2774 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2776 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2779 void ripng_distribute_update_interface(struct interface
*ifp
)
2781 struct distribute
*dist
;
2783 dist
= distribute_lookup(ifp
->name
);
2785 ripng_distribute_update(dist
);
2788 /* Update all interface's distribute list. */
2789 static void ripng_distribute_update_all(struct prefix_list
*notused
)
2791 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2792 struct interface
*ifp
;
2794 FOR_ALL_INTERFACES (vrf
, ifp
)
2795 ripng_distribute_update_interface(ifp
);
2798 static void ripng_distribute_update_all_wrapper(struct access_list
*notused
)
2800 ripng_distribute_update_all(NULL
);
2803 /* delete all the added ripng routes. */
2807 struct agg_node
*rp
;
2808 struct ripng_info
*rinfo
;
2809 struct ripng_aggregate
*aggregate
;
2810 struct list
*list
= NULL
;
2811 struct listnode
*listnode
= NULL
;
2814 /* Clear RIPng routes */
2815 for (rp
= agg_route_top(ripng
->table
); rp
;
2816 rp
= agg_route_next(rp
)) {
2817 if ((list
= rp
->info
) != NULL
) {
2818 rinfo
= listgetdata(listhead(list
));
2819 if (ripng_route_rte(rinfo
))
2820 ripng_zebra_ipv6_delete(rp
);
2822 for (ALL_LIST_ELEMENTS_RO(list
, listnode
,
2824 RIPNG_TIMER_OFF(rinfo
->t_timeout
);
2826 rinfo
->t_garbage_collect
);
2827 ripng_info_free(rinfo
);
2831 agg_unlock_node(rp
);
2834 if ((aggregate
= rp
->aggregate
) != NULL
) {
2835 ripng_aggregate_free(aggregate
);
2836 rp
->aggregate
= NULL
;
2837 agg_unlock_node(rp
);
2841 /* Cancel the RIPng timers */
2842 RIPNG_TIMER_OFF(ripng
->t_update
);
2843 RIPNG_TIMER_OFF(ripng
->t_triggered_update
);
2844 RIPNG_TIMER_OFF(ripng
->t_triggered_interval
);
2846 /* Cancel the read thread */
2847 if (ripng
->t_read
) {
2848 thread_cancel(ripng
->t_read
);
2849 ripng
->t_read
= NULL
;
2852 /* Close the RIPng socket */
2853 if (ripng
->sock
>= 0) {
2858 /* Static RIPng route configuration. */
2859 for (rp
= agg_route_top(ripng
->route
); rp
;
2860 rp
= agg_route_next(rp
))
2863 agg_unlock_node(rp
);
2866 /* RIPng aggregated prefixes */
2867 for (rp
= agg_route_top(ripng
->aggregate
); rp
;
2868 rp
= agg_route_next(rp
))
2871 agg_unlock_node(rp
);
2874 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2875 if (ripng
->route_map
[i
].name
)
2876 free(ripng
->route_map
[i
].name
);
2878 XFREE(MTYPE_ROUTE_TABLE
, ripng
->table
);
2879 XFREE(MTYPE_ROUTE_TABLE
, ripng
->route
);
2880 XFREE(MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2882 stream_free(ripng
->ibuf
);
2883 stream_free(ripng
->obuf
);
2885 XFREE(MTYPE_RIPNG
, ripng
);
2889 ripng_clean_network();
2890 ripng_passive_interface_clean();
2891 ripng_offset_clean();
2892 ripng_interface_clean();
2893 ripng_redistribute_clean();
2896 /* Reset all values to the default settings. */
2899 /* Call ripd related reset functions. */
2900 ripng_debug_reset();
2901 ripng_route_map_reset();
2903 /* Call library reset functions. */
2905 access_list_reset();
2906 prefix_list_reset();
2908 distribute_list_reset();
2910 ripng_interface_reset();
2912 ripng_zclient_reset();
2915 static void ripng_if_rmap_update(struct if_rmap
*if_rmap
)
2917 struct interface
*ifp
;
2918 struct ripng_interface
*ri
;
2919 struct route_map
*rmap
;
2921 ifp
= if_lookup_by_name(if_rmap
->ifname
, VRF_DEFAULT
);
2927 if (if_rmap
->routemap
[IF_RMAP_IN
]) {
2928 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_IN
]);
2930 ri
->routemap
[IF_RMAP_IN
] = rmap
;
2932 ri
->routemap
[IF_RMAP_IN
] = NULL
;
2934 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
2936 if (if_rmap
->routemap
[IF_RMAP_OUT
]) {
2937 rmap
= route_map_lookup_by_name(if_rmap
->routemap
[IF_RMAP_OUT
]);
2939 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
2941 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
2943 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
2946 void ripng_if_rmap_update_interface(struct interface
*ifp
)
2948 struct if_rmap
*if_rmap
;
2950 if_rmap
= if_rmap_lookup(ifp
->name
);
2952 ripng_if_rmap_update(if_rmap
);
2955 static void ripng_routemap_update_redistribute(void)
2960 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
2961 if (ripng
->route_map
[i
].name
)
2962 ripng
->route_map
[i
].map
=
2963 route_map_lookup_by_name(
2964 ripng
->route_map
[i
].name
);
2969 static void ripng_routemap_update(const char *unused
)
2971 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2972 struct interface
*ifp
;
2974 FOR_ALL_INTERFACES (vrf
, ifp
)
2975 ripng_if_rmap_update_interface(ifp
);
2977 ripng_routemap_update_redistribute();
2980 /* Initialize ripng structure and set commands. */
2983 /* Install RIPNG_NODE. */
2984 install_node(&cmd_ripng_node
, ripng_config_write
);
2986 /* Install ripng commands. */
2987 install_element(VIEW_NODE
, &show_ipv6_ripng_cmd
);
2988 install_element(VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
2990 install_element(ENABLE_NODE
, &clear_ipv6_rip_cmd
);
2992 install_element(CONFIG_NODE
, &router_ripng_cmd
);
2993 install_element(CONFIG_NODE
, &no_router_ripng_cmd
);
2995 install_default(RIPNG_NODE
);
2996 install_element(RIPNG_NODE
, &ripng_route_cmd
);
2997 install_element(RIPNG_NODE
, &no_ripng_route_cmd
);
2998 install_element(RIPNG_NODE
, &ripng_aggregate_address_cmd
);
2999 install_element(RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3001 install_element(RIPNG_NODE
, &ripng_default_metric_cmd
);
3002 install_element(RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3004 install_element(RIPNG_NODE
, &ripng_timers_cmd
);
3005 install_element(RIPNG_NODE
, &no_ripng_timers_cmd
);
3007 install_element (VIEW_NODE
, &show_ipv6_protocols_cmd
);
3008 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3009 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3010 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3011 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3012 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3013 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3016 install_element(RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3017 install_element(RIPNG_NODE
,
3018 &no_ripng_default_information_originate_cmd
);
3020 install_element(RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3021 install_element(RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3026 /* Access list install. */
3028 access_list_add_hook(ripng_distribute_update_all_wrapper
);
3029 access_list_delete_hook(ripng_distribute_update_all_wrapper
);
3031 /* Prefix list initialize.*/
3033 prefix_list_add_hook(ripng_distribute_update_all
);
3034 prefix_list_delete_hook(ripng_distribute_update_all
);
3036 /* Distribute list install. */
3037 distribute_list_init(RIPNG_NODE
);
3038 distribute_list_add_hook(ripng_distribute_update
);
3039 distribute_list_delete_hook(ripng_distribute_update
);
3041 /* Route-map for interface. */
3042 ripng_route_map_init();
3043 ripng_offset_init();
3045 route_map_add_hook(ripng_routemap_update
);
3046 route_map_delete_hook(ripng_routemap_update
);
3048 if_rmap_init(RIPNG_NODE
);
3049 if_rmap_hook_add(ripng_if_rmap_update
);
3050 if_rmap_hook_delete(ripng_if_rmap_update
);