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
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
34 #include "distribute.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
;
56 extern struct zebra_privs_t ripngd_privs
;
60 ripng_output_process (struct interface
*, struct sockaddr_in6
*, int);
63 ripng_triggered_update (struct thread
*);
65 /* RIPng next hop specification. */
68 enum ripng_nexthop_type
73 struct in6_addr address
;
77 ripng_route_rte (struct ripng_info
*rinfo
)
79 return (rinfo
->type
== ZEBRA_ROUTE_RIPNG
&& rinfo
->sub_type
== RIPNG_ROUTE_RTE
);
82 /* Allocate new ripng information. */
86 struct ripng_info
*new;
88 new = XCALLOC (MTYPE_RIPNG_ROUTE
, sizeof (struct ripng_info
));
92 /* Free ripng information. */
94 ripng_info_free (struct ripng_info
*rinfo
)
96 XFREE (MTYPE_RIPNG_ROUTE
, rinfo
);
99 /* Create ripng socket. */
101 ripng_make_socket (void)
105 struct sockaddr_in6 ripaddr
;
107 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
110 zlog (NULL
, LOG_ERR
, "Can't make ripng socket");
114 ret
= setsockopt_so_recvbuf (sock
, 8096);
117 ret
= setsockopt_ipv6_pktinfo (sock
, 1);
120 #ifdef IPTOS_PREC_INTERNETCONTROL
121 ret
= setsockopt_ipv6_tclass (sock
, IPTOS_PREC_INTERNETCONTROL
);
125 ret
= setsockopt_ipv6_multicast_hops (sock
, 255);
128 ret
= setsockopt_ipv6_multicast_loop (sock
, 0);
131 ret
= setsockopt_ipv6_hoplimit (sock
, 1);
135 memset (&ripaddr
, 0, sizeof (ripaddr
));
136 ripaddr
.sin6_family
= AF_INET6
;
138 ripaddr
.sin6_len
= sizeof (struct sockaddr_in6
);
139 #endif /* SIN6_LEN */
140 ripaddr
.sin6_port
= htons (RIPNG_PORT_DEFAULT
);
142 if (ripngd_privs
.change (ZPRIVS_RAISE
))
143 zlog_err ("ripng_make_socket: could not raise privs");
145 ret
= bind (sock
, (struct sockaddr
*) &ripaddr
, sizeof (ripaddr
));
148 zlog (NULL
, LOG_ERR
, "Can't bind ripng socket: %s.", safe_strerror (errno
));
149 if (ripngd_privs
.change (ZPRIVS_LOWER
))
150 zlog_err ("ripng_make_socket: could not lower privs");
153 if (ripngd_privs
.change (ZPRIVS_LOWER
))
154 zlog_err ("ripng_make_socket: could not lower privs");
158 /* Send RIPng packet. */
160 ripng_send_packet (caddr_t buf
, int bufsize
, struct sockaddr_in6
*to
,
161 struct interface
*ifp
)
166 struct cmsghdr
*cmsgptr
;
168 struct in6_pktinfo
*pkt
;
169 struct sockaddr_in6 addr
;
171 if (IS_RIPNG_DEBUG_SEND
) {
173 zlog_debug ("send to %s", inet6_ntoa (to
->sin6_addr
));
174 zlog_debug (" send interface %s", ifp
->name
);
175 zlog_debug (" send packet size %d", bufsize
);
178 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
179 addr
.sin6_family
= AF_INET6
;
181 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
182 #endif /* SIN6_LEN */
183 addr
.sin6_flowinfo
= htonl (RIPNG_PRIORITY_DEFAULT
);
185 /* When destination is specified. */
188 addr
.sin6_addr
= to
->sin6_addr
;
189 addr
.sin6_port
= to
->sin6_port
;
193 inet_pton(AF_INET6
, RIPNG_GROUP
, &addr
.sin6_addr
);
194 addr
.sin6_port
= htons (RIPNG_PORT_DEFAULT
);
197 msg
.msg_name
= (void *) &addr
;
198 msg
.msg_namelen
= sizeof (struct sockaddr_in6
);
201 msg
.msg_control
= (void *) adata
;
202 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
205 iov
.iov_len
= bufsize
;
207 cmsgptr
= (struct cmsghdr
*)adata
;
208 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof (struct in6_pktinfo
));
209 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
210 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
212 pkt
= (struct in6_pktinfo
*) CMSG_DATA (cmsgptr
);
213 memset (&pkt
->ipi6_addr
, 0, sizeof (struct in6_addr
));
214 pkt
->ipi6_ifindex
= ifp
->ifindex
;
216 ret
= sendmsg (ripng
->sock
, &msg
, 0);
220 zlog_err ("RIPng send fail on %s to %s: %s", ifp
->name
,
221 inet6_ntoa (to
->sin6_addr
), safe_strerror (errno
));
223 zlog_err ("RIPng send fail on %s: %s", ifp
->name
, safe_strerror (errno
));
229 /* Receive UDP RIPng packet from socket. */
231 ripng_recv_packet (int sock
, u_char
*buf
, int bufsize
,
232 struct sockaddr_in6
*from
, ifindex_t
*ifindex
,
238 struct cmsghdr
*cmsgptr
;
239 struct in6_addr dst
= { .s6_addr
= { 0 } };
241 memset(&dst
, 0, sizeof(struct in6_addr
));
243 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
244 point I can't determine size of cmsghdr */
247 /* Fill in message and iovec. */
248 msg
.msg_name
= (void *) from
;
249 msg
.msg_namelen
= sizeof (struct sockaddr_in6
);
252 msg
.msg_control
= (void *) adata
;
253 msg
.msg_controllen
= sizeof adata
;
255 iov
.iov_len
= bufsize
;
257 /* If recvmsg fail return minus value. */
258 ret
= recvmsg (sock
, &msg
, 0);
262 for (cmsgptr
= ZCMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
263 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
))
265 /* I want interface index which this packet comes from. */
266 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
&&
267 cmsgptr
->cmsg_type
== IPV6_PKTINFO
)
269 struct in6_pktinfo
*ptr
;
271 ptr
= (struct in6_pktinfo
*) CMSG_DATA (cmsgptr
);
272 *ifindex
= ptr
->ipi6_ifindex
;
273 dst
= ptr
->ipi6_addr
;
276 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
279 /* Incoming packet's multicast hop limit. */
280 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
&&
281 cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
)
283 int *phoplimit
= (int *) CMSG_DATA (cmsgptr
);
284 *hoplimit
= *phoplimit
;
288 /* Hoplimit check shold be done when destination address is
289 multicast address. */
290 if (! IN6_IS_ADDR_MULTICAST (&dst
))
296 /* Dump rip packet */
298 ripng_packet_dump (struct ripng_packet
*packet
, int size
, const char *sndrcv
)
302 const char *command_str
;
304 /* Set command string. */
305 if (packet
->command
== RIPNG_REQUEST
)
306 command_str
= "request";
307 else if (packet
->command
== RIPNG_RESPONSE
)
308 command_str
= "response";
310 command_str
= "unknown";
312 /* Dump packet header. */
313 zlog_debug ("%s %s version %d packet size %d",
314 sndrcv
, command_str
, packet
->version
, size
);
316 /* Dump each routing table entry. */
319 for (lim
= (caddr_t
) packet
+ size
; (caddr_t
) rte
< lim
; rte
++)
321 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
322 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte
->addr
), rte
->prefixlen
);
324 zlog_debug (" %s/%d metric %d tag %d",
325 inet6_ntoa (rte
->addr
), rte
->prefixlen
,
326 rte
->metric
, ntohs (rte
->tag
));
330 /* RIPng next hop address RTE (Route Table Entry). */
332 ripng_nexthop_rte (struct rte
*rte
,
333 struct sockaddr_in6
*from
,
334 struct ripng_nexthop
*nexthop
)
336 char buf
[INET6_BUFSIZ
];
338 /* Logging before checking RTE. */
339 if (IS_RIPNG_DEBUG_RECV
)
340 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
341 inet6_ntoa (rte
->addr
), ntohs (rte
->tag
), rte
->prefixlen
);
343 /* RFC2080 2.1.1 Next Hop:
344 The route tag and prefix length in the next hop RTE must be
345 set to zero on sending and ignored on receiption. */
346 if (ntohs (rte
->tag
) != 0)
347 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
348 ntohs (rte
->tag
), inet6_ntoa (from
->sin6_addr
));
350 if (rte
->prefixlen
!= 0)
351 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
352 rte
->prefixlen
, inet6_ntoa (from
->sin6_addr
));
354 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
355 next hop RTE indicates that the next hop address should be the
356 originator of the RIPng advertisement. An address specified as a
357 next hop must be a link-local address. */
358 if (IN6_IS_ADDR_UNSPECIFIED (&rte
->addr
))
360 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
361 memset (&nexthop
->address
, 0, sizeof (struct in6_addr
));
365 if (IN6_IS_ADDR_LINKLOCAL (&rte
->addr
))
367 nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
368 IPV6_ADDR_COPY (&nexthop
->address
, &rte
->addr
);
372 /* The purpose of the next hop RTE is to eliminate packets being
373 routed through extra hops in the system. It is particularly useful
374 when RIPng is not being run on all of the routers on a network.
375 Note that next hop RTE is "advisory". That is, if the provided
376 information is ignored, a possibly sub-optimal, but absolutely
377 valid, route may be taken. If the received next hop address is not
378 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
379 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
380 inet6_ntoa (rte
->addr
),
381 inet_ntop (AF_INET6
, &from
->sin6_addr
, buf
, INET6_BUFSIZ
));
383 nexthop
->flag
= RIPNG_NEXTHOP_UNSPEC
;
384 memset (&nexthop
->address
, 0, sizeof (struct in6_addr
));
389 /* If ifp has same link-local address then return 1. */
391 ripng_lladdr_check (struct interface
*ifp
, struct in6_addr
*addr
)
393 struct listnode
*node
;
394 struct connected
*connected
;
397 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, node
, connected
))
399 p
= connected
->address
;
401 if (p
->family
== AF_INET6
&&
402 IN6_IS_ADDR_LINKLOCAL (&p
->u
.prefix6
) &&
403 IN6_ARE_ADDR_EQUAL (&p
->u
.prefix6
, addr
))
409 /* RIPng route garbage collect timer. */
411 ripng_garbage_collect (struct thread
*t
)
413 struct ripng_info
*rinfo
;
414 struct route_node
*rp
;
416 rinfo
= THREAD_ARG (t
);
417 rinfo
->t_garbage_collect
= NULL
;
419 /* Off timeout timer. */
420 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
422 /* Get route_node pointer. */
425 /* Unlock route_node. */
426 listnode_delete (rp
->info
, rinfo
);
427 if (list_isempty ((struct list
*)rp
->info
))
429 list_free (rp
->info
);
431 route_unlock_node (rp
);
434 /* Free RIPng routing information. */
435 ripng_info_free (rinfo
);
440 static void ripng_timeout_update (struct ripng_info
*rinfo
);
442 /* Add new route to the ECMP list.
443 * RETURN: the new entry added in the list, or NULL if it is not the first
444 * entry and ECMP is not allowed.
447 ripng_ecmp_add (struct ripng_info
*rinfo_new
)
449 struct route_node
*rp
= rinfo_new
->rp
;
450 struct ripng_info
*rinfo
= NULL
;
451 struct list
*list
= NULL
;
453 if (rp
->info
== NULL
)
454 rp
->info
= list_new ();
455 list
= (struct list
*)rp
->info
;
457 /* If ECMP is not allowed and some entry already exists in the list,
459 if (listcount (list
) && !ripng
->ecmp
)
462 rinfo
= ripng_info_new ();
463 memcpy (rinfo
, rinfo_new
, sizeof (struct ripng_info
));
464 listnode_add (list
, rinfo
);
466 if (ripng_route_rte (rinfo
))
468 ripng_timeout_update (rinfo
);
469 ripng_zebra_ipv6_add (rp
);
472 ripng_aggregate_increment (rp
, rinfo
);
474 /* Set the route change flag on the first entry. */
475 rinfo
= listgetdata (listhead (list
));
476 SET_FLAG (rinfo
->flags
, RIPNG_RTF_CHANGED
);
478 /* Signal the output process to trigger an update. */
479 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
484 /* Replace the ECMP list with the new route.
485 * RETURN: the new entry added in the list
488 ripng_ecmp_replace (struct ripng_info
*rinfo_new
)
490 struct route_node
*rp
= rinfo_new
->rp
;
491 struct list
*list
= (struct list
*)rp
->info
;
492 struct ripng_info
*rinfo
= NULL
, *tmp_rinfo
= NULL
;
493 struct listnode
*node
= NULL
, *nextnode
= NULL
;
495 if (list
== NULL
|| listcount (list
) == 0)
496 return ripng_ecmp_add (rinfo_new
);
498 /* Get the first entry */
499 rinfo
= listgetdata (listhead (list
));
501 /* Learnt route replaced by a local one. Delete it from zebra. */
502 if (ripng_route_rte (rinfo
) && !ripng_route_rte (rinfo_new
))
503 if (CHECK_FLAG (rinfo
->flags
, RIPNG_RTF_FIB
))
504 ripng_zebra_ipv6_delete (rp
);
506 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
507 ripng_aggregate_decrement_list (rp
, list
);
509 /* Re-use the first entry, and delete the others. */
510 for (ALL_LIST_ELEMENTS (list
, node
, nextnode
, tmp_rinfo
))
511 if (tmp_rinfo
!= rinfo
)
513 RIPNG_TIMER_OFF (tmp_rinfo
->t_timeout
);
514 RIPNG_TIMER_OFF (tmp_rinfo
->t_garbage_collect
);
515 list_delete_node (list
, node
);
516 ripng_info_free (tmp_rinfo
);
519 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
520 RIPNG_TIMER_OFF (rinfo
->t_garbage_collect
);
521 memcpy (rinfo
, rinfo_new
, sizeof (struct ripng_info
));
523 if (ripng_route_rte (rinfo
))
525 ripng_timeout_update (rinfo
);
526 /* The ADD message implies an update. */
527 ripng_zebra_ipv6_add (rp
);
530 ripng_aggregate_increment (rp
, rinfo
);
532 /* Set the route change flag. */
533 SET_FLAG (rinfo
->flags
, RIPNG_RTF_CHANGED
);
535 /* Signal the output process to trigger an update. */
536 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
541 /* Delete one route from the ECMP list.
543 * null - the entry is freed, and other entries exist in the list
544 * the entry - the entry is the last one in the list; its metric is set
545 * to INFINITY, and the garbage collector is started for it
548 ripng_ecmp_delete (struct ripng_info
*rinfo
)
550 struct route_node
*rp
= rinfo
->rp
;
551 struct list
*list
= (struct list
*)rp
->info
;
553 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
555 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
556 ripng_aggregate_decrement (rp
, rinfo
);
558 if (listcount (list
) > 1)
560 /* Some other ECMP entries still exist. Just delete this entry. */
561 RIPNG_TIMER_OFF (rinfo
->t_garbage_collect
);
562 listnode_delete (list
, rinfo
);
563 if (ripng_route_rte (rinfo
) && CHECK_FLAG (rinfo
->flags
, RIPNG_RTF_FIB
))
564 /* The ADD message implies the update. */
565 ripng_zebra_ipv6_add (rp
);
566 ripng_info_free (rinfo
);
571 assert (rinfo
== listgetdata (listhead (list
)));
573 /* This is the only entry left in the list. We must keep it in
574 * the list for garbage collection time, with INFINITY metric. */
576 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
577 RIPNG_TIMER_ON (rinfo
->t_garbage_collect
,
578 ripng_garbage_collect
, ripng
->garbage_time
);
580 if (ripng_route_rte (rinfo
) && CHECK_FLAG (rinfo
->flags
, RIPNG_RTF_FIB
))
581 ripng_zebra_ipv6_delete (rp
);
584 /* Set the route change flag on the first entry. */
585 rinfo
= listgetdata (listhead (list
));
586 SET_FLAG (rinfo
->flags
, RIPNG_RTF_CHANGED
);
588 /* Signal the output process to trigger an update. */
589 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
594 /* Timeout RIPng routes. */
596 ripng_timeout (struct thread
*t
)
598 ripng_ecmp_delete ((struct ripng_info
*)THREAD_ARG (t
));
603 ripng_timeout_update (struct ripng_info
*rinfo
)
605 if (rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
607 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
608 RIPNG_TIMER_ON (rinfo
->t_timeout
, ripng_timeout
, ripng
->timeout_time
);
613 ripng_incoming_filter (struct prefix_ipv6
*p
, struct ripng_interface
*ri
)
615 struct distribute
*dist
;
616 struct access_list
*alist
;
617 struct prefix_list
*plist
;
619 /* Input distribute-list filtering. */
620 if (ri
->list
[RIPNG_FILTER_IN
])
622 if (access_list_apply (ri
->list
[RIPNG_FILTER_IN
],
623 (struct prefix
*) p
) == FILTER_DENY
)
625 if (IS_RIPNG_DEBUG_PACKET
)
626 zlog_debug ("%s/%d filtered by distribute in",
627 inet6_ntoa (p
->prefix
), p
->prefixlen
);
631 if (ri
->prefix
[RIPNG_FILTER_IN
])
633 if (prefix_list_apply (ri
->prefix
[RIPNG_FILTER_IN
],
634 (struct prefix
*) p
) == PREFIX_DENY
)
636 if (IS_RIPNG_DEBUG_PACKET
)
637 zlog_debug ("%s/%d filtered by prefix-list in",
638 inet6_ntoa (p
->prefix
), p
->prefixlen
);
643 /* All interface filter check. */
644 dist
= distribute_lookup (NULL
);
647 if (dist
->list
[DISTRIBUTE_IN
])
649 alist
= access_list_lookup (AFI_IP6
, dist
->list
[DISTRIBUTE_IN
]);
653 if (access_list_apply (alist
,
654 (struct prefix
*) p
) == FILTER_DENY
)
656 if (IS_RIPNG_DEBUG_PACKET
)
657 zlog_debug ("%s/%d filtered by distribute in",
658 inet6_ntoa (p
->prefix
), p
->prefixlen
);
663 if (dist
->prefix
[DISTRIBUTE_IN
])
665 plist
= prefix_list_lookup (AFI_IP6
, dist
->prefix
[DISTRIBUTE_IN
]);
669 if (prefix_list_apply (plist
,
670 (struct prefix
*) p
) == PREFIX_DENY
)
672 if (IS_RIPNG_DEBUG_PACKET
)
673 zlog_debug ("%s/%d filtered by prefix-list in",
674 inet6_ntoa (p
->prefix
), p
->prefixlen
);
684 ripng_outgoing_filter (struct prefix_ipv6
*p
, struct ripng_interface
*ri
)
686 struct distribute
*dist
;
687 struct access_list
*alist
;
688 struct prefix_list
*plist
;
690 if (ri
->list
[RIPNG_FILTER_OUT
])
692 if (access_list_apply (ri
->list
[RIPNG_FILTER_OUT
],
693 (struct prefix
*) p
) == FILTER_DENY
)
695 if (IS_RIPNG_DEBUG_PACKET
)
696 zlog_debug ("%s/%d is filtered by distribute out",
697 inet6_ntoa (p
->prefix
), p
->prefixlen
);
701 if (ri
->prefix
[RIPNG_FILTER_OUT
])
703 if (prefix_list_apply (ri
->prefix
[RIPNG_FILTER_OUT
],
704 (struct prefix
*) p
) == PREFIX_DENY
)
706 if (IS_RIPNG_DEBUG_PACKET
)
707 zlog_debug ("%s/%d is filtered by prefix-list out",
708 inet6_ntoa (p
->prefix
), p
->prefixlen
);
713 /* All interface filter check. */
714 dist
= distribute_lookup (NULL
);
717 if (dist
->list
[DISTRIBUTE_OUT
])
719 alist
= access_list_lookup (AFI_IP6
, dist
->list
[DISTRIBUTE_OUT
]);
723 if (access_list_apply (alist
,
724 (struct prefix
*) p
) == FILTER_DENY
)
726 if (IS_RIPNG_DEBUG_PACKET
)
727 zlog_debug ("%s/%d filtered by distribute out",
728 inet6_ntoa (p
->prefix
), p
->prefixlen
);
733 if (dist
->prefix
[DISTRIBUTE_OUT
])
735 plist
= prefix_list_lookup (AFI_IP6
, dist
->prefix
[DISTRIBUTE_OUT
]);
739 if (prefix_list_apply (plist
,
740 (struct prefix
*) p
) == PREFIX_DENY
)
742 if (IS_RIPNG_DEBUG_PACKET
)
743 zlog_debug ("%s/%d filtered by prefix-list out",
744 inet6_ntoa (p
->prefix
), p
->prefixlen
);
753 /* Process RIPng route according to RFC2080. */
755 ripng_route_process (struct rte
*rte
, struct sockaddr_in6
*from
,
756 struct ripng_nexthop
*ripng_nexthop
,
757 struct interface
*ifp
)
760 struct prefix_ipv6 p
;
761 struct route_node
*rp
;
762 struct ripng_info
*rinfo
= NULL
, newinfo
;
763 struct ripng_interface
*ri
;
764 struct in6_addr
*nexthop
;
766 struct list
*list
= NULL
;
767 struct listnode
*node
= NULL
;
769 /* Make prefix structure. */
770 memset (&p
, 0, sizeof (struct prefix_ipv6
));
772 /* p.prefix = rte->addr; */
773 IPV6_ADDR_COPY (&p
.prefix
, &rte
->addr
);
774 p
.prefixlen
= rte
->prefixlen
;
776 /* Make sure mask is applied. */
777 /* XXX We have to check the prefix is valid or not before call
779 apply_mask_ipv6 (&p
);
781 /* Apply input filters. */
784 ret
= ripng_incoming_filter (&p
, ri
);
788 memset (&newinfo
, 0, sizeof (newinfo
));
789 newinfo
.type
= ZEBRA_ROUTE_RIPNG
;
790 newinfo
.sub_type
= RIPNG_ROUTE_RTE
;
791 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
792 newinfo
.nexthop
= ripng_nexthop
->address
;
794 newinfo
.nexthop
= from
->sin6_addr
;
795 newinfo
.from
= from
->sin6_addr
;
796 newinfo
.ifindex
= ifp
->ifindex
;
797 newinfo
.metric
= rte
->metric
;
798 newinfo
.metric_out
= rte
->metric
; /* XXX */
799 newinfo
.tag
= ntohs (rte
->tag
); /* XXX */
802 if (ri
->routemap
[RIPNG_FILTER_IN
])
806 ret
= route_map_apply (ri
->routemap
[RIPNG_FILTER_IN
],
807 (struct prefix
*)&p
, RMAP_RIPNG
, &newinfo
);
809 if (ret
== RMAP_DENYMATCH
)
811 if (IS_RIPNG_DEBUG_PACKET
)
812 zlog_debug ("RIPng %s/%d is filtered by route-map in",
813 inet6_ntoa (p
.prefix
), p
.prefixlen
);
817 /* Get back the object */
818 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
) {
819 if (! IPV6_ADDR_SAME(&newinfo
.nexthop
, &ripng_nexthop
->address
) ) {
820 /* the nexthop get changed by the routemap */
821 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
))
822 ripng_nexthop
->address
= newinfo
.nexthop
;
824 ripng_nexthop
->address
= in6addr_any
;
827 if (! IPV6_ADDR_SAME(&newinfo
.nexthop
, &from
->sin6_addr
) ) {
828 /* the nexthop get changed by the routemap */
829 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop
)) {
830 ripng_nexthop
->flag
= RIPNG_NEXTHOP_ADDRESS
;
831 ripng_nexthop
->address
= newinfo
.nexthop
;
835 rte
->tag
= htons(newinfo
.tag_out
); /* XXX */
836 rte
->metric
= newinfo
.metric_out
; /* XXX: the routemap uses the metric_out field */
839 /* Once the entry has been validated, update the metric by
840 * adding the cost of the network on wich the message
841 * arrived. If the result is greater than infinity, use infinity
842 * (RFC2453 Sec. 3.9.2)
845 /* Zebra ripngd can handle offset-list in. */
846 ret
= ripng_offset_list_apply_in (&p
, ifp
, &rte
->metric
);
848 /* If offset-list does not modify the metric use interface's
851 rte
->metric
+= ifp
->metric
? ifp
->metric
: 1;
853 if (rte
->metric
> RIPNG_METRIC_INFINITY
)
854 rte
->metric
= RIPNG_METRIC_INFINITY
;
856 /* Set nexthop pointer. */
857 if (ripng_nexthop
->flag
== RIPNG_NEXTHOP_ADDRESS
)
858 nexthop
= &ripng_nexthop
->address
;
860 nexthop
= &from
->sin6_addr
;
862 /* Lookup RIPng routing table. */
863 rp
= route_node_get (ripng
->table
, (struct prefix
*) &p
);
866 newinfo
.nexthop
= *nexthop
;
867 newinfo
.metric
= rte
->metric
;
868 newinfo
.tag
= ntohs (rte
->tag
);
870 /* Check to see whether there is already RIPng route on the table. */
871 if ((list
= rp
->info
) != NULL
)
872 for (ALL_LIST_ELEMENTS_RO (list
, node
, rinfo
))
874 /* Need to compare with redistributed entry or local entry */
875 if (!ripng_route_rte (rinfo
))
878 if (IPV6_ADDR_SAME (&rinfo
->from
, &from
->sin6_addr
) &&
879 IPV6_ADDR_SAME (&rinfo
->nexthop
, nexthop
))
882 if (!listnextnode (node
))
884 /* Not found in the list */
886 if (rte
->metric
> rinfo
->metric
)
888 /* New route has a greater metric. Discard it. */
889 route_unlock_node (rp
);
893 if (rte
->metric
< rinfo
->metric
)
894 /* New route has a smaller metric. Replace the ECMP list
895 * with the new one in below. */
898 /* Metrics are same. Keep "rinfo" null and the new route
899 * is added in the ECMP list in below. */
905 /* Redistributed route check. */
906 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
907 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
909 route_unlock_node (rp
);
913 /* Local static route. */
914 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
915 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
) ||
916 (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
))
917 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
919 route_unlock_node (rp
);
926 /* Now, check to see whether there is already an explicit route
927 for the destination prefix. If there is no such route, add
928 this route to the routing table, unless the metric is
929 infinity (there is no point in adding a route which
931 if (rte
->metric
!= RIPNG_METRIC_INFINITY
)
932 ripng_ecmp_add (&newinfo
);
936 /* If there is an existing route, compare the next hop address
937 to the address of the router from which the datagram came.
938 If this datagram is from the same router as the existing
939 route, reinitialize the timeout. */
940 same
= (IN6_ARE_ADDR_EQUAL (&rinfo
->from
, &from
->sin6_addr
)
941 && (rinfo
->ifindex
== ifp
->ifindex
));
943 /* Next, compare the metrics. If the datagram is from the same
944 router as the existing route, and the new metric is different
945 than the old one; or, if the new metric is lower than the old
946 one; do the following actions: */
947 if ((same
&& rinfo
->metric
!= rte
->metric
) ||
948 rte
->metric
< rinfo
->metric
)
950 if (listcount (list
) == 1)
952 if (newinfo
.metric
!= RIPNG_METRIC_INFINITY
)
953 ripng_ecmp_replace (&newinfo
);
955 ripng_ecmp_delete (rinfo
);
959 if (newinfo
.metric
< rinfo
->metric
)
960 ripng_ecmp_replace (&newinfo
);
961 else /* newinfo.metric > rinfo->metric */
962 ripng_ecmp_delete (rinfo
);
965 else /* same & no change */
966 ripng_timeout_update (rinfo
);
968 /* Unlock tempolary lock of the route. */
969 route_unlock_node (rp
);
973 /* Add redistributed route to RIPng table. */
975 ripng_redistribute_add (int type
, int sub_type
, struct prefix_ipv6
*p
,
976 ifindex_t ifindex
, struct in6_addr
*nexthop
)
978 struct route_node
*rp
;
979 struct ripng_info
*rinfo
= NULL
, newinfo
;
980 struct list
*list
= NULL
;
982 /* Redistribute route */
983 if (IN6_IS_ADDR_LINKLOCAL (&p
->prefix
))
985 if (IN6_IS_ADDR_LOOPBACK (&p
->prefix
))
988 rp
= route_node_get (ripng
->table
, (struct prefix
*) p
);
990 memset (&newinfo
, 0, sizeof (struct ripng_info
));
992 newinfo
.sub_type
= sub_type
;
993 newinfo
.ifindex
= ifindex
;
996 if (nexthop
&& IN6_IS_ADDR_LINKLOCAL(nexthop
))
997 newinfo
.nexthop
= *nexthop
;
999 if ((list
= rp
->info
) != NULL
&& listcount (list
) != 0)
1001 rinfo
= listgetdata (listhead (list
));
1003 if (rinfo
->type
== ZEBRA_ROUTE_CONNECT
1004 && rinfo
->sub_type
== RIPNG_ROUTE_INTERFACE
1005 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
) {
1006 route_unlock_node (rp
);
1010 /* Manually configured RIPng route check.
1011 * They have the precedence on all the other entries.
1013 if (rinfo
->type
== ZEBRA_ROUTE_RIPNG
1014 && ((rinfo
->sub_type
== RIPNG_ROUTE_STATIC
) ||
1015 (rinfo
->sub_type
== RIPNG_ROUTE_DEFAULT
)) ) {
1016 if (type
!= ZEBRA_ROUTE_RIPNG
|| ((sub_type
!= RIPNG_ROUTE_STATIC
) &&
1017 (sub_type
!= RIPNG_ROUTE_DEFAULT
))) {
1018 route_unlock_node (rp
);
1023 rinfo
= ripng_ecmp_replace (&newinfo
);
1024 route_unlock_node (rp
);
1027 rinfo
= ripng_ecmp_add (&newinfo
);
1029 if (IS_RIPNG_DEBUG_EVENT
) {
1031 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
1032 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1033 ifindex2ifname(ifindex
));
1035 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
1036 inet6_ntoa(p
->prefix
), p
->prefixlen
, inet6_ntoa(*nexthop
),
1037 ifindex2ifname(ifindex
));
1040 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
1043 /* Delete redistributed route to RIPng table. */
1045 ripng_redistribute_delete (int type
, int sub_type
, struct prefix_ipv6
*p
,
1048 struct route_node
*rp
;
1049 struct ripng_info
*rinfo
;
1051 if (IN6_IS_ADDR_LINKLOCAL (&p
->prefix
))
1053 if (IN6_IS_ADDR_LOOPBACK (&p
->prefix
))
1056 rp
= route_node_lookup (ripng
->table
, (struct prefix
*) p
);
1060 struct list
*list
= rp
->info
;
1062 if (list
!= NULL
&& listcount (list
) != 0)
1064 rinfo
= listgetdata (listhead (list
));
1066 && rinfo
->type
== type
1067 && rinfo
->sub_type
== sub_type
1068 && rinfo
->ifindex
== ifindex
)
1070 /* Perform poisoned reverse. */
1071 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1072 RIPNG_TIMER_ON (rinfo
->t_garbage_collect
,
1073 ripng_garbage_collect
, ripng
->garbage_time
);
1074 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
1076 /* Aggregate count decrement. */
1077 ripng_aggregate_decrement (rp
, rinfo
);
1079 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1081 if (IS_RIPNG_DEBUG_EVENT
)
1082 zlog_debug ("Poisone %s/%d on the interface %s with an "
1083 "infinity metric [delete]",
1084 inet6_ntoa (p
->prefix
), p
->prefixlen
,
1085 ifindex2ifname (ifindex
));
1087 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
1090 route_unlock_node (rp
);
1094 /* Withdraw redistributed route. */
1096 ripng_redistribute_withdraw (int type
)
1098 struct route_node
*rp
;
1099 struct ripng_info
*rinfo
= NULL
;
1100 struct list
*list
= NULL
;
1105 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
1106 if ((list
= rp
->info
) != NULL
)
1108 rinfo
= listgetdata (listhead (list
));
1109 if ((rinfo
->type
== type
)
1110 && (rinfo
->sub_type
!= RIPNG_ROUTE_INTERFACE
))
1112 /* Perform poisoned reverse. */
1113 rinfo
->metric
= RIPNG_METRIC_INFINITY
;
1114 RIPNG_TIMER_ON (rinfo
->t_garbage_collect
,
1115 ripng_garbage_collect
, ripng
->garbage_time
);
1116 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
1118 /* Aggregate count decrement. */
1119 ripng_aggregate_decrement (rp
, rinfo
);
1121 rinfo
->flags
|= RIPNG_RTF_CHANGED
;
1123 if (IS_RIPNG_DEBUG_EVENT
) {
1124 struct prefix_ipv6
*p
= (struct prefix_ipv6
*) &rp
->p
;
1126 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
1127 inet6_ntoa(p
->prefix
), p
->prefixlen
,
1128 ifindex2ifname(rinfo
->ifindex
));
1131 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
1136 /* RIP routing information. */
1138 ripng_response_process (struct ripng_packet
*packet
, int size
,
1139 struct sockaddr_in6
*from
, struct interface
*ifp
,
1144 struct ripng_nexthop nexthop
;
1146 /* RFC2080 2.4.2 Response Messages:
1147 The Response must be ignored if it is not from the RIPng port. */
1148 if (ntohs (from
->sin6_port
) != RIPNG_PORT_DEFAULT
)
1150 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
1151 ntohs (from
->sin6_port
), inet6_ntoa (from
->sin6_addr
));
1152 ripng_peer_bad_packet (from
);
1156 /* The datagram's IPv6 source address should be checked to see
1157 whether the datagram is from a valid neighbor; the source of the
1158 datagram must be a link-local address. */
1159 if (! IN6_IS_ADDR_LINKLOCAL(&from
->sin6_addr
))
1161 zlog_warn ("RIPng packet comes from non link local address %s",
1162 inet6_ntoa (from
->sin6_addr
));
1163 ripng_peer_bad_packet (from
);
1167 /* It is also worth checking to see whether the response is from one
1168 of the router's own addresses. Interfaces on broadcast networks
1169 may receive copies of their own multicasts immediately. If a
1170 router processes its own output as new input, confusion is likely,
1171 and such datagrams must be ignored. */
1172 if (ripng_lladdr_check (ifp
, &from
->sin6_addr
))
1174 zlog_warn ("RIPng packet comes from my own link local address %s",
1175 inet6_ntoa (from
->sin6_addr
));
1176 ripng_peer_bad_packet (from
);
1180 /* As an additional check, periodic advertisements must have their
1181 hop counts set to 255, and inbound, multicast packets sent from the
1182 RIPng port (i.e. periodic advertisement or triggered update
1183 packets) must be examined to ensure that the hop count is 255. */
1184 if (hoplimit
>= 0 && hoplimit
!= 255)
1186 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
1187 hoplimit
, inet6_ntoa (from
->sin6_addr
));
1188 ripng_peer_bad_packet (from
);
1192 /* Update RIPng peer. */
1193 ripng_peer_update (from
, packet
->version
);
1195 /* Reset nexthop. */
1196 memset (&nexthop
, 0, sizeof (struct ripng_nexthop
));
1197 nexthop
.flag
= RIPNG_NEXTHOP_UNSPEC
;
1199 /* Set RTE pointer. */
1202 for (lim
= ((caddr_t
) packet
) + size
; (caddr_t
) rte
< lim
; rte
++)
1204 /* First of all, we have to check this RTE is next hop RTE or
1205 not. Next hop RTE is completely different with normal RTE so
1206 we need special treatment. */
1207 if (rte
->metric
== RIPNG_METRIC_NEXTHOP
)
1209 ripng_nexthop_rte (rte
, from
, &nexthop
);
1213 /* RTE information validation. */
1215 /* - is the destination prefix valid (e.g., not a multicast
1216 prefix and not a link-local address) A link-local address
1217 should never be present in an RTE. */
1218 if (IN6_IS_ADDR_MULTICAST (&rte
->addr
))
1220 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
1221 inet6_ntoa (rte
->addr
), rte
->prefixlen
, rte
->metric
);
1222 ripng_peer_bad_route (from
);
1225 if (IN6_IS_ADDR_LINKLOCAL (&rte
->addr
))
1227 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
1228 inet6_ntoa (rte
->addr
), rte
->prefixlen
, rte
->metric
);
1229 ripng_peer_bad_route (from
);
1232 if (IN6_IS_ADDR_LOOPBACK (&rte
->addr
))
1234 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
1235 inet6_ntoa (rte
->addr
), rte
->prefixlen
, rte
->metric
);
1236 ripng_peer_bad_route (from
);
1240 /* - is the prefix length valid (i.e., between 0 and 128,
1242 if (rte
->prefixlen
> 128)
1244 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
1245 inet6_ntoa (rte
->addr
), rte
->prefixlen
,
1246 inet6_ntoa (from
->sin6_addr
), ifp
->name
);
1247 ripng_peer_bad_route (from
);
1251 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1252 if (! (rte
->metric
>= 1 && rte
->metric
<= 16))
1254 zlog_warn ("Invalid metric %d from %s%%%s", rte
->metric
,
1255 inet6_ntoa (from
->sin6_addr
), ifp
->name
);
1256 ripng_peer_bad_route (from
);
1260 /* Vincent: XXX Should we compute the direclty reachable nexthop
1261 * for our RIPng network ?
1264 /* Routing table updates. */
1265 ripng_route_process (rte
, from
, &nexthop
, ifp
);
1269 /* Response to request message. */
1271 ripng_request_process (struct ripng_packet
*packet
,int size
,
1272 struct sockaddr_in6
*from
, struct interface
*ifp
)
1276 struct prefix_ipv6 p
;
1277 struct route_node
*rp
;
1278 struct ripng_info
*rinfo
;
1279 struct ripng_interface
*ri
;
1281 /* Does not reponse to the requests on the loopback interfaces */
1282 if (if_is_loopback (ifp
))
1285 /* Check RIPng process is enabled on this interface. */
1290 /* When passive interface is specified, suppress responses */
1294 /* RIPng peer update. */
1295 ripng_peer_update (from
, packet
->version
);
1297 lim
= ((caddr_t
) packet
) + size
;
1300 /* The Request is processed entry by entry. If there are no
1301 entries, no response is given. */
1302 if (lim
== (caddr_t
) rte
)
1305 /* There is one special case. If there is exactly one entry in the
1306 request, and it has a destination prefix of zero, a prefix length
1307 of zero, and a metric of infinity (i.e., 16), then this is a
1308 request to send the entire routing table. In that case, a call
1309 is made to the output process to send the routing table to the
1310 requesting address/port. */
1311 if (lim
== ((caddr_t
) (rte
+ 1)) &&
1312 IN6_IS_ADDR_UNSPECIFIED (&rte
->addr
) &&
1313 rte
->prefixlen
== 0 &&
1314 rte
->metric
== RIPNG_METRIC_INFINITY
)
1316 /* All route with split horizon */
1317 ripng_output_process (ifp
, from
, ripng_all_route
);
1321 /* Except for this special case, processing is quite simple.
1322 Examine the list of RTEs in the Request one by one. For each
1323 entry, look up the destination in the router's routing
1324 database and, if there is a route, put that route's metric in
1325 the metric field of the RTE. If there is no explicit route
1326 to the specified destination, put infinity in the metric
1327 field. Once all the entries have been filled in, change the
1328 command from Request to Response and send the datagram back
1329 to the requestor. */
1330 memset (&p
, 0, sizeof (struct prefix_ipv6
));
1331 p
.family
= AF_INET6
;
1333 for (; ((caddr_t
) rte
) < lim
; rte
++)
1335 p
.prefix
= rte
->addr
;
1336 p
.prefixlen
= rte
->prefixlen
;
1337 apply_mask_ipv6 (&p
);
1339 rp
= route_node_lookup (ripng
->table
, (struct prefix
*) &p
);
1343 rinfo
= listgetdata (listhead ((struct list
*)rp
->info
));
1344 rte
->metric
= rinfo
->metric
;
1345 route_unlock_node (rp
);
1348 rte
->metric
= RIPNG_METRIC_INFINITY
;
1350 packet
->command
= RIPNG_RESPONSE
;
1352 ripng_send_packet ((caddr_t
) packet
, size
, from
, ifp
);
1356 /* First entry point of reading RIPng packet. */
1358 ripng_read (struct thread
*thread
)
1362 struct sockaddr_in6 from
;
1363 struct ripng_packet
*packet
;
1364 ifindex_t ifindex
= 0;
1365 struct interface
*ifp
;
1368 /* Check ripng is active and alive. */
1369 assert (ripng
!= NULL
);
1370 assert (ripng
->sock
>= 0);
1372 /* Fetch thread data and set read pointer to empty for event
1373 managing. `sock' sould be same as ripng->sock. */
1374 sock
= THREAD_FD (thread
);
1375 ripng
->t_read
= NULL
;
1377 /* Add myself to the next event. */
1378 ripng_event (RIPNG_READ
, sock
);
1380 /* Read RIPng packet. */
1381 len
= ripng_recv_packet (sock
, STREAM_DATA (ripng
->ibuf
),
1382 STREAM_SIZE (ripng
->ibuf
), &from
, &ifindex
,
1386 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno
));
1390 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1391 (4)) must be multiple size of one RTE size (20). */
1392 if (((len
- 4) % 20) != 0)
1394 zlog_warn ("RIPng invalid packet size %d from %s", len
,
1395 inet6_ntoa (from
.sin6_addr
));
1396 ripng_peer_bad_packet (&from
);
1400 packet
= (struct ripng_packet
*) STREAM_DATA (ripng
->ibuf
);
1401 ifp
= if_lookup_by_index (ifindex
);
1403 /* RIPng packet received. */
1404 if (IS_RIPNG_DEBUG_EVENT
)
1405 zlog_debug ("RIPng packet received from %s port %d on %s",
1406 inet6_ntoa (from
.sin6_addr
), ntohs (from
.sin6_port
),
1407 ifp
? ifp
->name
: "unknown");
1409 /* Logging before packet checking. */
1410 if (IS_RIPNG_DEBUG_RECV
)
1411 ripng_packet_dump (packet
, len
, "RECV");
1413 /* Packet comes from unknown interface. */
1416 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex
);
1420 /* Packet version mismatch checking. */
1421 if (packet
->version
!= ripng
->version
)
1423 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1424 packet
->version
, ripng
->version
);
1425 ripng_peer_bad_packet (&from
);
1429 /* Process RIPng packet. */
1430 switch (packet
->command
)
1433 ripng_request_process (packet
, len
, &from
, ifp
);
1435 case RIPNG_RESPONSE
:
1436 ripng_response_process (packet
, len
, &from
, ifp
, hoplimit
);
1439 zlog_warn ("Invalid RIPng command %d", packet
->command
);
1440 ripng_peer_bad_packet (&from
);
1446 /* Walk down the RIPng routing table then clear changed flag. */
1448 ripng_clear_changed_flag (void)
1450 struct route_node
*rp
;
1451 struct ripng_info
*rinfo
= NULL
;
1452 struct list
*list
= NULL
;
1453 struct listnode
*listnode
= NULL
;
1455 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
1456 if ((list
= rp
->info
) != NULL
)
1457 for (ALL_LIST_ELEMENTS_RO (list
, listnode
, rinfo
))
1459 UNSET_FLAG (rinfo
->flags
, RIPNG_RTF_CHANGED
);
1460 /* This flag can be set only on the first entry. */
1465 /* Regular update of RIPng route. Send all routing formation to RIPng
1466 enabled interface. */
1468 ripng_update (struct thread
*t
)
1470 struct listnode
*node
;
1471 struct interface
*ifp
;
1472 struct ripng_interface
*ri
;
1474 /* Clear update timer thread. */
1475 ripng
->t_update
= NULL
;
1477 /* Logging update event. */
1478 if (IS_RIPNG_DEBUG_EVENT
)
1479 zlog_debug ("RIPng update timer expired!");
1481 /* Supply routes to each interface. */
1482 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
1486 if (if_is_loopback (ifp
) || ! if_is_up (ifp
))
1492 /* When passive interface is specified, suppress announce to the
1498 if (ri
->ri_send
== RIPNG_SEND_OFF
)
1500 if (IS_RIPNG_DEBUG_EVENT
)
1501 zlog (NULL
, LOG_DEBUG
,
1502 "[Event] RIPng send to if %d is suppressed by config",
1506 #endif /* RIPNG_ADVANCED */
1508 ripng_output_process (ifp
, NULL
, ripng_all_route
);
1511 /* Triggered updates may be suppressed if a regular update is due by
1512 the time the triggered update would be sent. */
1513 if (ripng
->t_triggered_interval
)
1515 thread_cancel (ripng
->t_triggered_interval
);
1516 ripng
->t_triggered_interval
= NULL
;
1520 /* Reset flush event. */
1521 ripng_event (RIPNG_UPDATE_EVENT
, 0);
1526 /* Triggered update interval timer. */
1528 ripng_triggered_interval (struct thread
*t
)
1530 ripng
->t_triggered_interval
= NULL
;
1535 ripng_triggered_update (t
);
1540 /* Execute triggered update. */
1542 ripng_triggered_update (struct thread
*t
)
1544 struct listnode
*node
;
1545 struct interface
*ifp
;
1546 struct ripng_interface
*ri
;
1549 ripng
->t_triggered_update
= NULL
;
1551 /* Cancel interval timer. */
1552 if (ripng
->t_triggered_interval
)
1554 thread_cancel (ripng
->t_triggered_interval
);
1555 ripng
->t_triggered_interval
= NULL
;
1559 /* Logging triggered update. */
1560 if (IS_RIPNG_DEBUG_EVENT
)
1561 zlog_debug ("RIPng triggered update!");
1563 /* Split Horizon processing is done when generating triggered
1564 updates as well as normal updates (see section 2.6). */
1565 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
1569 if (if_is_loopback (ifp
) || ! if_is_up (ifp
))
1575 /* When passive interface is specified, suppress announce to the
1580 ripng_output_process (ifp
, NULL
, ripng_changed_route
);
1583 /* Once all of the triggered updates have been generated, the route
1584 change flags should be cleared. */
1585 ripng_clear_changed_flag ();
1587 /* After a triggered update is sent, a timer should be set for a
1588 random interval between 1 and 5 seconds. If other changes that
1589 would trigger updates occur before the timer expires, a single
1590 update is triggered when the timer expires. */
1591 interval
= (random () % 5) + 1;
1593 ripng
->t_triggered_interval
=
1594 thread_add_timer (master
, ripng_triggered_interval
, NULL
, interval
);
1599 /* Write routing table entry to the stream and return next index of
1600 the routing table entry in the stream. */
1602 ripng_write_rte (int num
, struct stream
*s
, struct prefix_ipv6
*p
,
1603 struct in6_addr
*nexthop
, u_int16_t tag
, u_char metric
)
1605 /* RIPng packet header. */
1608 stream_putc (s
, RIPNG_RESPONSE
);
1609 stream_putc (s
, RIPNG_V1
);
1613 /* Write routing table entry. */
1615 stream_write (s
, (u_char
*) &p
->prefix
, sizeof (struct in6_addr
));
1617 stream_write (s
, (u_char
*) nexthop
, sizeof (struct in6_addr
));
1618 stream_putw (s
, tag
);
1620 stream_putc (s
, p
->prefixlen
);
1623 stream_putc (s
, metric
);
1628 /* Send RESPONSE message to specified destination. */
1630 ripng_output_process (struct interface
*ifp
, struct sockaddr_in6
*to
,
1634 struct route_node
*rp
;
1635 struct ripng_info
*rinfo
;
1636 struct ripng_interface
*ri
;
1637 struct ripng_aggregate
*aggregate
;
1638 struct prefix_ipv6
*p
;
1639 struct list
* ripng_rte_list
;
1640 struct list
*list
= NULL
;
1641 struct listnode
*listnode
= NULL
;
1643 if (IS_RIPNG_DEBUG_EVENT
) {
1645 zlog_debug ("RIPng update routes to neighbor %s",
1646 inet6_ntoa(to
->sin6_addr
));
1648 zlog_debug ("RIPng update routes on interface %s", ifp
->name
);
1651 /* Get RIPng interface. */
1654 ripng_rte_list
= ripng_rte_new();
1656 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
1658 if ((list
= rp
->info
) != NULL
&&
1659 (rinfo
= listgetdata (listhead (list
))) != NULL
&&
1660 rinfo
->suppress
== 0)
1662 /* If no route-map are applied, the RTE will be these following
1665 p
= (struct prefix_ipv6
*) &rp
->p
;
1666 rinfo
->metric_out
= rinfo
->metric
;
1667 rinfo
->tag_out
= rinfo
->tag
;
1668 memset(&rinfo
->nexthop_out
, 0, sizeof(rinfo
->nexthop_out
));
1669 /* In order to avoid some local loops,
1670 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1671 * otherwise set it to 0. The nexthop should not be propagated
1672 * beyond the local broadcast/multicast area in order
1673 * to avoid an IGP multi-level recursive look-up.
1675 if (rinfo
->ifindex
== ifp
->ifindex
)
1676 rinfo
->nexthop_out
= rinfo
->nexthop
;
1678 /* Apply output filters. */
1679 ret
= ripng_outgoing_filter (p
, ri
);
1683 /* Changed route only output. */
1684 if (route_type
== ripng_changed_route
&&
1685 (! (rinfo
->flags
& RIPNG_RTF_CHANGED
)))
1688 /* Split horizon. */
1689 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON
)
1691 /* We perform split horizon for RIPng routes. */
1693 struct ripng_info
*tmp_rinfo
= NULL
;
1695 for (ALL_LIST_ELEMENTS_RO (list
, listnode
, tmp_rinfo
))
1696 if (tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
&&
1697 tmp_rinfo
->ifindex
== ifp
->ifindex
)
1706 /* Preparation for route-map. */
1707 rinfo
->metric_set
= 0;
1710 * and tag_out are already initialized.
1713 /* Interface route-map */
1714 if (ri
->routemap
[RIPNG_FILTER_OUT
])
1718 ret
= route_map_apply (ri
->routemap
[RIPNG_FILTER_OUT
],
1719 (struct prefix
*) p
, RMAP_RIPNG
,
1722 if (ret
== RMAP_DENYMATCH
)
1724 if (IS_RIPNG_DEBUG_PACKET
)
1725 zlog_debug ("RIPng %s/%d is filtered by route-map out",
1726 inet6_ntoa (p
->prefix
), p
->prefixlen
);
1732 /* Redistribute route-map. */
1733 if (ripng
->route_map
[rinfo
->type
].name
)
1737 ret
= route_map_apply (ripng
->route_map
[rinfo
->type
].map
,
1738 (struct prefix
*) p
, RMAP_RIPNG
,
1741 if (ret
== RMAP_DENYMATCH
)
1743 if (IS_RIPNG_DEBUG_PACKET
)
1744 zlog_debug ("RIPng %s/%d is filtered by route-map",
1745 inet6_ntoa (p
->prefix
), p
->prefixlen
);
1750 /* When the route-map does not set metric. */
1751 if (! rinfo
->metric_set
)
1753 /* If the redistribute metric is set. */
1754 if (ripng
->route_map
[rinfo
->type
].metric_config
1755 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
1757 rinfo
->metric_out
= ripng
->route_map
[rinfo
->type
].metric
;
1761 /* If the route is not connected or localy generated
1762 one, use default-metric value */
1763 if (rinfo
->type
!= ZEBRA_ROUTE_RIPNG
1764 && rinfo
->type
!= ZEBRA_ROUTE_CONNECT
1765 && rinfo
->metric
!= RIPNG_METRIC_INFINITY
)
1766 rinfo
->metric_out
= ripng
->default_metric
;
1770 /* Apply offset-list */
1771 if (rinfo
->metric_out
!= RIPNG_METRIC_INFINITY
)
1772 ripng_offset_list_apply_out (p
, ifp
, &rinfo
->metric_out
);
1774 if (rinfo
->metric_out
> RIPNG_METRIC_INFINITY
)
1775 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1777 /* Perform split-horizon with poisoned reverse
1780 if (ri
->split_horizon
== RIPNG_SPLIT_HORIZON_POISONED_REVERSE
) {
1781 struct ripng_info
*tmp_rinfo
= NULL
;
1783 for (ALL_LIST_ELEMENTS_RO (list
, listnode
, tmp_rinfo
))
1784 if ((tmp_rinfo
->type
== ZEBRA_ROUTE_RIPNG
) &&
1785 tmp_rinfo
->ifindex
== ifp
->ifindex
)
1786 rinfo
->metric_out
= RIPNG_METRIC_INFINITY
;
1789 /* Add RTE to the list */
1790 ripng_rte_add(ripng_rte_list
, p
, rinfo
, NULL
);
1793 /* Process the aggregated RTE entry */
1794 if ((aggregate
= rp
->aggregate
) != NULL
&&
1795 aggregate
->count
> 0 &&
1796 aggregate
->suppress
== 0)
1798 /* If no route-map are applied, the RTE will be these following
1801 p
= (struct prefix_ipv6
*) &rp
->p
;
1802 aggregate
->metric_set
= 0;
1803 aggregate
->metric_out
= aggregate
->metric
;
1804 aggregate
->tag_out
= aggregate
->tag
;
1805 memset(&aggregate
->nexthop_out
, 0, sizeof(aggregate
->nexthop_out
));
1807 /* Apply output filters.*/
1808 ret
= ripng_outgoing_filter (p
, ri
);
1812 /* Interface route-map */
1813 if (ri
->routemap
[RIPNG_FILTER_OUT
])
1816 struct ripng_info newinfo
;
1818 /* let's cast the aggregate structure to ripng_info */
1819 memset (&newinfo
, 0, sizeof (struct ripng_info
));
1820 /* the nexthop is :: */
1821 newinfo
.metric
= aggregate
->metric
;
1822 newinfo
.metric_out
= aggregate
->metric_out
;
1823 newinfo
.tag
= aggregate
->tag
;
1824 newinfo
.tag_out
= aggregate
->tag_out
;
1826 ret
= route_map_apply (ri
->routemap
[RIPNG_FILTER_OUT
],
1827 (struct prefix
*) p
, RMAP_RIPNG
,
1830 if (ret
== RMAP_DENYMATCH
)
1832 if (IS_RIPNG_DEBUG_PACKET
)
1833 zlog_debug ("RIPng %s/%d is filtered by route-map out",
1834 inet6_ntoa (p
->prefix
), p
->prefixlen
);
1838 aggregate
->metric_out
= newinfo
.metric_out
;
1839 aggregate
->tag_out
= newinfo
.tag_out
;
1840 if (IN6_IS_ADDR_LINKLOCAL(&newinfo
.nexthop_out
))
1841 aggregate
->nexthop_out
= newinfo
.nexthop_out
;
1844 /* There is no redistribute routemap for the aggregated RTE */
1846 /* Changed route only output. */
1847 /* XXX, vincent, in order to increase time convergence,
1848 * it should be announced if a child has changed.
1850 if (route_type
== ripng_changed_route
)
1853 /* Apply offset-list */
1854 if (aggregate
->metric_out
!= RIPNG_METRIC_INFINITY
)
1855 ripng_offset_list_apply_out (p
, ifp
, &aggregate
->metric_out
);
1857 if (aggregate
->metric_out
> RIPNG_METRIC_INFINITY
)
1858 aggregate
->metric_out
= RIPNG_METRIC_INFINITY
;
1860 /* Add RTE to the list */
1861 ripng_rte_add(ripng_rte_list
, p
, NULL
, aggregate
);
1866 /* Flush the list */
1867 ripng_rte_send(ripng_rte_list
, ifp
, to
);
1868 ripng_rte_free(ripng_rte_list
);
1871 /* Create new RIPng instance and set it to global variable. */
1875 /* ripng should be NULL. */
1876 assert (ripng
== NULL
);
1878 /* Allocaste RIPng instance. */
1879 ripng
= XCALLOC (MTYPE_RIPNG
, sizeof (struct ripng
));
1881 /* Default version and timer values. */
1882 ripng
->version
= RIPNG_V1
;
1883 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
1884 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
1885 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
1886 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
1889 ripng
->ibuf
= stream_new (RIPNG_MAX_PACKET_SIZE
* 5);
1890 ripng
->obuf
= stream_new (RIPNG_MAX_PACKET_SIZE
);
1892 /* Initialize RIPng routig table. */
1893 ripng
->table
= route_table_init ();
1894 ripng
->route
= route_table_init ();
1895 ripng
->aggregate
= route_table_init ();
1898 ripng
->sock
= ripng_make_socket ();
1899 if (ripng
->sock
< 0)
1903 ripng_event (RIPNG_READ
, ripng
->sock
);
1904 ripng_event (RIPNG_UPDATE_EVENT
, 1);
1909 /* Send RIPng request to the interface. */
1911 ripng_request (struct interface
*ifp
)
1914 struct ripng_packet ripng_packet
;
1916 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1917 if (if_is_loopback(ifp
))
1920 /* If interface is down, don't send RIP packet. */
1921 if (! if_is_up (ifp
))
1924 if (IS_RIPNG_DEBUG_EVENT
)
1925 zlog_debug ("RIPng send request to %s", ifp
->name
);
1927 memset (&ripng_packet
, 0, sizeof (ripng_packet
));
1928 ripng_packet
.command
= RIPNG_REQUEST
;
1929 ripng_packet
.version
= RIPNG_V1
;
1930 rte
= ripng_packet
.rte
;
1931 rte
->metric
= RIPNG_METRIC_INFINITY
;
1933 return ripng_send_packet ((caddr_t
) &ripng_packet
, sizeof (ripng_packet
),
1939 ripng_update_jitter (int time
)
1941 return ((random () % (time
+ 1)) - (time
/ 2));
1945 ripng_event (enum ripng_event event
, int sock
)
1953 ripng
->t_read
= thread_add_read (master
, ripng_read
, NULL
, sock
);
1955 case RIPNG_UPDATE_EVENT
:
1956 if (ripng
->t_update
)
1958 thread_cancel (ripng
->t_update
);
1959 ripng
->t_update
= NULL
;
1961 /* Update timer jitter. */
1962 jitter
= ripng_update_jitter (ripng
->update_time
);
1965 thread_add_timer (master
, ripng_update
, NULL
,
1966 sock
? 2 : ripng
->update_time
+ jitter
);
1968 case RIPNG_TRIGGERED_UPDATE
:
1969 if (ripng
->t_triggered_interval
)
1971 else if (! ripng
->t_triggered_update
)
1972 ripng
->t_triggered_update
=
1973 thread_add_event (master
, ripng_triggered_update
, NULL
, 0);
1981 /* Print out routes update time. */
1983 ripng_vty_out_uptime (struct vty
*vty
, struct ripng_info
*rinfo
)
1988 char timebuf
[TIME_BUF
];
1989 struct thread
*thread
;
1991 if ((thread
= rinfo
->t_timeout
) != NULL
)
1993 clock
= thread_timer_remain_second (thread
);
1994 tm
= gmtime (&clock
);
1995 strftime (timebuf
, TIME_BUF
, "%M:%S", tm
);
1996 vty_out (vty
, "%5s", timebuf
);
1998 else if ((thread
= rinfo
->t_garbage_collect
) != NULL
)
2000 clock
= thread_timer_remain_second (thread
);
2001 tm
= gmtime (&clock
);
2002 strftime (timebuf
, TIME_BUF
, "%M:%S", tm
);
2003 vty_out (vty
, "%5s", timebuf
);
2008 ripng_route_subtype_print (struct ripng_info
*rinfo
)
2013 if (rinfo
->suppress
)
2016 switch (rinfo
->sub_type
)
2018 case RIPNG_ROUTE_RTE
:
2021 case RIPNG_ROUTE_STATIC
:
2024 case RIPNG_ROUTE_DEFAULT
:
2027 case RIPNG_ROUTE_REDISTRIBUTE
:
2030 case RIPNG_ROUTE_INTERFACE
:
2041 DEFUN (show_ipv6_ripng
,
2042 show_ipv6_ripng_cmd
,
2046 "Show RIPng routes\n")
2048 struct route_node
*rp
;
2049 struct ripng_info
*rinfo
;
2050 struct ripng_aggregate
*aggregate
;
2051 struct prefix_ipv6
*p
;
2052 struct list
*list
= NULL
;
2053 struct listnode
*listnode
= NULL
;
2059 /* Header of display. */
2060 vty_out (vty
, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2062 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2063 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2064 " Network Next Hop Via Metric Tag Time%s",
2065 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
2066 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
2068 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
2070 if ((aggregate
= rp
->aggregate
) != NULL
)
2072 p
= (struct prefix_ipv6
*) &rp
->p
;
2075 len
= vty_out (vty
, "R(a) %d/%d %s/%d ",
2076 aggregate
->count
, aggregate
->suppress
,
2077 inet6_ntoa (p
->prefix
), p
->prefixlen
);
2079 len
= vty_out (vty
, "R(a) %s/%d ",
2080 inet6_ntoa (p
->prefix
), p
->prefixlen
);
2082 vty_out (vty
, "%s", VTY_NEWLINE
);
2083 vty_out (vty
, "%*s", 18, " ");
2085 vty_out (vty
, "%*s", 28, " ");
2086 vty_out (vty
, "self %2d %3d%s", aggregate
->metric
,
2091 if ((list
= rp
->info
) != NULL
)
2092 for (ALL_LIST_ELEMENTS_RO (list
, listnode
, rinfo
))
2094 p
= (struct prefix_ipv6
*) &rp
->p
;
2097 len
= vty_out (vty
, "%c(%s) 0/%d %s/%d ",
2098 zebra_route_char(rinfo
->type
),
2099 ripng_route_subtype_print(rinfo
),
2101 inet6_ntoa (p
->prefix
), p
->prefixlen
);
2103 len
= vty_out (vty
, "%c(%s) %s/%d ",
2104 zebra_route_char(rinfo
->type
),
2105 ripng_route_subtype_print(rinfo
),
2106 inet6_ntoa (p
->prefix
), p
->prefixlen
);
2108 vty_out (vty
, "%s", VTY_NEWLINE
);
2109 vty_out (vty
, "%*s", 18, " ");
2110 len
= vty_out (vty
, "%s", inet6_ntoa (rinfo
->nexthop
));
2114 len
= vty_out (vty
, "%*s", len
, " ");
2117 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
) &&
2118 (rinfo
->sub_type
== RIPNG_ROUTE_RTE
))
2120 len
= vty_out (vty
, "%s", ifindex2ifname(rinfo
->ifindex
));
2121 } else if (rinfo
->metric
== RIPNG_METRIC_INFINITY
)
2123 len
= vty_out (vty
, "kill");
2125 len
= vty_out (vty
, "self");
2129 vty_out (vty
, "%*s", len
, " ");
2131 vty_out (vty
, " %2d %3d ",
2132 rinfo
->metric
, rinfo
->tag
);
2135 if ((rinfo
->type
== ZEBRA_ROUTE_RIPNG
) &&
2136 (rinfo
->sub_type
== RIPNG_ROUTE_RTE
))
2138 /* RTE from remote RIP routers */
2139 ripng_vty_out_uptime (vty
, rinfo
);
2140 } else if (rinfo
->metric
== RIPNG_METRIC_INFINITY
)
2142 /* poisonous reversed routes (gc) */
2143 ripng_vty_out_uptime (vty
, rinfo
);
2146 vty_out (vty
, "%s", VTY_NEWLINE
);
2153 DEFUN (show_ipv6_ripng_status
,
2154 show_ipv6_ripng_status_cmd
,
2155 "show ipv6 ripng status",
2158 "Show RIPng routes\n"
2159 "IPv6 routing protocol process parameters and statistics\n")
2161 struct listnode
*node
;
2162 struct interface
*ifp
;
2167 vty_out (vty
, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE
);
2168 vty_out (vty
, " Sending updates every %ld seconds with +/-50%%,",
2169 ripng
->update_time
);
2170 vty_out (vty
, " next due in %lu seconds%s",
2171 thread_timer_remain_second (ripng
->t_update
),
2173 vty_out (vty
, " Timeout after %ld seconds,", ripng
->timeout_time
);
2174 vty_out (vty
, " garbage collect after %ld seconds%s", ripng
->garbage_time
,
2177 /* Filtering status show. */
2178 config_show_distribute (vty
);
2180 /* Default metric information. */
2181 vty_out (vty
, " Default redistribution metric is %d%s",
2182 ripng
->default_metric
, VTY_NEWLINE
);
2184 /* Redistribute information. */
2185 vty_out (vty
, " Redistributing:");
2186 ripng_redistribute_write (vty
, 0);
2187 vty_out (vty
, "%s", VTY_NEWLINE
);
2189 vty_out (vty
, " Default version control: send version %d,", ripng
->version
);
2190 vty_out (vty
, " receive version %d %s", ripng
->version
,
2193 vty_out (vty
, " Interface Send Recv%s", VTY_NEWLINE
);
2195 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
2197 struct ripng_interface
*ri
;
2201 if (ri
->enable_network
|| ri
->enable_interface
)
2204 vty_out (vty
, " %-17s%-3d %-3d%s", ifp
->name
,
2211 vty_out (vty
, " Routing for Networks:%s", VTY_NEWLINE
);
2212 ripng_network_write (vty
, 0);
2214 vty_out (vty
, " Routing Information Sources:%s", VTY_NEWLINE
);
2215 vty_out (vty
, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE
);
2216 ripng_peer_display (vty
);
2221 DEFUN (router_ripng
,
2224 "Enable a routing process\n"
2225 "Make RIPng instance command\n")
2229 vty
->node
= RIPNG_NODE
;
2233 ret
= ripng_create ();
2235 /* Notice to user we couldn't create RIPng. */
2238 zlog_warn ("can't create RIPng");
2246 DEFUN (no_router_ripng
,
2247 no_router_ripng_cmd
,
2250 "Enable a routing process\n"
2251 "Make RIPng instance command\n")
2261 "Static route setup\n"
2262 "Set static RIPng route announcement\n")
2265 struct prefix_ipv6 p
;
2266 struct route_node
*rp
;
2268 ret
= str2prefix_ipv6 (argv
[0], (struct prefix_ipv6
*)&p
);
2271 vty_out (vty
, "Malformed address%s", VTY_NEWLINE
);
2274 apply_mask_ipv6 (&p
);
2276 rp
= route_node_get (ripng
->route
, (struct prefix
*) &p
);
2279 vty_out (vty
, "There is already same static route.%s", VTY_NEWLINE
);
2280 route_unlock_node (rp
);
2283 rp
->info
= (void *)1;
2285 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0, NULL
);
2290 DEFUN (no_ripng_route
,
2292 "no route IPV6ADDR",
2294 "Static route setup\n"
2295 "Delete static RIPng route announcement\n")
2298 struct prefix_ipv6 p
;
2299 struct route_node
*rp
;
2301 ret
= str2prefix_ipv6 (argv
[0], (struct prefix_ipv6
*)&p
);
2304 vty_out (vty
, "Malformed address%s", VTY_NEWLINE
);
2307 apply_mask_ipv6 (&p
);
2309 rp
= route_node_lookup (ripng
->route
, (struct prefix
*) &p
);
2312 vty_out (vty
, "Can't find static route.%s", VTY_NEWLINE
);
2316 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_STATIC
, &p
, 0);
2317 route_unlock_node (rp
);
2320 route_unlock_node (rp
);
2325 DEFUN (ripng_aggregate_address
,
2326 ripng_aggregate_address_cmd
,
2327 "aggregate-address X:X::X:X/M",
2328 "Set aggregate RIPng route announcement\n"
2329 "Aggregate network\n")
2333 struct route_node
*node
;
2335 ret
= str2prefix_ipv6 (argv
[0], (struct prefix_ipv6
*)&p
);
2338 vty_out (vty
, "Malformed address%s", VTY_NEWLINE
);
2342 /* Check aggregate alredy exist or not. */
2343 node
= route_node_get (ripng
->aggregate
, &p
);
2346 vty_out (vty
, "There is already same aggregate route.%s", VTY_NEWLINE
);
2347 route_unlock_node (node
);
2350 node
->info
= (void *)1;
2352 ripng_aggregate_add (&p
);
2357 DEFUN (no_ripng_aggregate_address
,
2358 no_ripng_aggregate_address_cmd
,
2359 "no aggregate-address X:X::X:X/M",
2361 "Delete aggregate RIPng route announcement\n"
2362 "Aggregate network")
2366 struct route_node
*rn
;
2368 ret
= str2prefix_ipv6 (argv
[0], (struct prefix_ipv6
*) &p
);
2371 vty_out (vty
, "Malformed address%s", VTY_NEWLINE
);
2375 rn
= route_node_lookup (ripng
->aggregate
, &p
);
2378 vty_out (vty
, "Can't find aggregate route.%s", VTY_NEWLINE
);
2381 route_unlock_node (rn
);
2383 route_unlock_node (rn
);
2385 ripng_aggregate_delete (&p
);
2390 DEFUN (ripng_default_metric
,
2391 ripng_default_metric_cmd
,
2392 "default-metric <1-16>",
2393 "Set a metric of redistribute routes\n"
2398 ripng
->default_metric
= atoi (argv
[0]);
2403 DEFUN (no_ripng_default_metric
,
2404 no_ripng_default_metric_cmd
,
2405 "no default-metric",
2407 "Set a metric of redistribute routes\n"
2412 ripng
->default_metric
= RIPNG_DEFAULT_METRIC_DEFAULT
;
2417 ALIAS (no_ripng_default_metric
,
2418 no_ripng_default_metric_val_cmd
,
2419 "no default-metric <1-16>",
2421 "Set a metric of redistribute routes\n"
2425 /* RIPng update timer setup. */
2426 DEFUN (ripng_update_timer
,
2427 ripng_update_timer_cmd
,
2428 "update-timer SECOND",
2429 "Set RIPng update timer in seconds\n"
2432 unsigned long update
;
2433 char *endptr
= NULL
;
2435 update
= strtoul (argv
[0], &endptr
, 10);
2436 if (update
== ULONG_MAX
|| *endptr
!= '\0')
2438 vty_out (vty
, "update timer value error%s", VTY_NEWLINE
);
2442 ripng
->update_time
= update
;
2444 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2448 DEFUN (no_ripng_update_timer
,
2449 no_ripng_update_timer_cmd
,
2450 "no update-timer SECOND",
2452 "Unset RIPng update timer in seconds\n"
2455 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2456 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2460 /* RIPng timeout timer setup. */
2461 DEFUN (ripng_timeout_timer
,
2462 ripng_timeout_timer_cmd
,
2463 "timeout-timer SECOND",
2464 "Set RIPng timeout timer in seconds\n"
2467 unsigned long timeout
;
2468 char *endptr
= NULL
;
2470 timeout
= strtoul (argv
[0], &endptr
, 10);
2471 if (timeout
== ULONG_MAX
|| *endptr
!= '\0')
2473 vty_out (vty
, "timeout timer value error%s", VTY_NEWLINE
);
2477 ripng
->timeout_time
= timeout
;
2482 DEFUN (no_ripng_timeout_timer
,
2483 no_ripng_timeout_timer_cmd
,
2484 "no timeout-timer SECOND",
2486 "Unset RIPng timeout timer in seconds\n"
2489 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2493 /* RIPng garbage timer setup. */
2494 DEFUN (ripng_garbage_timer
,
2495 ripng_garbage_timer_cmd
,
2496 "garbage-timer SECOND",
2497 "Set RIPng garbage timer in seconds\n"
2500 unsigned long garbage
;
2501 char *endptr
= NULL
;
2503 garbage
= strtoul (argv
[0], &endptr
, 10);
2504 if (garbage
== ULONG_MAX
|| *endptr
!= '\0')
2506 vty_out (vty
, "garbage timer value error%s", VTY_NEWLINE
);
2510 ripng
->garbage_time
= garbage
;
2515 DEFUN (no_ripng_garbage_timer
,
2516 no_ripng_garbage_timer_cmd
,
2517 "no garbage-timer SECOND",
2519 "Unset RIPng garbage timer in seconds\n"
2522 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2527 DEFUN (ripng_timers
,
2529 "timers basic <0-65535> <0-65535> <0-65535>",
2530 "RIPng timers setup\n"
2532 "Routing table update timer value in second. Default is 30.\n"
2533 "Routing information timeout timer. Default is 180.\n"
2534 "Garbage collection timer. Default is 120.\n")
2536 unsigned long update
;
2537 unsigned long timeout
;
2538 unsigned long garbage
;
2540 VTY_GET_INTEGER_RANGE("update timer", update
, argv
[0], 0, 65535);
2541 VTY_GET_INTEGER_RANGE("timeout timer", timeout
, argv
[1], 0, 65535);
2542 VTY_GET_INTEGER_RANGE("garbage timer", garbage
, argv
[2], 0, 65535);
2544 /* Set each timer value. */
2545 ripng
->update_time
= update
;
2546 ripng
->timeout_time
= timeout
;
2547 ripng
->garbage_time
= garbage
;
2549 /* Reset update timer thread. */
2550 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2555 DEFUN (no_ripng_timers
,
2556 no_ripng_timers_cmd
,
2559 "RIPng timers setup\n"
2562 /* Set each timer value to the default. */
2563 ripng
->update_time
= RIPNG_UPDATE_TIMER_DEFAULT
;
2564 ripng
->timeout_time
= RIPNG_TIMEOUT_TIMER_DEFAULT
;
2565 ripng
->garbage_time
= RIPNG_GARBAGE_TIMER_DEFAULT
;
2567 /* Reset update timer thread. */
2568 ripng_event (RIPNG_UPDATE_EVENT
, 0);
2573 ALIAS (no_ripng_timers
,
2574 no_ripng_timers_val_cmd
,
2575 "no timers basic <0-65535> <0-65535> <0-65535>",
2577 "RIPng timers setup\n"
2579 "Routing table update timer value in second. Default is 30.\n"
2580 "Routing information timeout timer. Default is 180.\n"
2581 "Garbage collection timer. Default is 120.\n")
2583 DEFUN (show_ipv6_protocols
, show_ipv6_protocols_cmd
,
2584 "show ipv6 protocols",
2587 "Routing protocol information")
2592 vty_out (vty
, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE
);
2594 vty_out (vty
, "Sending updates every %ld seconds, next due in %d seconds%s",
2595 ripng
->update_time
, 0,
2598 vty_out (vty
, "Timerout after %ld seconds, garbage correct %ld%s",
2599 ripng
->timeout_time
,
2600 ripng
->garbage_time
,
2603 vty_out (vty
, "Outgoing update filter list for all interfaces is not set");
2604 vty_out (vty
, "Incoming update filter list for all interfaces is not set");
2609 /* Please be carefull to use this command. */
2610 DEFUN (ripng_default_information_originate
,
2611 ripng_default_information_originate_cmd
,
2612 "default-information originate",
2613 "Default route information\n"
2614 "Distribute default route\n")
2616 struct prefix_ipv6 p
;
2618 if (! ripng
->default_information
) {
2619 ripng
->default_information
= 1;
2621 str2prefix_ipv6 ("::/0", &p
);
2622 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
, &p
, 0, NULL
);
2628 DEFUN (no_ripng_default_information_originate
,
2629 no_ripng_default_information_originate_cmd
,
2630 "no default-information originate",
2632 "Default route information\n"
2633 "Distribute default route\n")
2635 struct prefix_ipv6 p
;
2637 if (ripng
->default_information
) {
2638 ripng
->default_information
= 0;
2640 str2prefix_ipv6 ("::/0", &p
);
2641 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG
, RIPNG_ROUTE_DEFAULT
, &p
, 0);
2647 /* Update ECMP routes to zebra when ECMP is disabled. */
2649 ripng_ecmp_disable (void)
2651 struct route_node
*rp
;
2652 struct ripng_info
*rinfo
, *tmp_rinfo
;
2654 struct listnode
*node
, *nextnode
;
2659 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
2660 if ((list
= rp
->info
) != NULL
&& listcount (list
) > 1)
2662 rinfo
= listgetdata (listhead (list
));
2663 if (!ripng_route_rte (rinfo
))
2666 /* Drop all other entries, except the first one. */
2667 for (ALL_LIST_ELEMENTS (list
, node
, nextnode
, tmp_rinfo
))
2668 if (tmp_rinfo
!= rinfo
)
2670 RIPNG_TIMER_OFF (tmp_rinfo
->t_timeout
);
2671 RIPNG_TIMER_OFF (tmp_rinfo
->t_garbage_collect
);
2672 list_delete_node (list
, node
);
2673 ripng_info_free (tmp_rinfo
);
2677 ripng_zebra_ipv6_add (rp
);
2679 /* Set the route change flag. */
2680 SET_FLAG (rinfo
->flags
, RIPNG_RTF_CHANGED
);
2682 /* Signal the output process to trigger an update. */
2683 ripng_event (RIPNG_TRIGGERED_UPDATE
, 0);
2687 DEFUN (ripng_allow_ecmp
,
2688 ripng_allow_ecmp_cmd
,
2690 "Allow Equal Cost MultiPath\n")
2694 vty_out (vty
, "ECMP is already enabled.%s", VTY_NEWLINE
);
2699 zlog_info ("ECMP is enabled.");
2703 DEFUN (no_ripng_allow_ecmp
,
2704 no_ripng_allow_ecmp_cmd
,
2707 "Allow Equal Cost MultiPath\n")
2711 vty_out (vty
, "ECMP is already disabled.%s", VTY_NEWLINE
);
2716 zlog_info ("ECMP is disabled.");
2717 ripng_ecmp_disable ();
2721 /* RIPng configuration write function. */
2723 ripng_config_write (struct vty
*vty
)
2725 int ripng_network_write (struct vty
*, int);
2726 void ripng_redistribute_write (struct vty
*, int);
2728 struct route_node
*rp
;
2734 vty_out (vty
, "router ripng%s", VTY_NEWLINE
);
2736 if (ripng
->default_information
)
2737 vty_out (vty
, " default-information originate%s", VTY_NEWLINE
);
2739 ripng_network_write (vty
, 1);
2741 /* RIPng default metric configuration */
2742 if (ripng
->default_metric
!= RIPNG_DEFAULT_METRIC_DEFAULT
)
2743 vty_out (vty
, " default-metric %d%s",
2744 ripng
->default_metric
, VTY_NEWLINE
);
2746 ripng_redistribute_write (vty
, 1);
2748 /* RIP offset-list configuration. */
2749 config_write_ripng_offset_list (vty
);
2751 /* RIPng aggregate routes. */
2752 for (rp
= route_top (ripng
->aggregate
); rp
; rp
= route_next (rp
))
2753 if (rp
->info
!= NULL
)
2754 vty_out (vty
, " aggregate-address %s/%d%s",
2755 inet6_ntoa (rp
->p
.u
.prefix6
),
2760 /* ECMP configuration. */
2762 vty_out (vty
, " allow-ecmp%s", VTY_NEWLINE
);
2764 /* RIPng static routes. */
2765 for (rp
= route_top (ripng
->route
); rp
; rp
= route_next (rp
))
2766 if (rp
->info
!= NULL
)
2767 vty_out (vty
, " route %s/%d%s", inet6_ntoa (rp
->p
.u
.prefix6
),
2771 /* RIPng timers configuration. */
2772 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
||
2773 ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
||
2774 ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2776 vty_out (vty
, " timers basic %ld %ld %ld%s",
2778 ripng
->timeout_time
,
2779 ripng
->garbage_time
,
2783 if (ripng
->update_time
!= RIPNG_UPDATE_TIMER_DEFAULT
)
2784 vty_out (vty
, " update-timer %d%s", ripng
->update_time
,
2786 if (ripng
->timeout_time
!= RIPNG_TIMEOUT_TIMER_DEFAULT
)
2787 vty_out (vty
, " timeout-timer %d%s", ripng
->timeout_time
,
2789 if (ripng
->garbage_time
!= RIPNG_GARBAGE_TIMER_DEFAULT
)
2790 vty_out (vty
, " garbage-timer %d%s", ripng
->garbage_time
,
2794 write
+= config_write_distribute (vty
);
2796 write
+= config_write_if_rmap (vty
);
2803 /* RIPng node structure. */
2804 static struct cmd_node cmd_ripng_node
=
2807 "%s(config-router)# ",
2812 ripng_distribute_update (struct distribute
*dist
)
2814 struct interface
*ifp
;
2815 struct ripng_interface
*ri
;
2816 struct access_list
*alist
;
2817 struct prefix_list
*plist
;
2822 ifp
= if_lookup_by_name (dist
->ifname
);
2828 if (dist
->list
[DISTRIBUTE_IN
])
2830 alist
= access_list_lookup (AFI_IP6
, dist
->list
[DISTRIBUTE_IN
]);
2832 ri
->list
[RIPNG_FILTER_IN
] = alist
;
2834 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2837 ri
->list
[RIPNG_FILTER_IN
] = NULL
;
2839 if (dist
->list
[DISTRIBUTE_OUT
])
2841 alist
= access_list_lookup (AFI_IP6
, dist
->list
[DISTRIBUTE_OUT
]);
2843 ri
->list
[RIPNG_FILTER_OUT
] = alist
;
2845 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2848 ri
->list
[RIPNG_FILTER_OUT
] = NULL
;
2850 if (dist
->prefix
[DISTRIBUTE_IN
])
2852 plist
= prefix_list_lookup (AFI_IP6
, dist
->prefix
[DISTRIBUTE_IN
]);
2854 ri
->prefix
[RIPNG_FILTER_IN
] = plist
;
2856 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2859 ri
->prefix
[RIPNG_FILTER_IN
] = NULL
;
2861 if (dist
->prefix
[DISTRIBUTE_OUT
])
2863 plist
= prefix_list_lookup (AFI_IP6
, dist
->prefix
[DISTRIBUTE_OUT
]);
2865 ri
->prefix
[RIPNG_FILTER_OUT
] = plist
;
2867 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2870 ri
->prefix
[RIPNG_FILTER_OUT
] = NULL
;
2874 ripng_distribute_update_interface (struct interface
*ifp
)
2876 struct distribute
*dist
;
2878 dist
= distribute_lookup (ifp
->name
);
2880 ripng_distribute_update (dist
);
2883 /* Update all interface's distribute list. */
2885 ripng_distribute_update_all (struct prefix_list
*notused
)
2887 struct interface
*ifp
;
2888 struct listnode
*node
;
2890 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
2891 ripng_distribute_update_interface (ifp
);
2895 ripng_distribute_update_all_wrapper (struct access_list
*notused
)
2897 ripng_distribute_update_all(NULL
);
2900 /* delete all the added ripng routes. */
2905 struct route_node
*rp
;
2906 struct ripng_info
*rinfo
;
2907 struct ripng_aggregate
*aggregate
;
2908 struct list
*list
= NULL
;
2909 struct listnode
*listnode
= NULL
;
2912 /* Clear RIPng routes */
2913 for (rp
= route_top (ripng
->table
); rp
; rp
= route_next (rp
))
2915 if ((list
= rp
->info
) != NULL
)
2917 rinfo
= listgetdata (listhead (list
));
2918 if (ripng_route_rte (rinfo
))
2919 ripng_zebra_ipv6_delete (rp
);
2921 for (ALL_LIST_ELEMENTS_RO (list
, listnode
, rinfo
))
2923 RIPNG_TIMER_OFF (rinfo
->t_timeout
);
2924 RIPNG_TIMER_OFF (rinfo
->t_garbage_collect
);
2925 ripng_info_free (rinfo
);
2929 route_unlock_node (rp
);
2932 if ((aggregate
= rp
->aggregate
) != NULL
)
2934 ripng_aggregate_free (aggregate
);
2935 rp
->aggregate
= NULL
;
2936 route_unlock_node (rp
);
2940 /* Cancel the RIPng timers */
2941 RIPNG_TIMER_OFF (ripng
->t_update
);
2942 RIPNG_TIMER_OFF (ripng
->t_triggered_update
);
2943 RIPNG_TIMER_OFF (ripng
->t_triggered_interval
);
2945 /* Cancel the read thread */
2946 if (ripng
->t_read
) {
2947 thread_cancel (ripng
->t_read
);
2948 ripng
->t_read
= NULL
;
2951 /* Close the RIPng socket */
2952 if (ripng
->sock
>= 0) {
2957 /* Static RIPng route configuration. */
2958 for (rp
= route_top (ripng
->route
); rp
; rp
= route_next (rp
))
2961 route_unlock_node (rp
);
2964 /* RIPng aggregated prefixes */
2965 for (rp
= route_top (ripng
->aggregate
); rp
; rp
= route_next (rp
))
2968 route_unlock_node (rp
);
2971 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
2972 if (ripng
->route_map
[i
].name
)
2973 free (ripng
->route_map
[i
].name
);
2975 XFREE (MTYPE_ROUTE_TABLE
, ripng
->table
);
2976 XFREE (MTYPE_ROUTE_TABLE
, ripng
->route
);
2977 XFREE (MTYPE_ROUTE_TABLE
, ripng
->aggregate
);
2979 XFREE (MTYPE_RIPNG
, ripng
);
2983 ripng_clean_network();
2984 ripng_passive_interface_clean ();
2985 ripng_offset_clean ();
2986 ripng_interface_clean ();
2987 ripng_redistribute_clean ();
2990 /* Reset all values to the default settings. */
2994 /* Call ripd related reset functions. */
2995 ripng_debug_reset ();
2996 ripng_route_map_reset ();
2998 /* Call library reset functions. */
3000 access_list_reset ();
3001 prefix_list_reset ();
3003 distribute_list_reset ();
3005 ripng_interface_reset ();
3007 ripng_zclient_reset ();
3011 ripng_if_rmap_update (struct if_rmap
*if_rmap
)
3013 struct interface
*ifp
;
3014 struct ripng_interface
*ri
;
3015 struct route_map
*rmap
;
3017 ifp
= if_lookup_by_name (if_rmap
->ifname
);
3023 if (if_rmap
->routemap
[IF_RMAP_IN
])
3025 rmap
= route_map_lookup_by_name (if_rmap
->routemap
[IF_RMAP_IN
]);
3027 ri
->routemap
[IF_RMAP_IN
] = rmap
;
3029 ri
->routemap
[IF_RMAP_IN
] = NULL
;
3032 ri
->routemap
[RIPNG_FILTER_IN
] = NULL
;
3034 if (if_rmap
->routemap
[IF_RMAP_OUT
])
3036 rmap
= route_map_lookup_by_name (if_rmap
->routemap
[IF_RMAP_OUT
]);
3038 ri
->routemap
[IF_RMAP_OUT
] = rmap
;
3040 ri
->routemap
[IF_RMAP_OUT
] = NULL
;
3043 ri
->routemap
[RIPNG_FILTER_OUT
] = NULL
;
3047 ripng_if_rmap_update_interface (struct interface
*ifp
)
3049 struct if_rmap
*if_rmap
;
3051 if_rmap
= if_rmap_lookup (ifp
->name
);
3053 ripng_if_rmap_update (if_rmap
);
3057 ripng_routemap_update_redistribute (void)
3063 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
3065 if (ripng
->route_map
[i
].name
)
3066 ripng
->route_map
[i
].map
=
3067 route_map_lookup_by_name (ripng
->route_map
[i
].name
);
3073 ripng_routemap_update (const char *unused
)
3075 struct interface
*ifp
;
3076 struct listnode
*node
;
3078 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
3079 ripng_if_rmap_update_interface (ifp
);
3081 ripng_routemap_update_redistribute ();
3084 /* Initialize ripng structure and set commands. */
3089 srandom (time (NULL
));
3091 /* Install RIPNG_NODE. */
3092 install_node (&cmd_ripng_node
, ripng_config_write
);
3094 /* Install ripng commands. */
3095 install_element (VIEW_NODE
, &show_ipv6_ripng_cmd
);
3096 install_element (VIEW_NODE
, &show_ipv6_ripng_status_cmd
);
3098 install_element (ENABLE_NODE
, &show_ipv6_ripng_cmd
);
3099 install_element (ENABLE_NODE
, &show_ipv6_ripng_status_cmd
);
3101 install_element (CONFIG_NODE
, &router_ripng_cmd
);
3102 install_element (CONFIG_NODE
, &no_router_ripng_cmd
);
3104 install_default (RIPNG_NODE
);
3105 install_element (RIPNG_NODE
, &ripng_route_cmd
);
3106 install_element (RIPNG_NODE
, &no_ripng_route_cmd
);
3107 install_element (RIPNG_NODE
, &ripng_aggregate_address_cmd
);
3108 install_element (RIPNG_NODE
, &no_ripng_aggregate_address_cmd
);
3110 install_element (RIPNG_NODE
, &ripng_default_metric_cmd
);
3111 install_element (RIPNG_NODE
, &no_ripng_default_metric_cmd
);
3112 install_element (RIPNG_NODE
, &no_ripng_default_metric_val_cmd
);
3114 install_element (RIPNG_NODE
, &ripng_timers_cmd
);
3115 install_element (RIPNG_NODE
, &no_ripng_timers_cmd
);
3116 install_element (RIPNG_NODE
, &no_ripng_timers_val_cmd
);
3118 install_element (RIPNG_NODE
, &ripng_update_timer_cmd
);
3119 install_element (RIPNG_NODE
, &no_ripng_update_timer_cmd
);
3120 install_element (RIPNG_NODE
, &ripng_timeout_timer_cmd
);
3121 install_element (RIPNG_NODE
, &no_ripng_timeout_timer_cmd
);
3122 install_element (RIPNG_NODE
, &ripng_garbage_timer_cmd
);
3123 install_element (RIPNG_NODE
, &no_ripng_garbage_timer_cmd
);
3126 install_element (RIPNG_NODE
, &ripng_default_information_originate_cmd
);
3127 install_element (RIPNG_NODE
, &no_ripng_default_information_originate_cmd
);
3129 install_element (RIPNG_NODE
, &ripng_allow_ecmp_cmd
);
3130 install_element (RIPNG_NODE
, &no_ripng_allow_ecmp_cmd
);
3133 ripng_debug_init ();
3135 /* Access list install. */
3136 access_list_init ();
3137 access_list_add_hook (ripng_distribute_update_all_wrapper
);
3138 access_list_delete_hook (ripng_distribute_update_all_wrapper
);
3140 /* Prefix list initialize.*/
3141 prefix_list_init ();
3142 prefix_list_add_hook (ripng_distribute_update_all
);
3143 prefix_list_delete_hook (ripng_distribute_update_all
);
3145 /* Distribute list install. */
3146 distribute_list_init (RIPNG_NODE
);
3147 distribute_list_add_hook (ripng_distribute_update
);
3148 distribute_list_delete_hook (ripng_distribute_update
);
3150 /* Route-map for interface. */
3151 ripng_route_map_init ();
3152 ripng_offset_init ();
3154 route_map_add_hook (ripng_routemap_update
);
3155 route_map_delete_hook (ripng_routemap_update
);
3157 if_rmap_init (RIPNG_NODE
);
3158 if_rmap_hook_add (ripng_if_rmap_update
);
3159 if_rmap_hook_delete (ripng_if_rmap_update
);