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