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