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