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