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