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