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