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