blob: d8c34e80617bdee893219a2bb28db187c7b292ee [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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/* For struct udphdr. */
25#include <netinet/udp.h>
26
27#include "prefix.h"
28#include "filter.h"
29#include "log.h"
30#include "thread.h"
31#include "memory.h"
32#include "if.h"
33#include "stream.h"
34#include "table.h"
35#include "command.h"
36#include "sockopt.h"
37#include "distribute.h"
38#include "plist.h"
39#include "routemap.h"
paul718e3742002-12-13 20:15:29 +000040
41#include "ripngd/ripngd.h"
42#include "ripngd/ripng_route.h"
43#include "ripngd/ripng_debug.h"
paul41ce9262003-04-19 15:54:03 +000044#include "ripngd/ripng_ifrmap.h"
paul718e3742002-12-13 20:15:29 +000045
46#define min(a, b) ((a) < (b) ? (a) : (b))
47
48/* RIPng structure which includes many parameters related to RIPng
49 protocol. If ripng couldn't active or ripng doesn't configured,
50 ripng->fd must be negative value. */
51struct ripng *ripng = NULL;
52
53enum
54{
55 ripng_all_route,
56 ripng_changed_route,
57 ripng_split_horizon,
58 ripng_no_split_horizon
59};
60
61/* Prototypes. */
62void
63ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int);
64
65int
66ripng_triggered_update (struct thread *);
67
68/* RIPng next hop specification. */
69struct ripng_nexthop
70{
71 enum ripng_nexthop_type
72 {
73 RIPNG_NEXTHOP_UNSPEC,
74 RIPNG_NEXTHOP_ADDRESS
75 } flag;
76 struct in6_addr address;
77};
78
79/* Utility function for making IPv6 address string. */
80const char *
81inet6_ntop (struct in6_addr *p)
82{
83 static char buf[INET6_ADDRSTRLEN];
84
85 inet_ntop (AF_INET6, p, buf, INET6_ADDRSTRLEN);
86
87 return buf;
88}
89
90/* Allocate new ripng information. */
91struct ripng_info *
92ripng_info_new ()
93{
94 struct ripng_info *new;
95
96 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
97 return new;
98}
99
100/* Free ripng information. */
101void
102ripng_info_free (struct ripng_info *rinfo)
103{
104 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
105}
106
107static int
108setsockopt_so_recvbuf (int sock, int size)
109{
110 int ret;
111
112 ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int));
113 if (ret < 0)
114 zlog (NULL, LOG_ERR, "can't setsockopt SO_RCVBUF");
115 return ret;
116}
117
118/* Create ripng socket. */
119int
120ripng_make_socket (void)
121{
122 int ret;
123 int sock;
124 struct sockaddr_in6 ripaddr;
125
126 sock = socket (AF_INET6, SOCK_DGRAM, 0);
127 if (sock < 0)
128 {
129 zlog (NULL, LOG_ERR, "Can't make ripng socket");
130 return sock;
131 }
132
133 ret = setsockopt_so_recvbuf (sock, 8096);
134 if (ret < 0)
135 return ret;
136 ret = setsockopt_ipv6_pktinfo (sock, 1);
137 if (ret < 0)
138 return ret;
139 ret = setsockopt_ipv6_multicast_hops (sock, 255);
140 if (ret < 0)
141 return ret;
142 ret = setsockopt_ipv6_multicast_loop (sock, 0);
143 if (ret < 0)
144 return ret;
145 ret = setsockopt_ipv6_hoplimit (sock, 1);
146 if (ret < 0)
147 return ret;
148
149 memset (&ripaddr, 0, sizeof (ripaddr));
150 ripaddr.sin6_family = AF_INET6;
151#ifdef SIN6_LEN
152 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
153#endif /* SIN6_LEN */
154 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
155
156 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
157 if (ret < 0)
158 {
159 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", strerror (errno));
160 return ret;
161 }
162 return sock;
163}
164
165/* Send RIPng packet. */
166int
167ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
168 struct interface *ifp)
169{
170 int ret;
171 struct msghdr msg;
172 struct iovec iov;
173 struct cmsghdr *cmsgptr;
174 char adata [256];
175 struct in6_pktinfo *pkt;
176 struct sockaddr_in6 addr;
177
178#ifdef DEBUG
179 if (to)
180 zlog_info ("DEBUG RIPng: send to %s", inet6_ntop (&to->sin6_addr));
181 zlog_info ("DEBUG RIPng: send if %s", ifp->name);
182 zlog_info ("DEBUG RIPng: send packet size %d", bufsize);
183#endif /* DEBUG */
184
185 memset (&addr, 0, sizeof (struct sockaddr_in6));
186 addr.sin6_family = AF_INET6;
187#ifdef SIN6_LEN
188 addr.sin6_len = sizeof (struct sockaddr_in6);
189#endif /* SIN6_LEN */
190 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
191
192 /* When destination is specified. */
193 if (to != NULL)
194 {
195 addr.sin6_addr = to->sin6_addr;
196 addr.sin6_port = to->sin6_port;
197 }
198 else
199 {
200 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
201 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
202 }
203
204 msg.msg_name = (void *) &addr;
205 msg.msg_namelen = sizeof (struct sockaddr_in6);
206 msg.msg_iov = &iov;
207 msg.msg_iovlen = 1;
208 msg.msg_control = (void *) adata;
209 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
210
211 iov.iov_base = buf;
212 iov.iov_len = bufsize;
213
214 cmsgptr = (struct cmsghdr *)adata;
215 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
216 cmsgptr->cmsg_level = IPPROTO_IPV6;
217 cmsgptr->cmsg_type = IPV6_PKTINFO;
218
219 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
220 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
221 pkt->ipi6_ifindex = ifp->ifindex;
222
223 ret = sendmsg (ripng->sock, &msg, 0);
224
225 if (ret < 0)
226 zlog_warn ("RIPng send fail on %s: %s", ifp->name, strerror (errno));
227
228 return ret;
229}
230
231/* Receive UDP RIPng packet from socket. */
232int
233ripng_recv_packet (int sock, u_char *buf, int bufsize,
234 struct sockaddr_in6 *from, unsigned int *ifindex,
235 int *hoplimit)
236{
237 int ret;
238 struct msghdr msg;
239 struct iovec iov;
240 struct cmsghdr *cmsgptr;
241 struct in6_addr dst;
242
243 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
244 point I can't determine size of cmsghdr */
245 char adata[1024];
246
247 /* Fill in message and iovec. */
248 msg.msg_name = (void *) from;
249 msg.msg_namelen = sizeof (struct sockaddr_in6);
250 msg.msg_iov = &iov;
251 msg.msg_iovlen = 1;
252 msg.msg_control = (void *) adata;
253 msg.msg_controllen = sizeof adata;
254 iov.iov_base = buf;
255 iov.iov_len = bufsize;
256
257 /* If recvmsg fail return minus value. */
258 ret = recvmsg (sock, &msg, 0);
259 if (ret < 0)
260 return ret;
261
262 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
263 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
264 {
265 /* I want interface index which this packet comes from. */
266 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
267 cmsgptr->cmsg_type == IPV6_PKTINFO)
268 {
269 struct in6_pktinfo *ptr;
270
271 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
272 *ifindex = ptr->ipi6_ifindex;
273 dst = ptr->ipi6_addr;
274
275 if (*ifindex == 0)
276 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
277 }
278
279 /* Incoming packet's multicast hop limit. */
280 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
281 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
282 *hoplimit = *((int *) CMSG_DATA (cmsgptr));
283 }
284
285 /* Hoplimit check shold be done when destination address is
286 multicast address. */
287 if (! IN6_IS_ADDR_MULTICAST (&dst))
288 *hoplimit = -1;
289
290 return ret;
291}
292
293/* Dump rip packet */
294void
295ripng_packet_dump (struct ripng_packet *packet, int size, char *sndrcv)
296{
297 caddr_t lim;
298 struct rte *rte;
299 char *command_str;
300
301 /* Set command string. */
302 if (packet->command == RIPNG_REQUEST)
303 command_str = "request";
304 else if (packet->command == RIPNG_RESPONSE)
305 command_str = "response";
306 else
307 command_str = "unknown";
308
309 /* Dump packet header. */
310 zlog_info ("%s %s version %d packet size %d",
311 sndrcv, command_str, packet->version, size);
312
313 /* Dump each routing table entry. */
314 rte = packet->rte;
315
316 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
317 {
318 if (rte->metric == RIPNG_METRIC_NEXTHOP)
319 zlog_info (" nexthop %s/%d", inet6_ntop (&rte->addr), rte->prefixlen);
320 else
321 zlog_info (" %s/%d metric %d tag %d",
322 inet6_ntop (&rte->addr), rte->prefixlen,
323 rte->metric, ntohs (rte->tag));
324 }
325}
326
327/* RIPng next hop address RTE (Route Table Entry). */
328void
329ripng_nexthop_rte (struct rte *rte,
330 struct sockaddr_in6 *from,
331 struct ripng_nexthop *nexthop)
332{
333 char buf[INET6_BUFSIZ];
334
335 /* Logging before checking RTE. */
336 if (IS_RIPNG_DEBUG_RECV)
337 zlog_info ("RIPng nexthop RTE address %s tag %d prefixlen %d",
338 inet6_ntop (&rte->addr), ntohs (rte->tag), rte->prefixlen);
339
340 /* RFC2080 2.1.1 Next Hop:
341 The route tag and prefix length in the next hop RTE must be
342 set to zero on sending and ignored on receiption. */
343 if (ntohs (rte->tag) != 0)
344 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
345 ntohs (rte->tag), inet6_ntop (&from->sin6_addr));
346
347 if (rte->prefixlen != 0)
348 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
349 rte->prefixlen, inet6_ntop (&from->sin6_addr));
350
351 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
352 next hop RTE indicates that the next hop address should be the
353 originator of the RIPng advertisement. An address specified as a
354 next hop must be a link-local address. */
355 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
356 {
357 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
358 memset (&nexthop->address, 0, sizeof (struct in6_addr));
359 return;
360 }
361
362 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
363 {
364 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
365 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
366 return;
367 }
368
369 /* The purpose of the next hop RTE is to eliminate packets being
370 routed through extra hops in the system. It is particularly useful
371 when RIPng is not being run on all of the routers on a network.
372 Note that next hop RTE is "advisory". That is, if the provided
373 information is ignored, a possibly sub-optimal, but absolutely
374 valid, route may be taken. If the received next hop address is not
375 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
376 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
377 inet6_ntop (&rte->addr),
378 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
379
380 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
381 memset (&nexthop->address, 0, sizeof (struct in6_addr));
382
383 return;
384}
385
386/* If ifp has same link-local address then return 1. */
387int
388ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
389{
390 listnode listnode;
391 struct connected *connected;
392 struct prefix *p;
393
394 for (listnode = listhead (ifp->connected); listnode; nextnode (listnode))
395 if ((connected = getdata (listnode)) != NULL)
396 {
397 p = connected->address;
398
399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
408int
409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
423 /* Delete this route from the kernel. */
424 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
425 &rinfo->nexthop, rinfo->ifindex);
426 rinfo->flags &= ~RIPNG_RTF_FIB;
427
428 /* Aggregate count decrement. */
429 ripng_aggregate_decrement (rp, rinfo);
430
431 /* Unlock route_node. */
432 rp->info = NULL;
433 route_unlock_node (rp);
434
435 /* Free RIPng routing information. */
436 ripng_info_free (rinfo);
437
438 return 0;
439}
440
441/* Timeout RIPng routes. */
442int
443ripng_timeout (struct thread *t)
444{
445 struct ripng_info *rinfo;
446 struct route_node *rp;
447
448 rinfo = THREAD_ARG (t);
449 rinfo->t_timeout = NULL;
450
451 /* Get route_node pointer. */
452 rp = rinfo->rp;
453
454 /* - The garbage-collection timer is set for 120 seconds. */
455 RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
456 ripng->garbage_time);
457
458 /* - The metric for the route is set to 16 (infinity). This causes
459 the route to be removed from service. */
460 rinfo->metric = RIPNG_METRIC_INFINITY;
461
462 /* - The route change flag is to indicate that this entry has been
463 changed. */
464 rinfo->flags |= RIPNG_RTF_CHANGED;
465
466 /* - The output process is signalled to trigger a response. */
467 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
468
469 return 0;
470}
471
472void
473ripng_timeout_update (struct ripng_info *rinfo)
474{
475 if (rinfo->metric != RIPNG_METRIC_INFINITY)
476 {
477 RIPNG_TIMER_OFF (rinfo->t_timeout);
478 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
479 }
480}
481
482/* Process RIPng route according to RFC2080. */
483void
484ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
485 struct ripng_nexthop *ripng_nexthop,
486 struct interface *ifp)
487{
488 struct prefix_ipv6 p;
489 struct route_node *rp;
490 struct ripng_info *rinfo;
491 struct ripng_interface *ri;
492 struct in6_addr *nexthop;
493 u_char oldmetric;
494 int same = 0;
495
496 /* Make prefix structure. */
497 memset (&p, 0, sizeof (struct prefix_ipv6));
498 p.family = AF_INET6;
499 /* p.prefix = rte->addr; */
500 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
501 p.prefixlen = rte->prefixlen;
502
503 /* Make sure mask is applied. */
504 /* XXX We have to check the prefix is valid or not before call
505 apply_mask_ipv6. */
506 apply_mask_ipv6 (&p);
507
508 /* Apply input filters. */
509 ri = ifp->info;
510
511 if (ri->list[RIPNG_FILTER_IN])
512 {
513 if (access_list_apply (ri->list[RIPNG_FILTER_IN], &p) == FILTER_DENY)
514 {
515 if (IS_RIPNG_DEBUG_PACKET)
516 zlog_info ("RIPng %s/%d is filtered by distribute in",
517 inet6_ntop (&p.prefix), p.prefixlen);
518 return;
519 }
520 }
521 if (ri->prefix[RIPNG_FILTER_IN])
522 {
523 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], &p) == PREFIX_DENY)
524 {
525 if (IS_RIPNG_DEBUG_PACKET)
526 zlog_info ("RIPng %s/%d is filtered by prefix-list in",
527 inet6_ntop (&p.prefix), p.prefixlen);
528 return;
529 }
530 }
531
532 /* Modify entry. */
533 if (ri->routemap[RIPNG_FILTER_IN])
534 {
535 int ret;
536 struct ripng_info newinfo;
537
paul41ce9262003-04-19 15:54:03 +0000538 memset (&newinfo, 0, sizeof (struct ripng_info));
paul718e3742002-12-13 20:15:29 +0000539 newinfo.metric = rte->metric;
540
541 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
542 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
543
544 if (ret == RMAP_DENYMATCH)
545 {
546 if (IS_RIPNG_DEBUG_PACKET)
547 zlog_info ("RIPng %s/%d is filtered by route-map in",
548 inet6_ntop (&p.prefix), p.prefixlen);
549 return;
550 }
551
552 rte->metric = newinfo.metric;
553 }
554
555 /* Set nexthop pointer. */
556 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
557 nexthop = &ripng_nexthop->address;
558 else
559 nexthop = &from->sin6_addr;
560
561 /* Lookup RIPng routing table. */
562 rp = route_node_get (ripng->table, (struct prefix *) &p);
563
564 if (rp->info == NULL)
565 {
566 /* Now, check to see whether there is already an explicit route
567 for the destination prefix. If there is no such route, add
568 this route to the routing table, unless the metric is
569 infinity (there is no point in adding a route which
570 unusable). */
571 if (rte->metric != RIPNG_METRIC_INFINITY)
572 {
573 rinfo = ripng_info_new ();
574
575 /* - Setting the destination prefix and length to those in
576 the RTE. */
577 rp->info = rinfo;
578 rinfo->rp = rp;
579
580 /* - Setting the metric to the newly calculated metric (as
581 described above). */
582 rinfo->metric = rte->metric;
583 rinfo->tag = ntohs (rte->tag);
584
585 /* - Set the next hop address to be the address of the router
586 from which the datagram came or the next hop address
587 specified by a next hop RTE. */
588 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
589 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
590 rinfo->ifindex = ifp->ifindex;
591
592 /* - Initialize the timeout for the route. If the
593 garbage-collection timer is running for this route, stop it. */
594 ripng_timeout_update (rinfo);
595
596 /* - Set the route change flag. */
597 rinfo->flags |= RIPNG_RTF_CHANGED;
598
599 /* - Signal the output process to trigger an update (see section
600 2.5). */
601 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
602
603 /* Finally, route goes into the kernel. */
604 rinfo->type = ZEBRA_ROUTE_RIPNG;
605 rinfo->sub_type = RIPNG_ROUTE_RTE;
606
607 ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex);
608 rinfo->flags |= RIPNG_RTF_FIB;
609
610 /* Aggregate check. */
611 ripng_aggregate_increment (rp, rinfo);
612 }
613 }
614 else
615 {
616 rinfo = rp->info;
617
618 /* If there is an existing route, compare the next hop address
619 to the address of the router from which the datagram came.
620 If this datagram is from the same router as the existing
621 route, reinitialize the timeout. */
622 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
623 && (rinfo->ifindex == ifp->ifindex));
624
625 if (same)
626 ripng_timeout_update (rinfo);
627
628 /* Next, compare the metrics. If the datagram is from the same
629 router as the existing route, and the new metric is different
630 than the old one; or, if the new metric is lower than the old
631 one; do the following actions: */
632 if ((same && rinfo->metric != rte->metric) ||
633 rte->metric < rinfo->metric)
634 {
635 /* - Adopt the route from the datagram. That is, put the
636 new metric in, and adjust the next hop address (if
637 necessary). */
638 oldmetric = rinfo->metric;
639 rinfo->metric = rte->metric;
640 rinfo->tag = ntohs (rte->tag);
641
642 if (! IN6_ARE_ADDR_EQUAL (&rinfo->nexthop, nexthop))
643 {
644 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
645 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex);
646 rinfo->flags |= RIPNG_RTF_FIB;
647
648 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
649 }
650 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
651 rinfo->ifindex = ifp->ifindex;
652
653 /* - Set the route change flag and signal the output process
654 to trigger an update. */
655 rinfo->flags |= RIPNG_RTF_CHANGED;
656 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
657
658 /* - If the new metric is infinity, start the deletion
659 process (described above); */
660 if (rinfo->metric == RIPNG_METRIC_INFINITY)
661 {
662 /* If the new metric is infinity, the deletion process
663 begins for the route, which is no longer used for
664 routing packets. Note that the deletion process is
665 started only when the metric is first set to
666 infinity. If the metric was already infinity, then a
667 new deletion process is not started. */
668 if (oldmetric != RIPNG_METRIC_INFINITY)
669 {
670 /* - The garbage-collection timer is set for 120 seconds. */
671 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
672 ripng_garbage_collect, ripng->garbage_time);
673 RIPNG_TIMER_OFF (rinfo->t_timeout);
674
675 /* - The metric for the route is set to 16
676 (infinity). This causes the route to be removed
677 from service.*/
678 /* - The route change flag is to indicate that this
679 entry has been changed. */
680 /* - The output process is signalled to trigger a
681 response. */
682 ; /* Above processes are already done previously. */
683 }
684 }
685 else
686 {
687 /* otherwise, re-initialize the timeout. */
688 ripng_timeout_update (rinfo);
689
690 /* Should a new route to this network be established
691 while the garbage-collection timer is running, the
692 new route will replace the one that is about to be
693 deleted. In this case the garbage-collection timer
694 must be cleared. */
695 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
696 }
697 }
698 /* Unlock tempolary lock of the route. */
699 route_unlock_node (rp);
700 }
701}
702
703/* Add redistributed route to RIPng table. */
704void
705ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
706 unsigned int ifindex)
707{
708 struct route_node *rp;
709 struct ripng_info *rinfo;
710
711 /* Redistribute route */
712 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
713 return;
714 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
715 return;
716
717 rp = route_node_get (ripng->table, (struct prefix *) p);
718 rinfo = rp->info;
719
720 if (rinfo)
721 {
722 RIPNG_TIMER_OFF (rinfo->t_timeout);
723 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
724 route_unlock_node (rp);
725 }
726 else
727 {
728 rinfo = ripng_info_new ();
729 ripng_aggregate_increment (rp, rinfo);
730 }
731
732 rinfo->type = type;
733 rinfo->sub_type = sub_type;
734 rinfo->ifindex = ifindex;
735 rinfo->metric = 1;
736 rinfo->flags |= RIPNG_RTF_FIB;
737
738 rinfo->rp = rp;
739 rp->info = rinfo;
740}
741
742/* Delete redistributed route to RIPng table. */
743void
744ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
745 unsigned int ifindex)
746{
747 struct route_node *rp;
748 struct ripng_info *rinfo;
749
750 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
751 return;
752 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
753 return;
754
755 rp = route_node_lookup (ripng->table, (struct prefix *) p);
756
757 if (rp)
758 {
759 rinfo = rp->info;
760
761 if (rinfo != NULL
762 && rinfo->type == type
763 && rinfo->sub_type == sub_type
764 && rinfo->ifindex == ifindex)
765 {
766 rp->info = NULL;
767
768 RIPNG_TIMER_OFF (rinfo->t_timeout);
769 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
770
771 ripng_info_free (rinfo);
772
773 route_unlock_node (rp);
774 }
775
776 /* For unlock route_node_lookup (). */
777 route_unlock_node (rp);
778 }
779}
780
781/* Withdraw redistributed route. */
782void
783ripng_redistribute_withdraw (int type)
784{
785 struct route_node *rp;
786 struct ripng_info *rinfo;
787
788 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
789 if ((rinfo = rp->info) != NULL)
790 {
791 if (rinfo->type == type)
792 {
793 rp->info = NULL;
794
795 RIPNG_TIMER_OFF (rinfo->t_timeout);
796 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
797
798 ripng_info_free (rinfo);
799
800 route_unlock_node (rp);
801 }
802 }
803}
804
805/* RIP routing information. */
806void
807ripng_response_process (struct ripng_packet *packet, int size,
808 struct sockaddr_in6 *from, struct interface *ifp,
809 int hoplimit)
810{
811 caddr_t lim;
812 struct rte *rte;
813 struct ripng_nexthop nexthop;
814
815 /* RFC2080 2.4.2 Response Messages:
816 The Response must be ignored if it is not from the RIPng port. */
817 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
818 {
819 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
820 ntohs (from->sin6_port), inet6_ntop (&from->sin6_addr));
821 return;
822 }
823
824 /* The datagram's IPv6 source address should be checked to see
825 whether the datagram is from a valid neighbor; the source of the
826 datagram must be a link-local address. */
827 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
828 {
829 zlog_warn ("RIPng packet comes from non link local address %s",
830 inet6_ntop (&from->sin6_addr));
831 return;
832 }
833
834 /* It is also worth checking to see whether the response is from one
835 of the router's own addresses. Interfaces on broadcast networks
836 may receive copies of their own multicasts immediately. If a
837 router processes its own output as new input, confusion is likely,
838 and such datagrams must be ignored. */
839 if (ripng_lladdr_check (ifp, &from->sin6_addr))
840 {
841 zlog_warn ("RIPng packet comes from my own link local address %s",
842 inet6_ntop (&from->sin6_addr));
843 return;
844 }
845
846 /* As an additional check, periodic advertisements must have their
847 hop counts set to 255, and inbound, multicast packets sent from the
848 RIPng port (i.e. periodic advertisement or triggered update
849 packets) must be examined to ensure that the hop count is 255. */
850 if (hoplimit >= 0 && hoplimit != 255)
851 {
852 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
853 hoplimit, inet6_ntop (&from->sin6_addr));
854 return;
855 }
856
857 /* Reset nexthop. */
858 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
859 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
860
861 /* Set RTE pointer. */
862 rte = packet->rte;
863
864 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
865 {
866 /* First of all, we have to check this RTE is next hop RTE or
867 not. Next hop RTE is completely different with normal RTE so
868 we need special treatment. */
869 if (rte->metric == RIPNG_METRIC_NEXTHOP)
870 {
871 ripng_nexthop_rte (rte, from, &nexthop);
872 continue;
873 }
874
875 /* RTE information validation. */
876
877 /* - is the destination prefix valid (e.g., not a multicast
878 prefix and not a link-local address) A link-local address
879 should never be present in an RTE. */
880 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
881 {
882 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
883 inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
884 continue;
885 }
886 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
887 {
888 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
889 inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
890 continue;
891 }
892 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
893 {
894 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
895 inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
896 continue;
897 }
898
899 /* - is the prefix length valid (i.e., between 0 and 128,
900 inclusive) */
901 if (rte->prefixlen > 128)
902 {
903 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
904 inet6_ntop (&rte->addr), rte->prefixlen,
905 inet6_ntop (&from->sin6_addr), ifp->name);
906 continue;
907 }
908
909 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
910 if (! (rte->metric >= 1 && rte->metric <= 16))
911 {
912 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
913 inet6_ntop (&from->sin6_addr), ifp->name);
914 continue;
915 }
916
917 /* Metric calculation. */
918 rte->metric += ifp->metric;
919 if (rte->metric > RIPNG_METRIC_INFINITY)
920 rte->metric = RIPNG_METRIC_INFINITY;
921
922 /* Routing table updates. */
923 ripng_route_process (rte, from, &nexthop, ifp);
924 }
925}
926
927/* Response to request message. */
928void
929ripng_request_process (struct ripng_packet *packet,int size,
930 struct sockaddr_in6 *from, struct interface *ifp)
931{
932 caddr_t lim;
933 struct rte *rte;
934 struct prefix_ipv6 p;
935 struct route_node *rp;
936 struct ripng_info *rinfo;
937 struct ripng_interface *ri;
938
939 /* Check RIPng process is enabled on this interface. */
940 ri = ifp->info;
941 if (! ri->running)
942 return;
943
944 /* When passive interface is specified, suppress responses */
945 if (ri->passive)
946 return;
947
948 lim = ((caddr_t) packet) + size;
949 rte = packet->rte;
950
951 /* The Request is processed entry by entry. If there are no
952 entries, no response is given. */
953 if (lim == (caddr_t) rte)
954 return;
955
956 /* There is one special case. If there is exactly one entry in the
957 request, and it has a destination prefix of zero, a prefix length
958 of zero, and a metric of infinity (i.e., 16), then this is a
959 request to send the entire routing table. In that case, a call
960 is made to the output process to send the routing table to the
961 requesting address/port. */
962 if (lim == ((caddr_t) (rte + 1)) &&
963 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
964 rte->prefixlen == 0 &&
965 rte->metric == RIPNG_METRIC_INFINITY)
966 {
967 /* All route with split horizon */
968 ripng_output_process (ifp, from, ripng_all_route, ripng_split_horizon);
969 }
970 else
971 {
972 /* Except for this special case, processing is quite simple.
973 Examine the list of RTEs in the Request one by one. For each
974 entry, look up the destination in the router's routing
975 database and, if there is a route, put that route's metric in
976 the metric field of the RTE. If there is no explicit route
977 to the specified destination, put infinity in the metric
978 field. Once all the entries have been filled in, change the
979 command from Request to Response and send the datagram back
980 to the requestor. */
981 memset (&p, 0, sizeof (struct prefix_ipv6));
982 p.family = AF_INET6;
983
984 for (; ((caddr_t) rte) < lim; rte++)
985 {
986 p.prefix = rte->addr;
987 p.prefixlen = rte->prefixlen;
988 apply_mask_ipv6 (&p);
989
990 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
991
992 if (rp)
993 {
994 rinfo = rp->info;
995 rte->metric = rinfo->metric;
996 route_unlock_node (rp);
997 }
998 else
999 rte->metric = RIPNG_METRIC_INFINITY;
1000 }
1001 packet->command = RIPNG_RESPONSE;
1002
1003 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1004 }
1005}
1006
1007/* First entry point of reading RIPng packet. */
1008int
1009ripng_read (struct thread *thread)
1010{
1011 int len;
1012 int sock;
1013 struct sockaddr_in6 from;
1014 struct ripng_packet *packet;
1015 unsigned int ifindex;
1016 struct interface *ifp;
1017 int hoplimit = -1;
1018
1019 /* Check ripng is active and alive. */
1020 assert (ripng != NULL);
1021 assert (ripng->sock >= 0);
1022
1023 /* Fetch thread data and set read pointer to empty for event
1024 managing. `sock' sould be same as ripng->sock. */
1025 sock = THREAD_FD (thread);
1026 ripng->t_read = NULL;
1027
1028 /* Add myself to the next event. */
1029 ripng_event (RIPNG_READ, sock);
1030
1031 /* Read RIPng packet. */
1032 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1033 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1034 &hoplimit);
1035 if (len < 0)
1036 {
1037 zlog_warn ("RIPng recvfrom failed: %s.", strerror (errno));
1038 return len;
1039 }
1040
1041 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1042 (4)) must be multiple size of one RTE size (20). */
1043 if (((len - 4) % 20) != 0)
1044 {
1045 zlog_warn ("RIPng invalid packet size %d from %s", len,
1046 inet6_ntop (&from.sin6_addr));
1047 return 0;
1048 }
1049
1050 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1051 ifp = if_lookup_by_index (ifindex);
1052
1053 /* RIPng packet received. */
1054 if (IS_RIPNG_DEBUG_EVENT)
1055 zlog_info ("RIPng packet received from %s port %d on %s",
1056 inet6_ntop (&from.sin6_addr), ntohs (from.sin6_port),
1057 ifp ? ifp->name : "unknown");
1058
1059 /* Logging before packet checking. */
1060 if (IS_RIPNG_DEBUG_RECV)
1061 ripng_packet_dump (packet, len, "RECV");
1062
1063 /* Packet comes from unknown interface. */
1064 if (ifp == NULL)
1065 {
1066 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1067 return 0;
1068 }
1069
1070 /* Packet version mismatch checking. */
1071 if (packet->version != ripng->version)
1072 {
1073 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1074 packet->version, ripng->version);
1075 return 0;
1076 }
1077
1078 /* Process RIPng packet. */
1079 switch (packet->command)
1080 {
1081 case RIPNG_REQUEST:
1082 ripng_request_process (packet, len, &from, ifp);
1083 break;
1084 case RIPNG_RESPONSE:
1085 ripng_response_process (packet, len, &from, ifp, hoplimit);
1086 break;
1087 default:
1088 zlog_warn ("Invalid RIPng command %d", packet->command);
1089 break;
1090 }
1091 return 0;
1092}
1093
1094/* Walk down the RIPng routing table then clear changed flag. */
1095void
1096ripng_clear_changed_flag ()
1097{
1098 struct route_node *rp;
1099 struct ripng_info *rinfo;
1100
1101 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1102 if ((rinfo = rp->info) != NULL)
1103 if (rinfo->flags & RIPNG_RTF_CHANGED)
1104 rinfo->flags &= ~RIPNG_RTF_CHANGED;
1105}
1106
1107/* Regular update of RIPng route. Send all routing formation to RIPng
1108 enabled interface. */
1109int
1110ripng_update (struct thread *t)
1111{
1112 listnode node;
1113 struct interface *ifp;
1114 struct ripng_interface *ri;
1115
1116 /* Clear update timer thread. */
1117 ripng->t_update = NULL;
1118
1119 /* Logging update event. */
1120 if (IS_RIPNG_DEBUG_EVENT)
1121 zlog_info ("RIPng update timer expired!");
1122
1123 /* Supply routes to each interface. */
1124 for (node = listhead (iflist); node; nextnode (node))
1125 {
1126 ifp = getdata (node);
1127 ri = ifp->info;
1128
1129 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1130 continue;
1131
1132 if (! ri->running)
1133 continue;
1134
1135 /* When passive interface is specified, suppress announce to the
1136 interface. */
1137 if (ri->passive)
1138 continue;
1139
1140#if RIPNG_ADVANCED
1141 if (ri->ri_send == RIPNG_SEND_OFF)
1142 {
1143 if (IS_RIPNG_DEBUG_EVENT)
1144 zlog (NULL, LOG_INFO,
1145 "[Event] RIPng send to if %d is suppressed by config",
1146 ifp->ifindex);
1147 continue;
1148 }
1149#endif /* RIPNG_ADVANCED */
1150
1151 ripng_output_process (ifp, NULL, ripng_all_route, ripng_split_horizon);
1152 }
1153
1154 /* Triggered updates may be suppressed if a regular update is due by
1155 the time the triggered update would be sent. */
1156 if (ripng->t_triggered_interval)
1157 {
1158 thread_cancel (ripng->t_triggered_interval);
1159 ripng->t_triggered_interval = NULL;
1160 }
1161 ripng->trigger = 0;
1162
1163 /* Reset flush event. */
1164 ripng_event (RIPNG_UPDATE_EVENT, 0);
1165
1166 return 0;
1167}
1168
1169/* Triggered update interval timer. */
1170int
1171ripng_triggered_interval (struct thread *t)
1172{
1173 ripng->t_triggered_interval = NULL;
1174
1175 if (ripng->trigger)
1176 {
1177 ripng->trigger = 0;
1178 ripng_triggered_update (t);
1179 }
1180 return 0;
1181}
1182
1183/* Execute triggered update. */
1184int
1185ripng_triggered_update (struct thread *t)
1186{
1187 listnode node;
1188 struct interface *ifp;
1189 struct ripng_interface *ri;
1190 int interval;
1191
1192 ripng->t_triggered_update = NULL;
1193
1194 /* Cancel interval timer. */
1195 if (ripng->t_triggered_interval)
1196 {
1197 thread_cancel (ripng->t_triggered_interval);
1198 ripng->t_triggered_interval = NULL;
1199 }
1200 ripng->trigger = 0;
1201
1202 /* Logging triggered update. */
1203 if (IS_RIPNG_DEBUG_EVENT)
1204 zlog_info ("RIPng triggered update!");
1205
1206 /* Split Horizon processing is done when generating triggered
1207 updates as well as normal updates (see section 2.6). */
1208 for (node = listhead (iflist); node; nextnode (node))
1209 {
1210 ifp = getdata (node);
1211 ri = ifp->info;
1212
1213 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1214 continue;
1215
1216 if (! ri->running)
1217 continue;
1218
1219 /* When passive interface is specified, suppress announce to the
1220 interface. */
1221 if (ri->passive)
1222 continue;
1223
1224 ripng_output_process (ifp, NULL, ripng_changed_route,
1225 ripng_split_horizon);
1226 }
1227
1228 /* Once all of the triggered updates have been generated, the route
1229 change flags should be cleared. */
1230 ripng_clear_changed_flag ();
1231
1232 /* After a triggered update is sent, a timer should be set for a
1233 random interval between 1 and 5 seconds. If other changes that
1234 would trigger updates occur before the timer expires, a single
1235 update is triggered when the timer expires. */
1236 interval = (random () % 5) + 1;
1237
1238 ripng->t_triggered_interval =
1239 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1240
1241 return 0;
1242}
1243
1244/* Write routing table entry to the stream and return next index of
1245 the routing table entry in the stream. */
1246int
1247ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
1248 u_int16_t tag, u_char metric)
1249{
1250 /* RIPng packet header. */
1251 if (num == 0)
1252 {
1253 stream_putc (s, RIPNG_RESPONSE);
1254 stream_putc (s, RIPNG_V1);
1255 stream_putw (s, 0);
1256 }
1257
1258 /* Write routing table entry. */
1259 stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr));
1260 stream_putw (s, tag);
1261 stream_putc (s, p->prefixlen);
1262 stream_putc (s, metric);
1263
1264 return ++num;
1265}
1266
1267/* Send RESPONSE message to specified destination. */
1268void
1269ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
1270 int route_type, int split_horizon)
1271{
1272 int ret;
1273 struct stream *s;
1274 struct route_node *rp;
1275 struct ripng_info *rinfo;
1276 struct ripng_interface *ri;
1277 struct ripng_aggregate *aggregate;
1278 struct prefix_ipv6 *p;
1279 int num;
1280 int mtu;
1281 int rtemax;
1282 u_char metric;
1283 u_char metric_set;
1284
1285 if (IS_RIPNG_DEBUG_EVENT)
1286 zlog_info ("RIPng update routes on interface %s", ifp->name);
1287
1288 /* Output stream get from ripng structre. XXX this should be
1289 interface structure. */
1290 s = ripng->obuf;
1291
1292 /* Reset stream and RTE counter. */
1293 stream_reset (s);
1294 num = 0;
1295
1296 mtu = ifp->mtu;
1297 if (mtu < 0)
1298 mtu = IFMINMTU;
1299
1300 rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
1301 IPV6_HDRLEN -
1302 sizeof (struct udphdr) -
1303 sizeof (struct ripng_packet) +
1304 sizeof (struct rte)) / sizeof (struct rte);
1305
1306#ifdef DEBUG
1307 zlog_info ("DEBUG RIPng: ifmtu is %d", ifp->mtu);
1308 zlog_info ("DEBUG RIPng: rtemax is %d", rtemax);
1309#endif /* DEBUG */
1310
1311 /* Get RIPng interface. */
1312 ri = ifp->info;
1313
1314 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1315 {
1316 if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
1317 {
1318 p = (struct prefix_ipv6 *) &rp->p;
1319 metric = rinfo->metric;
1320
1321 /* Changed route only output. */
1322 if (route_type == ripng_changed_route &&
1323 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1324 continue;
1325
1326 /* Split horizon. */
1327 if (split_horizon == ripng_split_horizon &&
1328 rinfo->ifindex == ifp->ifindex)
1329 continue;
1330
1331 /* Apply output filters.*/
1332 if (ri->list[RIPNG_FILTER_OUT])
1333 {
1334 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
1335 (struct prefix *) p) == FILTER_DENY)
1336 {
1337 if (IS_RIPNG_DEBUG_PACKET)
1338 zlog_info ("RIPng %s/%d is filtered by distribute out",
1339 inet6_ntop (&p->prefix), p->prefixlen);
1340 continue;
1341 }
1342 }
1343 if (ri->prefix[RIPNG_FILTER_OUT])
1344 {
1345 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
1346 (struct prefix *) p) == PREFIX_DENY)
1347 {
1348 if (IS_RIPNG_DEBUG_PACKET)
1349 zlog_info ("RIPng %s/%d is filtered by prefix-list out",
1350 inet6_ntop (&p->prefix), p->prefixlen);
1351 continue;
1352 }
1353 }
1354
1355 /* Preparation for route-map. */
1356 metric_set = 0;
1357
1358 /* Route-map */
1359 if (ri->routemap[RIPNG_FILTER_OUT])
1360 {
1361 int ret;
1362 struct ripng_info newinfo;
1363
1364 memset (&newinfo, 0, sizeof (struct ripng_info));
1365 newinfo.metric = metric;
1366
1367 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1368 (struct prefix *) p, RMAP_RIPNG,
1369 &newinfo);
1370
1371 if (ret == RMAP_DENYMATCH)
1372 {
1373 if (IS_RIPNG_DEBUG_PACKET)
1374 zlog_info ("RIPng %s/%d is filtered by route-map out",
1375 inet6_ntop (&p->prefix), p->prefixlen);
1376 return;
1377 }
1378
1379 metric = newinfo.metric;
1380 metric_set = newinfo.metric_set;
1381 }
1382
1383 /* When the interface route-map does not set metric */
1384 if (! metric_set)
1385 {
1386 /* and the redistribute route-map is set. */
1387 if (ripng->route_map[rinfo->type].name)
1388 {
1389 int ret;
1390 struct ripng_info newinfo;
1391
1392 memset (&newinfo, 0, sizeof (struct ripng_info));
1393 newinfo.metric = metric;
1394
1395 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1396 (struct prefix *) p, RMAP_RIPNG,
1397 &newinfo);
1398
1399 if (ret == RMAP_DENYMATCH)
1400 {
1401 if (IS_RIPNG_DEBUG_PACKET)
1402 zlog_info ("RIPng %s/%d is filtered by route-map",
1403 inet6_ntop (&p->prefix), p->prefixlen);
1404 continue;
1405 }
1406
1407 metric = newinfo.metric;
1408 metric_set = newinfo.metric_set;
1409 }
1410
1411 /* When the redistribute route-map does not set metric. */
1412 if (! metric_set)
1413 {
1414 /* If the redistribute metric is set. */
1415 if (ripng->route_map[rinfo->type].metric_config
1416 && rinfo->metric != RIPNG_METRIC_INFINITY)
1417 {
1418 metric = ripng->route_map[rinfo->type].metric;
1419 }
1420 else
1421 {
1422 /* If the route is not connected or localy generated
1423 one, use default-metric value */
1424 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1425 && rinfo->type != ZEBRA_ROUTE_CONNECT
1426 && rinfo->metric != RIPNG_METRIC_INFINITY)
1427 metric = ripng->default_metric;
1428 }
1429 }
1430 }
1431
1432 /* Write RTE to the stream. */
1433 num = ripng_write_rte (num, s, p, rinfo->tag, metric);
1434 if (num == rtemax)
1435 {
1436 ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
1437 to, ifp);
1438
1439 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
1440 ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
1441 stream_get_endp(s), "SEND");
1442 num = 0;
1443 stream_reset (s);
1444 }
1445 }
1446 if ((aggregate = rp->aggregate) != NULL &&
1447 aggregate->count > 0 &&
1448 aggregate->suppress == 0)
1449 {
1450 p = (struct prefix_ipv6 *) &rp->p;
1451 metric = aggregate->metric;
1452
1453 /* Apply output filters.*/
1454 if (ri->list[RIPNG_FILTER_OUT])
1455 {
1456 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
1457 (struct prefix *) p) == FILTER_DENY)
1458 {
1459 if (IS_RIPNG_DEBUG_PACKET)
1460 zlog_info ("RIPng %s/%d is filtered by distribute out",
1461 inet6_ntop (&p->prefix), p->prefixlen);
1462 continue;
1463 }
1464 }
1465 if (ri->prefix[RIPNG_FILTER_OUT])
1466 {
1467 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
1468 (struct prefix *) p) == PREFIX_DENY)
1469 {
1470 if (IS_RIPNG_DEBUG_PACKET)
1471 zlog_info ("RIPng %s/%d is filtered by prefix-list out",
1472 inet6_ntop (&p->prefix), p->prefixlen);
1473 continue;
1474 }
1475 }
1476
1477 /* Route-map */
1478 if (ri->routemap[RIPNG_FILTER_OUT])
1479 {
1480 int ret;
1481 struct ripng_info newinfo;
1482
1483 memset (&newinfo, 0, sizeof (struct ripng_info));
1484 newinfo.metric = metric;
1485
1486 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1487 (struct prefix *) p, RMAP_RIPNG,
1488 &newinfo);
1489
1490 if (ret == RMAP_DENYMATCH)
1491 {
1492 if (IS_RIPNG_DEBUG_PACKET)
1493 zlog_info ("RIPng %s/%d is filtered by route-map out",
1494 inet6_ntop (&p->prefix), p->prefixlen);
1495 return;
1496 }
1497
1498 metric = newinfo.metric;
1499 }
1500
1501 /* Changed route only output. */
1502 if (route_type == ripng_changed_route)
1503 continue;
1504
1505 /* Write RTE to the stream. */
1506 num = ripng_write_rte (num, s, p, aggregate->tag, metric);
1507 if (num == rtemax)
1508 {
1509 ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
1510 to, ifp);
1511
1512 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
1513 ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
1514 stream_get_endp(s), "SEND");
1515 num = 0;
1516 stream_reset (s);
1517 }
1518 }
1519
1520 }
1521
1522 /* If unwritten RTE exist, flush it. */
1523 if (num != 0)
1524 {
1525 ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
1526 to, ifp);
1527
1528 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
1529 ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
1530 stream_get_endp (s), "SEND");
1531 num = 0;
1532 stream_reset (s);
1533 }
1534}
1535
1536/* Create new RIPng instance and set it to global variable. */
1537int
1538ripng_create ()
1539{
1540 /* ripng should be NULL. */
1541 assert (ripng == NULL);
1542
1543 /* Allocaste RIPng instance. */
1544 ripng = XMALLOC (0, sizeof (struct ripng));
1545 memset (ripng, 0, sizeof (struct ripng));
1546
1547 /* Default version and timer values. */
1548 ripng->version = RIPNG_V1;
1549 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1550 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1551 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1552 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1553
1554 /* Make buffer. */
1555 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1556 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1557
1558 /* Initialize RIPng routig table. */
1559 ripng->table = route_table_init ();
1560 ripng->route = route_table_init ();
1561 ripng->aggregate = route_table_init ();
1562
1563 /* Make socket. */
1564 ripng->sock = ripng_make_socket ();
1565 if (ripng->sock < 0)
1566 return ripng->sock;
1567
1568 /* Threads. */
1569 ripng_event (RIPNG_READ, ripng->sock);
1570 ripng_event (RIPNG_UPDATE_EVENT, 1);
1571
1572 return 0;
1573}
1574
1575/* Sned RIPng request to the interface. */
1576int
1577ripng_request (struct interface *ifp)
1578{
1579 struct rte *rte;
1580 struct ripng_packet ripng_packet;
1581
1582 if (IS_RIPNG_DEBUG_EVENT)
1583 zlog_info ("RIPng send request to %s", ifp->name);
1584
1585 memset (&ripng_packet, 0, sizeof (ripng_packet));
1586 ripng_packet.command = RIPNG_REQUEST;
1587 ripng_packet.version = RIPNG_V1;
1588 rte = ripng_packet.rte;
1589 rte->metric = RIPNG_METRIC_INFINITY;
1590
1591 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1592 NULL, ifp);
1593}
1594
1595/* Clean up installed RIPng routes. */
1596void
1597ripng_terminate ()
1598{
1599 struct route_node *rp;
1600 struct ripng_info *rinfo;
1601
1602 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1603 if ((rinfo = rp->info) != NULL)
1604 {
1605 if (rinfo->type == ZEBRA_ROUTE_RIPNG &&
1606 rinfo->sub_type == RIPNG_ROUTE_RTE)
1607 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
1608 &rinfo->nexthop, rinfo->ifindex);
1609 }
1610}
1611
1612int
1613ripng_update_jitter (int time)
1614{
1615 return ((rand () % (time + 1)) - (time / 2));
1616}
1617
1618void
1619ripng_event (enum ripng_event event, int sock)
1620{
1621 int ripng_request_all (struct thread *);
1622 int jitter = 0;
1623
1624 switch (event)
1625 {
1626 case RIPNG_READ:
1627 if (!ripng->t_read)
1628 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1629 break;
1630 case RIPNG_UPDATE_EVENT:
1631 if (ripng->t_update)
1632 {
1633 thread_cancel (ripng->t_update);
1634 ripng->t_update = NULL;
1635 }
1636 /* Update timer jitter. */
1637 jitter = ripng_update_jitter (ripng->update_time);
1638
1639 ripng->t_update =
1640 thread_add_timer (master, ripng_update, NULL,
1641 sock ? 2 : ripng->update_time + jitter);
1642 break;
1643 case RIPNG_TRIGGERED_UPDATE:
1644 if (ripng->t_triggered_interval)
1645 ripng->trigger = 1;
1646 else if (! ripng->t_triggered_update)
1647 ripng->t_triggered_update =
1648 thread_add_event (master, ripng_triggered_update, NULL, 0);
1649 break;
1650 default:
1651 break;
1652 }
1653}
1654
1655/* Each route type's strings and default preference. */
1656struct
1657{
1658 int key;
1659 char *str;
1660 char *str_long;
1661 int distance;
1662} route_info[] =
1663{
1664 { ZEBRA_ROUTE_SYSTEM, "X", "system", 10},
1665 { ZEBRA_ROUTE_KERNEL, "K", "kernel", 20},
1666 { ZEBRA_ROUTE_CONNECT, "C", "connected", 30},
1667 { ZEBRA_ROUTE_STATIC, "S", "static", 40},
1668 { ZEBRA_ROUTE_RIP, "R", "rip", 50},
1669 { ZEBRA_ROUTE_RIPNG, "R", "ripng", 50},
1670 { ZEBRA_ROUTE_OSPF, "O", "ospf", 60},
1671 { ZEBRA_ROUTE_OSPF6, "O", "ospf6", 60},
1672 { ZEBRA_ROUTE_BGP, "B", "bgp", 70},
1673};
1674
1675/* For messages. */
1676struct message ripng_route_info[] =
1677{
1678 { RIPNG_ROUTE_RTE, " "},
1679 { RIPNG_ROUTE_STATIC, "S"},
1680 { RIPNG_ROUTE_AGGREGATE, "a"}
1681};
1682
1683/* Print out routes update time. */
1684static void
1685ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1686{
1687 struct timeval timer_now;
1688 time_t clock;
1689 struct tm *tm;
1690#define TIME_BUF 25
1691 char timebuf [TIME_BUF];
1692 struct thread *thread;
1693
1694 gettimeofday (&timer_now, NULL);
1695
1696 if ((thread = rinfo->t_timeout) != NULL)
1697 {
1698 clock = thread->u.sands.tv_sec - timer_now.tv_sec;
1699 tm = gmtime (&clock);
1700 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1701 vty_out (vty, "%5s", timebuf);
1702 }
1703 else if ((thread = rinfo->t_garbage_collect) != NULL)
1704 {
1705 clock = thread->u.sands.tv_sec - timer_now.tv_sec;
1706 tm = gmtime (&clock);
1707 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1708 vty_out (vty, "%5s", timebuf);
1709 }
1710}
1711
1712DEFUN (show_ipv6_ripng,
1713 show_ipv6_ripng_cmd,
1714 "show ipv6 ripng",
1715 SHOW_STR
1716 IP_STR
1717 "Show RIPng routes\n")
1718{
1719 struct route_node *rp;
1720 struct ripng_info *rinfo;
1721 struct ripng_aggregate *aggregate;
1722 struct prefix_ipv6 *p;
1723 int len;
1724
1725 /* Header of display. */
1726 vty_out (vty, "%sCodes: R - RIPng%s%s"
1727 " Network "
1728 "Next Hop If Met Tag Time%s", VTY_NEWLINE,
1729 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1730
1731 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1732 {
1733 if ((aggregate = rp->aggregate) != NULL)
1734 {
1735 p = (struct prefix_ipv6 *) &rp->p;
1736
1737#ifdef DEBUG
1738 len = vty_out (vty, "Ra %d/%d %s/%d ",
1739 aggregate->count, aggregate->suppress,
1740 inet6_ntop (&p->prefix), p->prefixlen);
1741#else
1742 len = vty_out (vty, "Ra %s/%d ",
1743 inet6_ntop (&p->prefix), p->prefixlen);
1744#endif /* DEBUG */
1745
1746 len = 37 - len;
1747 if (len > 0)
1748 vty_out (vty, "%*s", len, " ");
1749
1750 vty_out (vty, "%*s", 26, " ");
1751 vty_out (vty, "%4d %3d%s", aggregate->metric,
1752 aggregate->tag,
1753 VTY_NEWLINE);
1754 }
1755
1756 if ((rinfo = rp->info) != NULL)
1757 {
1758 p = (struct prefix_ipv6 *) &rp->p;
1759
1760#ifdef DEBUG
1761 len = vty_out (vty, "%s%s 0/%d %s/%d ",
1762 route_info[rinfo->type].str,
1763 rinfo->suppress ? "s" : " ",
1764 rinfo->suppress,
1765 inet6_ntop (&p->prefix), p->prefixlen);
1766#else
1767 len = vty_out (vty, "%s%s %s/%d ",
1768 route_info[rinfo->type].str,
1769 rinfo->suppress ? "s" : " ",
1770 inet6_ntop (&p->prefix), p->prefixlen);
1771#endif /* DEBUG */
1772 len = 37 - len;
1773 if (len > 0)
1774 vty_out (vty, "%*s", len, " ");
1775
1776 len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop));
1777
1778 len = 26 - len;
1779 if (len > 0)
1780 vty_out (vty, "%*s", len, " ");
1781
1782 vty_out (vty, "%2d %2d %3d ",
1783 rinfo->ifindex, rinfo->metric, rinfo->tag);
1784
1785 if (rinfo->sub_type == RIPNG_ROUTE_RTE)
1786 ripng_vty_out_uptime (vty, rinfo);
1787
1788 vty_out (vty, "%s", VTY_NEWLINE);
1789 }
1790 }
1791
1792 return CMD_SUCCESS;
1793}
1794
1795DEFUN (router_ripng,
1796 router_ripng_cmd,
1797 "router ripng",
1798 "Enable a routing process\n"
1799 "Make RIPng instance command\n")
1800{
1801 int ret;
1802
1803 vty->node = RIPNG_NODE;
1804
1805 if (!ripng)
1806 {
1807 ret = ripng_create ();
1808
1809 /* Notice to user we couldn't create RIPng. */
1810 if (ret < 0)
1811 {
1812 zlog_warn ("can't create RIPng");
1813 return CMD_WARNING;
1814 }
1815 }
1816
1817 return CMD_SUCCESS;
1818}
1819
1820DEFUN (ripng_route,
1821 ripng_route_cmd,
1822 "route IPV6ADDR",
1823 "Static route setup\n"
1824 "Set static RIPng route announcement\n")
1825{
1826 int ret;
1827 struct prefix_ipv6 p;
1828 struct route_node *rp;
1829
1830 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
1831 if (ret <= 0)
1832 {
1833 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
1834 return CMD_WARNING;
1835 }
1836 apply_mask_ipv6 (&p);
1837
1838 rp = route_node_get (ripng->route, (struct prefix *) &p);
1839 if (rp->info)
1840 {
1841 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
1842 route_unlock_node (rp);
1843 return CMD_WARNING;
1844 }
1845 rp->info = (void *)1;
1846
1847 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
1848
1849 return CMD_SUCCESS;
1850}
1851
1852DEFUN (no_ripng_route,
1853 no_ripng_route_cmd,
1854 "no route IPV6ADDR",
1855 NO_STR
1856 "Static route setup\n"
1857 "Delete static RIPng route announcement\n")
1858{
1859 int ret;
1860 struct prefix_ipv6 p;
1861 struct route_node *rp;
1862
1863 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
1864 if (ret <= 0)
1865 {
1866 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
1867 return CMD_WARNING;
1868 }
1869 apply_mask_ipv6 (&p);
1870
1871 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
1872 if (! rp)
1873 {
1874 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
1875 return CMD_WARNING;
1876 }
1877
1878 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
1879 route_unlock_node (rp);
1880
1881 rp->info = NULL;
1882 route_unlock_node (rp);
1883
1884 return CMD_SUCCESS;
1885}
1886
1887DEFUN (ripng_aggregate_address,
1888 ripng_aggregate_address_cmd,
1889 "aggregate-address X:X::X:X/M",
1890 "Set aggregate RIPng route announcement\n"
1891 "Aggregate network\n")
1892{
1893 int ret;
1894 struct prefix p;
1895 struct route_node *node;
1896
1897 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
1898 if (ret <= 0)
1899 {
1900 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
1901 return CMD_WARNING;
1902 }
1903
1904 /* Check aggregate alredy exist or not. */
1905 node = route_node_get (ripng->aggregate, &p);
1906 if (node->info)
1907 {
1908 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
1909 route_unlock_node (node);
1910 return CMD_WARNING;
1911 }
1912 node->info = (void *)1;
1913
1914 ripng_aggregate_add (&p);
1915
1916 return CMD_SUCCESS;
1917}
1918
1919DEFUN (no_ripng_aggregate_address,
1920 no_ripng_aggregate_address_cmd,
1921 "no aggregate-address X:X::X:X/M",
1922 NO_STR
1923 "Delete aggregate RIPng route announcement\n"
1924 "Aggregate network")
1925{
1926 int ret;
1927 struct prefix p;
1928 struct route_node *rn;
1929
1930 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
1931 if (ret <= 0)
1932 {
1933 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
1934 return CMD_WARNING;
1935 }
1936
1937 rn = route_node_lookup (ripng->aggregate, &p);
1938 if (! rn)
1939 {
1940 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
1941 return CMD_WARNING;
1942 }
1943 route_unlock_node (rn);
1944 rn->info = NULL;
1945 route_unlock_node (rn);
1946
1947 ripng_aggregate_delete (&p);
1948
1949 return CMD_SUCCESS;
1950}
1951
1952DEFUN (ripng_default_metric,
1953 ripng_default_metric_cmd,
1954 "default-metric <1-16>",
1955 "Set a metric of redistribute routes\n"
1956 "Default metric\n")
1957{
1958 if (ripng)
1959 {
1960 ripng->default_metric = atoi (argv[0]);
1961 }
1962 return CMD_SUCCESS;
1963}
1964
1965DEFUN (no_ripng_default_metric,
1966 no_ripng_default_metric_cmd,
1967 "no default-metric",
1968 NO_STR
1969 "Set a metric of redistribute routes\n"
1970 "Default metric\n")
1971{
1972 if (ripng)
1973 {
1974 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1975 }
1976 return CMD_SUCCESS;
1977}
1978
1979ALIAS (no_ripng_default_metric,
1980 no_ripng_default_metric_val_cmd,
1981 "no default-metric <1-16>",
1982 NO_STR
1983 "Set a metric of redistribute routes\n"
1984 "Default metric\n")
1985
1986#if 0
1987/* RIPng update timer setup. */
1988DEFUN (ripng_update_timer,
1989 ripng_update_timer_cmd,
1990 "update-timer SECOND",
1991 "Set RIPng update timer in seconds\n"
1992 "Seconds\n")
1993{
1994 unsigned long update;
1995 char *endptr = NULL;
1996
1997 update = strtoul (argv[0], &endptr, 10);
1998 if (update == ULONG_MAX || *endptr != '\0')
1999 {
2000 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2001 return CMD_WARNING;
2002 }
2003
2004 ripng->update_time = update;
2005
2006 ripng_event (RIPNG_UPDATE_EVENT, 0);
2007 return CMD_SUCCESS;
2008}
2009
2010DEFUN (no_ripng_update_timer,
2011 no_ripng_update_timer_cmd,
2012 "no update-timer SECOND",
2013 NO_STR
2014 "Unset RIPng update timer in seconds\n"
2015 "Seconds\n")
2016{
2017 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2018 ripng_event (RIPNG_UPDATE_EVENT, 0);
2019 return CMD_SUCCESS;
2020}
2021
2022/* RIPng timeout timer setup. */
2023DEFUN (ripng_timeout_timer,
2024 ripng_timeout_timer_cmd,
2025 "timeout-timer SECOND",
2026 "Set RIPng timeout timer in seconds\n"
2027 "Seconds\n")
2028{
2029 unsigned long timeout;
2030 char *endptr = NULL;
2031
2032 timeout = strtoul (argv[0], &endptr, 10);
2033 if (timeout == ULONG_MAX || *endptr != '\0')
2034 {
2035 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2036 return CMD_WARNING;
2037 }
2038
2039 ripng->timeout_time = timeout;
2040
2041 return CMD_SUCCESS;
2042}
2043
2044DEFUN (no_ripng_timeout_timer,
2045 no_ripng_timeout_timer_cmd,
2046 "no timeout-timer SECOND",
2047 NO_STR
2048 "Unset RIPng timeout timer in seconds\n"
2049 "Seconds\n")
2050{
2051 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2052 return CMD_SUCCESS;
2053}
2054
2055/* RIPng garbage timer setup. */
2056DEFUN (ripng_garbage_timer,
2057 ripng_garbage_timer_cmd,
2058 "garbage-timer SECOND",
2059 "Set RIPng garbage timer in seconds\n"
2060 "Seconds\n")
2061{
2062 unsigned long garbage;
2063 char *endptr = NULL;
2064
2065 garbage = strtoul (argv[0], &endptr, 10);
2066 if (garbage == ULONG_MAX || *endptr != '\0')
2067 {
2068 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2069 return CMD_WARNING;
2070 }
2071
2072 ripng->garbage_time = garbage;
2073
2074 return CMD_SUCCESS;
2075}
2076
2077DEFUN (no_ripng_garbage_timer,
2078 no_ripng_garbage_timer_cmd,
2079 "no garbage-timer SECOND",
2080 NO_STR
2081 "Unset RIPng garbage timer in seconds\n"
2082 "Seconds\n")
2083{
2084 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2085 return CMD_SUCCESS;
2086}
2087#endif /* 0 */
2088
2089DEFUN (ripng_timers,
2090 ripng_timers_cmd,
2091 "timers basic <0-65535> <0-65535> <0-65535>",
2092 "RIPng timers setup\n"
2093 "Basic timer\n"
2094 "Routing table update timer value in second. Default is 30.\n"
2095 "Routing information timeout timer. Default is 180.\n"
2096 "Garbage collection timer. Default is 120.\n")
2097{
2098 unsigned long update;
2099 unsigned long timeout;
2100 unsigned long garbage;
2101 char *endptr = NULL;
2102
2103 update = strtoul (argv[0], &endptr, 10);
2104 if (update == ULONG_MAX || *endptr != '\0')
2105 {
2106 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2107 return CMD_WARNING;
2108 }
2109
2110 timeout = strtoul (argv[1], &endptr, 10);
2111 if (timeout == ULONG_MAX || *endptr != '\0')
2112 {
2113 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2114 return CMD_WARNING;
2115 }
2116
2117 garbage = strtoul (argv[2], &endptr, 10);
2118 if (garbage == ULONG_MAX || *endptr != '\0')
2119 {
2120 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2121 return CMD_WARNING;
2122 }
2123
2124 /* Set each timer value. */
2125 ripng->update_time = update;
2126 ripng->timeout_time = timeout;
2127 ripng->garbage_time = garbage;
2128
2129 /* Reset update timer thread. */
2130 ripng_event (RIPNG_UPDATE_EVENT, 0);
2131
2132 return CMD_SUCCESS;
2133}
2134
2135DEFUN (no_ripng_timers,
2136 no_ripng_timers_cmd,
2137 "no timers basic",
2138 NO_STR
2139 "RIPng timers setup\n"
2140 "Basic timer\n")
2141{
2142 /* Set each timer value to the default. */
2143 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2144 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2145 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2146
2147 /* Reset update timer thread. */
2148 ripng_event (RIPNG_UPDATE_EVENT, 0);
2149
2150 return CMD_SUCCESS;
2151}
2152
2153
2154DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2155 "show ipv6 protocols",
2156 SHOW_STR
2157 IP_STR
2158 "Routing protocol information")
2159{
2160 if (! ripng)
2161 return CMD_SUCCESS;
2162
2163 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2164
2165 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2166 ripng->update_time, 0,
2167 VTY_NEWLINE);
2168
2169 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2170 ripng->timeout_time,
2171 ripng->garbage_time,
2172 VTY_NEWLINE);
2173
2174 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2175 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2176
2177 return CMD_SUCCESS;
2178}
2179
2180/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002181DEFUN (ripng_default_information_originate,
2182 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002183 "default-information originate",
2184 "Default route information\n"
2185 "Distribute default route\n")
2186{
2187 struct prefix_ipv6 p;
2188
2189 ripng->default_information = 1;
2190
2191 str2prefix_ipv6 ("::/0", &p);
2192 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2193
2194 return CMD_SUCCESS;
2195}
2196
paula2c62832003-04-23 17:01:31 +00002197DEFUN (no_ripng_default_information_originate,
2198 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002199 "no default-information originate",
2200 NO_STR
2201 "Default route information\n"
2202 "Distribute default route\n")
2203{
2204 struct prefix_ipv6 p;
2205
2206 ripng->default_information = 0;
2207
2208 str2prefix_ipv6 ("::/0", &p);
2209 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2210
2211 return CMD_SUCCESS;
2212}
2213
2214/* RIPng configuration write function. */
2215int
2216ripng_config_write (struct vty *vty)
2217{
2218 int ripng_network_write (struct vty *);
2219 void ripng_redistribute_write (struct vty *);
2220 int write = 0;
2221 struct route_node *rp;
2222
2223 if (ripng)
2224 {
2225
2226 /* RIPng router. */
2227 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2228
2229 if (ripng->default_information)
2230 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2231
2232 ripng_network_write (vty);
2233
2234 /* RIPng default metric configuration */
2235 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2236 vty_out (vty, " default-metric %d%s",
2237 ripng->default_metric, VTY_NEWLINE);
2238
2239 ripng_redistribute_write (vty);
2240
2241 /* RIPng aggregate routes. */
2242 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2243 if (rp->info != NULL)
2244 vty_out (vty, " aggregate-address %s/%d%s",
2245 inet6_ntop (&rp->p.u.prefix6),
2246 rp->p.prefixlen,
2247
2248 VTY_NEWLINE);
2249
2250 /* RIPng static routes. */
2251 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2252 if (rp->info != NULL)
2253 vty_out (vty, " route %s/%d%s", inet6_ntop (&rp->p.u.prefix6),
2254 rp->p.prefixlen,
2255 VTY_NEWLINE);
2256
2257 /* RIPng timers configuration. */
2258 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2259 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2260 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2261 {
2262 vty_out (vty, " timers basic %ld %ld %ld%s",
2263 ripng->update_time,
2264 ripng->timeout_time,
2265 ripng->garbage_time,
2266 VTY_NEWLINE);
2267 }
2268#if 0
2269 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2270 vty_out (vty, " update-timer %d%s", ripng->update_time,
2271 VTY_NEWLINE);
2272 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2273 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2274 VTY_NEWLINE);
2275 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2276 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2277 VTY_NEWLINE);
2278#endif /* 0 */
2279
2280 write += config_write_distribute (vty);
2281
2282 write += config_write_if_rmap (vty);
2283
2284 write++;
2285 }
2286 return write;
2287}
2288
2289/* RIPng node structure. */
2290struct cmd_node cmd_ripng_node =
2291{
2292 RIPNG_NODE,
2293 "%s(config-router)# ",
2294 1,
2295};
2296
2297void
2298ripng_distribute_update (struct distribute *dist)
2299{
2300 struct interface *ifp;
2301 struct ripng_interface *ri;
2302 struct access_list *alist;
2303 struct prefix_list *plist;
2304
2305 if (! dist->ifname)
2306 return;
2307
2308 ifp = if_lookup_by_name (dist->ifname);
2309 if (ifp == NULL)
2310 return;
2311
2312 ri = ifp->info;
2313
2314 if (dist->list[DISTRIBUTE_IN])
2315 {
2316 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2317 if (alist)
2318 ri->list[RIPNG_FILTER_IN] = alist;
2319 else
2320 ri->list[RIPNG_FILTER_IN] = NULL;
2321 }
2322 else
2323 ri->list[RIPNG_FILTER_IN] = NULL;
2324
2325 if (dist->list[DISTRIBUTE_OUT])
2326 {
2327 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2328 if (alist)
2329 ri->list[RIPNG_FILTER_OUT] = alist;
2330 else
2331 ri->list[RIPNG_FILTER_OUT] = NULL;
2332 }
2333 else
2334 ri->list[RIPNG_FILTER_OUT] = NULL;
2335
2336 if (dist->prefix[DISTRIBUTE_IN])
2337 {
2338 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2339 if (plist)
2340 ri->prefix[RIPNG_FILTER_IN] = plist;
2341 else
2342 ri->prefix[RIPNG_FILTER_IN] = NULL;
2343 }
2344 else
2345 ri->prefix[RIPNG_FILTER_IN] = NULL;
2346
2347 if (dist->prefix[DISTRIBUTE_OUT])
2348 {
2349 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2350 if (plist)
2351 ri->prefix[RIPNG_FILTER_OUT] = plist;
2352 else
2353 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2354 }
2355 else
2356 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2357}
2358void
2359ripng_distribute_update_interface (struct interface *ifp)
2360{
2361 struct distribute *dist;
2362
2363 dist = distribute_lookup (ifp->name);
2364 if (dist)
2365 ripng_distribute_update (dist);
2366}
2367
2368/* Update all interface's distribute list. */
2369void
2370ripng_distribute_update_all ()
2371{
2372 struct interface *ifp;
2373 listnode node;
2374
2375 for (node = listhead (iflist); node; nextnode (node))
2376 {
2377 ifp = getdata (node);
2378 ripng_distribute_update_interface (ifp);
2379 }
2380}
2381
2382void
2383ripng_if_rmap_update (struct if_rmap *if_rmap)
2384{
2385 struct interface *ifp;
2386 struct ripng_interface *ri;
2387 struct route_map *rmap;
2388
2389 ifp = if_lookup_by_name (if_rmap->ifname);
2390 if (ifp == NULL)
2391 return;
2392
2393 ri = ifp->info;
2394
2395 if (if_rmap->routemap[IF_RMAP_IN])
2396 {
2397 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2398 if (rmap)
2399 ri->routemap[IF_RMAP_IN] = rmap;
2400 else
2401 ri->routemap[IF_RMAP_IN] = NULL;
2402 }
2403 else
2404 ri->routemap[RIPNG_FILTER_IN] = NULL;
2405
2406 if (if_rmap->routemap[IF_RMAP_OUT])
2407 {
2408 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2409 if (rmap)
2410 ri->routemap[IF_RMAP_OUT] = rmap;
2411 else
2412 ri->routemap[IF_RMAP_OUT] = NULL;
2413 }
2414 else
2415 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2416}
2417
2418void
2419ripng_if_rmap_update_interface (struct interface *ifp)
2420{
2421 struct if_rmap *if_rmap;
2422
2423 if_rmap = if_rmap_lookup (ifp->name);
2424 if (if_rmap)
2425 ripng_if_rmap_update (if_rmap);
2426}
2427
2428void
2429ripng_routemap_update_redistribute (void)
2430{
2431 int i;
2432
2433 if (ripng)
2434 {
2435 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2436 {
2437 if (ripng->route_map[i].name)
2438 ripng->route_map[i].map =
2439 route_map_lookup_by_name (ripng->route_map[i].name);
2440 }
2441 }
2442}
2443
2444void
2445ripng_routemap_update ()
2446{
2447 struct interface *ifp;
2448 listnode node;
2449
2450 for (node = listhead (iflist); node; nextnode (node))
2451 {
2452 ifp = getdata (node);
2453 ripng_if_rmap_update_interface (ifp);
2454 }
2455
2456 ripng_routemap_update_redistribute ();
2457}
2458
2459/* Initialize ripng structure and set commands. */
2460void
2461ripng_init ()
2462{
2463 /* Randomize. */
2464 srand (time (NULL));
2465
2466 /* Install RIPNG_NODE. */
2467 install_node (&cmd_ripng_node, ripng_config_write);
2468
2469 /* Install ripng commands. */
2470 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
2471
2472 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
2473
2474 install_element (CONFIG_NODE, &router_ripng_cmd);
2475
2476 install_default (RIPNG_NODE);
2477 install_element (RIPNG_NODE, &ripng_route_cmd);
2478 install_element (RIPNG_NODE, &no_ripng_route_cmd);
2479 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
2480 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
2481
2482 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
2483 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
2484 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
2485
2486 install_element (RIPNG_NODE, &ripng_timers_cmd);
2487 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
2488#if 0
2489 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2490 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2491 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2492 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2493 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2494 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2495#endif /* 0 */
2496
paula2c62832003-04-23 17:01:31 +00002497 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
2498 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00002499
2500 ripng_if_init ();
2501 ripng_debug_init ();
2502
2503 /* Access list install. */
2504 access_list_init ();
2505 access_list_add_hook (ripng_distribute_update_all);
2506 access_list_delete_hook (ripng_distribute_update_all);
2507
2508 /* Prefix list initialize.*/
2509 prefix_list_init ();
2510 prefix_list_add_hook (ripng_distribute_update_all);
2511 prefix_list_delete_hook (ripng_distribute_update_all);
2512
2513 /* Distribute list install. */
2514 distribute_list_init (RIPNG_NODE);
2515 distribute_list_add_hook (ripng_distribute_update);
2516 distribute_list_delete_hook (ripng_distribute_update);
2517
2518 /* Route-map for interface. */
2519 ripng_route_map_init ();
2520 route_map_add_hook (ripng_routemap_update);
2521 route_map_delete_hook (ripng_routemap_update);
2522
paul41ce9262003-04-19 15:54:03 +00002523 if_rmap_init ();
paul718e3742002-12-13 20:15:29 +00002524 if_rmap_hook_add (ripng_if_rmap_update);
2525 if_rmap_hook_delete (ripng_if_rmap_update);
2526}