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