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