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