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