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