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