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