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