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