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