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