]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripngd.c
*: reindent
[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);
845 } else {
846 /* If there is an existing route, compare the next hop address
847 to the address of the router from which the datagram came.
848 If this datagram is from the same router as the existing
849 route, reinitialize the timeout. */
850 same = (IN6_ARE_ADDR_EQUAL(&rinfo->from, &from->sin6_addr)
851 && (rinfo->ifindex == ifp->ifindex));
852
853 /*
854 * RFC 2080 - Section 2.4.2:
855 * "If the new metric is the same as the old one, examine the
856 * timeout
857 * for the existing route. If it is at least halfway to the
858 * expiration
859 * point, switch to the new route. This heuristic is optional,
860 * but
861 * highly recommended".
862 */
863 if (!ripng->ecmp && !same && rinfo->metric == rte->metric
864 && rinfo->t_timeout
865 && (thread_timer_remain_second(rinfo->t_timeout)
866 < (ripng->timeout_time / 2))) {
867 ripng_ecmp_replace(&newinfo);
868 }
869 /* Next, compare the metrics. If the datagram is from the same
870 router as the existing route, and the new metric is different
871 than the old one; or, if the new metric is lower than the old
872 one; do the following actions: */
873 else if ((same && rinfo->metric != rte->metric)
874 || rte->metric < rinfo->metric) {
875 if (listcount(list) == 1) {
876 if (newinfo.metric != RIPNG_METRIC_INFINITY)
877 ripng_ecmp_replace(&newinfo);
878 else
879 ripng_ecmp_delete(rinfo);
880 } else {
881 if (newinfo.metric < rinfo->metric)
882 ripng_ecmp_replace(&newinfo);
883 else /* newinfo.metric > rinfo->metric */
884 ripng_ecmp_delete(rinfo);
885 }
886 } else /* same & no change */
887 ripng_timeout_update(rinfo);
888
889 /* Unlock tempolary lock of the route. */
890 route_unlock_node(rp);
891 }
718e3744 892}
893
ac4d0be5 894/* Add redistributed route to RIPng table. */
895void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p,
896 ifindex_t ifindex, struct in6_addr *nexthop,
897 route_tag_t tag)
898{
899 struct route_node *rp;
900 struct ripng_info *rinfo = NULL, newinfo;
901 struct list *list = NULL;
902
903 /* Redistribute route */
904 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
905 return;
906 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
907 return;
908
909 rp = route_node_get(ripng->table, (struct prefix *)p);
910
911 memset(&newinfo, 0, sizeof(struct ripng_info));
912 newinfo.type = type;
913 newinfo.sub_type = sub_type;
914 newinfo.ifindex = ifindex;
915 newinfo.metric = 1;
916 if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
917 newinfo.tag = tag;
918 newinfo.rp = rp;
919 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
920 newinfo.nexthop = *nexthop;
921
922 if ((list = rp->info) != NULL && listcount(list) != 0) {
923 rinfo = listgetdata(listhead(list));
924
925 if (rinfo->type == ZEBRA_ROUTE_CONNECT
926 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
927 && rinfo->metric != RIPNG_METRIC_INFINITY) {
928 route_unlock_node(rp);
929 return;
930 }
718e3744 931
ac4d0be5 932 /* Manually configured RIPng route check.
933 * They have the precedence on all the other entries.
934 **/
935 if (rinfo->type == ZEBRA_ROUTE_RIPNG
936 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
937 || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))) {
938 if (type != ZEBRA_ROUTE_RIPNG
939 || ((sub_type != RIPNG_ROUTE_STATIC)
940 && (sub_type != RIPNG_ROUTE_DEFAULT))) {
941 route_unlock_node(rp);
942 return;
943 }
944 }
718e3744 945
ac4d0be5 946 ripng_ecmp_replace(&newinfo);
947 route_unlock_node(rp);
948 } else
949 ripng_ecmp_add(&newinfo);
950
951 if (IS_RIPNG_DEBUG_EVENT) {
952 if (!nexthop)
953 zlog_debug(
954 "Redistribute new prefix %s/%d on the interface %s",
955 inet6_ntoa(p->prefix), p->prefixlen,
956 ifindex2ifname(ifindex, VRF_DEFAULT));
957 else
958 zlog_debug(
959 "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
960 inet6_ntoa(p->prefix), p->prefixlen,
961 inet6_ntoa(*nexthop),
962 ifindex2ifname(ifindex, VRF_DEFAULT));
963 }
718e3744 964
ac4d0be5 965 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
966}
967
968/* Delete redistributed route to RIPng table. */
969void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p,
970 ifindex_t ifindex)
971{
972 struct route_node *rp;
973 struct ripng_info *rinfo;
974
975 if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
976 return;
977 if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
978 return;
979
980 rp = route_node_lookup(ripng->table, (struct prefix *)p);
981
982 if (rp) {
983 struct list *list = rp->info;
984
985 if (list != NULL && listcount(list) != 0) {
986 rinfo = listgetdata(listhead(list));
987 if (rinfo != NULL && rinfo->type == type
988 && rinfo->sub_type == sub_type
989 && rinfo->ifindex == ifindex) {
990 /* Perform poisoned reverse. */
991 rinfo->metric = RIPNG_METRIC_INFINITY;
992 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
993 ripng_garbage_collect,
994 ripng->garbage_time);
995 RIPNG_TIMER_OFF(rinfo->t_timeout);
996
997 /* Aggregate count decrement. */
998 ripng_aggregate_decrement(rp, rinfo);
999
1000 rinfo->flags |= RIPNG_RTF_CHANGED;
1001
1002 if (IS_RIPNG_DEBUG_EVENT)
1003 zlog_debug(
1004 "Poisone %s/%d on the interface %s with an "
1005 "infinity metric [delete]",
1006 inet6_ntoa(p->prefix),
1007 p->prefixlen,
1008 ifindex2ifname(ifindex,
1009 VRF_DEFAULT));
1010
1011 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
1012 }
1013 }
1014 route_unlock_node(rp);
1015 }
718e3744 1016}
1017
1018/* Withdraw redistributed route. */
ac4d0be5 1019void ripng_redistribute_withdraw(int type)
1020{
1021 struct route_node *rp;
1022 struct ripng_info *rinfo = NULL;
1023 struct list *list = NULL;
1024
1025 if (!ripng)
1026 return;
1027
1028 for (rp = route_top(ripng->table); rp; rp = route_next(rp))
1029 if ((list = rp->info) != NULL) {
1030 rinfo = listgetdata(listhead(list));
1031 if ((rinfo->type == type)
1032 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) {
1033 /* Perform poisoned reverse. */
1034 rinfo->metric = RIPNG_METRIC_INFINITY;
1035 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
1036 ripng_garbage_collect,
1037 ripng->garbage_time);
1038 RIPNG_TIMER_OFF(rinfo->t_timeout);
1039
1040 /* Aggregate count decrement. */
1041 ripng_aggregate_decrement(rp, rinfo);
1042
1043 rinfo->flags |= RIPNG_RTF_CHANGED;
1044
1045 if (IS_RIPNG_DEBUG_EVENT) {
1046 struct prefix_ipv6 *p =
1047 (struct prefix_ipv6 *)&rp->p;
1048
1049 zlog_debug(
1050 "Poisone %s/%d on the interface %s [withdraw]",
1051 inet6_ntoa(p->prefix),
1052 p->prefixlen,
1053 ifindex2ifname(rinfo->ifindex,
1054 VRF_DEFAULT));
1055 }
1056
1057 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
1058 }
1059 }
1060}
718e3744 1061
ac4d0be5 1062/* RIP routing information. */
1063static void ripng_response_process(struct ripng_packet *packet, int size,
1064 struct sockaddr_in6 *from,
1065 struct interface *ifp, int hoplimit)
1066{
1067 caddr_t lim;
1068 struct rte *rte;
1069 struct ripng_nexthop nexthop;
1070
1071 /* RFC2080 2.4.2 Response Messages:
1072 The Response must be ignored if it is not from the RIPng port. */
1073 if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
1074 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1075 ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr));
1076 ripng_peer_bad_packet(from);
1077 return;
1078 }
718e3744 1079
ac4d0be5 1080 /* The datagram's IPv6 source address should be checked to see
1081 whether the datagram is from a valid neighbor; the source of the
1082 datagram must be a link-local address. */
1083 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
1084 zlog_warn("RIPng packet comes from non link local address %s",
1085 inet6_ntoa(from->sin6_addr));
1086 ripng_peer_bad_packet(from);
1087 return;
1088 }
a94434b6 1089
ac4d0be5 1090 /* It is also worth checking to see whether the response is from one
1091 of the router's own addresses. Interfaces on broadcast networks
1092 may receive copies of their own multicasts immediately. If a
1093 router processes its own output as new input, confusion is likely,
1094 and such datagrams must be ignored. */
1095 if (ripng_lladdr_check(ifp, &from->sin6_addr)) {
1096 zlog_warn(
1097 "RIPng packet comes from my own link local address %s",
1098 inet6_ntoa(from->sin6_addr));
1099 ripng_peer_bad_packet(from);
1100 return;
1101 }
a94434b6 1102
ac4d0be5 1103 /* As an additional check, periodic advertisements must have their
1104 hop counts set to 255, and inbound, multicast packets sent from the
1105 RIPng port (i.e. periodic advertisement or triggered update
1106 packets) must be examined to ensure that the hop count is 255. */
1107 if (hoplimit >= 0 && hoplimit != 255) {
1108 zlog_warn(
1109 "RIPng packet comes with non 255 hop count %d from %s",
1110 hoplimit, inet6_ntoa(from->sin6_addr));
1111 ripng_peer_bad_packet(from);
1112 return;
1113 }
718e3744 1114
ac4d0be5 1115 /* Update RIPng peer. */
1116 ripng_peer_update(from, packet->version);
a94434b6 1117
ac4d0be5 1118 /* Reset nexthop. */
1119 memset(&nexthop, 0, sizeof(struct ripng_nexthop));
1120 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
718e3744 1121
ac4d0be5 1122 /* Set RTE pointer. */
1123 rte = packet->rte;
718e3744 1124
ac4d0be5 1125 for (lim = ((caddr_t)packet) + size; (caddr_t)rte < lim; rte++) {
1126 /* First of all, we have to check this RTE is next hop RTE or
1127 not. Next hop RTE is completely different with normal RTE so
1128 we need special treatment. */
1129 if (rte->metric == RIPNG_METRIC_NEXTHOP) {
1130 ripng_nexthop_rte(rte, from, &nexthop);
1131 continue;
1132 }
718e3744 1133
ac4d0be5 1134 /* RTE information validation. */
1135
1136 /* - is the destination prefix valid (e.g., not a multicast
1137 prefix and not a link-local address) A link-local address
1138 should never be present in an RTE. */
1139 if (IN6_IS_ADDR_MULTICAST(&rte->addr)) {
1140 zlog_warn(
1141 "Destination prefix is a multicast address %s/%d [%d]",
1142 inet6_ntoa(rte->addr), rte->prefixlen,
1143 rte->metric);
1144 ripng_peer_bad_route(from);
1145 continue;
1146 }
1147 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
1148 zlog_warn(
1149 "Destination prefix is a link-local address %s/%d [%d]",
1150 inet6_ntoa(rte->addr), rte->prefixlen,
1151 rte->metric);
1152 ripng_peer_bad_route(from);
1153 continue;
1154 }
1155 if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
1156 zlog_warn(
1157 "Destination prefix is a loopback address %s/%d [%d]",
1158 inet6_ntoa(rte->addr), rte->prefixlen,
1159 rte->metric);
1160 ripng_peer_bad_route(from);
1161 continue;
1162 }
718e3744 1163
ac4d0be5 1164 /* - is the prefix length valid (i.e., between 0 and 128,
1165 inclusive) */
1166 if (rte->prefixlen > 128) {
1167 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1168 inet6_ntoa(rte->addr), rte->prefixlen,
1169 inet6_ntoa(from->sin6_addr), ifp->name);
1170 ripng_peer_bad_route(from);
1171 continue;
1172 }
718e3744 1173
ac4d0be5 1174 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1175 if (!(rte->metric >= 1 && rte->metric <= 16)) {
1176 zlog_warn("Invalid metric %d from %s%%%s", rte->metric,
1177 inet6_ntoa(from->sin6_addr), ifp->name);
1178 ripng_peer_bad_route(from);
1179 continue;
1180 }
718e3744 1181
ac4d0be5 1182 /* Vincent: XXX Should we compute the direclty reachable nexthop
1183 * for our RIPng network ?
1184 **/
718e3744 1185
ac4d0be5 1186 /* Routing table updates. */
1187 ripng_route_process(rte, from, &nexthop, ifp);
1188 }
718e3744 1189}
1190
1191/* Response to request message. */
ac4d0be5 1192static void ripng_request_process(struct ripng_packet *packet, int size,
1193 struct sockaddr_in6 *from,
1194 struct interface *ifp)
1195{
1196 caddr_t lim;
1197 struct rte *rte;
1198 struct prefix_ipv6 p;
1199 struct route_node *rp;
1200 struct ripng_info *rinfo;
1201 struct ripng_interface *ri;
1202
1203 /* Does not reponse to the requests on the loopback interfaces */
1204 if (if_is_loopback(ifp))
1205 return;
1206
1207 /* Check RIPng process is enabled on this interface. */
1208 ri = ifp->info;
1209 if (!ri->running)
1210 return;
1211
1212 /* When passive interface is specified, suppress responses */
1213 if (ri->passive)
1214 return;
1215
1216 /* RIPng peer update. */
1217 ripng_peer_update(from, packet->version);
1218
1219 lim = ((caddr_t)packet) + size;
1220 rte = packet->rte;
1221
1222 /* The Request is processed entry by entry. If there are no
1223 entries, no response is given. */
1224 if (lim == (caddr_t)rte)
1225 return;
1226
1227 /* There is one special case. If there is exactly one entry in the
1228 request, and it has a destination prefix of zero, a prefix length
1229 of zero, and a metric of infinity (i.e., 16), then this is a
1230 request to send the entire routing table. In that case, a call
1231 is made to the output process to send the routing table to the
1232 requesting address/port. */
1233 if (lim == ((caddr_t)(rte + 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte->addr)
1234 && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) {
1235 /* All route with split horizon */
1236 ripng_output_process(ifp, from, ripng_all_route);
1237 } else {
1238 /* Except for this special case, processing is quite simple.
1239 Examine the list of RTEs in the Request one by one. For each
1240 entry, look up the destination in the router's routing
1241 database and, if there is a route, put that route's metric in
1242 the metric field of the RTE. If there is no explicit route
1243 to the specified destination, put infinity in the metric
1244 field. Once all the entries have been filled in, change the
1245 command from Request to Response and send the datagram back
1246 to the requestor. */
1247 memset(&p, 0, sizeof(struct prefix_ipv6));
1248 p.family = AF_INET6;
1249
1250 for (; ((caddr_t)rte) < lim; rte++) {
1251 p.prefix = rte->addr;
1252 p.prefixlen = rte->prefixlen;
1253 apply_mask_ipv6(&p);
1254
1255 rp = route_node_lookup(ripng->table,
1256 (struct prefix *)&p);
1257
1258 if (rp) {
1259 rinfo = listgetdata(
1260 listhead((struct list *)rp->info));
1261 rte->metric = rinfo->metric;
1262 route_unlock_node(rp);
1263 } else
1264 rte->metric = RIPNG_METRIC_INFINITY;
1265 }
1266 packet->command = RIPNG_RESPONSE;
1267
1268 ripng_send_packet((caddr_t)packet, size, from, ifp);
1269 }
718e3744 1270}
1271
1272/* First entry point of reading RIPng packet. */
ac4d0be5 1273static int ripng_read(struct thread *thread)
1274{
1275 int len;
1276 int sock;
1277 struct sockaddr_in6 from;
1278 struct ripng_packet *packet;
1279 ifindex_t ifindex = 0;
1280 struct interface *ifp;
1281 int hoplimit = -1;
1282
1283 /* Check ripng is active and alive. */
1284 assert(ripng != NULL);
1285 assert(ripng->sock >= 0);
1286
1287 /* Fetch thread data and set read pointer to empty for event
1288 managing. `sock' sould be same as ripng->sock. */
1289 sock = THREAD_FD(thread);
1290 ripng->t_read = NULL;
1291
1292 /* Add myself to the next event. */
1293 ripng_event(RIPNG_READ, sock);
1294
1295 /* Read RIPng packet. */
1296 len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
1297 STREAM_SIZE(ripng->ibuf), &from, &ifindex,
1298 &hoplimit);
1299 if (len < 0) {
1300 zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno));
1301 return len;
1302 }
718e3744 1303
ac4d0be5 1304 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1305 (4)) must be multiple size of one RTE size (20). */
1306 if (((len - 4) % 20) != 0) {
1307 zlog_warn("RIPng invalid packet size %d from %s", len,
1308 inet6_ntoa(from.sin6_addr));
1309 ripng_peer_bad_packet(&from);
1310 return 0;
1311 }
718e3744 1312
ac4d0be5 1313 packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
1314 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
718e3744 1315
ac4d0be5 1316 /* RIPng packet received. */
1317 if (IS_RIPNG_DEBUG_EVENT)
1318 zlog_debug("RIPng packet received from %s port %d on %s",
1319 inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
1320 ifp ? ifp->name : "unknown");
718e3744 1321
ac4d0be5 1322 /* Logging before packet checking. */
1323 if (IS_RIPNG_DEBUG_RECV)
1324 ripng_packet_dump(packet, len, "RECV");
718e3744 1325
ac4d0be5 1326 /* Packet comes from unknown interface. */
1327 if (ifp == NULL) {
1328 zlog_warn("RIPng packet comes from unknown interface %d",
1329 ifindex);
1330 return 0;
1331 }
718e3744 1332
ac4d0be5 1333 /* Packet version mismatch checking. */
1334 if (packet->version != ripng->version) {
1335 zlog_warn(
1336 "RIPng packet version %d doesn't fit to my version %d",
1337 packet->version, ripng->version);
1338 ripng_peer_bad_packet(&from);
1339 return 0;
1340 }
718e3744 1341
ac4d0be5 1342 /* Process RIPng packet. */
1343 switch (packet->command) {
1344 case RIPNG_REQUEST:
1345 ripng_request_process(packet, len, &from, ifp);
1346 break;
1347 case RIPNG_RESPONSE:
1348 ripng_response_process(packet, len, &from, ifp, hoplimit);
1349 break;
1350 default:
1351 zlog_warn("Invalid RIPng command %d", packet->command);
1352 ripng_peer_bad_packet(&from);
1353 break;
1354 }
1355 return 0;
718e3744 1356}
1357
1358/* Walk down the RIPng routing table then clear changed flag. */
ac4d0be5 1359static void ripng_clear_changed_flag(void)
718e3744 1360{
ac4d0be5 1361 struct route_node *rp;
1362 struct ripng_info *rinfo = NULL;
1363 struct list *list = NULL;
1364 struct listnode *listnode = NULL;
718e3744 1365
ac4d0be5 1366 for (rp = route_top(ripng->table); rp; rp = route_next(rp))
1367 if ((list = rp->info) != NULL)
1368 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1369 UNSET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
1370 /* This flag can be set only on the first entry.
1371 */
1372 break;
1373 }
718e3744 1374}
1375
1376/* Regular update of RIPng route. Send all routing formation to RIPng
1377 enabled interface. */
ac4d0be5 1378static int ripng_update(struct thread *t)
718e3744 1379{
ac4d0be5 1380 struct listnode *node;
1381 struct interface *ifp;
1382 struct ripng_interface *ri;
718e3744 1383
ac4d0be5 1384 /* Clear update timer thread. */
1385 ripng->t_update = NULL;
718e3744 1386
ac4d0be5 1387 /* Logging update event. */
1388 if (IS_RIPNG_DEBUG_EVENT)
1389 zlog_debug("RIPng update timer expired!");
718e3744 1390
ac4d0be5 1391 /* Supply routes to each interface. */
1392 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
1393 ri = ifp->info;
718e3744 1394
ac4d0be5 1395 if (if_is_loopback(ifp) || !if_is_up(ifp))
1396 continue;
718e3744 1397
ac4d0be5 1398 if (!ri->running)
1399 continue;
718e3744 1400
ac4d0be5 1401 /* When passive interface is specified, suppress announce to the
1402 interface. */
1403 if (ri->passive)
1404 continue;
718e3744 1405
1406#if RIPNG_ADVANCED
ac4d0be5 1407 if (ri->ri_send == RIPNG_SEND_OFF) {
1408 if (IS_RIPNG_DEBUG_EVENT)
1409 zlog_debug(
1410 "[Event] RIPng send to if %d is suppressed by config",
1411 ifp->ifindex);
1412 continue;
1413 }
718e3744 1414#endif /* RIPNG_ADVANCED */
1415
ac4d0be5 1416 ripng_output_process(ifp, NULL, ripng_all_route);
1417 }
718e3744 1418
ac4d0be5 1419 /* Triggered updates may be suppressed if a regular update is due by
1420 the time the triggered update would be sent. */
1421 if (ripng->t_triggered_interval) {
1422 thread_cancel(ripng->t_triggered_interval);
1423 ripng->t_triggered_interval = NULL;
1424 }
1425 ripng->trigger = 0;
718e3744 1426
ac4d0be5 1427 /* Reset flush event. */
1428 ripng_event(RIPNG_UPDATE_EVENT, 0);
718e3744 1429
ac4d0be5 1430 return 0;
718e3744 1431}
1432
1433/* Triggered update interval timer. */
ac4d0be5 1434static int ripng_triggered_interval(struct thread *t)
718e3744 1435{
ac4d0be5 1436 ripng->t_triggered_interval = NULL;
718e3744 1437
ac4d0be5 1438 if (ripng->trigger) {
1439 ripng->trigger = 0;
1440 ripng_triggered_update(t);
1441 }
1442 return 0;
1443}
718e3744 1444
1445/* Execute triggered update. */
ac4d0be5 1446int ripng_triggered_update(struct thread *t)
718e3744 1447{
ac4d0be5 1448 struct listnode *node;
1449 struct interface *ifp;
1450 struct ripng_interface *ri;
1451 int interval;
718e3744 1452
ac4d0be5 1453 ripng->t_triggered_update = NULL;
718e3744 1454
ac4d0be5 1455 /* Cancel interval timer. */
1456 if (ripng->t_triggered_interval) {
1457 thread_cancel(ripng->t_triggered_interval);
1458 ripng->t_triggered_interval = NULL;
1459 }
1460 ripng->trigger = 0;
718e3744 1461
ac4d0be5 1462 /* Logging triggered update. */
1463 if (IS_RIPNG_DEBUG_EVENT)
1464 zlog_debug("RIPng triggered update!");
718e3744 1465
ac4d0be5 1466 /* Split Horizon processing is done when generating triggered
1467 updates as well as normal updates (see section 2.6). */
1468 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
1469 ri = ifp->info;
718e3744 1470
ac4d0be5 1471 if (if_is_loopback(ifp) || !if_is_up(ifp))
1472 continue;
718e3744 1473
ac4d0be5 1474 if (!ri->running)
1475 continue;
718e3744 1476
ac4d0be5 1477 /* When passive interface is specified, suppress announce to the
1478 interface. */
1479 if (ri->passive)
1480 continue;
718e3744 1481
ac4d0be5 1482 ripng_output_process(ifp, NULL, ripng_changed_route);
1483 }
718e3744 1484
ac4d0be5 1485 /* Once all of the triggered updates have been generated, the route
1486 change flags should be cleared. */
1487 ripng_clear_changed_flag();
718e3744 1488
ac4d0be5 1489 /* After a triggered update is sent, a timer should be set for a
1490 random interval between 1 and 5 seconds. If other changes that
1491 would trigger updates occur before the timer expires, a single
1492 update is triggered when the timer expires. */
1493 interval = (random() % 5) + 1;
718e3744 1494
ac4d0be5 1495 ripng->t_triggered_interval = thread_add_timer(
1496 master, ripng_triggered_interval, NULL, interval);
718e3744 1497
ac4d0be5 1498 return 0;
718e3744 1499}
1500
1501/* Write routing table entry to the stream and return next index of
1502 the routing table entry in the stream. */
ac4d0be5 1503int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
1504 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
1505{
1506 /* RIPng packet header. */
1507 if (num == 0) {
1508 stream_putc(s, RIPNG_RESPONSE);
1509 stream_putc(s, RIPNG_V1);
1510 stream_putw(s, 0);
1511 }
718e3744 1512
ac4d0be5 1513 /* Write routing table entry. */
1514 if (!nexthop)
1515 stream_write(s, (u_char *)&p->prefix, sizeof(struct in6_addr));
1516 else
1517 stream_write(s, (u_char *)nexthop, sizeof(struct in6_addr));
1518 stream_putw(s, tag);
1519 if (p)
1520 stream_putc(s, p->prefixlen);
1521 else
1522 stream_putc(s, 0);
1523 stream_putc(s, metric);
718e3744 1524
ac4d0be5 1525 return ++num;
718e3744 1526}
1527
1528/* Send RESPONSE message to specified destination. */
ac4d0be5 1529void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
1530 int route_type)
1531{
1532 int ret;
1533 struct route_node *rp;
1534 struct ripng_info *rinfo;
1535 struct ripng_interface *ri;
1536 struct ripng_aggregate *aggregate;
1537 struct prefix_ipv6 *p;
1538 struct list *ripng_rte_list;
1539 struct list *list = NULL;
1540 struct listnode *listnode = NULL;
1541
1542 if (IS_RIPNG_DEBUG_EVENT) {
1543 if (to)
1544 zlog_debug("RIPng update routes to neighbor %s",
1545 inet6_ntoa(to->sin6_addr));
1546 else
1547 zlog_debug("RIPng update routes on interface %s",
1548 ifp->name);
1549 }
a94434b6 1550
ac4d0be5 1551 /* Get RIPng interface. */
1552 ri = ifp->info;
1553
1554 ripng_rte_list = ripng_rte_new();
1555
1556 for (rp = route_top(ripng->table); rp; rp = route_next(rp)) {
1557 if ((list = rp->info) != NULL
1558 && (rinfo = listgetdata(listhead(list))) != NULL
1559 && rinfo->suppress == 0) {
1560 /* If no route-map are applied, the RTE will be these
1561 * following
1562 * informations.
1563 */
1564 p = (struct prefix_ipv6 *)&rp->p;
1565 rinfo->metric_out = rinfo->metric;
1566 rinfo->tag_out = rinfo->tag;
1567 memset(&rinfo->nexthop_out, 0,
1568 sizeof(rinfo->nexthop_out));
1569 /* In order to avoid some local loops,
1570 * if the RIPng route has a nexthop via this interface,
1571 * keep the nexthop,
1572 * otherwise set it to 0. The nexthop should not be
1573 * propagated
1574 * beyond the local broadcast/multicast area in order
1575 * to avoid an IGP multi-level recursive look-up.
1576 */
1577 if (rinfo->ifindex == ifp->ifindex)
1578 rinfo->nexthop_out = rinfo->nexthop;
1579
1580 /* Apply output filters. */
1581 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1582 if (ret < 0)
1583 continue;
1584
1585 /* Changed route only output. */
1586 if (route_type == ripng_changed_route
1587 && (!(rinfo->flags & RIPNG_RTF_CHANGED)))
1588 continue;
1589
1590 /* Split horizon. */
1591 if (ri->split_horizon == RIPNG_SPLIT_HORIZON) {
1592 /* We perform split horizon for RIPng routes. */
1593 int suppress = 0;
1594 struct ripng_info *tmp_rinfo = NULL;
1595
1596 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1597 tmp_rinfo))
1598 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG
1599 && tmp_rinfo->ifindex
1600 == ifp->ifindex) {
1601 suppress = 1;
1602 break;
1603 }
1604 if (suppress)
1605 continue;
1606 }
1607
1608 /* Preparation for route-map. */
1609 rinfo->metric_set = 0;
1610 /* nexthop_out,
1611 * metric_out
1612 * and tag_out are already initialized.
1613 */
1614
1615 /* Interface route-map */
1616 if (ri->routemap[RIPNG_FILTER_OUT]) {
1617 int ret;
1618
1619 ret = route_map_apply(
1620 ri->routemap[RIPNG_FILTER_OUT],
1621 (struct prefix *)p, RMAP_RIPNG, rinfo);
1622
1623 if (ret == RMAP_DENYMATCH) {
1624 if (IS_RIPNG_DEBUG_PACKET)
1625 zlog_debug(
1626 "RIPng %s/%d is filtered by route-map out",
1627 inet6_ntoa(p->prefix),
1628 p->prefixlen);
1629 continue;
1630 }
1631 }
1632
1633 /* Redistribute route-map. */
1634 if (ripng->route_map[rinfo->type].name) {
1635 int ret;
1636
1637 ret = route_map_apply(
1638 ripng->route_map[rinfo->type].map,
1639 (struct prefix *)p, RMAP_RIPNG, rinfo);
1640
1641 if (ret == RMAP_DENYMATCH) {
1642 if (IS_RIPNG_DEBUG_PACKET)
1643 zlog_debug(
1644 "RIPng %s/%d is filtered by route-map",
1645 inet6_ntoa(p->prefix),
1646 p->prefixlen);
1647 continue;
1648 }
1649 }
1650
1651 /* When the route-map does not set metric. */
1652 if (!rinfo->metric_set) {
1653 /* If the redistribute metric is set. */
1654 if (ripng->route_map[rinfo->type].metric_config
1655 && rinfo->metric != RIPNG_METRIC_INFINITY) {
1656 rinfo->metric_out =
1657 ripng->route_map[rinfo->type]
1658 .metric;
1659 } else {
1660 /* If the route is not connected or
1661 localy generated
1662 one, use default-metric value */
1663 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1664 && rinfo->type
1665 != ZEBRA_ROUTE_CONNECT
1666 && rinfo->metric
1667 != RIPNG_METRIC_INFINITY)
1668 rinfo->metric_out =
1669 ripng->default_metric;
1670 }
1671 }
1672
1673 /* Apply offset-list */
1674 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1675 ripng_offset_list_apply_out(p, ifp,
1676 &rinfo->metric_out);
1677
1678 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1679 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1680
1681 /* Perform split-horizon with poisoned reverse
1682 * for RIPng routes.
1683 **/
1684 if (ri->split_horizon
1685 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1686 struct ripng_info *tmp_rinfo = NULL;
1687
1688 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1689 tmp_rinfo))
1690 if ((tmp_rinfo->type
1691 == ZEBRA_ROUTE_RIPNG)
1692 && tmp_rinfo->ifindex
1693 == ifp->ifindex)
1694 rinfo->metric_out =
1695 RIPNG_METRIC_INFINITY;
1696 }
1697
1698 /* Add RTE to the list */
1699 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
718e3744 1700 }
718e3744 1701
ac4d0be5 1702 /* Process the aggregated RTE entry */
1703 if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0
1704 && aggregate->suppress == 0) {
1705 /* If no route-map are applied, the RTE will be these
1706 * following
1707 * informations.
1708 */
1709 p = (struct prefix_ipv6 *)&rp->p;
1710 aggregate->metric_set = 0;
1711 aggregate->metric_out = aggregate->metric;
1712 aggregate->tag_out = aggregate->tag;
1713 memset(&aggregate->nexthop_out, 0,
1714 sizeof(aggregate->nexthop_out));
1715
1716 /* Apply output filters.*/
1717 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1718 if (ret < 0)
1719 continue;
1720
1721 /* Interface route-map */
1722 if (ri->routemap[RIPNG_FILTER_OUT]) {
1723 int ret;
1724 struct ripng_info newinfo;
1725
1726 /* let's cast the aggregate structure to
1727 * ripng_info */
1728 memset(&newinfo, 0, sizeof(struct ripng_info));
1729 /* the nexthop is :: */
1730 newinfo.metric = aggregate->metric;
1731 newinfo.metric_out = aggregate->metric_out;
1732 newinfo.tag = aggregate->tag;
1733 newinfo.tag_out = aggregate->tag_out;
1734
1735 ret = route_map_apply(
1736 ri->routemap[RIPNG_FILTER_OUT],
1737 (struct prefix *)p, RMAP_RIPNG,
1738 &newinfo);
1739
1740 if (ret == RMAP_DENYMATCH) {
1741 if (IS_RIPNG_DEBUG_PACKET)
1742 zlog_debug(
1743 "RIPng %s/%d is filtered by route-map out",
1744 inet6_ntoa(p->prefix),
1745 p->prefixlen);
1746 continue;
1747 }
1748
1749 aggregate->metric_out = newinfo.metric_out;
1750 aggregate->tag_out = newinfo.tag_out;
1751 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1752 aggregate->nexthop_out =
1753 newinfo.nexthop_out;
1754 }
1755
1756 /* There is no redistribute routemap for the aggregated
1757 * RTE */
1758
1759 /* Changed route only output. */
1760 /* XXX, vincent, in order to increase time convergence,
1761 * it should be announced if a child has changed.
1762 */
1763 if (route_type == ripng_changed_route)
1764 continue;
1765
1766 /* Apply offset-list */
1767 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1768 ripng_offset_list_apply_out(
1769 p, ifp, &aggregate->metric_out);
1770
1771 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1772 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1773
1774 /* Add RTE to the list */
1775 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
1776 }
718e3744 1777 }
1778
ac4d0be5 1779 /* Flush the list */
1780 ripng_rte_send(ripng_rte_list, ifp, to);
1781 ripng_rte_free(ripng_rte_list);
718e3744 1782}
1783
1784/* Create new RIPng instance and set it to global variable. */
ac4d0be5 1785static int ripng_create(void)
718e3744 1786{
ac4d0be5 1787 /* ripng should be NULL. */
1788 assert(ripng == NULL);
718e3744 1789
ac4d0be5 1790 /* Allocaste RIPng instance. */
1791 ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
718e3744 1792
ac4d0be5 1793 /* Default version and timer values. */
1794 ripng->version = RIPNG_V1;
1795 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1796 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1797 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1798 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
718e3744 1799
ac4d0be5 1800 /* Make buffer. */
1801 ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
1802 ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
718e3744 1803
ac4d0be5 1804 /* Initialize RIPng routig table. */
1805 ripng->table = route_table_init();
1806 ripng->route = route_table_init();
1807 ripng->aggregate = route_table_init();
718e3744 1808
ac4d0be5 1809 /* Make socket. */
1810 ripng->sock = ripng_make_socket();
1811 if (ripng->sock < 0)
1812 return ripng->sock;
1813
1814 /* Threads. */
1815 ripng_event(RIPNG_READ, ripng->sock);
1816 ripng_event(RIPNG_UPDATE_EVENT, 1);
1817
1818 return 0;
718e3744 1819}
1820
a94434b6 1821/* Send RIPng request to the interface. */
ac4d0be5 1822int ripng_request(struct interface *ifp)
718e3744 1823{
ac4d0be5 1824 struct rte *rte;
1825 struct ripng_packet ripng_packet;
718e3744 1826
ac4d0be5 1827 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1828 */
1829 if (if_is_loopback(ifp))
1830 return 0;
a94434b6 1831
ac4d0be5 1832 /* If interface is down, don't send RIP packet. */
1833 if (!if_is_up(ifp))
1834 return 0;
a94434b6 1835
ac4d0be5 1836 if (IS_RIPNG_DEBUG_EVENT)
1837 zlog_debug("RIPng send request to %s", ifp->name);
718e3744 1838
ac4d0be5 1839 memset(&ripng_packet, 0, sizeof(ripng_packet));
1840 ripng_packet.command = RIPNG_REQUEST;
1841 ripng_packet.version = RIPNG_V1;
1842 rte = ripng_packet.rte;
1843 rte->metric = RIPNG_METRIC_INFINITY;
718e3744 1844
ac4d0be5 1845 return ripng_send_packet((caddr_t)&ripng_packet, sizeof(ripng_packet),
1846 NULL, ifp);
718e3744 1847}
1848
6b0655a2 1849
ac4d0be5 1850static int ripng_update_jitter(int time)
718e3744 1851{
ac4d0be5 1852 return ((random() % (time + 1)) - (time / 2));
718e3744 1853}
1854
ac4d0be5 1855void ripng_event(enum ripng_event event, int sock)
718e3744 1856{
ac4d0be5 1857 int jitter = 0;
718e3744 1858
ac4d0be5 1859 switch (event) {
1860 case RIPNG_READ:
1861 if (!ripng->t_read)
1862 ripng->t_read =
1863 thread_add_read(master, ripng_read, NULL, sock);
1864 break;
1865 case RIPNG_UPDATE_EVENT:
1866 if (ripng->t_update) {
1867 thread_cancel(ripng->t_update);
1868 ripng->t_update = NULL;
1869 }
1870 /* Update timer jitter. */
1871 jitter = ripng_update_jitter(ripng->update_time);
1872
1873 ripng->t_update = thread_add_timer(
1874 master, ripng_update, NULL,
1875 sock ? 2 : ripng->update_time + jitter);
1876 break;
1877 case RIPNG_TRIGGERED_UPDATE:
1878 if (ripng->t_triggered_interval)
1879 ripng->trigger = 1;
1880 else if (!ripng->t_triggered_update)
1881 ripng->t_triggered_update = thread_add_event(
1882 master, ripng_triggered_update, NULL, 0);
1883 break;
1884 default:
1885 break;
1886 }
718e3744 1887}
6b0655a2 1888
718e3744 1889
718e3744 1890/* Print out routes update time. */
ac4d0be5 1891static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
718e3744 1892{
ac4d0be5 1893 time_t clock;
1894 struct tm *tm;
718e3744 1895#define TIME_BUF 25
ac4d0be5 1896 char timebuf[TIME_BUF];
1897 struct thread *thread;
1898
1899 if ((thread = rinfo->t_timeout) != NULL) {
1900 clock = thread_timer_remain_second(thread);
1901 tm = gmtime(&clock);
1902 strftime(timebuf, TIME_BUF, "%M:%S", tm);
1903 vty_out(vty, "%5s", timebuf);
1904 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
1905 clock = thread_timer_remain_second(thread);
1906 tm = gmtime(&clock);
1907 strftime(timebuf, TIME_BUF, "%M:%S", tm);
1908 vty_out(vty, "%5s", timebuf);
1909 }
718e3744 1910}
1911
ac4d0be5 1912static char *ripng_route_subtype_print(struct ripng_info *rinfo)
1913{
1914 static char str[3];
1915 memset(str, 0, 3);
1916
1917 if (rinfo->suppress)
1918 strcat(str, "S");
1919
1920 switch (rinfo->sub_type) {
1921 case RIPNG_ROUTE_RTE:
1922 strcat(str, "n");
1923 break;
1924 case RIPNG_ROUTE_STATIC:
1925 strcat(str, "s");
1926 break;
1927 case RIPNG_ROUTE_DEFAULT:
1928 strcat(str, "d");
1929 break;
1930 case RIPNG_ROUTE_REDISTRIBUTE:
1931 strcat(str, "r");
1932 break;
1933 case RIPNG_ROUTE_INTERFACE:
1934 strcat(str, "i");
1935 break;
1936 default:
1937 strcat(str, "?");
1938 break;
1939 }
a94434b6 1940
ac4d0be5 1941 return str;
a94434b6 1942}
1943
718e3744 1944DEFUN (show_ipv6_ripng,
1945 show_ipv6_ripng_cmd,
1946 "show ipv6 ripng",
1947 SHOW_STR
8d0f15fd 1948 IPV6_STR
718e3744 1949 "Show RIPng routes\n")
1950{
ac4d0be5 1951 struct route_node *rp;
1952 struct ripng_info *rinfo;
1953 struct ripng_aggregate *aggregate;
1954 struct prefix_ipv6 *p;
1955 struct list *list = NULL;
1956 struct listnode *listnode = NULL;
1957 int len;
1958
1959 if (!ripng)
1960 return CMD_SUCCESS;
1961
1962 /* Header of display. */
1963 vty_out(vty,
1964 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
1965 "Sub-codes:%s"
1966 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
1967 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
1968 " Network Next Hop Via Metric Tag Time%s",
1969 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
1970 VTY_NEWLINE);
1971
1972 for (rp = route_top(ripng->table); rp; rp = route_next(rp)) {
1973 if ((aggregate = rp->aggregate) != NULL) {
1974 p = (struct prefix_ipv6 *)&rp->p;
718e3744 1975
1976#ifdef DEBUG
ac4d0be5 1977 vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count,
1978 aggregate->suppress, inet6_ntoa(p->prefix),
1979 p->prefixlen);
718e3744 1980#else
ac4d0be5 1981 vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix),
1982 p->prefixlen);
718e3744 1983#endif /* DEBUG */
ac4d0be5 1984 vty_out(vty, "%s", VTY_NEWLINE);
1985 vty_out(vty, "%*s", 18, " ");
718e3744 1986
ac4d0be5 1987 vty_out(vty, "%*s", 28, " ");
1988 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "%s",
1989 aggregate->metric, (route_tag_t)aggregate->tag,
1990 VTY_NEWLINE);
1991 }
718e3744 1992
ac4d0be5 1993 if ((list = rp->info) != NULL)
1994 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1995 p = (struct prefix_ipv6 *)&rp->p;
718e3744 1996
1997#ifdef DEBUG
ac4d0be5 1998 vty_out(vty, "%c(%s) 0/%d %s/%d ",
1999 zebra_route_char(rinfo->type),
2000 ripng_route_subtype_print(rinfo),
2001 rinfo->suppress, inet6_ntoa(p->prefix),
2002 p->prefixlen);
718e3744 2003#else
ac4d0be5 2004 vty_out(vty, "%c(%s) %s/%d ",
2005 zebra_route_char(rinfo->type),
2006 ripng_route_subtype_print(rinfo),
2007 inet6_ntoa(p->prefix), p->prefixlen);
718e3744 2008#endif /* DEBUG */
ac4d0be5 2009 vty_out(vty, "%s", VTY_NEWLINE);
2010 vty_out(vty, "%*s", 18, " ");
2011 len = vty_out(vty, "%s",
2012 inet6_ntoa(rinfo->nexthop));
2013
2014 len = 28 - len;
2015 if (len > 0)
2016 len = vty_out(vty, "%*s", len, " ");
2017
2018 /* from */
2019 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2020 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2021 len = vty_out(
2022 vty, "%s",
2023 ifindex2ifname(rinfo->ifindex,
2024 VRF_DEFAULT));
2025 } else if (rinfo->metric
2026 == RIPNG_METRIC_INFINITY) {
2027 len = vty_out(vty, "kill");
2028 } else
2029 len = vty_out(vty, "self");
2030
2031 len = 9 - len;
2032 if (len > 0)
2033 vty_out(vty, "%*s", len, " ");
2034
2035 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2036 rinfo->metric, (route_tag_t)rinfo->tag);
2037
2038 /* time */
2039 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2040 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2041 /* RTE from remote RIP routers */
2042 ripng_vty_out_uptime(vty, rinfo);
2043 } else if (rinfo->metric
2044 == RIPNG_METRIC_INFINITY) {
2045 /* poisonous reversed routes (gc) */
2046 ripng_vty_out_uptime(vty, rinfo);
2047 }
2048
2049 vty_out(vty, "%s", VTY_NEWLINE);
2050 }
718e3744 2051 }
718e3744 2052
ac4d0be5 2053 return CMD_SUCCESS;
718e3744 2054}
2055
a94434b6 2056DEFUN (show_ipv6_ripng_status,
2057 show_ipv6_ripng_status_cmd,
2058 "show ipv6 ripng status",
2059 SHOW_STR
8d0f15fd 2060 IPV6_STR
a94434b6 2061 "Show RIPng routes\n"
2062 "IPv6 routing protocol process parameters and statistics\n")
2063{
ac4d0be5 2064 struct listnode *node;
2065 struct interface *ifp;
a94434b6 2066
ac4d0be5 2067 if (!ripng)
2068 return CMD_SUCCESS;
a94434b6 2069
ac4d0be5 2070 vty_out(vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2071 vty_out(vty, " Sending updates every %ld seconds with +/-50%%,",
2072 ripng->update_time);
2073 vty_out(vty, " next due in %lu seconds%s",
2074 thread_timer_remain_second(ripng->t_update), VTY_NEWLINE);
2075 vty_out(vty, " Timeout after %ld seconds,", ripng->timeout_time);
2076 vty_out(vty, " garbage collect after %ld seconds%s",
2077 ripng->garbage_time, VTY_NEWLINE);
a94434b6 2078
ac4d0be5 2079 /* Filtering status show. */
2080 config_show_distribute(vty);
a94434b6 2081
ac4d0be5 2082 /* Default metric information. */
2083 vty_out(vty, " Default redistribution metric is %d%s",
2084 ripng->default_metric, VTY_NEWLINE);
a94434b6 2085
ac4d0be5 2086 /* Redistribute information. */
2087 vty_out(vty, " Redistributing:");
2088 ripng_redistribute_write(vty, 0);
2089 vty_out(vty, "%s", VTY_NEWLINE);
a94434b6 2090
ac4d0be5 2091 vty_out(vty, " Default version control: send version %d,",
2092 ripng->version);
2093 vty_out(vty, " receive version %d %s", ripng->version, VTY_NEWLINE);
a94434b6 2094
ac4d0be5 2095 vty_out(vty, " Interface Send Recv%s", VTY_NEWLINE);
a94434b6 2096
ac4d0be5 2097 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
2098 struct ripng_interface *ri;
a94434b6 2099
ac4d0be5 2100 ri = ifp->info;
a94434b6 2101
ac4d0be5 2102 if (ri->enable_network || ri->enable_interface) {
2103
2104 vty_out(vty, " %-17s%-3d %-3d%s", ifp->name,
2105 ripng->version, ripng->version, VTY_NEWLINE);
2106 }
a94434b6 2107 }
a94434b6 2108
ac4d0be5 2109 vty_out(vty, " Routing for Networks:%s", VTY_NEWLINE);
2110 ripng_network_write(vty, 0);
a94434b6 2111
ac4d0be5 2112 vty_out(vty, " Routing Information Sources:%s", VTY_NEWLINE);
2113 vty_out(vty,
2114 " Gateway BadPackets BadRoutes Distance Last Update%s",
2115 VTY_NEWLINE);
2116 ripng_peer_display(vty);
a94434b6 2117
ac4d0be5 2118 return CMD_SUCCESS;
a94434b6 2119}
2120
d7f966ab
RW
2121DEFUN (clear_ipv6_rip,
2122 clear_ipv6_rip_cmd,
2123 "clear ipv6 ripng",
2124 CLEAR_STR
2125 IPV6_STR
2126 "Clear IPv6 RIP database")
2127{
ac4d0be5 2128 struct route_node *rp;
2129 struct ripng_info *rinfo;
2130 struct list *list;
2131 struct listnode *listnode;
d7f966ab 2132
ac4d0be5 2133 /* Clear received RIPng routes */
2134 for (rp = route_top(ripng->table); rp; rp = route_next(rp)) {
2135 list = rp->info;
2136 if (list == NULL)
2137 continue;
d7f966ab 2138
ac4d0be5 2139 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2140 if (!ripng_route_rte(rinfo))
2141 continue;
d7f966ab 2142
ac4d0be5 2143 if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
2144 ripng_zebra_ipv6_delete(rp);
2145 break;
2146 }
d7f966ab 2147
ac4d0be5 2148 if (rinfo) {
2149 RIPNG_TIMER_OFF(rinfo->t_timeout);
2150 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
2151 listnode_delete(list, rinfo);
2152 ripng_info_free(rinfo);
2153 }
d7f966ab 2154
ac4d0be5 2155 if (list_isempty(list)) {
2156 list_free(list);
2157 rp->info = NULL;
2158 route_unlock_node(rp);
2159 }
d7f966ab 2160 }
d7f966ab 2161
ac4d0be5 2162 return CMD_SUCCESS;
d7f966ab
RW
2163}
2164
505e5056 2165DEFUN_NOSH (router_ripng,
718e3744 2166 router_ripng_cmd,
2167 "router ripng",
2168 "Enable a routing process\n"
2169 "Make RIPng instance command\n")
2170{
ac4d0be5 2171 int ret;
718e3744 2172
ac4d0be5 2173 vty->node = RIPNG_NODE;
718e3744 2174
ac4d0be5 2175 if (!ripng) {
2176 ret = ripng_create();
718e3744 2177
ac4d0be5 2178 /* Notice to user we couldn't create RIPng. */
2179 if (ret < 0) {
2180 zlog_warn("can't create RIPng");
2181 return CMD_WARNING;
2182 }
718e3744 2183 }
718e3744 2184
ac4d0be5 2185 return CMD_SUCCESS;
718e3744 2186}
2187
a94434b6 2188DEFUN (no_router_ripng,
2189 no_router_ripng_cmd,
2190 "no router ripng",
2191 NO_STR
2192 "Enable a routing process\n"
2193 "Make RIPng instance command\n")
2194{
ac4d0be5 2195 if (ripng)
2196 ripng_clean();
2197 return CMD_SUCCESS;
a94434b6 2198}
2199
718e3744 2200DEFUN (ripng_route,
2201 ripng_route_cmd,
2202 "route IPV6ADDR",
2203 "Static route setup\n"
2204 "Set static RIPng route announcement\n")
2205{
ac4d0be5 2206 int idx_ipv6addr = 1;
2207 int ret;
2208 struct prefix_ipv6 p;
2209 struct route_node *rp;
718e3744 2210
ac4d0be5 2211 ret = str2prefix_ipv6(argv[idx_ipv6addr]->arg,
2212 (struct prefix_ipv6 *)&p);
2213 if (ret <= 0) {
2214 vty_out(vty, "Malformed address%s", VTY_NEWLINE);
2215 return CMD_WARNING;
2216 }
2217 apply_mask_ipv6(&p);
2218
2219 rp = route_node_get(ripng->route, (struct prefix *)&p);
2220 if (rp->info) {
2221 vty_out(vty, "There is already same static route.%s",
2222 VTY_NEWLINE);
2223 route_unlock_node(rp);
2224 return CMD_WARNING;
2225 }
2226 rp->info = (void *)1;
718e3744 2227
ac4d0be5 2228 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0,
2229 NULL, 0);
718e3744 2230
ac4d0be5 2231 return CMD_SUCCESS;
718e3744 2232}
2233
2234DEFUN (no_ripng_route,
2235 no_ripng_route_cmd,
2236 "no route IPV6ADDR",
2237 NO_STR
2238 "Static route setup\n"
2239 "Delete static RIPng route announcement\n")
2240{
ac4d0be5 2241 int idx_ipv6addr = 2;
2242 int ret;
2243 struct prefix_ipv6 p;
2244 struct route_node *rp;
718e3744 2245
ac4d0be5 2246 ret = str2prefix_ipv6(argv[idx_ipv6addr]->arg,
2247 (struct prefix_ipv6 *)&p);
2248 if (ret <= 0) {
2249 vty_out(vty, "Malformed address%s", VTY_NEWLINE);
2250 return CMD_WARNING;
2251 }
2252 apply_mask_ipv6(&p);
718e3744 2253
ac4d0be5 2254 rp = route_node_lookup(ripng->route, (struct prefix *)&p);
2255 if (!rp) {
2256 vty_out(vty, "Can't find static route.%s", VTY_NEWLINE);
2257 return CMD_WARNING;
2258 }
718e3744 2259
ac4d0be5 2260 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2261 route_unlock_node(rp);
718e3744 2262
ac4d0be5 2263 rp->info = NULL;
2264 route_unlock_node(rp);
718e3744 2265
ac4d0be5 2266 return CMD_SUCCESS;
718e3744 2267}
2268
2269DEFUN (ripng_aggregate_address,
2270 ripng_aggregate_address_cmd,
2271 "aggregate-address X:X::X:X/M",
2272 "Set aggregate RIPng route announcement\n"
2273 "Aggregate network\n")
2274{
ac4d0be5 2275 int idx_ipv6_prefixlen = 1;
2276 int ret;
2277 struct prefix p;
2278 struct route_node *node;
718e3744 2279
ac4d0be5 2280 ret = str2prefix_ipv6(argv[idx_ipv6_prefixlen]->arg,
2281 (struct prefix_ipv6 *)&p);
2282 if (ret <= 0) {
2283 vty_out(vty, "Malformed address%s", VTY_NEWLINE);
2284 return CMD_WARNING;
2285 }
718e3744 2286
ac4d0be5 2287 /* Check aggregate alredy exist or not. */
2288 node = route_node_get(ripng->aggregate, &p);
2289 if (node->info) {
2290 vty_out(vty, "There is already same aggregate route.%s",
2291 VTY_NEWLINE);
2292 route_unlock_node(node);
2293 return CMD_WARNING;
2294 }
2295 node->info = (void *)1;
718e3744 2296
ac4d0be5 2297 ripng_aggregate_add(&p);
718e3744 2298
ac4d0be5 2299 return CMD_SUCCESS;
718e3744 2300}
2301
2302DEFUN (no_ripng_aggregate_address,
2303 no_ripng_aggregate_address_cmd,
2304 "no aggregate-address X:X::X:X/M",
2305 NO_STR
2306 "Delete aggregate RIPng route announcement\n"
2307 "Aggregate network")
2308{
ac4d0be5 2309 int idx_ipv6_prefixlen = 2;
2310 int ret;
2311 struct prefix p;
2312 struct route_node *rn;
718e3744 2313
ac4d0be5 2314 ret = str2prefix_ipv6(argv[idx_ipv6_prefixlen]->arg,
2315 (struct prefix_ipv6 *)&p);
2316 if (ret <= 0) {
2317 vty_out(vty, "Malformed address%s", VTY_NEWLINE);
2318 return CMD_WARNING;
2319 }
718e3744 2320
ac4d0be5 2321 rn = route_node_lookup(ripng->aggregate, &p);
2322 if (!rn) {
2323 vty_out(vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2324 return CMD_WARNING;
2325 }
2326 route_unlock_node(rn);
2327 rn->info = NULL;
2328 route_unlock_node(rn);
718e3744 2329
ac4d0be5 2330 ripng_aggregate_delete(&p);
718e3744 2331
ac4d0be5 2332 return CMD_SUCCESS;
718e3744 2333}
2334
2335DEFUN (ripng_default_metric,
2336 ripng_default_metric_cmd,
6147e2c6 2337 "default-metric (1-16)",
718e3744 2338 "Set a metric of redistribute routes\n"
2339 "Default metric\n")
2340{
ac4d0be5 2341 int idx_number = 1;
2342 if (ripng) {
2343 ripng->default_metric = atoi(argv[idx_number]->arg);
2344 }
2345 return CMD_SUCCESS;
718e3744 2346}
2347
2348DEFUN (no_ripng_default_metric,
2349 no_ripng_default_metric_cmd,
55c727dd 2350 "no default-metric [(1-16)]",
718e3744 2351 NO_STR
2352 "Set a metric of redistribute routes\n"
2353 "Default metric\n")
2354{
ac4d0be5 2355 if (ripng) {
2356 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2357 }
2358 return CMD_SUCCESS;
718e3744 2359}
2360
718e3744 2361
2362#if 0
2363/* RIPng update timer setup. */
2364DEFUN (ripng_update_timer,
2365 ripng_update_timer_cmd,
2366 "update-timer SECOND",
2367 "Set RIPng update timer in seconds\n"
2368 "Seconds\n")
2369{
2370 unsigned long update;
2371 char *endptr = NULL;
2372
2373 update = strtoul (argv[0], &endptr, 10);
2374 if (update == ULONG_MAX || *endptr != '\0')
2375 {
2376 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2377 return CMD_WARNING;
2378 }
2379
2380 ripng->update_time = update;
2381
2382 ripng_event (RIPNG_UPDATE_EVENT, 0);
2383 return CMD_SUCCESS;
2384}
2385
2386DEFUN (no_ripng_update_timer,
2387 no_ripng_update_timer_cmd,
2388 "no update-timer SECOND",
2389 NO_STR
2390 "Unset RIPng update timer in seconds\n"
2391 "Seconds\n")
2392{
2393 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2394 ripng_event (RIPNG_UPDATE_EVENT, 0);
2395 return CMD_SUCCESS;
2396}
2397
2398/* RIPng timeout timer setup. */
2399DEFUN (ripng_timeout_timer,
2400 ripng_timeout_timer_cmd,
2401 "timeout-timer SECOND",
2402 "Set RIPng timeout timer in seconds\n"
2403 "Seconds\n")
2404{
2405 unsigned long timeout;
2406 char *endptr = NULL;
2407
2408 timeout = strtoul (argv[0], &endptr, 10);
2409 if (timeout == ULONG_MAX || *endptr != '\0')
2410 {
2411 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2412 return CMD_WARNING;
2413 }
2414
2415 ripng->timeout_time = timeout;
2416
2417 return CMD_SUCCESS;
2418}
2419
2420DEFUN (no_ripng_timeout_timer,
2421 no_ripng_timeout_timer_cmd,
2422 "no timeout-timer SECOND",
2423 NO_STR
2424 "Unset RIPng timeout timer in seconds\n"
2425 "Seconds\n")
2426{
2427 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2428 return CMD_SUCCESS;
2429}
2430
2431/* RIPng garbage timer setup. */
2432DEFUN (ripng_garbage_timer,
2433 ripng_garbage_timer_cmd,
2434 "garbage-timer SECOND",
2435 "Set RIPng garbage timer in seconds\n"
2436 "Seconds\n")
2437{
2438 unsigned long garbage;
2439 char *endptr = NULL;
2440
2441 garbage = strtoul (argv[0], &endptr, 10);
2442 if (garbage == ULONG_MAX || *endptr != '\0')
2443 {
2444 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2445 return CMD_WARNING;
2446 }
2447
2448 ripng->garbage_time = garbage;
2449
2450 return CMD_SUCCESS;
2451}
2452
2453DEFUN (no_ripng_garbage_timer,
2454 no_ripng_garbage_timer_cmd,
2455 "no garbage-timer SECOND",
2456 NO_STR
2457 "Unset RIPng garbage timer in seconds\n"
2458 "Seconds\n")
2459{
2460 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2461 return CMD_SUCCESS;
2462}
2463#endif /* 0 */
2464
2465DEFUN (ripng_timers,
2466 ripng_timers_cmd,
6147e2c6 2467 "timers basic (0-65535) (0-65535) (0-65535)",
718e3744 2468 "RIPng timers setup\n"
2469 "Basic timer\n"
2470 "Routing table update timer value in second. Default is 30.\n"
2471 "Routing information timeout timer. Default is 180.\n"
2472 "Garbage collection timer. Default is 120.\n")
2473{
ac4d0be5 2474 int idx_number = 2;
2475 int idx_number_2 = 3;
2476 int idx_number_3 = 4;
2477 unsigned long update;
2478 unsigned long timeout;
2479 unsigned long garbage;
718e3744 2480
ac4d0be5 2481 VTY_GET_INTEGER_RANGE("update timer", update, argv[idx_number]->arg, 0,
2482 65535);
2483 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[idx_number_2]->arg,
2484 0, 65535);
2485 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[idx_number_3]->arg,
2486 0, 65535);
718e3744 2487
ac4d0be5 2488 /* Set each timer value. */
2489 ripng->update_time = update;
2490 ripng->timeout_time = timeout;
2491 ripng->garbage_time = garbage;
718e3744 2492
ac4d0be5 2493 /* Reset update timer thread. */
2494 ripng_event(RIPNG_UPDATE_EVENT, 0);
718e3744 2495
ac4d0be5 2496 return CMD_SUCCESS;
718e3744 2497}
2498
2499DEFUN (no_ripng_timers,
2500 no_ripng_timers_cmd,
d04c479d 2501 "no timers basic [(0-65535) (0-65535) (0-65535)]",
718e3744 2502 NO_STR
2503 "RIPng timers setup\n"
c8952fc1
QY
2504 "Basic timer\n"
2505 "Routing table update timer value in second. Default is 30.\n"
2506 "Routing information timeout timer. Default is 180.\n"
2507 "Garbage collection timer. Default is 120.\n")
718e3744 2508{
ac4d0be5 2509 /* Set each timer value to the default. */
2510 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2511 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2512 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
718e3744 2513
ac4d0be5 2514 /* Reset update timer thread. */
2515 ripng_event(RIPNG_UPDATE_EVENT, 0);
718e3744 2516
ac4d0be5 2517 return CMD_SUCCESS;
718e3744 2518}
2519
d7d73ffc 2520#if 0
dd4f9f99
DW
2521DEFUN (show_ipv6_protocols,
2522 show_ipv6_protocols_cmd,
718e3744 2523 "show ipv6 protocols",
2524 SHOW_STR
8d0f15fd 2525 IPV6_STR
718e3744 2526 "Routing protocol information")
2527{
2528 if (! ripng)
2529 return CMD_SUCCESS;
2530
2531 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2532
2533 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2534 ripng->update_time, 0,
2535 VTY_NEWLINE);
2536
2537 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2538 ripng->timeout_time,
2539 ripng->garbage_time,
2540 VTY_NEWLINE);
2541
2542 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2543 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2544
2545 return CMD_SUCCESS;
2546}
d7d73ffc 2547#endif
718e3744 2548
2549/* Please be carefull to use this command. */
a2c62831 2550DEFUN (ripng_default_information_originate,
2551 ripng_default_information_originate_cmd,
718e3744 2552 "default-information originate",
2553 "Default route information\n"
2554 "Distribute default route\n")
2555{
ac4d0be5 2556 struct prefix_ipv6 p;
718e3744 2557
ac4d0be5 2558 if (!ripng->default_information) {
2559 ripng->default_information = 1;
718e3744 2560
ac4d0be5 2561 str2prefix_ipv6("::/0", &p);
2562 ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT,
2563 &p, 0, NULL, 0);
2564 }
718e3744 2565
ac4d0be5 2566 return CMD_SUCCESS;
718e3744 2567}
2568
a2c62831 2569DEFUN (no_ripng_default_information_originate,
2570 no_ripng_default_information_originate_cmd,
718e3744 2571 "no default-information originate",
2572 NO_STR
2573 "Default route information\n"
2574 "Distribute default route\n")
2575{
ac4d0be5 2576 struct prefix_ipv6 p;
718e3744 2577
ac4d0be5 2578 if (ripng->default_information) {
2579 ripng->default_information = 0;
718e3744 2580
ac4d0be5 2581 str2prefix_ipv6("::/0", &p);
2582 ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG,
2583 RIPNG_ROUTE_DEFAULT, &p, 0);
2584 }
718e3744 2585
ac4d0be5 2586 return CMD_SUCCESS;
718e3744 2587}
2588
fac76f9c 2589/* Update ECMP routes to zebra when ECMP is disabled. */
ac4d0be5 2590static void ripng_ecmp_disable(void)
2591{
2592 struct route_node *rp;
2593 struct ripng_info *rinfo, *tmp_rinfo;
2594 struct list *list;
2595 struct listnode *node, *nextnode;
2596
2597 if (!ripng)
2598 return;
2599
2600 for (rp = route_top(ripng->table); rp; rp = route_next(rp))
2601 if ((list = rp->info) != NULL && listcount(list) > 1) {
2602 rinfo = listgetdata(listhead(list));
2603 if (!ripng_route_rte(rinfo))
2604 continue;
2605
2606 /* Drop all other entries, except the first one. */
2607 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2608 if (tmp_rinfo != rinfo) {
2609 RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
2610 RIPNG_TIMER_OFF(
2611 tmp_rinfo->t_garbage_collect);
2612 list_delete_node(list, node);
2613 ripng_info_free(tmp_rinfo);
2614 }
2615
2616 /* Update zebra. */
2617 ripng_zebra_ipv6_add(rp);
2618
2619 /* Set the route change flag. */
2620 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2621
2622 /* Signal the output process to trigger an update. */
2623 ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
2624 }
fac76f9c
FL
2625}
2626
2627DEFUN (ripng_allow_ecmp,
2628 ripng_allow_ecmp_cmd,
2629 "allow-ecmp",
2630 "Allow Equal Cost MultiPath\n")
2631{
ac4d0be5 2632 if (ripng->ecmp) {
2633 vty_out(vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2634 return CMD_WARNING;
2635 }
fac76f9c 2636
ac4d0be5 2637 ripng->ecmp = 1;
2638 zlog_info("ECMP is enabled.");
2639 return CMD_SUCCESS;
fac76f9c
FL
2640}
2641
2642DEFUN (no_ripng_allow_ecmp,
2643 no_ripng_allow_ecmp_cmd,
2644 "no allow-ecmp",
2645 NO_STR
2646 "Allow Equal Cost MultiPath\n")
2647{
ac4d0be5 2648 if (!ripng->ecmp) {
2649 vty_out(vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2650 return CMD_WARNING;
2651 }
fac76f9c 2652
ac4d0be5 2653 ripng->ecmp = 0;
2654 zlog_info("ECMP is disabled.");
2655 ripng_ecmp_disable();
2656 return CMD_SUCCESS;
fac76f9c
FL
2657}
2658
718e3744 2659/* RIPng configuration write function. */
ac4d0be5 2660static int ripng_config_write(struct vty *vty)
718e3744 2661{
ac4d0be5 2662 int ripng_network_write(struct vty *, int);
2663 void ripng_redistribute_write(struct vty *, int);
2664 int write = 0;
2665 struct route_node *rp;
718e3744 2666
ac4d0be5 2667 if (ripng) {
718e3744 2668
ac4d0be5 2669 /* RIPng router. */
2670 vty_out(vty, "router ripng%s", VTY_NEWLINE);
2671
2672 if (ripng->default_information)
2673 vty_out(vty, " default-information originate%s",
2674 VTY_NEWLINE);
2675
2676 ripng_network_write(vty, 1);
2677
2678 /* RIPng default metric configuration */
2679 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2680 vty_out(vty, " default-metric %d%s",
2681 ripng->default_metric, VTY_NEWLINE);
2682
2683 ripng_redistribute_write(vty, 1);
2684
2685 /* RIP offset-list configuration. */
2686 config_write_ripng_offset_list(vty);
2687
2688 /* RIPng aggregate routes. */
2689 for (rp = route_top(ripng->aggregate); rp; rp = route_next(rp))
2690 if (rp->info != NULL)
2691 vty_out(vty, " aggregate-address %s/%d%s",
2692 inet6_ntoa(rp->p.u.prefix6),
2693 rp->p.prefixlen,
2694
2695 VTY_NEWLINE);
2696
2697 /* ECMP configuration. */
2698 if (ripng->ecmp)
2699 vty_out(vty, " allow-ecmp%s", VTY_NEWLINE);
2700
2701 /* RIPng static routes. */
2702 for (rp = route_top(ripng->route); rp; rp = route_next(rp))
2703 if (rp->info != NULL)
2704 vty_out(vty, " route %s/%d%s",
2705 inet6_ntoa(rp->p.u.prefix6),
2706 rp->p.prefixlen, VTY_NEWLINE);
2707
2708 /* RIPng timers configuration. */
2709 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT
2710 || ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT
2711 || ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) {
2712 vty_out(vty, " timers basic %ld %ld %ld%s",
2713 ripng->update_time, ripng->timeout_time,
2714 ripng->garbage_time, VTY_NEWLINE);
2715 }
718e3744 2716#if 0
2717 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2718 vty_out (vty, " update-timer %d%s", ripng->update_time,
2719 VTY_NEWLINE);
2720 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2721 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2722 VTY_NEWLINE);
2723 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2724 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2725 VTY_NEWLINE);
2726#endif /* 0 */
2727
ac4d0be5 2728 write += config_write_distribute(vty);
718e3744 2729
ac4d0be5 2730 write += config_write_if_rmap(vty);
718e3744 2731
ac4d0be5 2732 write++;
2733 }
2734 return write;
718e3744 2735}
2736
2737/* RIPng node structure. */
ac4d0be5 2738static struct cmd_node cmd_ripng_node = {
2739 RIPNG_NODE, "%s(config-router)# ", 1,
718e3744 2740};
2741
ac4d0be5 2742static void ripng_distribute_update(struct distribute *dist)
2743{
2744 struct interface *ifp;
2745 struct ripng_interface *ri;
2746 struct access_list *alist;
2747 struct prefix_list *plist;
2748
2749 if (!dist->ifname)
2750 return;
2751
2752 ifp = if_lookup_by_name(dist->ifname, VRF_DEFAULT);
2753 if (ifp == NULL)
2754 return;
2755
2756 ri = ifp->info;
2757
2758 if (dist->list[DISTRIBUTE_V6_IN]) {
2759 alist = access_list_lookup(AFI_IP6,
2760 dist->list[DISTRIBUTE_V6_IN]);
2761 if (alist)
2762 ri->list[RIPNG_FILTER_IN] = alist;
2763 else
2764 ri->list[RIPNG_FILTER_IN] = NULL;
2765 } else
2766 ri->list[RIPNG_FILTER_IN] = NULL;
2767
2768 if (dist->list[DISTRIBUTE_V6_OUT]) {
2769 alist = access_list_lookup(AFI_IP6,
2770 dist->list[DISTRIBUTE_V6_OUT]);
2771 if (alist)
2772 ri->list[RIPNG_FILTER_OUT] = alist;
2773 else
2774 ri->list[RIPNG_FILTER_OUT] = NULL;
2775 } else
2776 ri->list[RIPNG_FILTER_OUT] = NULL;
2777
2778 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2779 plist = prefix_list_lookup(AFI_IP6,
2780 dist->prefix[DISTRIBUTE_V6_IN]);
2781 if (plist)
2782 ri->prefix[RIPNG_FILTER_IN] = plist;
2783 else
2784 ri->prefix[RIPNG_FILTER_IN] = NULL;
2785 } else
2786 ri->prefix[RIPNG_FILTER_IN] = NULL;
2787
2788 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2789 plist = prefix_list_lookup(AFI_IP6,
2790 dist->prefix[DISTRIBUTE_V6_OUT]);
2791 if (plist)
2792 ri->prefix[RIPNG_FILTER_OUT] = plist;
2793 else
2794 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2795 } else
2796 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2797}
2798
2799void ripng_distribute_update_interface(struct interface *ifp)
2800{
2801 struct distribute *dist;
2802
2803 dist = distribute_lookup(ifp->name);
2804 if (dist)
2805 ripng_distribute_update(dist);
718e3744 2806}
2807
2808/* Update all interface's distribute list. */
ac4d0be5 2809static void ripng_distribute_update_all(struct prefix_list *notused)
718e3744 2810{
ac4d0be5 2811 struct interface *ifp;
2812 struct listnode *node;
718e3744 2813
ac4d0be5 2814 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
2815 ripng_distribute_update_interface(ifp);
718e3744 2816}
c9e52be3 2817
ac4d0be5 2818static void ripng_distribute_update_all_wrapper(struct access_list *notused)
c9e52be3 2819{
ac4d0be5 2820 ripng_distribute_update_all(NULL);
c9e52be3 2821}
6b0655a2 2822
a94434b6 2823/* delete all the added ripng routes. */
ac4d0be5 2824void ripng_clean()
2825{
2826 int i;
2827 struct route_node *rp;
2828 struct ripng_info *rinfo;
2829 struct ripng_aggregate *aggregate;
2830 struct list *list = NULL;
2831 struct listnode *listnode = NULL;
2832
2833 if (ripng) {
2834 /* Clear RIPng routes */
2835 for (rp = route_top(ripng->table); rp; rp = route_next(rp)) {
2836 if ((list = rp->info) != NULL) {
2837 rinfo = listgetdata(listhead(list));
2838 if (ripng_route_rte(rinfo))
2839 ripng_zebra_ipv6_delete(rp);
2840
2841 for (ALL_LIST_ELEMENTS_RO(list, listnode,
2842 rinfo)) {
2843 RIPNG_TIMER_OFF(rinfo->t_timeout);
2844 RIPNG_TIMER_OFF(
2845 rinfo->t_garbage_collect);
2846 ripng_info_free(rinfo);
2847 }
2848 list_delete(list);
2849 rp->info = NULL;
2850 route_unlock_node(rp);
2851 }
2852
2853 if ((aggregate = rp->aggregate) != NULL) {
2854 ripng_aggregate_free(aggregate);
2855 rp->aggregate = NULL;
2856 route_unlock_node(rp);
2857 }
2858 }
a94434b6 2859
ac4d0be5 2860 /* Cancel the RIPng timers */
2861 RIPNG_TIMER_OFF(ripng->t_update);
2862 RIPNG_TIMER_OFF(ripng->t_triggered_update);
2863 RIPNG_TIMER_OFF(ripng->t_triggered_interval);
a94434b6 2864
ac4d0be5 2865 /* Cancel the read thread */
2866 if (ripng->t_read) {
2867 thread_cancel(ripng->t_read);
2868 ripng->t_read = NULL;
2869 }
a94434b6 2870
ac4d0be5 2871 /* Close the RIPng socket */
2872 if (ripng->sock >= 0) {
2873 close(ripng->sock);
2874 ripng->sock = -1;
2875 }
a94434b6 2876
ac4d0be5 2877 /* Static RIPng route configuration. */
2878 for (rp = route_top(ripng->route); rp; rp = route_next(rp))
2879 if (rp->info) {
2880 rp->info = NULL;
2881 route_unlock_node(rp);
2882 }
a94434b6 2883
ac4d0be5 2884 /* RIPng aggregated prefixes */
2885 for (rp = route_top(ripng->aggregate); rp; rp = route_next(rp))
2886 if (rp->info) {
2887 rp->info = NULL;
2888 route_unlock_node(rp);
2889 }
a94434b6 2890
ac4d0be5 2891 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2892 if (ripng->route_map[i].name)
2893 free(ripng->route_map[i].name);
a94434b6 2894
ac4d0be5 2895 XFREE(MTYPE_ROUTE_TABLE, ripng->table);
2896 XFREE(MTYPE_ROUTE_TABLE, ripng->route);
2897 XFREE(MTYPE_ROUTE_TABLE, ripng->aggregate);
a94434b6 2898
ac4d0be5 2899 stream_free(ripng->ibuf);
2900 stream_free(ripng->obuf);
0581e54d 2901
ac4d0be5 2902 XFREE(MTYPE_RIPNG, ripng);
2903 ripng = NULL;
2904 } /* if (ripng) */
a94434b6 2905
ac4d0be5 2906 ripng_clean_network();
2907 ripng_passive_interface_clean();
2908 ripng_offset_clean();
2909 ripng_interface_clean();
2910 ripng_redistribute_clean();
a94434b6 2911}
2912
2913/* Reset all values to the default settings. */
ac4d0be5 2914void ripng_reset()
a94434b6 2915{
ac4d0be5 2916 /* Call ripd related reset functions. */
2917 ripng_debug_reset();
2918 ripng_route_map_reset();
a94434b6 2919
ac4d0be5 2920 /* Call library reset functions. */
2921 vty_reset();
2922 access_list_reset();
2923 prefix_list_reset();
a94434b6 2924
ac4d0be5 2925 distribute_list_reset();
a94434b6 2926
ac4d0be5 2927 ripng_interface_reset();
a94434b6 2928
ac4d0be5 2929 ripng_zclient_reset();
a94434b6 2930}
718e3744 2931
ac4d0be5 2932static void ripng_if_rmap_update(struct if_rmap *if_rmap)
718e3744 2933{
ac4d0be5 2934 struct interface *ifp;
2935 struct ripng_interface *ri;
2936 struct route_map *rmap;
718e3744 2937
ac4d0be5 2938 ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT);
2939 if (ifp == NULL)
2940 return;
718e3744 2941
ac4d0be5 2942 ri = ifp->info;
718e3744 2943
ac4d0be5 2944 if (if_rmap->routemap[IF_RMAP_IN]) {
2945 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2946 if (rmap)
2947 ri->routemap[IF_RMAP_IN] = rmap;
2948 else
2949 ri->routemap[IF_RMAP_IN] = NULL;
2950 } else
2951 ri->routemap[RIPNG_FILTER_IN] = NULL;
718e3744 2952
ac4d0be5 2953 if (if_rmap->routemap[IF_RMAP_OUT]) {
2954 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2955 if (rmap)
2956 ri->routemap[IF_RMAP_OUT] = rmap;
2957 else
2958 ri->routemap[IF_RMAP_OUT] = NULL;
2959 } else
2960 ri->routemap[RIPNG_FILTER_OUT] = NULL;
718e3744 2961}
2962
ac4d0be5 2963void ripng_if_rmap_update_interface(struct interface *ifp)
718e3744 2964{
ac4d0be5 2965 struct if_rmap *if_rmap;
718e3744 2966
ac4d0be5 2967 if_rmap = if_rmap_lookup(ifp->name);
2968 if (if_rmap)
2969 ripng_if_rmap_update(if_rmap);
718e3744 2970}
2971
ac4d0be5 2972static void ripng_routemap_update_redistribute(void)
718e3744 2973{
ac4d0be5 2974 int i;
718e3744 2975
ac4d0be5 2976 if (ripng) {
2977 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2978 if (ripng->route_map[i].name)
2979 ripng->route_map[i].map =
2980 route_map_lookup_by_name(
2981 ripng->route_map[i].name);
2982 }
718e3744 2983 }
718e3744 2984}
2985
ac4d0be5 2986static void ripng_routemap_update(const char *unused)
718e3744 2987{
ac4d0be5 2988 struct interface *ifp;
2989 struct listnode *node;
718e3744 2990
ac4d0be5 2991 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
2992 ripng_if_rmap_update_interface(ifp);
718e3744 2993
ac4d0be5 2994 ripng_routemap_update_redistribute();
718e3744 2995}
2996
2997/* Initialize ripng structure and set commands. */
ac4d0be5 2998void ripng_init()
718e3744 2999{
ac4d0be5 3000 /* Install RIPNG_NODE. */
3001 install_node(&cmd_ripng_node, ripng_config_write);
718e3744 3002
ac4d0be5 3003 /* Install ripng commands. */
3004 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
3005 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
718e3744 3006
ac4d0be5 3007 install_element(ENABLE_NODE, &clear_ipv6_rip_cmd);
d7f966ab 3008
ac4d0be5 3009 install_element(CONFIG_NODE, &router_ripng_cmd);
3010 install_element(CONFIG_NODE, &no_router_ripng_cmd);
718e3744 3011
ac4d0be5 3012 install_default(RIPNG_NODE);
3013 install_element(RIPNG_NODE, &ripng_route_cmd);
3014 install_element(RIPNG_NODE, &no_ripng_route_cmd);
3015 install_element(RIPNG_NODE, &ripng_aggregate_address_cmd);
3016 install_element(RIPNG_NODE, &no_ripng_aggregate_address_cmd);
718e3744 3017
ac4d0be5 3018 install_element(RIPNG_NODE, &ripng_default_metric_cmd);
3019 install_element(RIPNG_NODE, &no_ripng_default_metric_cmd);
718e3744 3020
ac4d0be5 3021 install_element(RIPNG_NODE, &ripng_timers_cmd);
3022 install_element(RIPNG_NODE, &no_ripng_timers_cmd);
718e3744 3023#if 0
ee9216cf 3024 install_element (VIEW_NODE, &show_ipv6_protocols_cmd);
718e3744 3025 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3026 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3027 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3028 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3029 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3030 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3031#endif /* 0 */
3032
ac4d0be5 3033 install_element(RIPNG_NODE, &ripng_default_information_originate_cmd);
3034 install_element(RIPNG_NODE,
3035 &no_ripng_default_information_originate_cmd);
718e3744 3036
ac4d0be5 3037 install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd);
3038 install_element(RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
fac76f9c 3039
ac4d0be5 3040 ripng_if_init();
3041 ripng_debug_init();
718e3744 3042
ac4d0be5 3043 /* Access list install. */
3044 access_list_init();
3045 access_list_add_hook(ripng_distribute_update_all_wrapper);
3046 access_list_delete_hook(ripng_distribute_update_all_wrapper);
718e3744 3047
ac4d0be5 3048 /* Prefix list initialize.*/
3049 prefix_list_init();
3050 prefix_list_add_hook(ripng_distribute_update_all);
3051 prefix_list_delete_hook(ripng_distribute_update_all);
718e3744 3052
ac4d0be5 3053 /* Distribute list install. */
3054 distribute_list_init(RIPNG_NODE);
3055 distribute_list_add_hook(ripng_distribute_update);
3056 distribute_list_delete_hook(ripng_distribute_update);
718e3744 3057
ac4d0be5 3058 /* Route-map for interface. */
3059 ripng_route_map_init();
3060 ripng_offset_init();
a94434b6 3061
ac4d0be5 3062 route_map_add_hook(ripng_routemap_update);
3063 route_map_delete_hook(ripng_routemap_update);
718e3744 3064
ac4d0be5 3065 if_rmap_init(RIPNG_NODE);
3066 if_rmap_hook_add(ripng_if_rmap_update);
3067 if_rmap_hook_delete(ripng_if_rmap_update);
718e3744 3068}