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