]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripngd.c
ospf6d: fix heap uaf
[mirror_frr.git] / ripngd / ripngd.c
CommitLineData
718e3744 1/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
718e3744 24#include "prefix.h"
25#include "filter.h"
26#include "log.h"
27#include "thread.h"
28#include "memory.h"
29#include "if.h"
30#include "stream.h"
31#include "table.h"
32#include "command.h"
33#include "sockopt.h"
34#include "distribute.h"
35#include "plist.h"
36#include "routemap.h"
0750d21f 37#include "if_rmap.h"
27d47aa7 38#include "privs.h"
718e3744 39
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
a94434b6 43#include "ripngd/ripng_nexthop.h"
718e3744 44
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. */
48struct ripng *ripng = NULL;
49
50enum
51{
52 ripng_all_route,
53 ripng_changed_route,
718e3744 54};
55
27d47aa7 56extern struct zebra_privs_t ripngd_privs;
57
718e3744 58/* Prototypes. */
59void
a94434b6 60ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
718e3744 61
62int
63ripng_triggered_update (struct thread *);
64
65/* RIPng next hop specification. */
66struct ripng_nexthop
67{
68 enum ripng_nexthop_type
69 {
70 RIPNG_NEXTHOP_UNSPEC,
71 RIPNG_NEXTHOP_ADDRESS
72 } flag;
73 struct in6_addr address;
74};
718e3744 75
6ac29a51 76static int
a94434b6 77ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
718e3744 82/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
6b0655a2 98
718e3744 99/* Create ripng socket. */
6ac29a51 100static int
718e3744 101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
4525281a 110 zlog_err("Can't make ripng socket");
718e3744 111 return sock;
112 }
113
6228a3b8 114 setsockopt_so_recvbuf (sock, 8096);
718e3744 115 ret = setsockopt_ipv6_pktinfo (sock, 1);
116 if (ret < 0)
117 return ret;
6d0732c8
SH
118#ifdef IPTOS_PREC_INTERNETCONTROL
119 ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
120 if (ret < 0)
121 return ret;
122#endif
718e3744 123 ret = setsockopt_ipv6_multicast_hops (sock, 255);
124 if (ret < 0)
125 return ret;
126 ret = setsockopt_ipv6_multicast_loop (sock, 0);
127 if (ret < 0)
128 return ret;
129 ret = setsockopt_ipv6_hoplimit (sock, 1);
130 if (ret < 0)
131 return ret;
132
133 memset (&ripaddr, 0, sizeof (ripaddr));
134 ripaddr.sin6_family = AF_INET6;
135#ifdef SIN6_LEN
136 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
137#endif /* SIN6_LEN */
138 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
139
27d47aa7 140 if (ripngd_privs.change (ZPRIVS_RAISE))
141 zlog_err ("ripng_make_socket: could not raise privs");
142
718e3744 143 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
144 if (ret < 0)
27d47aa7 145 {
4525281a 146 zlog_err("Can't bind ripng socket: %s.", safe_strerror(errno));
27d47aa7 147 if (ripngd_privs.change (ZPRIVS_LOWER))
148 zlog_err ("ripng_make_socket: could not lower privs");
149 return ret;
150 }
151 if (ripngd_privs.change (ZPRIVS_LOWER))
152 zlog_err ("ripng_make_socket: could not lower privs");
718e3744 153 return sock;
154}
155
156/* Send RIPng packet. */
157int
158ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
159 struct interface *ifp)
160{
161 int ret;
162 struct msghdr msg;
163 struct iovec iov;
164 struct cmsghdr *cmsgptr;
165 char adata [256];
166 struct in6_pktinfo *pkt;
167 struct sockaddr_in6 addr;
168
a94434b6 169 if (IS_RIPNG_DEBUG_SEND) {
170 if (to)
3a2ce6a1 171 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
c6106812 172 zlog_debug (" send interface %s", ifp->name);
173 zlog_debug (" send packet size %d", bufsize);
a94434b6 174 }
718e3744 175
176 memset (&addr, 0, sizeof (struct sockaddr_in6));
177 addr.sin6_family = AF_INET6;
178#ifdef SIN6_LEN
179 addr.sin6_len = sizeof (struct sockaddr_in6);
180#endif /* SIN6_LEN */
181 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
182
183 /* When destination is specified. */
184 if (to != NULL)
185 {
186 addr.sin6_addr = to->sin6_addr;
187 addr.sin6_port = to->sin6_port;
188 }
189 else
190 {
191 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
192 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
193 }
194
195 msg.msg_name = (void *) &addr;
196 msg.msg_namelen = sizeof (struct sockaddr_in6);
197 msg.msg_iov = &iov;
198 msg.msg_iovlen = 1;
199 msg.msg_control = (void *) adata;
200 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
201
202 iov.iov_base = buf;
203 iov.iov_len = bufsize;
204
205 cmsgptr = (struct cmsghdr *)adata;
206 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
207 cmsgptr->cmsg_level = IPPROTO_IPV6;
208 cmsgptr->cmsg_type = IPV6_PKTINFO;
209
210 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
211 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
212 pkt->ipi6_ifindex = ifp->ifindex;
213
214 ret = sendmsg (ripng->sock, &msg, 0);
215
a94434b6 216 if (ret < 0) {
217 if (to)
218 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
3a2ce6a1 219 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
a94434b6 220 else
6099b3b5 221 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
a94434b6 222 }
718e3744 223
224 return ret;
225}
226
227/* Receive UDP RIPng packet from socket. */
6ac29a51 228static int
718e3744 229ripng_recv_packet (int sock, u_char *buf, int bufsize,
b892f1dd 230 struct sockaddr_in6 *from, ifindex_t *ifindex,
718e3744 231 int *hoplimit)
232{
233 int ret;
234 struct msghdr msg;
235 struct iovec iov;
236 struct cmsghdr *cmsgptr;
c5e0075f 237 struct in6_addr dst = { .s6_addr = { 0 } };
718e3744 238
37477535
DS
239 memset(&dst, 0, sizeof(struct in6_addr));
240
718e3744 241 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
242 point I can't determine size of cmsghdr */
243 char adata[1024];
244
245 /* Fill in message and iovec. */
246 msg.msg_name = (void *) from;
247 msg.msg_namelen = sizeof (struct sockaddr_in6);
248 msg.msg_iov = &iov;
249 msg.msg_iovlen = 1;
250 msg.msg_control = (void *) adata;
251 msg.msg_controllen = sizeof adata;
252 iov.iov_base = buf;
253 iov.iov_len = bufsize;
254
255 /* If recvmsg fail return minus value. */
256 ret = recvmsg (sock, &msg, 0);
257 if (ret < 0)
258 return ret;
259
b99760ab 260 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
718e3744 261 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
262 {
263 /* I want interface index which this packet comes from. */
264 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265 cmsgptr->cmsg_type == IPV6_PKTINFO)
266 {
267 struct in6_pktinfo *ptr;
268
269 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270 *ifindex = ptr->ipi6_ifindex;
271 dst = ptr->ipi6_addr;
272
273 if (*ifindex == 0)
274 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275 }
276
277 /* Incoming packet's multicast hop limit. */
278 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
5eb9d11b
SH
280 {
281 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282 *hoplimit = *phoplimit;
283 }
718e3744 284 }
285
286 /* Hoplimit check shold be done when destination address is
287 multicast address. */
288 if (! IN6_IS_ADDR_MULTICAST (&dst))
289 *hoplimit = -1;
290
291 return ret;
292}
293
294/* Dump rip packet */
295void
7a1d583c 296ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
718e3744 297{
298 caddr_t lim;
299 struct rte *rte;
7a1d583c 300 const char *command_str;
718e3744 301
302 /* Set command string. */
303 if (packet->command == RIPNG_REQUEST)
304 command_str = "request";
305 else if (packet->command == RIPNG_RESPONSE)
306 command_str = "response";
307 else
308 command_str = "unknown";
309
310 /* Dump packet header. */
c6106812 311 zlog_debug ("%s %s version %d packet size %d",
718e3744 312 sndrcv, command_str, packet->version, size);
313
314 /* Dump each routing table entry. */
315 rte = packet->rte;
316
317 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318 {
319 if (rte->metric == RIPNG_METRIC_NEXTHOP)
3a2ce6a1 320 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
718e3744 321 else
dc9ffce8 322 zlog_debug (" %s/%d metric %d tag %"ROUTE_TAG_PRI,
3a2ce6a1 323 inet6_ntoa (rte->addr), rte->prefixlen,
dc9ffce8 324 rte->metric, (route_tag_t)ntohs (rte->tag));
718e3744 325 }
326}
327
328/* RIPng next hop address RTE (Route Table Entry). */
6ac29a51 329static void
718e3744 330ripng_nexthop_rte (struct rte *rte,
331 struct sockaddr_in6 *from,
332 struct ripng_nexthop *nexthop)
333{
334 char buf[INET6_BUFSIZ];
335
336 /* Logging before checking RTE. */
337 if (IS_RIPNG_DEBUG_RECV)
dc9ffce8
CF
338 zlog_debug ("RIPng nexthop RTE address %s tag %"ROUTE_TAG_PRI" prefixlen %d",
339 inet6_ntoa (rte->addr), (route_tag_t)ntohs (rte->tag), rte->prefixlen);
718e3744 340
341 /* RFC2080 2.1.1 Next Hop:
342 The route tag and prefix length in the next hop RTE must be
343 set to zero on sending and ignored on receiption. */
344 if (ntohs (rte->tag) != 0)
dc9ffce8
CF
345 zlog_warn ("RIPng nexthop RTE with non zero tag value %"ROUTE_TAG_PRI" from %s",
346 (route_tag_t)ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
718e3744 347
348 if (rte->prefixlen != 0)
349 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
3a2ce6a1 350 rte->prefixlen, inet6_ntoa (from->sin6_addr));
718e3744 351
352 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353 next hop RTE indicates that the next hop address should be the
354 originator of the RIPng advertisement. An address specified as a
355 next hop must be a link-local address. */
356 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357 {
358 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359 memset (&nexthop->address, 0, sizeof (struct in6_addr));
360 return;
361 }
362
363 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364 {
365 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367 return;
368 }
369
370 /* The purpose of the next hop RTE is to eliminate packets being
371 routed through extra hops in the system. It is particularly useful
372 when RIPng is not being run on all of the routers on a network.
373 Note that next hop RTE is "advisory". That is, if the provided
374 information is ignored, a possibly sub-optimal, but absolutely
375 valid, route may be taken. If the received next hop address is not
376 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
377 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
3a2ce6a1 378 inet6_ntoa (rte->addr),
718e3744 379 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382 memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384 return;
385}
386
387/* If ifp has same link-local address then return 1. */
6ac29a51 388static int
718e3744 389ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390{
1eb8ef25 391 struct listnode *node;
718e3744 392 struct connected *connected;
393 struct prefix *p;
394
1eb8ef25 395 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396 {
397 p = connected->address;
718e3744 398
1eb8ef25 399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
718e3744 404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
6ac29a51 408static int
718e3744 409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
718e3744 423 /* Unlock route_node. */
c880b636
FL
424 listnode_delete (rp->info, rinfo);
425 if (list_isempty ((struct list *)rp->info))
426 {
427 list_free (rp->info);
428 rp->info = NULL;
429 route_unlock_node (rp);
430 }
718e3744 431
432 /* Free RIPng routing information. */
433 ripng_info_free (rinfo);
434
435 return 0;
436}
437
c880b636
FL
438static void ripng_timeout_update (struct ripng_info *rinfo);
439
440/* Add new route to the ECMP list.
fac76f9c
FL
441 * RETURN: the new entry added in the list, or NULL if it is not the first
442 * entry and ECMP is not allowed.
c880b636
FL
443 */
444struct ripng_info *
445ripng_ecmp_add (struct ripng_info *rinfo_new)
718e3744 446{
c880b636
FL
447 struct route_node *rp = rinfo_new->rp;
448 struct ripng_info *rinfo = NULL;
449 struct list *list = NULL;
718e3744 450
c880b636
FL
451 if (rp->info == NULL)
452 rp->info = list_new ();
453 list = (struct list *)rp->info;
718e3744 454
fac76f9c
FL
455 /* If ECMP is not allowed and some entry already exists in the list,
456 * do nothing. */
457 if (listcount (list) && !ripng->ecmp)
458 return NULL;
459
c880b636
FL
460 rinfo = ripng_info_new ();
461 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
462 listnode_add (list, rinfo);
463
464 if (ripng_route_rte (rinfo))
465 {
466 ripng_timeout_update (rinfo);
467 ripng_zebra_ipv6_add (rp);
468 }
469
470 ripng_aggregate_increment (rp, rinfo);
471
472 /* Set the route change flag on the first entry. */
473 rinfo = listgetdata (listhead (list));
474 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
475
476 /* Signal the output process to trigger an update. */
477 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
478
479 return rinfo;
480}
481
482/* Replace the ECMP list with the new route.
483 * RETURN: the new entry added in the list
484 */
485struct ripng_info *
486ripng_ecmp_replace (struct ripng_info *rinfo_new)
487{
488 struct route_node *rp = rinfo_new->rp;
489 struct list *list = (struct list *)rp->info;
490 struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
491 struct listnode *node = NULL, *nextnode = NULL;
492
493 if (list == NULL || listcount (list) == 0)
494 return ripng_ecmp_add (rinfo_new);
495
496 /* Get the first entry */
497 rinfo = listgetdata (listhead (list));
718e3744 498
c880b636
FL
499 /* Learnt route replaced by a local one. Delete it from zebra. */
500 if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
501 if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
502 ripng_zebra_ipv6_delete (rp);
718e3744 503
c880b636
FL
504 if (rinfo->metric != RIPNG_METRIC_INFINITY)
505 ripng_aggregate_decrement_list (rp, list);
a94434b6 506
c880b636
FL
507 /* Re-use the first entry, and delete the others. */
508 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
509 if (tmp_rinfo != rinfo)
510 {
511 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
512 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
513 list_delete_node (list, node);
514 ripng_info_free (tmp_rinfo);
515 }
718e3744 516
c880b636
FL
517 RIPNG_TIMER_OFF (rinfo->t_timeout);
518 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
519 memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
718e3744 520
c880b636
FL
521 if (ripng_route_rte (rinfo))
522 {
523 ripng_timeout_update (rinfo);
524 /* The ADD message implies an update. */
525 ripng_zebra_ipv6_add (rp);
526 }
527
528 ripng_aggregate_increment (rp, rinfo);
529
530 /* Set the route change flag. */
531 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
532
533 /* Signal the output process to trigger an update. */
718e3744 534 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
535
c880b636
FL
536 return rinfo;
537}
538
539/* Delete one route from the ECMP list.
540 * RETURN:
541 * null - the entry is freed, and other entries exist in the list
542 * the entry - the entry is the last one in the list; its metric is set
543 * to INFINITY, and the garbage collector is started for it
544 */
545struct ripng_info *
546ripng_ecmp_delete (struct ripng_info *rinfo)
547{
548 struct route_node *rp = rinfo->rp;
549 struct list *list = (struct list *)rp->info;
550
551 RIPNG_TIMER_OFF (rinfo->t_timeout);
552
553 if (rinfo->metric != RIPNG_METRIC_INFINITY)
554 ripng_aggregate_decrement (rp, rinfo);
555
556 if (listcount (list) > 1)
557 {
558 /* Some other ECMP entries still exist. Just delete this entry. */
559 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
560 listnode_delete (list, rinfo);
561 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
562 /* The ADD message implies the update. */
563 ripng_zebra_ipv6_add (rp);
564 ripng_info_free (rinfo);
565 rinfo = NULL;
566 }
567 else
568 {
569 assert (rinfo == listgetdata (listhead (list)));
570
571 /* This is the only entry left in the list. We must keep it in
572 * the list for garbage collection time, with INFINITY metric. */
573
574 rinfo->metric = RIPNG_METRIC_INFINITY;
575 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
576 ripng_garbage_collect, ripng->garbage_time);
577
578 if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
579 ripng_zebra_ipv6_delete (rp);
580 }
581
582 /* Set the route change flag on the first entry. */
583 rinfo = listgetdata (listhead (list));
584 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
585
586 /* Signal the output process to trigger an update. */
587 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
588
589 return rinfo;
590}
591
592/* Timeout RIPng routes. */
593static int
594ripng_timeout (struct thread *t)
595{
596 ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
718e3744 597 return 0;
598}
599
6ac29a51 600static void
718e3744 601ripng_timeout_update (struct ripng_info *rinfo)
602{
603 if (rinfo->metric != RIPNG_METRIC_INFINITY)
604 {
605 RIPNG_TIMER_OFF (rinfo->t_timeout);
606 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
607 }
608}
609
6ac29a51 610static int
644ed6c5
MB
611ripng_filter (int ripng_distribute, struct prefix_ipv6 *p,
612 struct ripng_interface *ri)
a94434b6 613{
614 struct distribute *dist;
615 struct access_list *alist;
616 struct prefix_list *plist;
644ed6c5 617 int distribute = ripng_distribute == RIPNG_FILTER_OUT ?
fb23cf4a 618 DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN;
644ed6c5 619 const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
a94434b6 620
621 /* Input distribute-list filtering. */
644ed6c5 622 if (ri->list[ripng_distribute])
a94434b6 623 {
644ed6c5 624 if (access_list_apply (ri->list[ripng_distribute],
a94434b6 625 (struct prefix *) p) == FILTER_DENY)
626 {
627 if (IS_RIPNG_DEBUG_PACKET)
644ed6c5
MB
628 zlog_debug ("%s/%d filtered by distribute %s",
629 inet6_ntoa (p->prefix), p->prefixlen, inout);
a94434b6 630 return -1;
631 }
632 }
644ed6c5 633 if (ri->prefix[ripng_distribute])
a94434b6 634{
644ed6c5 635 if (prefix_list_apply (ri->prefix[ripng_distribute],
a94434b6 636 (struct prefix *) p) == PREFIX_DENY)
637 {
638 if (IS_RIPNG_DEBUG_PACKET)
644ed6c5
MB
639 zlog_debug ("%s/%d filtered by prefix-list %s",
640 inet6_ntoa (p->prefix), p->prefixlen, inout);
a94434b6 641 return -1;
642 }
643 }
644
645 /* All interface filter check. */
646 dist = distribute_lookup (NULL);
647 if (dist)
648 {
644ed6c5 649 if (dist->list[distribute])
a94434b6 650 {
644ed6c5 651 alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
a94434b6 652
653 if (alist)
654 {
655 if (access_list_apply (alist,
656 (struct prefix *) p) == FILTER_DENY)
657 {
658 if (IS_RIPNG_DEBUG_PACKET)
644ed6c5
MB
659 zlog_debug ("%s/%d filtered by distribute %s",
660 inet6_ntoa (p->prefix), p->prefixlen, inout);
a94434b6 661 return -1;
662 }
663 }
664 }
644ed6c5 665 if (dist->prefix[distribute])
a94434b6 666 {
644ed6c5 667 plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
a94434b6 668
669 if (plist)
670 {
671 if (prefix_list_apply (plist,
672 (struct prefix *) p) == PREFIX_DENY)
673 {
674 if (IS_RIPNG_DEBUG_PACKET)
644ed6c5
MB
675 zlog_debug ("%s/%d filtered by prefix-list %s",
676 inet6_ntoa (p->prefix), p->prefixlen, inout);
a94434b6 677 return -1;
678 }
679 }
680 }
681 }
682 return 0;
683}
684
718e3744 685/* Process RIPng route according to RFC2080. */
6ac29a51 686static void
718e3744 687ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
688 struct ripng_nexthop *ripng_nexthop,
689 struct interface *ifp)
690{
a94434b6 691 int ret;
718e3744 692 struct prefix_ipv6 p;
693 struct route_node *rp;
c880b636 694 struct ripng_info *rinfo = NULL, newinfo;
718e3744 695 struct ripng_interface *ri;
696 struct in6_addr *nexthop;
718e3744 697 int same = 0;
c880b636
FL
698 struct list *list = NULL;
699 struct listnode *node = NULL;
718e3744 700
701 /* Make prefix structure. */
702 memset (&p, 0, sizeof (struct prefix_ipv6));
703 p.family = AF_INET6;
704 /* p.prefix = rte->addr; */
705 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
706 p.prefixlen = rte->prefixlen;
707
708 /* Make sure mask is applied. */
709 /* XXX We have to check the prefix is valid or not before call
710 apply_mask_ipv6. */
711 apply_mask_ipv6 (&p);
712
713 /* Apply input filters. */
714 ri = ifp->info;
715
644ed6c5 716 ret = ripng_filter (RIPNG_FILTER_IN, &p, ri);
a94434b6 717 if (ret < 0)
718 return;
718e3744 719
c880b636
FL
720 memset (&newinfo, 0, sizeof (newinfo));
721 newinfo.type = ZEBRA_ROUTE_RIPNG;
722 newinfo.sub_type = RIPNG_ROUTE_RTE;
723 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
724 newinfo.nexthop = ripng_nexthop->address;
725 else
726 newinfo.nexthop = from->sin6_addr;
727 newinfo.from = from->sin6_addr;
728 newinfo.ifindex = ifp->ifindex;
729 newinfo.metric = rte->metric;
730 newinfo.metric_out = rte->metric; /* XXX */
731 newinfo.tag = ntohs (rte->tag); /* XXX */
732
718e3744 733 /* Modify entry. */
734 if (ri->routemap[RIPNG_FILTER_IN])
735 {
736 int ret;
718e3744 737
738 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
739 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
740
741 if (ret == RMAP_DENYMATCH)
742 {
743 if (IS_RIPNG_DEBUG_PACKET)
c6106812 744 zlog_debug ("RIPng %s/%d is filtered by route-map in",
3a2ce6a1 745 inet6_ntoa (p.prefix), p.prefixlen);
718e3744 746 return;
747 }
748
a94434b6 749 /* Get back the object */
750 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
751 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
752 /* the nexthop get changed by the routemap */
753 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
754 ripng_nexthop->address = newinfo.nexthop;
755 else
756 ripng_nexthop->address = in6addr_any;
757 }
758 } else {
759 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
760 /* the nexthop get changed by the routemap */
761 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
762 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
763 ripng_nexthop->address = newinfo.nexthop;
764 }
765 }
766 }
767 rte->tag = htons(newinfo.tag_out); /* XXX */
768 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
718e3744 769 }
770
a94434b6 771 /* Once the entry has been validated, update the metric by
772 * adding the cost of the network on wich the message
773 * arrived. If the result is greater than infinity, use infinity
774 * (RFC2453 Sec. 3.9.2)
775 **/
776
777 /* Zebra ripngd can handle offset-list in. */
778 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
779
780 /* If offset-list does not modify the metric use interface's
781 * one. */
782 if (! ret)
7b3b98ae 783 rte->metric += ifp->metric ? ifp->metric : 1;
a94434b6 784
785 if (rte->metric > RIPNG_METRIC_INFINITY)
786 rte->metric = RIPNG_METRIC_INFINITY;
787
718e3744 788 /* Set nexthop pointer. */
789 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
790 nexthop = &ripng_nexthop->address;
791 else
792 nexthop = &from->sin6_addr;
793
794 /* Lookup RIPng routing table. */
795 rp = route_node_get (ripng->table, (struct prefix *) &p);
796
c880b636
FL
797 newinfo.rp = rp;
798 newinfo.nexthop = *nexthop;
799 newinfo.metric = rte->metric;
800 newinfo.tag = ntohs (rte->tag);
801
802 /* Check to see whether there is already RIPng route on the table. */
803 if ((list = rp->info) != NULL)
804 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
805 {
806 /* Need to compare with redistributed entry or local entry */
807 if (!ripng_route_rte (rinfo))
808 break;
809
810 if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
811 IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
812 break;
813
814 if (!listnextnode (node))
815 {
816 /* Not found in the list */
817
818 if (rte->metric > rinfo->metric)
819 {
820 /* New route has a greater metric. Discard it. */
821 route_unlock_node (rp);
822 return;
823 }
824
825 if (rte->metric < rinfo->metric)
826 /* New route has a smaller metric. Replace the ECMP list
827 * with the new one in below. */
828 break;
829
705e86f0
RW
830 /* Metrics are same. Unless ECMP is disabled, keep "rinfo" null and
831 * the new route is added in the ECMP list in below. */
832 if (! ripng->ecmp)
833 break;
c880b636
FL
834 }
835 }
836
a94434b6 837 if (rinfo)
838 {
839 /* Redistributed route check. */
840 if (rinfo->type != ZEBRA_ROUTE_RIPNG
841 && rinfo->metric != RIPNG_METRIC_INFINITY)
c880b636
FL
842 {
843 route_unlock_node (rp);
844 return;
845 }
a94434b6 846
847 /* Local static route. */
848 if (rinfo->type == ZEBRA_ROUTE_RIPNG
849 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
850 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
851 && rinfo->metric != RIPNG_METRIC_INFINITY)
c880b636
FL
852 {
853 route_unlock_node (rp);
854 return;
855 }
a94434b6 856 }
857
c880b636 858 if (!rinfo)
718e3744 859 {
860 /* Now, check to see whether there is already an explicit route
861 for the destination prefix. If there is no such route, add
862 this route to the routing table, unless the metric is
863 infinity (there is no point in adding a route which
864 unusable). */
865 if (rte->metric != RIPNG_METRIC_INFINITY)
c880b636 866 ripng_ecmp_add (&newinfo);
718e3744 867 }
868 else
869 {
718e3744 870 /* If there is an existing route, compare the next hop address
871 to the address of the router from which the datagram came.
872 If this datagram is from the same router as the existing
873 route, reinitialize the timeout. */
874 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
875 && (rinfo->ifindex == ifp->ifindex));
876
705e86f0
RW
877 /*
878 * RFC 2080 - Section 2.4.2:
879 * "If the new metric is the same as the old one, examine the timeout
880 * for the existing route. If it is at least halfway to the expiration
881 * point, switch to the new route. This heuristic is optional, but
882 * highly recommended".
883 */
884 if (!ripng->ecmp && !same &&
885 rinfo->metric == rte->metric && rinfo->t_timeout &&
886 (thread_timer_remain_second (rinfo->t_timeout) < (ripng->timeout_time / 2)))
887 {
888 ripng_ecmp_replace (&newinfo);
889 }
718e3744 890 /* Next, compare the metrics. If the datagram is from the same
891 router as the existing route, and the new metric is different
892 than the old one; or, if the new metric is lower than the old
893 one; do the following actions: */
705e86f0 894 else if ((same && rinfo->metric != rte->metric) ||
718e3744 895 rte->metric < rinfo->metric)
896 {
c880b636
FL
897 if (listcount (list) == 1)
898 {
899 if (newinfo.metric != RIPNG_METRIC_INFINITY)
900 ripng_ecmp_replace (&newinfo);
901 else
902 ripng_ecmp_delete (rinfo);
903 }
904 else
905 {
906 if (newinfo.metric < rinfo->metric)
907 ripng_ecmp_replace (&newinfo);
908 else /* newinfo.metric > rinfo->metric */
909 ripng_ecmp_delete (rinfo);
910 }
718e3744 911 }
c880b636
FL
912 else /* same & no change */
913 ripng_timeout_update (rinfo);
914
718e3744 915 /* Unlock tempolary lock of the route. */
916 route_unlock_node (rp);
917 }
918}
919
920/* Add redistributed route to RIPng table. */
921void
922ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
1796a585
CF
923 ifindex_t ifindex, struct in6_addr *nexthop,
924 route_tag_t tag)
718e3744 925{
926 struct route_node *rp;
c880b636
FL
927 struct ripng_info *rinfo = NULL, newinfo;
928 struct list *list = NULL;
718e3744 929
930 /* Redistribute route */
931 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
932 return;
933 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
934 return;
935
936 rp = route_node_get (ripng->table, (struct prefix *) p);
718e3744 937
c880b636
FL
938 memset (&newinfo, 0, sizeof (struct ripng_info));
939 newinfo.type = type;
940 newinfo.sub_type = sub_type;
941 newinfo.ifindex = ifindex;
942 newinfo.metric = 1;
1796a585
CF
943 if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
944 newinfo.tag = tag;
c880b636
FL
945 newinfo.rp = rp;
946 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
947 newinfo.nexthop = *nexthop;
948
949 if ((list = rp->info) != NULL && listcount (list) != 0)
718e3744 950 {
c880b636
FL
951 rinfo = listgetdata (listhead (list));
952
a94434b6 953 if (rinfo->type == ZEBRA_ROUTE_CONNECT
954 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
955 && rinfo->metric != RIPNG_METRIC_INFINITY) {
956 route_unlock_node (rp);
957 return;
958 }
959
960 /* Manually configured RIPng route check.
961 * They have the precedence on all the other entries.
962 **/
963 if (rinfo->type == ZEBRA_ROUTE_RIPNG
964 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
965 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
966 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
967 (sub_type != RIPNG_ROUTE_DEFAULT))) {
968 route_unlock_node (rp);
969 return;
970 }
971 }
a94434b6 972
4afc1b4d 973 ripng_ecmp_replace (&newinfo);
718e3744 974 route_unlock_node (rp);
975 }
c880b636 976 else
4afc1b4d 977 ripng_ecmp_add (&newinfo);
a94434b6 978
979 if (IS_RIPNG_DEBUG_EVENT) {
980 if (!nexthop)
c6106812 981 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
baaea325
DS
982 inet6_ntoa(p->prefix), p->prefixlen,
983 ifindex2ifname(ifindex, VRF_DEFAULT));
a94434b6 984 else
c6106812 985 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
baaea325
DS
986 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
987 ifindex2ifname(ifindex, VRF_DEFAULT));
a94434b6 988 }
989
990 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
718e3744 991}
992
993/* Delete redistributed route to RIPng table. */
994void
995ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
b892f1dd 996 ifindex_t ifindex)
718e3744 997{
998 struct route_node *rp;
999 struct ripng_info *rinfo;
1000
1001 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1002 return;
1003 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1004 return;
1005
1006 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1007
1008 if (rp)
1009 {
c880b636
FL
1010 struct list *list = rp->info;
1011
1012 if (list != NULL && listcount (list) != 0)
1013 {
1014 rinfo = listgetdata (listhead (list));
1015 if (rinfo != NULL
1016 && rinfo->type == type
1017 && rinfo->sub_type == sub_type
1018 && rinfo->ifindex == ifindex)
1019 {
1020 /* Perform poisoned reverse. */
1021 rinfo->metric = RIPNG_METRIC_INFINITY;
1022 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1023 ripng_garbage_collect, ripng->garbage_time);
1024 RIPNG_TIMER_OFF (rinfo->t_timeout);
1025
1026 /* Aggregate count decrement. */
1027 ripng_aggregate_decrement (rp, rinfo);
1028
1029 rinfo->flags |= RIPNG_RTF_CHANGED;
1030
1031 if (IS_RIPNG_DEBUG_EVENT)
1032 zlog_debug ("Poisone %s/%d on the interface %s with an "
1033 "infinity metric [delete]",
1034 inet6_ntoa (p->prefix), p->prefixlen,
baaea325 1035 ifindex2ifname (ifindex, VRF_DEFAULT));
c880b636
FL
1036
1037 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1038 }
1039 }
1040 route_unlock_node (rp);
718e3744 1041 }
1042}
1043
1044/* Withdraw redistributed route. */
1045void
1046ripng_redistribute_withdraw (int type)
1047{
1048 struct route_node *rp;
c880b636
FL
1049 struct ripng_info *rinfo = NULL;
1050 struct list *list = NULL;
718e3744 1051
a94434b6 1052 if (!ripng)
1053 return;
1054
718e3744 1055 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
c880b636 1056 if ((list = rp->info) != NULL)
718e3744 1057 {
c880b636 1058 rinfo = listgetdata (listhead (list));
a94434b6 1059 if ((rinfo->type == type)
1060 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
718e3744 1061 {
a94434b6 1062 /* Perform poisoned reverse. */
1063 rinfo->metric = RIPNG_METRIC_INFINITY;
1064 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1065 ripng_garbage_collect, ripng->garbage_time);
718e3744 1066 RIPNG_TIMER_OFF (rinfo->t_timeout);
718e3744 1067
a94434b6 1068 /* Aggregate count decrement. */
1069 ripng_aggregate_decrement (rp, rinfo);
1070
1071 rinfo->flags |= RIPNG_RTF_CHANGED;
1072
1073 if (IS_RIPNG_DEBUG_EVENT) {
1074 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
718e3744 1075
c6106812 1076 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
baaea325
DS
1077 inet6_ntoa(p->prefix), p->prefixlen,
1078 ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
a94434b6 1079 }
1080
1081 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
718e3744 1082 }
1083 }
1084}
1085
1086/* RIP routing information. */
6ac29a51 1087static void
718e3744 1088ripng_response_process (struct ripng_packet *packet, int size,
1089 struct sockaddr_in6 *from, struct interface *ifp,
1090 int hoplimit)
1091{
1092 caddr_t lim;
1093 struct rte *rte;
1094 struct ripng_nexthop nexthop;
1095
1096 /* RFC2080 2.4.2 Response Messages:
1097 The Response must be ignored if it is not from the RIPng port. */
1098 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1099 {
1100 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
3a2ce6a1 1101 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
a94434b6 1102 ripng_peer_bad_packet (from);
718e3744 1103 return;
1104 }
1105
1106 /* The datagram's IPv6 source address should be checked to see
1107 whether the datagram is from a valid neighbor; the source of the
1108 datagram must be a link-local address. */
1109 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1110 {
1111 zlog_warn ("RIPng packet comes from non link local address %s",
3a2ce6a1 1112 inet6_ntoa (from->sin6_addr));
a94434b6 1113 ripng_peer_bad_packet (from);
718e3744 1114 return;
1115 }
1116
1117 /* It is also worth checking to see whether the response is from one
1118 of the router's own addresses. Interfaces on broadcast networks
1119 may receive copies of their own multicasts immediately. If a
1120 router processes its own output as new input, confusion is likely,
1121 and such datagrams must be ignored. */
1122 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1123 {
1124 zlog_warn ("RIPng packet comes from my own link local address %s",
3a2ce6a1 1125 inet6_ntoa (from->sin6_addr));
a94434b6 1126 ripng_peer_bad_packet (from);
718e3744 1127 return;
1128 }
1129
1130 /* As an additional check, periodic advertisements must have their
1131 hop counts set to 255, and inbound, multicast packets sent from the
1132 RIPng port (i.e. periodic advertisement or triggered update
1133 packets) must be examined to ensure that the hop count is 255. */
1134 if (hoplimit >= 0 && hoplimit != 255)
1135 {
1136 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
3a2ce6a1 1137 hoplimit, inet6_ntoa (from->sin6_addr));
a94434b6 1138 ripng_peer_bad_packet (from);
718e3744 1139 return;
1140 }
1141
a94434b6 1142 /* Update RIPng peer. */
1143 ripng_peer_update (from, packet->version);
1144
718e3744 1145 /* Reset nexthop. */
1146 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1147 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1148
1149 /* Set RTE pointer. */
1150 rte = packet->rte;
1151
1152 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1153 {
1154 /* First of all, we have to check this RTE is next hop RTE or
1155 not. Next hop RTE is completely different with normal RTE so
1156 we need special treatment. */
1157 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1158 {
1159 ripng_nexthop_rte (rte, from, &nexthop);
1160 continue;
1161 }
1162
1163 /* RTE information validation. */
1164
1165 /* - is the destination prefix valid (e.g., not a multicast
1166 prefix and not a link-local address) A link-local address
1167 should never be present in an RTE. */
1168 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1169 {
1170 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
3a2ce6a1 1171 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
a94434b6 1172 ripng_peer_bad_route (from);
718e3744 1173 continue;
1174 }
1175 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1176 {
1177 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
3a2ce6a1 1178 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
a94434b6 1179 ripng_peer_bad_route (from);
718e3744 1180 continue;
1181 }
1182 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1183 {
1184 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
3a2ce6a1 1185 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
a94434b6 1186 ripng_peer_bad_route (from);
718e3744 1187 continue;
1188 }
1189
1190 /* - is the prefix length valid (i.e., between 0 and 128,
1191 inclusive) */
1192 if (rte->prefixlen > 128)
1193 {
1194 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
3a2ce6a1 1195 inet6_ntoa (rte->addr), rte->prefixlen,
1196 inet6_ntoa (from->sin6_addr), ifp->name);
a94434b6 1197 ripng_peer_bad_route (from);
718e3744 1198 continue;
1199 }
1200
1201 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1202 if (! (rte->metric >= 1 && rte->metric <= 16))
1203 {
1204 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
3a2ce6a1 1205 inet6_ntoa (from->sin6_addr), ifp->name);
a94434b6 1206 ripng_peer_bad_route (from);
718e3744 1207 continue;
1208 }
1209
a94434b6 1210 /* Vincent: XXX Should we compute the direclty reachable nexthop
1211 * for our RIPng network ?
1212 **/
718e3744 1213
1214 /* Routing table updates. */
1215 ripng_route_process (rte, from, &nexthop, ifp);
1216 }
1217}
1218
1219/* Response to request message. */
6ac29a51 1220static void
718e3744 1221ripng_request_process (struct ripng_packet *packet,int size,
1222 struct sockaddr_in6 *from, struct interface *ifp)
1223{
1224 caddr_t lim;
1225 struct rte *rte;
1226 struct prefix_ipv6 p;
1227 struct route_node *rp;
1228 struct ripng_info *rinfo;
1229 struct ripng_interface *ri;
1230
a94434b6 1231 /* Does not reponse to the requests on the loopback interfaces */
1232 if (if_is_loopback (ifp))
1233 return;
1234
718e3744 1235 /* Check RIPng process is enabled on this interface. */
1236 ri = ifp->info;
1237 if (! ri->running)
1238 return;
1239
1240 /* When passive interface is specified, suppress responses */
1241 if (ri->passive)
1242 return;
1243
a94434b6 1244 /* RIPng peer update. */
1245 ripng_peer_update (from, packet->version);
1246
718e3744 1247 lim = ((caddr_t) packet) + size;
1248 rte = packet->rte;
1249
1250 /* The Request is processed entry by entry. If there are no
1251 entries, no response is given. */
1252 if (lim == (caddr_t) rte)
1253 return;
1254
1255 /* There is one special case. If there is exactly one entry in the
1256 request, and it has a destination prefix of zero, a prefix length
1257 of zero, and a metric of infinity (i.e., 16), then this is a
1258 request to send the entire routing table. In that case, a call
1259 is made to the output process to send the routing table to the
1260 requesting address/port. */
1261 if (lim == ((caddr_t) (rte + 1)) &&
1262 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1263 rte->prefixlen == 0 &&
1264 rte->metric == RIPNG_METRIC_INFINITY)
1265 {
1266 /* All route with split horizon */
a94434b6 1267 ripng_output_process (ifp, from, ripng_all_route);
718e3744 1268 }
1269 else
1270 {
1271 /* Except for this special case, processing is quite simple.
1272 Examine the list of RTEs in the Request one by one. For each
1273 entry, look up the destination in the router's routing
1274 database and, if there is a route, put that route's metric in
1275 the metric field of the RTE. If there is no explicit route
1276 to the specified destination, put infinity in the metric
1277 field. Once all the entries have been filled in, change the
1278 command from Request to Response and send the datagram back
1279 to the requestor. */
1280 memset (&p, 0, sizeof (struct prefix_ipv6));
1281 p.family = AF_INET6;
1282
1283 for (; ((caddr_t) rte) < lim; rte++)
1284 {
1285 p.prefix = rte->addr;
1286 p.prefixlen = rte->prefixlen;
1287 apply_mask_ipv6 (&p);
1288
1289 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1290
1291 if (rp)
1292 {
c880b636 1293 rinfo = listgetdata (listhead ((struct list *)rp->info));
718e3744 1294 rte->metric = rinfo->metric;
1295 route_unlock_node (rp);
1296 }
1297 else
1298 rte->metric = RIPNG_METRIC_INFINITY;
1299 }
1300 packet->command = RIPNG_RESPONSE;
1301
1302 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1303 }
1304}
1305
1306/* First entry point of reading RIPng packet. */
6ac29a51 1307static int
718e3744 1308ripng_read (struct thread *thread)
1309{
1310 int len;
1311 int sock;
1312 struct sockaddr_in6 from;
1313 struct ripng_packet *packet;
b892f1dd 1314 ifindex_t ifindex = 0;
718e3744 1315 struct interface *ifp;
1316 int hoplimit = -1;
1317
1318 /* Check ripng is active and alive. */
1319 assert (ripng != NULL);
1320 assert (ripng->sock >= 0);
1321
1322 /* Fetch thread data and set read pointer to empty for event
1323 managing. `sock' sould be same as ripng->sock. */
1324 sock = THREAD_FD (thread);
1325 ripng->t_read = NULL;
1326
1327 /* Add myself to the next event. */
1328 ripng_event (RIPNG_READ, sock);
1329
1330 /* Read RIPng packet. */
1331 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1332 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1333 &hoplimit);
1334 if (len < 0)
1335 {
6099b3b5 1336 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
718e3744 1337 return len;
1338 }
1339
1340 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1341 (4)) must be multiple size of one RTE size (20). */
1342 if (((len - 4) % 20) != 0)
1343 {
1344 zlog_warn ("RIPng invalid packet size %d from %s", len,
3a2ce6a1 1345 inet6_ntoa (from.sin6_addr));
a94434b6 1346 ripng_peer_bad_packet (&from);
718e3744 1347 return 0;
1348 }
1349
1350 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
7e2b7603 1351 ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
718e3744 1352
1353 /* RIPng packet received. */
1354 if (IS_RIPNG_DEBUG_EVENT)
c6106812 1355 zlog_debug ("RIPng packet received from %s port %d on %s",
3a2ce6a1 1356 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
718e3744 1357 ifp ? ifp->name : "unknown");
1358
1359 /* Logging before packet checking. */
1360 if (IS_RIPNG_DEBUG_RECV)
1361 ripng_packet_dump (packet, len, "RECV");
1362
1363 /* Packet comes from unknown interface. */
1364 if (ifp == NULL)
1365 {
1366 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1367 return 0;
1368 }
1369
1370 /* Packet version mismatch checking. */
1371 if (packet->version != ripng->version)
1372 {
1373 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1374 packet->version, ripng->version);
a94434b6 1375 ripng_peer_bad_packet (&from);
718e3744 1376 return 0;
1377 }
1378
1379 /* Process RIPng packet. */
1380 switch (packet->command)
1381 {
1382 case RIPNG_REQUEST:
1383 ripng_request_process (packet, len, &from, ifp);
1384 break;
1385 case RIPNG_RESPONSE:
1386 ripng_response_process (packet, len, &from, ifp, hoplimit);
1387 break;
1388 default:
1389 zlog_warn ("Invalid RIPng command %d", packet->command);
a94434b6 1390 ripng_peer_bad_packet (&from);
718e3744 1391 break;
1392 }
1393 return 0;
1394}
1395
1396/* Walk down the RIPng routing table then clear changed flag. */
6ac29a51
PJ
1397static void
1398ripng_clear_changed_flag (void)
718e3744 1399{
1400 struct route_node *rp;
c880b636
FL
1401 struct ripng_info *rinfo = NULL;
1402 struct list *list = NULL;
1403 struct listnode *listnode = NULL;
718e3744 1404
1405 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
c880b636
FL
1406 if ((list = rp->info) != NULL)
1407 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1408 {
1409 UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1410 /* This flag can be set only on the first entry. */
1411 break;
1412 }
718e3744 1413}
1414
1415/* Regular update of RIPng route. Send all routing formation to RIPng
1416 enabled interface. */
6ac29a51 1417static int
718e3744 1418ripng_update (struct thread *t)
1419{
52dc7ee6 1420 struct listnode *node;
718e3744 1421 struct interface *ifp;
1422 struct ripng_interface *ri;
1423
1424 /* Clear update timer thread. */
1425 ripng->t_update = NULL;
1426
1427 /* Logging update event. */
1428 if (IS_RIPNG_DEBUG_EVENT)
c6106812 1429 zlog_debug ("RIPng update timer expired!");
718e3744 1430
1431 /* Supply routes to each interface. */
b2d7c082 1432 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
718e3744 1433 {
718e3744 1434 ri = ifp->info;
1435
1436 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1437 continue;
1438
1439 if (! ri->running)
1440 continue;
1441
1442 /* When passive interface is specified, suppress announce to the
1443 interface. */
1444 if (ri->passive)
1445 continue;
1446
1447#if RIPNG_ADVANCED
1448 if (ri->ri_send == RIPNG_SEND_OFF)
1449 {
1450 if (IS_RIPNG_DEBUG_EVENT)
4525281a 1451 zlog_debug ("[Event] RIPng send to if %d is suppressed by config",
718e3744 1452 ifp->ifindex);
1453 continue;
1454 }
1455#endif /* RIPNG_ADVANCED */
1456
a94434b6 1457 ripng_output_process (ifp, NULL, ripng_all_route);
718e3744 1458 }
1459
1460 /* Triggered updates may be suppressed if a regular update is due by
1461 the time the triggered update would be sent. */
1462 if (ripng->t_triggered_interval)
1463 {
1464 thread_cancel (ripng->t_triggered_interval);
1465 ripng->t_triggered_interval = NULL;
1466 }
1467 ripng->trigger = 0;
1468
1469 /* Reset flush event. */
1470 ripng_event (RIPNG_UPDATE_EVENT, 0);
1471
1472 return 0;
1473}
1474
1475/* Triggered update interval timer. */
6ac29a51 1476static int
718e3744 1477ripng_triggered_interval (struct thread *t)
1478{
1479 ripng->t_triggered_interval = NULL;
1480
1481 if (ripng->trigger)
1482 {
1483 ripng->trigger = 0;
1484 ripng_triggered_update (t);
1485 }
1486 return 0;
1487}
1488
1489/* Execute triggered update. */
1490int
1491ripng_triggered_update (struct thread *t)
1492{
52dc7ee6 1493 struct listnode *node;
718e3744 1494 struct interface *ifp;
1495 struct ripng_interface *ri;
1496 int interval;
1497
1498 ripng->t_triggered_update = NULL;
1499
1500 /* Cancel interval timer. */
1501 if (ripng->t_triggered_interval)
1502 {
1503 thread_cancel (ripng->t_triggered_interval);
1504 ripng->t_triggered_interval = NULL;
1505 }
1506 ripng->trigger = 0;
1507
1508 /* Logging triggered update. */
1509 if (IS_RIPNG_DEBUG_EVENT)
c6106812 1510 zlog_debug ("RIPng triggered update!");
718e3744 1511
1512 /* Split Horizon processing is done when generating triggered
1513 updates as well as normal updates (see section 2.6). */
b2d7c082 1514 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
718e3744 1515 {
718e3744 1516 ri = ifp->info;
1517
1518 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1519 continue;
1520
1521 if (! ri->running)
1522 continue;
1523
1524 /* When passive interface is specified, suppress announce to the
1525 interface. */
1526 if (ri->passive)
1527 continue;
1528
a94434b6 1529 ripng_output_process (ifp, NULL, ripng_changed_route);
718e3744 1530 }
1531
1532 /* Once all of the triggered updates have been generated, the route
1533 change flags should be cleared. */
1534 ripng_clear_changed_flag ();
1535
1536 /* After a triggered update is sent, a timer should be set for a
1537 random interval between 1 and 5 seconds. If other changes that
1538 would trigger updates occur before the timer expires, a single
1539 update is triggered when the timer expires. */
1540 interval = (random () % 5) + 1;
1541
1542 ripng->t_triggered_interval =
1543 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1544
1545 return 0;
1546}
1547
1548/* Write routing table entry to the stream and return next index of
1549 the routing table entry in the stream. */
1550int
1551ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
a94434b6 1552 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
718e3744 1553{
1554 /* RIPng packet header. */
1555 if (num == 0)
1556 {
1557 stream_putc (s, RIPNG_RESPONSE);
1558 stream_putc (s, RIPNG_V1);
1559 stream_putw (s, 0);
1560 }
1561
1562 /* Write routing table entry. */
a94434b6 1563 if (!nexthop)
c9e52be3 1564 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
a94434b6 1565 else
c9e52be3 1566 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
718e3744 1567 stream_putw (s, tag);
a94434b6 1568 if (p)
1569 stream_putc (s, p->prefixlen);
1570 else
1571 stream_putc (s, 0);
718e3744 1572 stream_putc (s, metric);
1573
1574 return ++num;
1575}
1576
1577/* Send RESPONSE message to specified destination. */
1578void
1579ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
a94434b6 1580 int route_type)
718e3744 1581{
1582 int ret;
718e3744 1583 struct route_node *rp;
1584 struct ripng_info *rinfo;
1585 struct ripng_interface *ri;
1586 struct ripng_aggregate *aggregate;
1587 struct prefix_ipv6 *p;
a94434b6 1588 struct list * ripng_rte_list;
c880b636
FL
1589 struct list *list = NULL;
1590 struct listnode *listnode = NULL;
718e3744 1591
a94434b6 1592 if (IS_RIPNG_DEBUG_EVENT) {
1593 if (to)
c6106812 1594 zlog_debug ("RIPng update routes to neighbor %s",
3a2ce6a1 1595 inet6_ntoa(to->sin6_addr));
a94434b6 1596 else
c6106812 1597 zlog_debug ("RIPng update routes on interface %s", ifp->name);
a94434b6 1598 }
718e3744 1599
718e3744 1600 /* Get RIPng interface. */
1601 ri = ifp->info;
a94434b6 1602
1603 ripng_rte_list = ripng_rte_new();
1604
718e3744 1605 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1606 {
c880b636
FL
1607 if ((list = rp->info) != NULL &&
1608 (rinfo = listgetdata (listhead (list))) != NULL &&
1609 rinfo->suppress == 0)
718e3744 1610 {
a94434b6 1611 /* If no route-map are applied, the RTE will be these following
1612 * informations.
1613 */
718e3744 1614 p = (struct prefix_ipv6 *) &rp->p;
a94434b6 1615 rinfo->metric_out = rinfo->metric;
1616 rinfo->tag_out = rinfo->tag;
1617 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1618 /* In order to avoid some local loops,
1619 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1620 * otherwise set it to 0. The nexthop should not be propagated
1621 * beyond the local broadcast/multicast area in order
1622 * to avoid an IGP multi-level recursive look-up.
1623 */
1624 if (rinfo->ifindex == ifp->ifindex)
1625 rinfo->nexthop_out = rinfo->nexthop;
1626
1627 /* Apply output filters. */
644ed6c5 1628 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
a94434b6 1629 if (ret < 0)
1630 continue;
718e3744 1631
1632 /* Changed route only output. */
1633 if (route_type == ripng_changed_route &&
1634 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1635 continue;
1636
1637 /* Split horizon. */
a94434b6 1638 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1639 {
1640 /* We perform split horizon for RIPng routes. */
c880b636
FL
1641 int suppress = 0;
1642 struct ripng_info *tmp_rinfo = NULL;
1643
1644 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1645 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1646 tmp_rinfo->ifindex == ifp->ifindex)
1647 {
1648 suppress = 1;
1649 break;
1650 }
1651 if (suppress)
a94434b6 1652 continue;
1653 }
718e3744 1654
1655 /* Preparation for route-map. */
a94434b6 1656 rinfo->metric_set = 0;
1657 /* nexthop_out,
1658 * metric_out
1659 * and tag_out are already initialized.
1660 */
718e3744 1661
a94434b6 1662 /* Interface route-map */
718e3744 1663 if (ri->routemap[RIPNG_FILTER_OUT])
1664 {
1665 int ret;
718e3744 1666
1667 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1668 (struct prefix *) p, RMAP_RIPNG,
a94434b6 1669 rinfo);
718e3744 1670
1671 if (ret == RMAP_DENYMATCH)
1672 {
1673 if (IS_RIPNG_DEBUG_PACKET)
c6106812 1674 zlog_debug ("RIPng %s/%d is filtered by route-map out",
3a2ce6a1 1675 inet6_ntoa (p->prefix), p->prefixlen);
a94434b6 1676 continue;
718e3744 1677 }
1678
718e3744 1679 }
1680
a94434b6 1681 /* Redistribute route-map. */
1682 if (ripng->route_map[rinfo->type].name)
718e3744 1683 {
a94434b6 1684 int ret;
1685
1686 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1687 (struct prefix *) p, RMAP_RIPNG,
bb3a023e 1688 rinfo);
a94434b6 1689
1690 if (ret == RMAP_DENYMATCH)
718e3744 1691 {
a94434b6 1692 if (IS_RIPNG_DEBUG_PACKET)
c6106812 1693 zlog_debug ("RIPng %s/%d is filtered by route-map",
3a2ce6a1 1694 inet6_ntoa (p->prefix), p->prefixlen);
a94434b6 1695 continue;
718e3744 1696 }
a94434b6 1697 }
718e3744 1698
a94434b6 1699 /* When the route-map does not set metric. */
1700 if (! rinfo->metric_set)
1701 {
1702 /* If the redistribute metric is set. */
1703 if (ripng->route_map[rinfo->type].metric_config
1704 && rinfo->metric != RIPNG_METRIC_INFINITY)
1705 {
1706 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1707 }
1708 else
718e3744 1709 {
a94434b6 1710 /* If the route is not connected or localy generated
1711 one, use default-metric value */
1712 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1713 && rinfo->type != ZEBRA_ROUTE_CONNECT
718e3744 1714 && rinfo->metric != RIPNG_METRIC_INFINITY)
a94434b6 1715 rinfo->metric_out = ripng->default_metric;
718e3744 1716 }
1717 }
1718
a94434b6 1719 /* Apply offset-list */
1720 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1721 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
1722
1723 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1724 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1725
1726 /* Perform split-horizon with poisoned reverse
1727 * for RIPng routes.
1728 **/
1729 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
c880b636
FL
1730 struct ripng_info *tmp_rinfo = NULL;
1731
1732 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1733 if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1734 tmp_rinfo->ifindex == ifp->ifindex)
1735 rinfo->metric_out = RIPNG_METRIC_INFINITY;
a94434b6 1736 }
1737
1738 /* Add RTE to the list */
1739 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
718e3744 1740 }
a94434b6 1741
1742 /* Process the aggregated RTE entry */
718e3744 1743 if ((aggregate = rp->aggregate) != NULL &&
1744 aggregate->count > 0 &&
1745 aggregate->suppress == 0)
1746 {
a94434b6 1747 /* If no route-map are applied, the RTE will be these following
1748 * informations.
1749 */
718e3744 1750 p = (struct prefix_ipv6 *) &rp->p;
a94434b6 1751 aggregate->metric_set = 0;
1752 aggregate->metric_out = aggregate->metric;
1753 aggregate->tag_out = aggregate->tag;
1754 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
718e3744 1755
1756 /* Apply output filters.*/
644ed6c5 1757 ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
a94434b6 1758 if (ret < 0)
1759 continue;
718e3744 1760
a94434b6 1761 /* Interface route-map */
718e3744 1762 if (ri->routemap[RIPNG_FILTER_OUT])
1763 {
1764 int ret;
1765 struct ripng_info newinfo;
1766
a94434b6 1767 /* let's cast the aggregate structure to ripng_info */
718e3744 1768 memset (&newinfo, 0, sizeof (struct ripng_info));
a94434b6 1769 /* the nexthop is :: */
1770 newinfo.metric = aggregate->metric;
1771 newinfo.metric_out = aggregate->metric_out;
1772 newinfo.tag = aggregate->tag;
1773 newinfo.tag_out = aggregate->tag_out;
718e3744 1774
1775 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1776 (struct prefix *) p, RMAP_RIPNG,
1777 &newinfo);
1778
1779 if (ret == RMAP_DENYMATCH)
1780 {
1781 if (IS_RIPNG_DEBUG_PACKET)
c6106812 1782 zlog_debug ("RIPng %s/%d is filtered by route-map out",
3a2ce6a1 1783 inet6_ntoa (p->prefix), p->prefixlen);
a94434b6 1784 continue;
718e3744 1785 }
1786
a94434b6 1787 aggregate->metric_out = newinfo.metric_out;
1788 aggregate->tag_out = newinfo.tag_out;
1789 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1790 aggregate->nexthop_out = newinfo.nexthop_out;
718e3744 1791 }
1792
a94434b6 1793 /* There is no redistribute routemap for the aggregated RTE */
1794
718e3744 1795 /* Changed route only output. */
a94434b6 1796 /* XXX, vincent, in order to increase time convergence,
1797 * it should be announced if a child has changed.
1798 */
718e3744 1799 if (route_type == ripng_changed_route)
1800 continue;
1801
a94434b6 1802 /* Apply offset-list */
1803 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1804 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
1805
1806 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1807 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1808
1809 /* Add RTE to the list */
1810 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
718e3744 1811 }
1812
1813 }
718e3744 1814
a94434b6 1815 /* Flush the list */
1816 ripng_rte_send(ripng_rte_list, ifp, to);
1817 ripng_rte_free(ripng_rte_list);
718e3744 1818}
1819
1820/* Create new RIPng instance and set it to global variable. */
6ac29a51
PJ
1821static int
1822ripng_create (void)
718e3744 1823{
1824 /* ripng should be NULL. */
1825 assert (ripng == NULL);
1826
1827 /* Allocaste RIPng instance. */
393deb9b 1828 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
718e3744 1829
1830 /* Default version and timer values. */
1831 ripng->version = RIPNG_V1;
1832 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1833 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1834 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1835 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1836
1837 /* Make buffer. */
1838 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1839 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1840
1841 /* Initialize RIPng routig table. */
1842 ripng->table = route_table_init ();
1843 ripng->route = route_table_init ();
1844 ripng->aggregate = route_table_init ();
1845
1846 /* Make socket. */
1847 ripng->sock = ripng_make_socket ();
1848 if (ripng->sock < 0)
1849 return ripng->sock;
1850
1851 /* Threads. */
1852 ripng_event (RIPNG_READ, ripng->sock);
1853 ripng_event (RIPNG_UPDATE_EVENT, 1);
1854
1855 return 0;
1856}
1857
a94434b6 1858/* Send RIPng request to the interface. */
718e3744 1859int
1860ripng_request (struct interface *ifp)
1861{
1862 struct rte *rte;
1863 struct ripng_packet ripng_packet;
1864
a94434b6 1865 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1866 if (if_is_loopback(ifp))
1867 return 0;
1868
1869 /* If interface is down, don't send RIP packet. */
1870 if (! if_is_up (ifp))
1871 return 0;
1872
718e3744 1873 if (IS_RIPNG_DEBUG_EVENT)
c6106812 1874 zlog_debug ("RIPng send request to %s", ifp->name);
718e3744 1875
1876 memset (&ripng_packet, 0, sizeof (ripng_packet));
1877 ripng_packet.command = RIPNG_REQUEST;
1878 ripng_packet.version = RIPNG_V1;
1879 rte = ripng_packet.rte;
1880 rte->metric = RIPNG_METRIC_INFINITY;
1881
1882 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1883 NULL, ifp);
1884}
1885
6b0655a2 1886
6ac29a51 1887static int
718e3744 1888ripng_update_jitter (int time)
1889{
b06fd125 1890 return ((random () % (time + 1)) - (time / 2));
718e3744 1891}
1892
1893void
1894ripng_event (enum ripng_event event, int sock)
1895{
718e3744 1896 int jitter = 0;
1897
1898 switch (event)
1899 {
1900 case RIPNG_READ:
1901 if (!ripng->t_read)
1902 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1903 break;
1904 case RIPNG_UPDATE_EVENT:
1905 if (ripng->t_update)
1906 {
1907 thread_cancel (ripng->t_update);
1908 ripng->t_update = NULL;
1909 }
1910 /* Update timer jitter. */
1911 jitter = ripng_update_jitter (ripng->update_time);
1912
1913 ripng->t_update =
1914 thread_add_timer (master, ripng_update, NULL,
1915 sock ? 2 : ripng->update_time + jitter);
1916 break;
1917 case RIPNG_TRIGGERED_UPDATE:
1918 if (ripng->t_triggered_interval)
1919 ripng->trigger = 1;
1920 else if (! ripng->t_triggered_update)
1921 ripng->t_triggered_update =
1922 thread_add_event (master, ripng_triggered_update, NULL, 0);
1923 break;
1924 default:
1925 break;
1926 }
1927}
6b0655a2 1928
718e3744 1929
718e3744 1930/* Print out routes update time. */
1931static void
1932ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1933{
718e3744 1934 time_t clock;
1935 struct tm *tm;
1936#define TIME_BUF 25
1937 char timebuf [TIME_BUF];
1938 struct thread *thread;
1939
718e3744 1940 if ((thread = rinfo->t_timeout) != NULL)
1941 {
6dfa827b 1942 clock = thread_timer_remain_second (thread);
718e3744 1943 tm = gmtime (&clock);
1944 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1945 vty_out (vty, "%5s", timebuf);
1946 }
1947 else if ((thread = rinfo->t_garbage_collect) != NULL)
1948 {
6dfa827b 1949 clock = thread_timer_remain_second (thread);
718e3744 1950 tm = gmtime (&clock);
1951 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1952 vty_out (vty, "%5s", timebuf);
1953 }
1954}
1955
6ac29a51 1956static char *
a94434b6 1957ripng_route_subtype_print (struct ripng_info *rinfo)
1958{
1959 static char str[3];
1960 memset(str, 0, 3);
1961
1962 if (rinfo->suppress)
1963 strcat(str, "S");
1964
1965 switch (rinfo->sub_type)
1966 {
1967 case RIPNG_ROUTE_RTE:
1968 strcat(str, "n");
1969 break;
1970 case RIPNG_ROUTE_STATIC:
1971 strcat(str, "s");
1972 break;
1973 case RIPNG_ROUTE_DEFAULT:
1974 strcat(str, "d");
1975 break;
1976 case RIPNG_ROUTE_REDISTRIBUTE:
1977 strcat(str, "r");
1978 break;
1979 case RIPNG_ROUTE_INTERFACE:
1980 strcat(str, "i");
1981 break;
1982 default:
1983 strcat(str, "?");
1984 break;
1985 }
1986
1987 return str;
1988}
1989
718e3744 1990DEFUN (show_ipv6_ripng,
1991 show_ipv6_ripng_cmd,
1992 "show ipv6 ripng",
1993 SHOW_STR
8d0f15fd 1994 IPV6_STR
718e3744 1995 "Show RIPng routes\n")
1996{
1997 struct route_node *rp;
1998 struct ripng_info *rinfo;
1999 struct ripng_aggregate *aggregate;
2000 struct prefix_ipv6 *p;
c880b636
FL
2001 struct list *list = NULL;
2002 struct listnode *listnode = NULL;
718e3744 2003 int len;
2004
a94434b6 2005 if (! ripng)
2006 return CMD_SUCCESS;
2007
718e3744 2008 /* Header of display. */
a94434b6 2009 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2010 "Sub-codes:%s"
2011 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2012 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2013 " Network Next Hop Via Metric Tag Time%s",
2014 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
718e3744 2015 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2016
2017 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2018 {
2019 if ((aggregate = rp->aggregate) != NULL)
2020 {
2021 p = (struct prefix_ipv6 *) &rp->p;
2022
2023#ifdef DEBUG
4afc1b4d 2024 vty_out (vty, "R(a) %d/%d %s/%d ",
718e3744 2025 aggregate->count, aggregate->suppress,
3a2ce6a1 2026 inet6_ntoa (p->prefix), p->prefixlen);
718e3744 2027#else
4afc1b4d 2028 vty_out (vty, "R(a) %s/%d ",
3a2ce6a1 2029 inet6_ntoa (p->prefix), p->prefixlen);
718e3744 2030#endif /* DEBUG */
a94434b6 2031 vty_out (vty, "%s", VTY_NEWLINE);
2032 vty_out (vty, "%*s", 18, " ");
718e3744 2033
a94434b6 2034 vty_out (vty, "%*s", 28, " ");
dc9ffce8
CF
2035 vty_out (vty, "self %2d %3"ROUTE_TAG_PRI"%s", aggregate->metric,
2036 (route_tag_t)aggregate->tag,
718e3744 2037 VTY_NEWLINE);
2038 }
2039
c880b636
FL
2040 if ((list = rp->info) != NULL)
2041 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
718e3744 2042 {
2043 p = (struct prefix_ipv6 *) &rp->p;
2044
2045#ifdef DEBUG
4afc1b4d 2046 vty_out (vty, "%c(%s) 0/%d %s/%d ",
f52d13cb 2047 zebra_route_char(rinfo->type),
a94434b6 2048 ripng_route_subtype_print(rinfo),
718e3744 2049 rinfo->suppress,
3a2ce6a1 2050 inet6_ntoa (p->prefix), p->prefixlen);
718e3744 2051#else
4afc1b4d 2052 vty_out (vty, "%c(%s) %s/%d ",
f52d13cb 2053 zebra_route_char(rinfo->type),
a94434b6 2054 ripng_route_subtype_print(rinfo),
3a2ce6a1 2055 inet6_ntoa (p->prefix), p->prefixlen);
718e3744 2056#endif /* DEBUG */
a94434b6 2057 vty_out (vty, "%s", VTY_NEWLINE);
2058 vty_out (vty, "%*s", 18, " ");
3a2ce6a1 2059 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
a94434b6 2060
2061 len = 28 - len;
718e3744 2062 if (len > 0)
a94434b6 2063 len = vty_out (vty, "%*s", len, " ");
718e3744 2064
a94434b6 2065 /* from */
2066 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2067 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2068 {
baaea325 2069 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
a94434b6 2070 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2071 {
2072 len = vty_out (vty, "kill");
2073 } else
2074 len = vty_out (vty, "self");
718e3744 2075
a94434b6 2076 len = 9 - len;
718e3744 2077 if (len > 0)
2078 vty_out (vty, "%*s", len, " ");
2079
dc9ffce8
CF
2080 vty_out (vty, " %2d %3"ROUTE_TAG_PRI" ",
2081 rinfo->metric, (route_tag_t)rinfo->tag);
718e3744 2082
a94434b6 2083 /* time */
2084 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2085 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2086 {
2087 /* RTE from remote RIP routers */
718e3744 2088 ripng_vty_out_uptime (vty, rinfo);
a94434b6 2089 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2090 {
2091 /* poisonous reversed routes (gc) */
2092 ripng_vty_out_uptime (vty, rinfo);
2093 }
718e3744 2094
2095 vty_out (vty, "%s", VTY_NEWLINE);
2096 }
2097 }
2098
2099 return CMD_SUCCESS;
2100}
2101
a94434b6 2102DEFUN (show_ipv6_ripng_status,
2103 show_ipv6_ripng_status_cmd,
2104 "show ipv6 ripng status",
2105 SHOW_STR
8d0f15fd 2106 IPV6_STR
a94434b6 2107 "Show RIPng routes\n"
2108 "IPv6 routing protocol process parameters and statistics\n")
2109{
52dc7ee6 2110 struct listnode *node;
1eb8ef25 2111 struct interface *ifp;
a94434b6 2112
2113 if (! ripng)
2114 return CMD_SUCCESS;
2115
2116 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2117 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2118 ripng->update_time);
6dfa827b
VJ
2119 vty_out (vty, " next due in %lu seconds%s",
2120 thread_timer_remain_second (ripng->t_update),
a94434b6 2121 VTY_NEWLINE);
2122 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2123 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2124 VTY_NEWLINE);
2125
2126 /* Filtering status show. */
2127 config_show_distribute (vty);
2128
2129 /* Default metric information. */
2130 vty_out (vty, " Default redistribution metric is %d%s",
2131 ripng->default_metric, VTY_NEWLINE);
2132
2133 /* Redistribute information. */
2134 vty_out (vty, " Redistributing:");
2135 ripng_redistribute_write (vty, 0);
2136 vty_out (vty, "%s", VTY_NEWLINE);
2137
2138 vty_out (vty, " Default version control: send version %d,", ripng->version);
2139 vty_out (vty, " receive version %d %s", ripng->version,
2140 VTY_NEWLINE);
2141
2142 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2143
b2d7c082 2144 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
a94434b6 2145 {
2146 struct ripng_interface *ri;
1eb8ef25 2147
a94434b6 2148 ri = ifp->info;
2149
2150 if (ri->enable_network || ri->enable_interface)
2151 {
2152
2153 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2154 ripng->version,
2155 ripng->version,
2156 VTY_NEWLINE);
2157 }
2158 }
2159
2160 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2161 ripng_network_write (vty, 0);
2162
2163 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2164 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2165 ripng_peer_display (vty);
2166
2167 return CMD_SUCCESS;
2168}
2169
d7f966ab
RW
2170DEFUN (clear_ipv6_rip,
2171 clear_ipv6_rip_cmd,
2172 "clear ipv6 ripng",
2173 CLEAR_STR
2174 IPV6_STR
2175 "Clear IPv6 RIP database")
2176{
2177 struct route_node *rp;
2178 struct ripng_info *rinfo;
2179 struct list *list;
2180 struct listnode *listnode;
2181
2182 /* Clear received RIPng routes */
2183 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2184 {
2185 list = rp->info;
2186 if (list == NULL)
2187 continue;
2188
2189 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2190 {
2191 if (! ripng_route_rte (rinfo))
2192 continue;
2193
2194 if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
2195 ripng_zebra_ipv6_delete (rp);
2196 break;
2197 }
2198
2199 if (rinfo)
2200 {
2201 RIPNG_TIMER_OFF (rinfo->t_timeout);
2202 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2203 listnode_delete (list, rinfo);
2204 ripng_info_free (rinfo);
2205 }
2206
2207 if (list_isempty (list))
2208 {
2209 list_free (list);
2210 rp->info = NULL;
2211 route_unlock_node (rp);
2212 }
2213 }
2214
2215 return CMD_SUCCESS;
2216}
2217
505e5056 2218DEFUN_NOSH (router_ripng,
718e3744 2219 router_ripng_cmd,
2220 "router ripng",
2221 "Enable a routing process\n"
2222 "Make RIPng instance command\n")
2223{
2224 int ret;
2225
2226 vty->node = RIPNG_NODE;
2227
2228 if (!ripng)
2229 {
2230 ret = ripng_create ();
2231
2232 /* Notice to user we couldn't create RIPng. */
2233 if (ret < 0)
2234 {
2235 zlog_warn ("can't create RIPng");
2236 return CMD_WARNING;
2237 }
2238 }
2239
2240 return CMD_SUCCESS;
2241}
2242
a94434b6 2243DEFUN (no_router_ripng,
2244 no_router_ripng_cmd,
2245 "no router ripng",
2246 NO_STR
2247 "Enable a routing process\n"
2248 "Make RIPng instance command\n")
2249{
2250 if(ripng)
2251 ripng_clean();
2252 return CMD_SUCCESS;
2253}
2254
718e3744 2255DEFUN (ripng_route,
2256 ripng_route_cmd,
2257 "route IPV6ADDR",
2258 "Static route setup\n"
2259 "Set static RIPng route announcement\n")
2260{
ab34a28a 2261 int idx_ipv6addr = 1;
718e3744 2262 int ret;
2263 struct prefix_ipv6 p;
2264 struct route_node *rp;
2265
ab34a28a 2266 ret = str2prefix_ipv6 (argv[idx_ipv6addr]->arg, (struct prefix_ipv6 *)&p);
718e3744 2267 if (ret <= 0)
2268 {
2269 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2270 return CMD_WARNING;
2271 }
2272 apply_mask_ipv6 (&p);
2273
2274 rp = route_node_get (ripng->route, (struct prefix *) &p);
2275 if (rp->info)
2276 {
2277 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2278 route_unlock_node (rp);
2279 return CMD_WARNING;
2280 }
2281 rp->info = (void *)1;
2282
1796a585 2283 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL, 0);
718e3744 2284
2285 return CMD_SUCCESS;
2286}
2287
2288DEFUN (no_ripng_route,
2289 no_ripng_route_cmd,
2290 "no route IPV6ADDR",
2291 NO_STR
2292 "Static route setup\n"
2293 "Delete static RIPng route announcement\n")
2294{
ab34a28a 2295 int idx_ipv6addr = 2;
718e3744 2296 int ret;
2297 struct prefix_ipv6 p;
2298 struct route_node *rp;
2299
ab34a28a 2300 ret = str2prefix_ipv6 (argv[idx_ipv6addr]->arg, (struct prefix_ipv6 *)&p);
718e3744 2301 if (ret <= 0)
2302 {
2303 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2304 return CMD_WARNING;
2305 }
2306 apply_mask_ipv6 (&p);
2307
2308 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2309 if (! rp)
2310 {
2311 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2312 return CMD_WARNING;
2313 }
2314
2315 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2316 route_unlock_node (rp);
2317
2318 rp->info = NULL;
2319 route_unlock_node (rp);
2320
2321 return CMD_SUCCESS;
2322}
2323
2324DEFUN (ripng_aggregate_address,
2325 ripng_aggregate_address_cmd,
2326 "aggregate-address X:X::X:X/M",
2327 "Set aggregate RIPng route announcement\n"
2328 "Aggregate network\n")
2329{
ab34a28a 2330 int idx_ipv6_prefixlen = 1;
718e3744 2331 int ret;
2332 struct prefix p;
2333 struct route_node *node;
2334
ab34a28a 2335 ret = str2prefix_ipv6 (argv[idx_ipv6_prefixlen]->arg, (struct prefix_ipv6 *)&p);
718e3744 2336 if (ret <= 0)
2337 {
2338 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2339 return CMD_WARNING;
2340 }
2341
2342 /* Check aggregate alredy exist or not. */
2343 node = route_node_get (ripng->aggregate, &p);
2344 if (node->info)
2345 {
2346 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2347 route_unlock_node (node);
2348 return CMD_WARNING;
2349 }
2350 node->info = (void *)1;
2351
2352 ripng_aggregate_add (&p);
2353
2354 return CMD_SUCCESS;
2355}
2356
2357DEFUN (no_ripng_aggregate_address,
2358 no_ripng_aggregate_address_cmd,
2359 "no aggregate-address X:X::X:X/M",
2360 NO_STR
2361 "Delete aggregate RIPng route announcement\n"
2362 "Aggregate network")
2363{
ab34a28a 2364 int idx_ipv6_prefixlen = 2;
718e3744 2365 int ret;
2366 struct prefix p;
2367 struct route_node *rn;
2368
ab34a28a 2369 ret = str2prefix_ipv6 (argv[idx_ipv6_prefixlen]->arg, (struct prefix_ipv6 *) &p);
718e3744 2370 if (ret <= 0)
2371 {
2372 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2373 return CMD_WARNING;
2374 }
2375
2376 rn = route_node_lookup (ripng->aggregate, &p);
2377 if (! rn)
2378 {
2379 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2380 return CMD_WARNING;
2381 }
2382 route_unlock_node (rn);
2383 rn->info = NULL;
2384 route_unlock_node (rn);
2385
2386 ripng_aggregate_delete (&p);
2387
2388 return CMD_SUCCESS;
2389}
2390
2391DEFUN (ripng_default_metric,
2392 ripng_default_metric_cmd,
6147e2c6 2393 "default-metric (1-16)",
718e3744 2394 "Set a metric of redistribute routes\n"
2395 "Default metric\n")
2396{
ab34a28a 2397 int idx_number = 1;
718e3744 2398 if (ripng)
2399 {
ab34a28a 2400 ripng->default_metric = atoi (argv[idx_number]->arg);
718e3744 2401 }
2402 return CMD_SUCCESS;
2403}
2404
2405DEFUN (no_ripng_default_metric,
2406 no_ripng_default_metric_cmd,
55c727dd 2407 "no default-metric [(1-16)]",
718e3744 2408 NO_STR
2409 "Set a metric of redistribute routes\n"
2410 "Default metric\n")
2411{
2412 if (ripng)
2413 {
2414 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2415 }
2416 return CMD_SUCCESS;
2417}
2418
718e3744 2419
2420#if 0
2421/* RIPng update timer setup. */
2422DEFUN (ripng_update_timer,
2423 ripng_update_timer_cmd,
2424 "update-timer SECOND",
2425 "Set RIPng update timer in seconds\n"
2426 "Seconds\n")
2427{
2428 unsigned long update;
2429 char *endptr = NULL;
2430
2431 update = strtoul (argv[0], &endptr, 10);
2432 if (update == ULONG_MAX || *endptr != '\0')
2433 {
2434 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2435 return CMD_WARNING;
2436 }
2437
2438 ripng->update_time = update;
2439
2440 ripng_event (RIPNG_UPDATE_EVENT, 0);
2441 return CMD_SUCCESS;
2442}
2443
2444DEFUN (no_ripng_update_timer,
2445 no_ripng_update_timer_cmd,
2446 "no update-timer SECOND",
2447 NO_STR
2448 "Unset RIPng update timer in seconds\n"
2449 "Seconds\n")
2450{
2451 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2452 ripng_event (RIPNG_UPDATE_EVENT, 0);
2453 return CMD_SUCCESS;
2454}
2455
2456/* RIPng timeout timer setup. */
2457DEFUN (ripng_timeout_timer,
2458 ripng_timeout_timer_cmd,
2459 "timeout-timer SECOND",
2460 "Set RIPng timeout timer in seconds\n"
2461 "Seconds\n")
2462{
2463 unsigned long timeout;
2464 char *endptr = NULL;
2465
2466 timeout = strtoul (argv[0], &endptr, 10);
2467 if (timeout == ULONG_MAX || *endptr != '\0')
2468 {
2469 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2470 return CMD_WARNING;
2471 }
2472
2473 ripng->timeout_time = timeout;
2474
2475 return CMD_SUCCESS;
2476}
2477
2478DEFUN (no_ripng_timeout_timer,
2479 no_ripng_timeout_timer_cmd,
2480 "no timeout-timer SECOND",
2481 NO_STR
2482 "Unset RIPng timeout timer in seconds\n"
2483 "Seconds\n")
2484{
2485 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2486 return CMD_SUCCESS;
2487}
2488
2489/* RIPng garbage timer setup. */
2490DEFUN (ripng_garbage_timer,
2491 ripng_garbage_timer_cmd,
2492 "garbage-timer SECOND",
2493 "Set RIPng garbage timer in seconds\n"
2494 "Seconds\n")
2495{
2496 unsigned long garbage;
2497 char *endptr = NULL;
2498
2499 garbage = strtoul (argv[0], &endptr, 10);
2500 if (garbage == ULONG_MAX || *endptr != '\0')
2501 {
2502 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2503 return CMD_WARNING;
2504 }
2505
2506 ripng->garbage_time = garbage;
2507
2508 return CMD_SUCCESS;
2509}
2510
2511DEFUN (no_ripng_garbage_timer,
2512 no_ripng_garbage_timer_cmd,
2513 "no garbage-timer SECOND",
2514 NO_STR
2515 "Unset RIPng garbage timer in seconds\n"
2516 "Seconds\n")
2517{
2518 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2519 return CMD_SUCCESS;
2520}
2521#endif /* 0 */
2522
2523DEFUN (ripng_timers,
2524 ripng_timers_cmd,
6147e2c6 2525 "timers basic (0-65535) (0-65535) (0-65535)",
718e3744 2526 "RIPng timers setup\n"
2527 "Basic timer\n"
2528 "Routing table update timer value in second. Default is 30.\n"
2529 "Routing information timeout timer. Default is 180.\n"
2530 "Garbage collection timer. Default is 120.\n")
2531{
ab34a28a
DW
2532 int idx_number = 2;
2533 int idx_number_2 = 3;
2534 int idx_number_3 = 4;
718e3744 2535 unsigned long update;
2536 unsigned long timeout;
2537 unsigned long garbage;
718e3744 2538
ab34a28a
DW
2539 VTY_GET_INTEGER_RANGE("update timer", update, argv[idx_number]->arg, 0, 65535);
2540 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[idx_number_2]->arg, 0, 65535);
2541 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[idx_number_3]->arg, 0, 65535);
718e3744 2542
2543 /* Set each timer value. */
2544 ripng->update_time = update;
2545 ripng->timeout_time = timeout;
2546 ripng->garbage_time = garbage;
2547
2548 /* Reset update timer thread. */
2549 ripng_event (RIPNG_UPDATE_EVENT, 0);
2550
2551 return CMD_SUCCESS;
2552}
2553
2554DEFUN (no_ripng_timers,
2555 no_ripng_timers_cmd,
d04c479d 2556 "no timers basic [(0-65535) (0-65535) (0-65535)]",
718e3744 2557 NO_STR
2558 "RIPng timers setup\n"
c8952fc1
QY
2559 "Basic timer\n"
2560 "Routing table update timer value in second. Default is 30.\n"
2561 "Routing information timeout timer. Default is 180.\n"
2562 "Garbage collection timer. Default is 120.\n")
718e3744 2563{
2564 /* Set each timer value to the default. */
2565 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2566 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2567 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2568
2569 /* Reset update timer thread. */
2570 ripng_event (RIPNG_UPDATE_EVENT, 0);
2571
2572 return CMD_SUCCESS;
2573}
2574
d7d73ffc 2575#if 0
dd4f9f99
DW
2576DEFUN (show_ipv6_protocols,
2577 show_ipv6_protocols_cmd,
718e3744 2578 "show ipv6 protocols",
2579 SHOW_STR
8d0f15fd 2580 IPV6_STR
718e3744 2581 "Routing protocol information")
2582{
2583 if (! ripng)
2584 return CMD_SUCCESS;
2585
2586 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2587
2588 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2589 ripng->update_time, 0,
2590 VTY_NEWLINE);
2591
2592 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2593 ripng->timeout_time,
2594 ripng->garbage_time,
2595 VTY_NEWLINE);
2596
2597 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2598 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2599
2600 return CMD_SUCCESS;
2601}
d7d73ffc 2602#endif
718e3744 2603
2604/* Please be carefull to use this command. */
a2c62831 2605DEFUN (ripng_default_information_originate,
2606 ripng_default_information_originate_cmd,
718e3744 2607 "default-information originate",
2608 "Default route information\n"
2609 "Distribute default route\n")
2610{
2611 struct prefix_ipv6 p;
2612
a94434b6 2613 if (! ripng ->default_information) {
2614 ripng->default_information = 1;
718e3744 2615
a94434b6 2616 str2prefix_ipv6 ("::/0", &p);
1796a585 2617 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
a94434b6 2618 }
718e3744 2619
2620 return CMD_SUCCESS;
2621}
2622
a2c62831 2623DEFUN (no_ripng_default_information_originate,
2624 no_ripng_default_information_originate_cmd,
718e3744 2625 "no default-information originate",
2626 NO_STR
2627 "Default route information\n"
2628 "Distribute default route\n")
2629{
2630 struct prefix_ipv6 p;
2631
a94434b6 2632 if (ripng->default_information) {
2633 ripng->default_information = 0;
718e3744 2634
a94434b6 2635 str2prefix_ipv6 ("::/0", &p);
2636 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2637 }
718e3744 2638
2639 return CMD_SUCCESS;
2640}
2641
fac76f9c
FL
2642/* Update ECMP routes to zebra when ECMP is disabled. */
2643static void
2644ripng_ecmp_disable (void)
2645{
2646 struct route_node *rp;
2647 struct ripng_info *rinfo, *tmp_rinfo;
2648 struct list *list;
2649 struct listnode *node, *nextnode;
2650
2651 if (!ripng)
2652 return;
2653
2654 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2655 if ((list = rp->info) != NULL && listcount (list) > 1)
2656 {
2657 rinfo = listgetdata (listhead (list));
2658 if (!ripng_route_rte (rinfo))
2659 continue;
2660
2661 /* Drop all other entries, except the first one. */
2662 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
2663 if (tmp_rinfo != rinfo)
2664 {
2665 RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
2666 RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
2667 list_delete_node (list, node);
2668 ripng_info_free (tmp_rinfo);
2669 }
2670
2671 /* Update zebra. */
2672 ripng_zebra_ipv6_add (rp);
2673
2674 /* Set the route change flag. */
2675 SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
2676
2677 /* Signal the output process to trigger an update. */
2678 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
2679 }
2680}
2681
2682DEFUN (ripng_allow_ecmp,
2683 ripng_allow_ecmp_cmd,
2684 "allow-ecmp",
2685 "Allow Equal Cost MultiPath\n")
2686{
2687 if (ripng->ecmp)
2688 {
2689 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2690 return CMD_WARNING;
2691 }
2692
2693 ripng->ecmp = 1;
2694 zlog_info ("ECMP is enabled.");
2695 return CMD_SUCCESS;
2696}
2697
2698DEFUN (no_ripng_allow_ecmp,
2699 no_ripng_allow_ecmp_cmd,
2700 "no allow-ecmp",
2701 NO_STR
2702 "Allow Equal Cost MultiPath\n")
2703{
2704 if (!ripng->ecmp)
2705 {
2706 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2707 return CMD_WARNING;
2708 }
2709
2710 ripng->ecmp = 0;
2711 zlog_info ("ECMP is disabled.");
2712 ripng_ecmp_disable ();
2713 return CMD_SUCCESS;
2714}
2715
718e3744 2716/* RIPng configuration write function. */
6ac29a51 2717static int
718e3744 2718ripng_config_write (struct vty *vty)
2719{
a94434b6 2720 int ripng_network_write (struct vty *, int);
2721 void ripng_redistribute_write (struct vty *, int);
718e3744 2722 int write = 0;
2723 struct route_node *rp;
2724
2725 if (ripng)
2726 {
2727
2728 /* RIPng router. */
2729 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2730
2731 if (ripng->default_information)
2732 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2733
a94434b6 2734 ripng_network_write (vty, 1);
718e3744 2735
2736 /* RIPng default metric configuration */
2737 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2738 vty_out (vty, " default-metric %d%s",
2739 ripng->default_metric, VTY_NEWLINE);
2740
a94434b6 2741 ripng_redistribute_write (vty, 1);
2742
2743 /* RIP offset-list configuration. */
2744 config_write_ripng_offset_list (vty);
718e3744 2745
2746 /* RIPng aggregate routes. */
2747 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2748 if (rp->info != NULL)
2749 vty_out (vty, " aggregate-address %s/%d%s",
3a2ce6a1 2750 inet6_ntoa (rp->p.u.prefix6),
718e3744 2751 rp->p.prefixlen,
2752
2753 VTY_NEWLINE);
2754
fac76f9c
FL
2755 /* ECMP configuration. */
2756 if (ripng->ecmp)
2757 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
2758
718e3744 2759 /* RIPng static routes. */
2760 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2761 if (rp->info != NULL)
3a2ce6a1 2762 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
718e3744 2763 rp->p.prefixlen,
2764 VTY_NEWLINE);
2765
2766 /* RIPng timers configuration. */
2767 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2768 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2769 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2770 {
2771 vty_out (vty, " timers basic %ld %ld %ld%s",
2772 ripng->update_time,
2773 ripng->timeout_time,
2774 ripng->garbage_time,
2775 VTY_NEWLINE);
2776 }
2777#if 0
2778 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2779 vty_out (vty, " update-timer %d%s", ripng->update_time,
2780 VTY_NEWLINE);
2781 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2782 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2783 VTY_NEWLINE);
2784 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2785 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2786 VTY_NEWLINE);
2787#endif /* 0 */
2788
2789 write += config_write_distribute (vty);
2790
2791 write += config_write_if_rmap (vty);
2792
2793 write++;
2794 }
2795 return write;
2796}
2797
2798/* RIPng node structure. */
7fc626de 2799static struct cmd_node cmd_ripng_node =
718e3744 2800{
2801 RIPNG_NODE,
2802 "%s(config-router)# ",
2803 1,
2804};
2805
6ac29a51 2806static void
718e3744 2807ripng_distribute_update (struct distribute *dist)
2808{
2809 struct interface *ifp;
2810 struct ripng_interface *ri;
2811 struct access_list *alist;
2812 struct prefix_list *plist;
2813
2814 if (! dist->ifname)
2815 return;
2816
1306c09a 2817 ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
718e3744 2818 if (ifp == NULL)
2819 return;
2820
2821 ri = ifp->info;
2822
fb23cf4a 2823 if (dist->list[DISTRIBUTE_V6_IN])
718e3744 2824 {
fb23cf4a 2825 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_IN]);
718e3744 2826 if (alist)
2827 ri->list[RIPNG_FILTER_IN] = alist;
2828 else
2829 ri->list[RIPNG_FILTER_IN] = NULL;
2830 }
2831 else
2832 ri->list[RIPNG_FILTER_IN] = NULL;
2833
fb23cf4a 2834 if (dist->list[DISTRIBUTE_V6_OUT])
718e3744 2835 {
fb23cf4a 2836 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_OUT]);
718e3744 2837 if (alist)
2838 ri->list[RIPNG_FILTER_OUT] = alist;
2839 else
2840 ri->list[RIPNG_FILTER_OUT] = NULL;
2841 }
2842 else
2843 ri->list[RIPNG_FILTER_OUT] = NULL;
2844
fb23cf4a 2845 if (dist->prefix[DISTRIBUTE_V6_IN])
718e3744 2846 {
fb23cf4a 2847 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_IN]);
718e3744 2848 if (plist)
2849 ri->prefix[RIPNG_FILTER_IN] = plist;
2850 else
2851 ri->prefix[RIPNG_FILTER_IN] = NULL;
2852 }
2853 else
2854 ri->prefix[RIPNG_FILTER_IN] = NULL;
2855
fb23cf4a 2856 if (dist->prefix[DISTRIBUTE_V6_OUT])
718e3744 2857 {
fb23cf4a 2858 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_OUT]);
718e3744 2859 if (plist)
2860 ri->prefix[RIPNG_FILTER_OUT] = plist;
2861 else
2862 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2863 }
2864 else
2865 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2866}
a94434b6 2867
718e3744 2868void
2869ripng_distribute_update_interface (struct interface *ifp)
2870{
2871 struct distribute *dist;
2872
2873 dist = distribute_lookup (ifp->name);
2874 if (dist)
2875 ripng_distribute_update (dist);
2876}
2877
2878/* Update all interface's distribute list. */
6ac29a51 2879static void
c9e52be3 2880ripng_distribute_update_all (struct prefix_list *notused)
718e3744 2881{
2882 struct interface *ifp;
52dc7ee6 2883 struct listnode *node;
718e3744 2884
b2d7c082 2885 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
1eb8ef25 2886 ripng_distribute_update_interface (ifp);
718e3744 2887}
c9e52be3 2888
6ac29a51 2889static void
c9e52be3 2890ripng_distribute_update_all_wrapper (struct access_list *notused)
2891{
2892 ripng_distribute_update_all(NULL);
2893}
6b0655a2 2894
a94434b6 2895/* delete all the added ripng routes. */
2896void
2897ripng_clean()
2898{
2899 int i;
2900 struct route_node *rp;
2901 struct ripng_info *rinfo;
c880b636
FL
2902 struct ripng_aggregate *aggregate;
2903 struct list *list = NULL;
2904 struct listnode *listnode = NULL;
a94434b6 2905
2906 if (ripng) {
2907 /* Clear RIPng routes */
c880b636
FL
2908 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2909 {
2910 if ((list = rp->info) != NULL)
2911 {
2912 rinfo = listgetdata (listhead (list));
2913 if (ripng_route_rte (rinfo))
2914 ripng_zebra_ipv6_delete (rp);
2915
2916 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2917 {
2918 RIPNG_TIMER_OFF (rinfo->t_timeout);
2919 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2920 ripng_info_free (rinfo);
2921 }
2922 list_delete (list);
2923 rp->info = NULL;
2924 route_unlock_node (rp);
2925 }
2926
2927 if ((aggregate = rp->aggregate) != NULL)
2928 {
2929 ripng_aggregate_free (aggregate);
2930 rp->aggregate = NULL;
2931 route_unlock_node (rp);
2932 }
a94434b6 2933 }
2934
2935 /* Cancel the RIPng timers */
2936 RIPNG_TIMER_OFF (ripng->t_update);
2937 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2938 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2939
2940 /* Cancel the read thread */
2941 if (ripng->t_read) {
2942 thread_cancel (ripng->t_read);
2943 ripng->t_read = NULL;
2944 }
2945
2946 /* Close the RIPng socket */
2947 if (ripng->sock >= 0) {
2948 close(ripng->sock);
2949 ripng->sock = -1;
2950 }
2951
2952 /* Static RIPng route configuration. */
2953 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2954 if (rp->info) {
2955 rp->info = NULL;
2956 route_unlock_node (rp);
2957 }
2958
2959 /* RIPng aggregated prefixes */
2960 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2961 if (rp->info) {
2962 rp->info = NULL;
2963 route_unlock_node (rp);
2964 }
2965
2966 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2967 if (ripng->route_map[i].name)
2968 free (ripng->route_map[i].name);
2969
2970 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2971 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2972 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2973
2974 XFREE (MTYPE_RIPNG, ripng);
2975 ripng = NULL;
2976 } /* if (ripng) */
2977
2978 ripng_clean_network();
2979 ripng_passive_interface_clean ();
2980 ripng_offset_clean ();
2981 ripng_interface_clean ();
2982 ripng_redistribute_clean ();
2983}
2984
2985/* Reset all values to the default settings. */
2986void
2987ripng_reset ()
2988{
2989 /* Call ripd related reset functions. */
2990 ripng_debug_reset ();
2991 ripng_route_map_reset ();
2992
2993 /* Call library reset functions. */
2994 vty_reset ();
2995 access_list_reset ();
2996 prefix_list_reset ();
2997
2998 distribute_list_reset ();
2999
3000 ripng_interface_reset ();
3001
3002 ripng_zclient_reset ();
3003}
718e3744 3004
6ac29a51 3005static void
718e3744 3006ripng_if_rmap_update (struct if_rmap *if_rmap)
3007{
3008 struct interface *ifp;
3009 struct ripng_interface *ri;
3010 struct route_map *rmap;
3011
1306c09a 3012 ifp = if_lookup_by_name (if_rmap->ifname, VRF_DEFAULT);
718e3744 3013 if (ifp == NULL)
3014 return;
3015
3016 ri = ifp->info;
3017
3018 if (if_rmap->routemap[IF_RMAP_IN])
3019 {
3020 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3021 if (rmap)
3022 ri->routemap[IF_RMAP_IN] = rmap;
3023 else
3024 ri->routemap[IF_RMAP_IN] = NULL;
3025 }
3026 else
3027 ri->routemap[RIPNG_FILTER_IN] = NULL;
3028
3029 if (if_rmap->routemap[IF_RMAP_OUT])
3030 {
3031 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3032 if (rmap)
3033 ri->routemap[IF_RMAP_OUT] = rmap;
3034 else
3035 ri->routemap[IF_RMAP_OUT] = NULL;
3036 }
3037 else
3038 ri->routemap[RIPNG_FILTER_OUT] = NULL;
3039}
3040
3041void
3042ripng_if_rmap_update_interface (struct interface *ifp)
3043{
3044 struct if_rmap *if_rmap;
3045
3046 if_rmap = if_rmap_lookup (ifp->name);
3047 if (if_rmap)
3048 ripng_if_rmap_update (if_rmap);
3049}
3050
6ac29a51 3051static void
718e3744 3052ripng_routemap_update_redistribute (void)
3053{
3054 int i;
3055
3056 if (ripng)
3057 {
3058 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3059 {
3060 if (ripng->route_map[i].name)
3061 ripng->route_map[i].map =
3062 route_map_lookup_by_name (ripng->route_map[i].name);
3063 }
3064 }
3065}
3066
6ac29a51 3067static void
98b718a9 3068ripng_routemap_update (const char *unused)
718e3744 3069{
3070 struct interface *ifp;
52dc7ee6 3071 struct listnode *node;
718e3744 3072
b2d7c082 3073 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
1eb8ef25 3074 ripng_if_rmap_update_interface (ifp);
718e3744 3075
3076 ripng_routemap_update_redistribute ();
3077}
3078
3079/* Initialize ripng structure and set commands. */
3080void
3081ripng_init ()
3082{
718e3744 3083 /* Install RIPNG_NODE. */
3084 install_node (&cmd_ripng_node, ripng_config_write);
3085
3086 /* Install ripng commands. */
3087 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
a94434b6 3088 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
718e3744 3089
d7f966ab
RW
3090 install_element (ENABLE_NODE, &clear_ipv6_rip_cmd);
3091
718e3744 3092 install_element (CONFIG_NODE, &router_ripng_cmd);
a94434b6 3093 install_element (CONFIG_NODE, &no_router_ripng_cmd);
718e3744 3094
3095 install_default (RIPNG_NODE);
3096 install_element (RIPNG_NODE, &ripng_route_cmd);
3097 install_element (RIPNG_NODE, &no_ripng_route_cmd);
3098 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3099 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3100
3101 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3102 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
718e3744 3103
3104 install_element (RIPNG_NODE, &ripng_timers_cmd);
3105 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
3106#if 0
ee9216cf 3107 install_element (VIEW_NODE, &show_ipv6_protocols_cmd);
718e3744 3108 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3109 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3110 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3111 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3112 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3113 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3114#endif /* 0 */
3115
a2c62831 3116 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3117 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
718e3744 3118
fac76f9c
FL
3119 install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
3120 install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
3121
718e3744 3122 ripng_if_init ();
3123 ripng_debug_init ();
3124
3125 /* Access list install. */
3126 access_list_init ();
c9e52be3 3127 access_list_add_hook (ripng_distribute_update_all_wrapper);
3128 access_list_delete_hook (ripng_distribute_update_all_wrapper);
718e3744 3129
3130 /* Prefix list initialize.*/
3131 prefix_list_init ();
3132 prefix_list_add_hook (ripng_distribute_update_all);
3133 prefix_list_delete_hook (ripng_distribute_update_all);
3134
3135 /* Distribute list install. */
3136 distribute_list_init (RIPNG_NODE);
3137 distribute_list_add_hook (ripng_distribute_update);
3138 distribute_list_delete_hook (ripng_distribute_update);
3139
3140 /* Route-map for interface. */
3141 ripng_route_map_init ();
a94434b6 3142 ripng_offset_init ();
3143
718e3744 3144 route_map_add_hook (ripng_routemap_update);
3145 route_map_delete_hook (ripng_routemap_update);
3146
0750d21f 3147 if_rmap_init (RIPNG_NODE);
718e3744 3148 if_rmap_hook_add (ripng_if_rmap_update);
3149 if_rmap_hook_delete (ripng_if_rmap_update);
3150}