blob: 7b00e0375f93cf7e198d613572854c9e8e8cbbb5 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
paul718e3742002-12-13 20:15:29 +000024#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"
hasso0750d212003-05-24 21:41:49 +000037#include "if_rmap.h"
paul27d47aa2003-11-17 09:04:53 +000038#include "privs.h"
paul718e3742002-12-13 20:15:29 +000039
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
hassoa94434b2003-05-25 17:10:12 +000043#include "ripngd/ripng_nexthop.h"
paul718e3742002-12-13 20:15:29 +000044
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,
paul718e3742002-12-13 20:15:29 +000054};
55
paul27d47aa2003-11-17 09:04:53 +000056extern struct zebra_privs_t ripngd_privs;
57
paul718e3742002-12-13 20:15:29 +000058/* Prototypes. */
59void
hassoa94434b2003-05-25 17:10:12 +000060ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
paul718e3742002-12-13 20:15:29 +000061
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};
paul718e3742002-12-13 20:15:29 +000075
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static int
hassoa94434b2003-05-25 17:10:12 +000077ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
paul718e3742002-12-13 20:15:29 +000082/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
98
paul718e3742002-12-13 20:15:29 +000099/* Create ripng socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100100static int
paul718e3742002-12-13 20:15:29 +0000101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't make ripng socket");
111 return sock;
112 }
113
114 ret = setsockopt_so_recvbuf (sock, 8096);
115 if (ret < 0)
116 return ret;
117 ret = setsockopt_ipv6_pktinfo (sock, 1);
118 if (ret < 0)
119 return ret;
120 ret = setsockopt_ipv6_multicast_hops (sock, 255);
121 if (ret < 0)
122 return ret;
123 ret = setsockopt_ipv6_multicast_loop (sock, 0);
124 if (ret < 0)
125 return ret;
126 ret = setsockopt_ipv6_hoplimit (sock, 1);
127 if (ret < 0)
128 return ret;
129
130 memset (&ripaddr, 0, sizeof (ripaddr));
131 ripaddr.sin6_family = AF_INET6;
132#ifdef SIN6_LEN
133 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
134#endif /* SIN6_LEN */
135 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
136
paul27d47aa2003-11-17 09:04:53 +0000137 if (ripngd_privs.change (ZPRIVS_RAISE))
138 zlog_err ("ripng_make_socket: could not raise privs");
139
paul718e3742002-12-13 20:15:29 +0000140 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
141 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000142 {
ajs6099b3b2004-11-20 02:06:59 +0000143 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000144 if (ripngd_privs.change (ZPRIVS_LOWER))
145 zlog_err ("ripng_make_socket: could not lower privs");
146 return ret;
147 }
148 if (ripngd_privs.change (ZPRIVS_LOWER))
149 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000150 return sock;
151}
152
153/* Send RIPng packet. */
154int
155ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
156 struct interface *ifp)
157{
158 int ret;
159 struct msghdr msg;
160 struct iovec iov;
161 struct cmsghdr *cmsgptr;
162 char adata [256];
163 struct in6_pktinfo *pkt;
164 struct sockaddr_in6 addr;
165
hassoa94434b2003-05-25 17:10:12 +0000166 if (IS_RIPNG_DEBUG_SEND) {
167 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000168 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000169 zlog_debug (" send interface %s", ifp->name);
170 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000171 }
paul718e3742002-12-13 20:15:29 +0000172
173 memset (&addr, 0, sizeof (struct sockaddr_in6));
174 addr.sin6_family = AF_INET6;
175#ifdef SIN6_LEN
176 addr.sin6_len = sizeof (struct sockaddr_in6);
177#endif /* SIN6_LEN */
178 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
179
180 /* When destination is specified. */
181 if (to != NULL)
182 {
183 addr.sin6_addr = to->sin6_addr;
184 addr.sin6_port = to->sin6_port;
185 }
186 else
187 {
188 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
189 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
190 }
191
192 msg.msg_name = (void *) &addr;
193 msg.msg_namelen = sizeof (struct sockaddr_in6);
194 msg.msg_iov = &iov;
195 msg.msg_iovlen = 1;
196 msg.msg_control = (void *) adata;
197 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
198
199 iov.iov_base = buf;
200 iov.iov_len = bufsize;
201
202 cmsgptr = (struct cmsghdr *)adata;
203 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
204 cmsgptr->cmsg_level = IPPROTO_IPV6;
205 cmsgptr->cmsg_type = IPV6_PKTINFO;
206
207 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
208 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
209 pkt->ipi6_ifindex = ifp->ifindex;
210
211 ret = sendmsg (ripng->sock, &msg, 0);
212
hassoa94434b2003-05-25 17:10:12 +0000213 if (ret < 0) {
214 if (to)
215 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000216 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000217 else
ajs6099b3b2004-11-20 02:06:59 +0000218 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000219 }
paul718e3742002-12-13 20:15:29 +0000220
221 return ret;
222}
223
224/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100225static int
paul718e3742002-12-13 20:15:29 +0000226ripng_recv_packet (int sock, u_char *buf, int bufsize,
227 struct sockaddr_in6 *from, unsigned int *ifindex,
228 int *hoplimit)
229{
230 int ret;
231 struct msghdr msg;
232 struct iovec iov;
233 struct cmsghdr *cmsgptr;
234 struct in6_addr dst;
235
236 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
237 point I can't determine size of cmsghdr */
238 char adata[1024];
239
240 /* Fill in message and iovec. */
241 msg.msg_name = (void *) from;
242 msg.msg_namelen = sizeof (struct sockaddr_in6);
243 msg.msg_iov = &iov;
244 msg.msg_iovlen = 1;
245 msg.msg_control = (void *) adata;
246 msg.msg_controllen = sizeof adata;
247 iov.iov_base = buf;
248 iov.iov_len = bufsize;
249
250 /* If recvmsg fail return minus value. */
251 ret = recvmsg (sock, &msg, 0);
252 if (ret < 0)
253 return ret;
254
ajsb99760a2005-01-04 16:24:43 +0000255 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000256 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
257 {
258 /* I want interface index which this packet comes from. */
259 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
260 cmsgptr->cmsg_type == IPV6_PKTINFO)
261 {
262 struct in6_pktinfo *ptr;
263
264 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
265 *ifindex = ptr->ipi6_ifindex;
266 dst = ptr->ipi6_addr;
267
268 if (*ifindex == 0)
269 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
270 }
271
272 /* Incoming packet's multicast hop limit. */
273 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
274 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
275 *hoplimit = *((int *) CMSG_DATA (cmsgptr));
276 }
277
278 /* Hoplimit check shold be done when destination address is
279 multicast address. */
280 if (! IN6_IS_ADDR_MULTICAST (&dst))
281 *hoplimit = -1;
282
283 return ret;
284}
285
286/* Dump rip packet */
287void
hasso7a1d5832004-10-08 06:32:23 +0000288ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000289{
290 caddr_t lim;
291 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000292 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000293
294 /* Set command string. */
295 if (packet->command == RIPNG_REQUEST)
296 command_str = "request";
297 else if (packet->command == RIPNG_RESPONSE)
298 command_str = "response";
299 else
300 command_str = "unknown";
301
302 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000303 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000304 sndrcv, command_str, packet->version, size);
305
306 /* Dump each routing table entry. */
307 rte = packet->rte;
308
309 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
310 {
311 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000312 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000313 else
ajsc6106812004-12-08 19:51:16 +0000314 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000315 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000316 rte->metric, ntohs (rte->tag));
317 }
318}
319
320/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100321static void
paul718e3742002-12-13 20:15:29 +0000322ripng_nexthop_rte (struct rte *rte,
323 struct sockaddr_in6 *from,
324 struct ripng_nexthop *nexthop)
325{
326 char buf[INET6_BUFSIZ];
327
328 /* Logging before checking RTE. */
329 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000330 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000331 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000332
333 /* RFC2080 2.1.1 Next Hop:
334 The route tag and prefix length in the next hop RTE must be
335 set to zero on sending and ignored on receiption. */
336 if (ntohs (rte->tag) != 0)
337 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000338 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000339
340 if (rte->prefixlen != 0)
341 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000342 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000343
344 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
345 next hop RTE indicates that the next hop address should be the
346 originator of the RIPng advertisement. An address specified as a
347 next hop must be a link-local address. */
348 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
349 {
350 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
351 memset (&nexthop->address, 0, sizeof (struct in6_addr));
352 return;
353 }
354
355 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
356 {
357 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
358 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
359 return;
360 }
361
362 /* The purpose of the next hop RTE is to eliminate packets being
363 routed through extra hops in the system. It is particularly useful
364 when RIPng is not being run on all of the routers on a network.
365 Note that next hop RTE is "advisory". That is, if the provided
366 information is ignored, a possibly sub-optimal, but absolutely
367 valid, route may be taken. If the received next hop address is not
368 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
369 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000370 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000371 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
372
373 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
374 memset (&nexthop->address, 0, sizeof (struct in6_addr));
375
376 return;
377}
378
379/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100380static int
paul718e3742002-12-13 20:15:29 +0000381ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
382{
paul1eb8ef22005-04-07 07:30:20 +0000383 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000384 struct connected *connected;
385 struct prefix *p;
386
paul1eb8ef22005-04-07 07:30:20 +0000387 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
388 {
389 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000390
paul1eb8ef22005-04-07 07:30:20 +0000391 if (p->family == AF_INET6 &&
392 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
393 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
394 return 1;
395 }
paul718e3742002-12-13 20:15:29 +0000396 return 0;
397}
398
399/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100400static int
paul718e3742002-12-13 20:15:29 +0000401ripng_garbage_collect (struct thread *t)
402{
403 struct ripng_info *rinfo;
404 struct route_node *rp;
405
406 rinfo = THREAD_ARG (t);
407 rinfo->t_garbage_collect = NULL;
408
409 /* Off timeout timer. */
410 RIPNG_TIMER_OFF (rinfo->t_timeout);
411
412 /* Get route_node pointer. */
413 rp = rinfo->rp;
414
paul718e3742002-12-13 20:15:29 +0000415 /* Unlock route_node. */
416 rp->info = NULL;
417 route_unlock_node (rp);
418
419 /* Free RIPng routing information. */
420 ripng_info_free (rinfo);
421
422 return 0;
423}
424
425/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100426static int
paul718e3742002-12-13 20:15:29 +0000427ripng_timeout (struct thread *t)
428{
429 struct ripng_info *rinfo;
430 struct route_node *rp;
431
432 rinfo = THREAD_ARG (t);
433 rinfo->t_timeout = NULL;
434
435 /* Get route_node pointer. */
436 rp = rinfo->rp;
437
438 /* - The garbage-collection timer is set for 120 seconds. */
439 RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
440 ripng->garbage_time);
441
hassoa94434b2003-05-25 17:10:12 +0000442 /* Delete this route from the kernel. */
443 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
444 rinfo->ifindex);
paul718e3742002-12-13 20:15:29 +0000445 /* - The metric for the route is set to 16 (infinity). This causes
446 the route to be removed from service. */
447 rinfo->metric = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +0000448 rinfo->flags &= ~RIPNG_RTF_FIB;
449
450 /* Aggregate count decrement. */
451 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +0000452
453 /* - The route change flag is to indicate that this entry has been
454 changed. */
455 rinfo->flags |= RIPNG_RTF_CHANGED;
456
457 /* - The output process is signalled to trigger a response. */
458 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
459
460 return 0;
461}
462
Paul Jakma6ac29a52008-08-15 13:45:30 +0100463static void
paul718e3742002-12-13 20:15:29 +0000464ripng_timeout_update (struct ripng_info *rinfo)
465{
466 if (rinfo->metric != RIPNG_METRIC_INFINITY)
467 {
468 RIPNG_TIMER_OFF (rinfo->t_timeout);
469 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
470 }
471}
472
Paul Jakma6ac29a52008-08-15 13:45:30 +0100473static int
hassoa94434b2003-05-25 17:10:12 +0000474ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
475{
476 struct distribute *dist;
477 struct access_list *alist;
478 struct prefix_list *plist;
479
480 /* Input distribute-list filtering. */
481 if (ri->list[RIPNG_FILTER_IN])
482 {
483 if (access_list_apply (ri->list[RIPNG_FILTER_IN],
484 (struct prefix *) p) == FILTER_DENY)
485 {
486 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000487 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000488 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000489 return -1;
490 }
491 }
492 if (ri->prefix[RIPNG_FILTER_IN])
493 {
494 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
495 (struct prefix *) p) == PREFIX_DENY)
496 {
497 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000498 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000499 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000500 return -1;
501 }
502 }
503
504 /* All interface filter check. */
505 dist = distribute_lookup (NULL);
506 if (dist)
507 {
508 if (dist->list[DISTRIBUTE_IN])
509 {
510 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
511
512 if (alist)
513 {
514 if (access_list_apply (alist,
515 (struct prefix *) p) == FILTER_DENY)
516 {
517 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000518 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000519 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000520 return -1;
521 }
522 }
523 }
524 if (dist->prefix[DISTRIBUTE_IN])
525 {
526 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
527
528 if (plist)
529 {
530 if (prefix_list_apply (plist,
531 (struct prefix *) p) == PREFIX_DENY)
532 {
533 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000534 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000535 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000536 return -1;
537 }
538 }
539 }
540 }
541 return 0;
542}
543
Paul Jakma6ac29a52008-08-15 13:45:30 +0100544static int
hassoa94434b2003-05-25 17:10:12 +0000545ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
546{
547 struct distribute *dist;
548 struct access_list *alist;
549 struct prefix_list *plist;
550
551 if (ri->list[RIPNG_FILTER_OUT])
552 {
553 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
554 (struct prefix *) p) == FILTER_DENY)
555 {
556 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000557 zlog_debug ("%s/%d is filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000558 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000559 return -1;
560 }
561 }
562 if (ri->prefix[RIPNG_FILTER_OUT])
563 {
564 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
565 (struct prefix *) p) == PREFIX_DENY)
566 {
567 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000568 zlog_debug ("%s/%d is filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000569 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000570 return -1;
571 }
572 }
573
574 /* All interface filter check. */
575 dist = distribute_lookup (NULL);
576 if (dist)
577 {
578 if (dist->list[DISTRIBUTE_OUT])
579 {
580 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
581
582 if (alist)
583 {
584 if (access_list_apply (alist,
585 (struct prefix *) p) == FILTER_DENY)
586 {
587 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000588 zlog_debug ("%s/%d filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000589 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000590 return -1;
591 }
592 }
593 }
594 if (dist->prefix[DISTRIBUTE_OUT])
595 {
596 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
597
598 if (plist)
599 {
600 if (prefix_list_apply (plist,
601 (struct prefix *) p) == PREFIX_DENY)
602 {
603 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000604 zlog_debug ("%s/%d filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000605 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000606 return -1;
607 }
608 }
609 }
610 }
611 return 0;
612}
613
paul718e3742002-12-13 20:15:29 +0000614/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100615static void
paul718e3742002-12-13 20:15:29 +0000616ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
617 struct ripng_nexthop *ripng_nexthop,
618 struct interface *ifp)
619{
hassoa94434b2003-05-25 17:10:12 +0000620 int ret;
paul718e3742002-12-13 20:15:29 +0000621 struct prefix_ipv6 p;
622 struct route_node *rp;
623 struct ripng_info *rinfo;
624 struct ripng_interface *ri;
625 struct in6_addr *nexthop;
626 u_char oldmetric;
627 int same = 0;
628
629 /* Make prefix structure. */
630 memset (&p, 0, sizeof (struct prefix_ipv6));
631 p.family = AF_INET6;
632 /* p.prefix = rte->addr; */
633 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
634 p.prefixlen = rte->prefixlen;
635
636 /* Make sure mask is applied. */
637 /* XXX We have to check the prefix is valid or not before call
638 apply_mask_ipv6. */
639 apply_mask_ipv6 (&p);
640
641 /* Apply input filters. */
642 ri = ifp->info;
643
hassoa94434b2003-05-25 17:10:12 +0000644 ret = ripng_incoming_filter (&p, ri);
645 if (ret < 0)
646 return;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Modify entry. */
649 if (ri->routemap[RIPNG_FILTER_IN])
650 {
651 int ret;
652 struct ripng_info newinfo;
653
paul41ce9262003-04-19 15:54:03 +0000654 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +0000655 newinfo.type = ZEBRA_ROUTE_RIPNG;
656 newinfo.sub_type = RIPNG_ROUTE_RTE;
657 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
658 newinfo.nexthop = ripng_nexthop->address;
659 else
660 newinfo.nexthop = from->sin6_addr;
661 newinfo.from = from->sin6_addr;
662 newinfo.ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000663 newinfo.metric = rte->metric;
hassoa94434b2003-05-25 17:10:12 +0000664 newinfo.metric_out = rte->metric; /* XXX */
665 newinfo.tag = ntohs(rte->tag); /* XXX */
paul718e3742002-12-13 20:15:29 +0000666
667 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
668 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
669
670 if (ret == RMAP_DENYMATCH)
671 {
672 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000673 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000674 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000675 return;
676 }
677
hassoa94434b2003-05-25 17:10:12 +0000678 /* Get back the object */
679 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
680 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
681 /* the nexthop get changed by the routemap */
682 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
683 ripng_nexthop->address = newinfo.nexthop;
684 else
685 ripng_nexthop->address = in6addr_any;
686 }
687 } else {
688 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
689 /* the nexthop get changed by the routemap */
690 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
691 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
692 ripng_nexthop->address = newinfo.nexthop;
693 }
694 }
695 }
696 rte->tag = htons(newinfo.tag_out); /* XXX */
697 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000698 }
699
hassoa94434b2003-05-25 17:10:12 +0000700 /* Once the entry has been validated, update the metric by
701 * adding the cost of the network on wich the message
702 * arrived. If the result is greater than infinity, use infinity
703 * (RFC2453 Sec. 3.9.2)
704 **/
705
706 /* Zebra ripngd can handle offset-list in. */
707 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
708
709 /* If offset-list does not modify the metric use interface's
710 * one. */
711 if (! ret)
712 rte->metric += ifp->metric;
713
714 if (rte->metric > RIPNG_METRIC_INFINITY)
715 rte->metric = RIPNG_METRIC_INFINITY;
716
paul718e3742002-12-13 20:15:29 +0000717 /* Set nexthop pointer. */
718 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
719 nexthop = &ripng_nexthop->address;
720 else
721 nexthop = &from->sin6_addr;
722
723 /* Lookup RIPng routing table. */
724 rp = route_node_get (ripng->table, (struct prefix *) &p);
725
hassoa94434b2003-05-25 17:10:12 +0000726 /* Sanity check */
727 rinfo = rp->info;
728 if (rinfo)
729 {
730 /* Redistributed route check. */
731 if (rinfo->type != ZEBRA_ROUTE_RIPNG
732 && rinfo->metric != RIPNG_METRIC_INFINITY)
733 return;
734
735 /* Local static route. */
736 if (rinfo->type == ZEBRA_ROUTE_RIPNG
737 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
738 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
739 && rinfo->metric != RIPNG_METRIC_INFINITY)
740 return;
741 }
742
paul718e3742002-12-13 20:15:29 +0000743 if (rp->info == NULL)
744 {
745 /* Now, check to see whether there is already an explicit route
746 for the destination prefix. If there is no such route, add
747 this route to the routing table, unless the metric is
748 infinity (there is no point in adding a route which
749 unusable). */
750 if (rte->metric != RIPNG_METRIC_INFINITY)
751 {
752 rinfo = ripng_info_new ();
753
754 /* - Setting the destination prefix and length to those in
755 the RTE. */
756 rp->info = rinfo;
757 rinfo->rp = rp;
758
759 /* - Setting the metric to the newly calculated metric (as
760 described above). */
761 rinfo->metric = rte->metric;
762 rinfo->tag = ntohs (rte->tag);
763
764 /* - Set the next hop address to be the address of the router
765 from which the datagram came or the next hop address
766 specified by a next hop RTE. */
767 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
768 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
769 rinfo->ifindex = ifp->ifindex;
770
771 /* - Initialize the timeout for the route. If the
772 garbage-collection timer is running for this route, stop it. */
773 ripng_timeout_update (rinfo);
774
775 /* - Set the route change flag. */
776 rinfo->flags |= RIPNG_RTF_CHANGED;
777
778 /* - Signal the output process to trigger an update (see section
779 2.5). */
780 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
781
782 /* Finally, route goes into the kernel. */
783 rinfo->type = ZEBRA_ROUTE_RIPNG;
784 rinfo->sub_type = RIPNG_ROUTE_RTE;
785
hassodeba3552005-08-27 06:19:39 +0000786 ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex,
787 rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000788 rinfo->flags |= RIPNG_RTF_FIB;
789
790 /* Aggregate check. */
791 ripng_aggregate_increment (rp, rinfo);
792 }
793 }
794 else
795 {
796 rinfo = rp->info;
797
798 /* If there is an existing route, compare the next hop address
799 to the address of the router from which the datagram came.
800 If this datagram is from the same router as the existing
801 route, reinitialize the timeout. */
802 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
803 && (rinfo->ifindex == ifp->ifindex));
804
805 if (same)
806 ripng_timeout_update (rinfo);
807
808 /* Next, compare the metrics. If the datagram is from the same
809 router as the existing route, and the new metric is different
810 than the old one; or, if the new metric is lower than the old
811 one; do the following actions: */
812 if ((same && rinfo->metric != rte->metric) ||
813 rte->metric < rinfo->metric)
814 {
815 /* - Adopt the route from the datagram. That is, put the
816 new metric in, and adjust the next hop address (if
817 necessary). */
818 oldmetric = rinfo->metric;
819 rinfo->metric = rte->metric;
820 rinfo->tag = ntohs (rte->tag);
hassoa94434b2003-05-25 17:10:12 +0000821 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
822 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000823
hassoa94434b2003-05-25 17:10:12 +0000824 /* Should a new route to this network be established
825 while the garbage-collection timer is running, the
826 new route will replace the one that is about to be
827 deleted. In this case the garbage-collection timer
828 must be cleared. */
829
830 if (oldmetric == RIPNG_METRIC_INFINITY &&
831 rinfo->metric < RIPNG_METRIC_INFINITY)
832 {
833 rinfo->type = ZEBRA_ROUTE_RIPNG;
834 rinfo->sub_type = RIPNG_ROUTE_RTE;
835
836 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
837
838 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
hassodeba3552005-08-27 06:19:39 +0000839 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
hassoa94434b2003-05-25 17:10:12 +0000840
hassodeba3552005-08-27 06:19:39 +0000841 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
hassoa94434b2003-05-25 17:10:12 +0000842 rinfo->flags |= RIPNG_RTF_FIB;
843
844 /* The aggregation counter needs to be updated because
845 the prefixes, which are into the gc, have been
846 removed from the aggregator (see ripng_timout). */
847 ripng_aggregate_increment (rp, rinfo);
848 }
849
850 /* Update nexthop and/or metric value. */
851 if (oldmetric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +0000852 {
853 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
hassodeba3552005-08-27 06:19:39 +0000854 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000855 rinfo->flags |= RIPNG_RTF_FIB;
856
hassoa94434b2003-05-25 17:10:12 +0000857 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
858 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000859 }
paul718e3742002-12-13 20:15:29 +0000860
861 /* - Set the route change flag and signal the output process
862 to trigger an update. */
863 rinfo->flags |= RIPNG_RTF_CHANGED;
864 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
865
866 /* - If the new metric is infinity, start the deletion
867 process (described above); */
868 if (rinfo->metric == RIPNG_METRIC_INFINITY)
869 {
870 /* If the new metric is infinity, the deletion process
871 begins for the route, which is no longer used for
872 routing packets. Note that the deletion process is
873 started only when the metric is first set to
874 infinity. If the metric was already infinity, then a
875 new deletion process is not started. */
876 if (oldmetric != RIPNG_METRIC_INFINITY)
877 {
878 /* - The garbage-collection timer is set for 120 seconds. */
879 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
880 ripng_garbage_collect, ripng->garbage_time);
881 RIPNG_TIMER_OFF (rinfo->t_timeout);
882
883 /* - The metric for the route is set to 16
884 (infinity). This causes the route to be removed
885 from service.*/
hassoa94434b2003-05-25 17:10:12 +0000886 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
887 rinfo->flags &= ~RIPNG_RTF_FIB;
888
889 /* Aggregate count decrement. */
890 ripng_aggregate_decrement (rp, rinfo);
891
paul718e3742002-12-13 20:15:29 +0000892 /* - The route change flag is to indicate that this
893 entry has been changed. */
894 /* - The output process is signalled to trigger a
895 response. */
896 ; /* Above processes are already done previously. */
897 }
898 }
899 else
900 {
901 /* otherwise, re-initialize the timeout. */
902 ripng_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000903 }
904 }
905 /* Unlock tempolary lock of the route. */
906 route_unlock_node (rp);
907 }
908}
909
910/* Add redistributed route to RIPng table. */
911void
912ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +0000913 unsigned int ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000914{
915 struct route_node *rp;
916 struct ripng_info *rinfo;
917
918 /* Redistribute route */
919 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
920 return;
921 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
922 return;
hassoa94434b2003-05-25 17:10:12 +0000923#if defined (MUSICA) || defined (LINUX)
924 /* XXX As long as the RIPng redistribution is applied to all the connected
925 * routes, one needs to filter the ::/96 prefixes.
926 * However it could be a wanted case, it will be removed soon.
927 */
928 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
929 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
930 return;
931#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +0000932
933 rp = route_node_get (ripng->table, (struct prefix *) p);
934 rinfo = rp->info;
935
936 if (rinfo)
937 {
hassoa94434b2003-05-25 17:10:12 +0000938 if (rinfo->type == ZEBRA_ROUTE_CONNECT
939 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
940 && rinfo->metric != RIPNG_METRIC_INFINITY) {
941 route_unlock_node (rp);
942 return;
943 }
944
945 /* Manually configured RIPng route check.
946 * They have the precedence on all the other entries.
947 **/
948 if (rinfo->type == ZEBRA_ROUTE_RIPNG
949 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
950 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
951 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
952 (sub_type != RIPNG_ROUTE_DEFAULT))) {
953 route_unlock_node (rp);
954 return;
955 }
956 }
957
paul718e3742002-12-13 20:15:29 +0000958 RIPNG_TIMER_OFF (rinfo->t_timeout);
959 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
hassoa94434b2003-05-25 17:10:12 +0000960
961 /* Tells the other daemons about the deletion of
962 * this RIPng route
963 **/
964 if (ripng_route_rte (rinfo))
965 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
966 rinfo->metric);
967
968 rp->info = NULL;
969 ripng_info_free (rinfo);
970
paul718e3742002-12-13 20:15:29 +0000971 route_unlock_node (rp);
hassoa94434b2003-05-25 17:10:12 +0000972
paul718e3742002-12-13 20:15:29 +0000973 }
hassoa94434b2003-05-25 17:10:12 +0000974
975 rinfo = ripng_info_new ();
paul718e3742002-12-13 20:15:29 +0000976
977 rinfo->type = type;
978 rinfo->sub_type = sub_type;
979 rinfo->ifindex = ifindex;
980 rinfo->metric = 1;
paul718e3742002-12-13 20:15:29 +0000981 rinfo->rp = rp;
hassoa94434b2003-05-25 17:10:12 +0000982
983 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
984 rinfo->nexthop = *nexthop;
985
986 rinfo->flags |= RIPNG_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000987 rp->info = rinfo;
hassoa94434b2003-05-25 17:10:12 +0000988
989 /* Aggregate check. */
990 ripng_aggregate_increment (rp, rinfo);
991
992 rinfo->flags |= RIPNG_RTF_CHANGED;
993
994 if (IS_RIPNG_DEBUG_EVENT) {
995 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +0000996 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000997 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +0000998 ifindex2ifname(ifindex));
999 else
ajsc6106812004-12-08 19:51:16 +00001000 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001001 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001002 ifindex2ifname(ifindex));
1003 }
1004
1005 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001006}
1007
1008/* Delete redistributed route to RIPng table. */
1009void
1010ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1011 unsigned int ifindex)
1012{
1013 struct route_node *rp;
1014 struct ripng_info *rinfo;
1015
1016 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1017 return;
1018 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1019 return;
hassoa94434b2003-05-25 17:10:12 +00001020#if defined (MUSICA) || defined (LINUX)
1021 /* XXX As long as the RIPng redistribution is applied to all the connected
1022 * routes, one needs to filter the ::/96 prefixes.
1023 * However it could be a wanted case, it will be removed soon.
1024 */
1025 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
1026 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
1027 return;
1028#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +00001029
1030 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1031
1032 if (rp)
1033 {
1034 rinfo = rp->info;
1035
1036 if (rinfo != NULL
1037 && rinfo->type == type
1038 && rinfo->sub_type == sub_type
1039 && rinfo->ifindex == ifindex)
1040 {
hassoa94434b2003-05-25 17:10:12 +00001041 /* Perform poisoned reverse. */
1042 rinfo->metric = RIPNG_METRIC_INFINITY;
1043 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1044 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001045 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001046
1047 /* Aggregate count decrement. */
1048 ripng_aggregate_decrement (rp, rinfo);
1049
1050 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001051
hassoa94434b2003-05-25 17:10:12 +00001052 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001053 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso3a2ce6a2005-04-08 01:30:51 +00001054 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001055 ifindex2ifname(ifindex));
paul718e3742002-12-13 20:15:29 +00001056
hassoa94434b2003-05-25 17:10:12 +00001057 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001058 }
paul718e3742002-12-13 20:15:29 +00001059 }
1060}
1061
1062/* Withdraw redistributed route. */
1063void
1064ripng_redistribute_withdraw (int type)
1065{
1066 struct route_node *rp;
1067 struct ripng_info *rinfo;
1068
hassoa94434b2003-05-25 17:10:12 +00001069 if (!ripng)
1070 return;
1071
paul718e3742002-12-13 20:15:29 +00001072 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1073 if ((rinfo = rp->info) != NULL)
1074 {
hassoa94434b2003-05-25 17:10:12 +00001075 if ((rinfo->type == type)
1076 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001077 {
hassoa94434b2003-05-25 17:10:12 +00001078 /* Perform poisoned reverse. */
1079 rinfo->metric = RIPNG_METRIC_INFINITY;
1080 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1081 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001082 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001083
hassoa94434b2003-05-25 17:10:12 +00001084 /* Aggregate count decrement. */
1085 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001086
hassoa94434b2003-05-25 17:10:12 +00001087 rinfo->flags |= RIPNG_RTF_CHANGED;
1088
1089 if (IS_RIPNG_DEBUG_EVENT) {
1090 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1091
ajsc6106812004-12-08 19:51:16 +00001092 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001093 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001094 ifindex2ifname(rinfo->ifindex));
1095 }
1096
1097 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001098 }
1099 }
1100}
1101
1102/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001103static void
paul718e3742002-12-13 20:15:29 +00001104ripng_response_process (struct ripng_packet *packet, int size,
1105 struct sockaddr_in6 *from, struct interface *ifp,
1106 int hoplimit)
1107{
1108 caddr_t lim;
1109 struct rte *rte;
1110 struct ripng_nexthop nexthop;
1111
1112 /* RFC2080 2.4.2 Response Messages:
1113 The Response must be ignored if it is not from the RIPng port. */
1114 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1115 {
1116 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001117 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001118 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001119 return;
1120 }
1121
1122 /* The datagram's IPv6 source address should be checked to see
1123 whether the datagram is from a valid neighbor; the source of the
1124 datagram must be a link-local address. */
1125 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1126 {
1127 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001128 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001129 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001130 return;
1131 }
1132
1133 /* It is also worth checking to see whether the response is from one
1134 of the router's own addresses. Interfaces on broadcast networks
1135 may receive copies of their own multicasts immediately. If a
1136 router processes its own output as new input, confusion is likely,
1137 and such datagrams must be ignored. */
1138 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1139 {
1140 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001141 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001142 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001143 return;
1144 }
1145
1146 /* As an additional check, periodic advertisements must have their
1147 hop counts set to 255, and inbound, multicast packets sent from the
1148 RIPng port (i.e. periodic advertisement or triggered update
1149 packets) must be examined to ensure that the hop count is 255. */
1150 if (hoplimit >= 0 && hoplimit != 255)
1151 {
1152 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001153 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001154 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001155 return;
1156 }
1157
hassoa94434b2003-05-25 17:10:12 +00001158 /* Update RIPng peer. */
1159 ripng_peer_update (from, packet->version);
1160
paul718e3742002-12-13 20:15:29 +00001161 /* Reset nexthop. */
1162 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1163 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1164
1165 /* Set RTE pointer. */
1166 rte = packet->rte;
1167
1168 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1169 {
1170 /* First of all, we have to check this RTE is next hop RTE or
1171 not. Next hop RTE is completely different with normal RTE so
1172 we need special treatment. */
1173 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1174 {
1175 ripng_nexthop_rte (rte, from, &nexthop);
1176 continue;
1177 }
1178
1179 /* RTE information validation. */
1180
1181 /* - is the destination prefix valid (e.g., not a multicast
1182 prefix and not a link-local address) A link-local address
1183 should never be present in an RTE. */
1184 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1185 {
1186 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001187 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001188 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001189 continue;
1190 }
1191 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1192 {
1193 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001194 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001195 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001196 continue;
1197 }
1198 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1199 {
1200 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001201 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001202 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001203 continue;
1204 }
1205
1206 /* - is the prefix length valid (i.e., between 0 and 128,
1207 inclusive) */
1208 if (rte->prefixlen > 128)
1209 {
1210 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001211 inet6_ntoa (rte->addr), rte->prefixlen,
1212 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001213 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001214 continue;
1215 }
1216
1217 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1218 if (! (rte->metric >= 1 && rte->metric <= 16))
1219 {
1220 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001221 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001222 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001223 continue;
1224 }
1225
hassoa94434b2003-05-25 17:10:12 +00001226 /* Vincent: XXX Should we compute the direclty reachable nexthop
1227 * for our RIPng network ?
1228 **/
paul718e3742002-12-13 20:15:29 +00001229
1230 /* Routing table updates. */
1231 ripng_route_process (rte, from, &nexthop, ifp);
1232 }
1233}
1234
1235/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001236static void
paul718e3742002-12-13 20:15:29 +00001237ripng_request_process (struct ripng_packet *packet,int size,
1238 struct sockaddr_in6 *from, struct interface *ifp)
1239{
1240 caddr_t lim;
1241 struct rte *rte;
1242 struct prefix_ipv6 p;
1243 struct route_node *rp;
1244 struct ripng_info *rinfo;
1245 struct ripng_interface *ri;
1246
hassoa94434b2003-05-25 17:10:12 +00001247 /* Does not reponse to the requests on the loopback interfaces */
1248 if (if_is_loopback (ifp))
1249 return;
1250
paul718e3742002-12-13 20:15:29 +00001251 /* Check RIPng process is enabled on this interface. */
1252 ri = ifp->info;
1253 if (! ri->running)
1254 return;
1255
1256 /* When passive interface is specified, suppress responses */
1257 if (ri->passive)
1258 return;
1259
hassoa94434b2003-05-25 17:10:12 +00001260 /* RIPng peer update. */
1261 ripng_peer_update (from, packet->version);
1262
paul718e3742002-12-13 20:15:29 +00001263 lim = ((caddr_t) packet) + size;
1264 rte = packet->rte;
1265
1266 /* The Request is processed entry by entry. If there are no
1267 entries, no response is given. */
1268 if (lim == (caddr_t) rte)
1269 return;
1270
1271 /* There is one special case. If there is exactly one entry in the
1272 request, and it has a destination prefix of zero, a prefix length
1273 of zero, and a metric of infinity (i.e., 16), then this is a
1274 request to send the entire routing table. In that case, a call
1275 is made to the output process to send the routing table to the
1276 requesting address/port. */
1277 if (lim == ((caddr_t) (rte + 1)) &&
1278 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1279 rte->prefixlen == 0 &&
1280 rte->metric == RIPNG_METRIC_INFINITY)
1281 {
1282 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001283 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001284 }
1285 else
1286 {
1287 /* Except for this special case, processing is quite simple.
1288 Examine the list of RTEs in the Request one by one. For each
1289 entry, look up the destination in the router's routing
1290 database and, if there is a route, put that route's metric in
1291 the metric field of the RTE. If there is no explicit route
1292 to the specified destination, put infinity in the metric
1293 field. Once all the entries have been filled in, change the
1294 command from Request to Response and send the datagram back
1295 to the requestor. */
1296 memset (&p, 0, sizeof (struct prefix_ipv6));
1297 p.family = AF_INET6;
1298
1299 for (; ((caddr_t) rte) < lim; rte++)
1300 {
1301 p.prefix = rte->addr;
1302 p.prefixlen = rte->prefixlen;
1303 apply_mask_ipv6 (&p);
1304
1305 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1306
1307 if (rp)
1308 {
1309 rinfo = rp->info;
1310 rte->metric = rinfo->metric;
1311 route_unlock_node (rp);
1312 }
1313 else
1314 rte->metric = RIPNG_METRIC_INFINITY;
1315 }
1316 packet->command = RIPNG_RESPONSE;
1317
1318 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1319 }
1320}
1321
1322/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001323static int
paul718e3742002-12-13 20:15:29 +00001324ripng_read (struct thread *thread)
1325{
1326 int len;
1327 int sock;
1328 struct sockaddr_in6 from;
1329 struct ripng_packet *packet;
1330 unsigned int ifindex;
1331 struct interface *ifp;
1332 int hoplimit = -1;
1333
1334 /* Check ripng is active and alive. */
1335 assert (ripng != NULL);
1336 assert (ripng->sock >= 0);
1337
1338 /* Fetch thread data and set read pointer to empty for event
1339 managing. `sock' sould be same as ripng->sock. */
1340 sock = THREAD_FD (thread);
1341 ripng->t_read = NULL;
1342
1343 /* Add myself to the next event. */
1344 ripng_event (RIPNG_READ, sock);
1345
1346 /* Read RIPng packet. */
1347 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1348 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1349 &hoplimit);
1350 if (len < 0)
1351 {
ajs6099b3b2004-11-20 02:06:59 +00001352 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001353 return len;
1354 }
1355
1356 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1357 (4)) must be multiple size of one RTE size (20). */
1358 if (((len - 4) % 20) != 0)
1359 {
1360 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001361 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001362 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001363 return 0;
1364 }
1365
1366 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1367 ifp = if_lookup_by_index (ifindex);
1368
1369 /* RIPng packet received. */
1370 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001371 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001372 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001373 ifp ? ifp->name : "unknown");
1374
1375 /* Logging before packet checking. */
1376 if (IS_RIPNG_DEBUG_RECV)
1377 ripng_packet_dump (packet, len, "RECV");
1378
1379 /* Packet comes from unknown interface. */
1380 if (ifp == NULL)
1381 {
1382 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1383 return 0;
1384 }
1385
1386 /* Packet version mismatch checking. */
1387 if (packet->version != ripng->version)
1388 {
1389 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1390 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001391 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001392 return 0;
1393 }
1394
1395 /* Process RIPng packet. */
1396 switch (packet->command)
1397 {
1398 case RIPNG_REQUEST:
1399 ripng_request_process (packet, len, &from, ifp);
1400 break;
1401 case RIPNG_RESPONSE:
1402 ripng_response_process (packet, len, &from, ifp, hoplimit);
1403 break;
1404 default:
1405 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001406 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001407 break;
1408 }
1409 return 0;
1410}
1411
1412/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001413static void
1414ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001415{
1416 struct route_node *rp;
1417 struct ripng_info *rinfo;
1418
1419 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1420 if ((rinfo = rp->info) != NULL)
1421 if (rinfo->flags & RIPNG_RTF_CHANGED)
1422 rinfo->flags &= ~RIPNG_RTF_CHANGED;
1423}
1424
1425/* Regular update of RIPng route. Send all routing formation to RIPng
1426 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001427static int
paul718e3742002-12-13 20:15:29 +00001428ripng_update (struct thread *t)
1429{
hasso52dc7ee2004-09-23 19:18:23 +00001430 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001431 struct interface *ifp;
1432 struct ripng_interface *ri;
1433
1434 /* Clear update timer thread. */
1435 ripng->t_update = NULL;
1436
1437 /* Logging update event. */
1438 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001439 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001440
1441 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001442 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001443 {
paul718e3742002-12-13 20:15:29 +00001444 ri = ifp->info;
1445
1446 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1447 continue;
1448
1449 if (! ri->running)
1450 continue;
1451
1452 /* When passive interface is specified, suppress announce to the
1453 interface. */
1454 if (ri->passive)
1455 continue;
1456
1457#if RIPNG_ADVANCED
1458 if (ri->ri_send == RIPNG_SEND_OFF)
1459 {
1460 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001461 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001462 "[Event] RIPng send to if %d is suppressed by config",
1463 ifp->ifindex);
1464 continue;
1465 }
1466#endif /* RIPNG_ADVANCED */
1467
hassoa94434b2003-05-25 17:10:12 +00001468 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001469 }
1470
1471 /* Triggered updates may be suppressed if a regular update is due by
1472 the time the triggered update would be sent. */
1473 if (ripng->t_triggered_interval)
1474 {
1475 thread_cancel (ripng->t_triggered_interval);
1476 ripng->t_triggered_interval = NULL;
1477 }
1478 ripng->trigger = 0;
1479
1480 /* Reset flush event. */
1481 ripng_event (RIPNG_UPDATE_EVENT, 0);
1482
1483 return 0;
1484}
1485
1486/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001487static int
paul718e3742002-12-13 20:15:29 +00001488ripng_triggered_interval (struct thread *t)
1489{
1490 ripng->t_triggered_interval = NULL;
1491
1492 if (ripng->trigger)
1493 {
1494 ripng->trigger = 0;
1495 ripng_triggered_update (t);
1496 }
1497 return 0;
1498}
1499
1500/* Execute triggered update. */
1501int
1502ripng_triggered_update (struct thread *t)
1503{
hasso52dc7ee2004-09-23 19:18:23 +00001504 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001505 struct interface *ifp;
1506 struct ripng_interface *ri;
1507 int interval;
1508
1509 ripng->t_triggered_update = NULL;
1510
1511 /* Cancel interval timer. */
1512 if (ripng->t_triggered_interval)
1513 {
1514 thread_cancel (ripng->t_triggered_interval);
1515 ripng->t_triggered_interval = NULL;
1516 }
1517 ripng->trigger = 0;
1518
1519 /* Logging triggered update. */
1520 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001521 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001522
1523 /* Split Horizon processing is done when generating triggered
1524 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001525 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001526 {
paul718e3742002-12-13 20:15:29 +00001527 ri = ifp->info;
1528
1529 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1530 continue;
1531
1532 if (! ri->running)
1533 continue;
1534
1535 /* When passive interface is specified, suppress announce to the
1536 interface. */
1537 if (ri->passive)
1538 continue;
1539
hassoa94434b2003-05-25 17:10:12 +00001540 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001541 }
1542
1543 /* Once all of the triggered updates have been generated, the route
1544 change flags should be cleared. */
1545 ripng_clear_changed_flag ();
1546
1547 /* After a triggered update is sent, a timer should be set for a
1548 random interval between 1 and 5 seconds. If other changes that
1549 would trigger updates occur before the timer expires, a single
1550 update is triggered when the timer expires. */
1551 interval = (random () % 5) + 1;
1552
1553 ripng->t_triggered_interval =
1554 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1555
1556 return 0;
1557}
1558
1559/* Write routing table entry to the stream and return next index of
1560 the routing table entry in the stream. */
1561int
1562ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001563 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001564{
1565 /* RIPng packet header. */
1566 if (num == 0)
1567 {
1568 stream_putc (s, RIPNG_RESPONSE);
1569 stream_putc (s, RIPNG_V1);
1570 stream_putw (s, 0);
1571 }
1572
1573 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001574 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001575 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001576 else
hassoc9e52be2004-09-26 16:09:34 +00001577 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001578 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001579 if (p)
1580 stream_putc (s, p->prefixlen);
1581 else
1582 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001583 stream_putc (s, metric);
1584
1585 return ++num;
1586}
1587
1588/* Send RESPONSE message to specified destination. */
1589void
1590ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001591 int route_type)
paul718e3742002-12-13 20:15:29 +00001592{
1593 int ret;
paul718e3742002-12-13 20:15:29 +00001594 struct route_node *rp;
1595 struct ripng_info *rinfo;
1596 struct ripng_interface *ri;
1597 struct ripng_aggregate *aggregate;
1598 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001599 struct list * ripng_rte_list;
paul718e3742002-12-13 20:15:29 +00001600
hassoa94434b2003-05-25 17:10:12 +00001601 if (IS_RIPNG_DEBUG_EVENT) {
1602 if (to)
ajsc6106812004-12-08 19:51:16 +00001603 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001604 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001605 else
ajsc6106812004-12-08 19:51:16 +00001606 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001607 }
paul718e3742002-12-13 20:15:29 +00001608
paul718e3742002-12-13 20:15:29 +00001609 /* Get RIPng interface. */
1610 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001611
1612 ripng_rte_list = ripng_rte_new();
1613
paul718e3742002-12-13 20:15:29 +00001614 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1615 {
1616 if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
1617 {
hassoa94434b2003-05-25 17:10:12 +00001618 /* If no route-map are applied, the RTE will be these following
1619 * informations.
1620 */
paul718e3742002-12-13 20:15:29 +00001621 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001622 rinfo->metric_out = rinfo->metric;
1623 rinfo->tag_out = rinfo->tag;
1624 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1625 /* In order to avoid some local loops,
1626 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1627 * otherwise set it to 0. The nexthop should not be propagated
1628 * beyond the local broadcast/multicast area in order
1629 * to avoid an IGP multi-level recursive look-up.
1630 */
1631 if (rinfo->ifindex == ifp->ifindex)
1632 rinfo->nexthop_out = rinfo->nexthop;
1633
1634 /* Apply output filters. */
1635 ret = ripng_outgoing_filter (p, ri);
1636 if (ret < 0)
1637 continue;
paul718e3742002-12-13 20:15:29 +00001638
1639 /* Changed route only output. */
1640 if (route_type == ripng_changed_route &&
1641 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1642 continue;
1643
1644 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001645 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1646 {
1647 /* We perform split horizon for RIPng routes. */
1648 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1649 rinfo->ifindex == ifp->ifindex)
1650 continue;
1651 }
paul718e3742002-12-13 20:15:29 +00001652
1653 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001654 rinfo->metric_set = 0;
1655 /* nexthop_out,
1656 * metric_out
1657 * and tag_out are already initialized.
1658 */
paul718e3742002-12-13 20:15:29 +00001659
hassoa94434b2003-05-25 17:10:12 +00001660 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001661 if (ri->routemap[RIPNG_FILTER_OUT])
1662 {
1663 int ret;
paul718e3742002-12-13 20:15:29 +00001664
1665 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1666 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001667 rinfo);
paul718e3742002-12-13 20:15:29 +00001668
1669 if (ret == RMAP_DENYMATCH)
1670 {
1671 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001672 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001673 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001674 continue;
paul718e3742002-12-13 20:15:29 +00001675 }
1676
paul718e3742002-12-13 20:15:29 +00001677 }
1678
hassoa94434b2003-05-25 17:10:12 +00001679 /* Redistribute route-map. */
1680 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001681 {
hassoa94434b2003-05-25 17:10:12 +00001682 int ret;
1683
1684 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1685 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001686 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001687
1688 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001689 {
hassoa94434b2003-05-25 17:10:12 +00001690 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001691 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001692 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001693 continue;
paul718e3742002-12-13 20:15:29 +00001694 }
hassoa94434b2003-05-25 17:10:12 +00001695 }
paul718e3742002-12-13 20:15:29 +00001696
hassoa94434b2003-05-25 17:10:12 +00001697 /* When the route-map does not set metric. */
1698 if (! rinfo->metric_set)
1699 {
1700 /* If the redistribute metric is set. */
1701 if (ripng->route_map[rinfo->type].metric_config
1702 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001703 {
hassoa94434b2003-05-25 17:10:12 +00001704 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1705 }
1706 else
1707 {
1708 /* If the route is not connected or localy generated
1709 one, use default-metric value */
1710 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1711 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001712 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001713 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001714 }
1715 }
1716
hassoa94434b2003-05-25 17:10:12 +00001717 /* Apply offset-list */
1718 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1719 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001720
hassoa94434b2003-05-25 17:10:12 +00001721 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1722 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1723
1724 /* Perform split-horizon with poisoned reverse
1725 * for RIPng routes.
1726 **/
1727 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1728 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1729 rinfo->ifindex == ifp->ifindex)
1730 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1731 }
1732
1733 /* Add RTE to the list */
1734 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001735 }
hassoa94434b2003-05-25 17:10:12 +00001736
1737 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001738 if ((aggregate = rp->aggregate) != NULL &&
1739 aggregate->count > 0 &&
1740 aggregate->suppress == 0)
1741 {
hassoa94434b2003-05-25 17:10:12 +00001742 /* If no route-map are applied, the RTE will be these following
1743 * informations.
1744 */
paul718e3742002-12-13 20:15:29 +00001745 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001746 aggregate->metric_set = 0;
1747 aggregate->metric_out = aggregate->metric;
1748 aggregate->tag_out = aggregate->tag;
1749 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001750
1751 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001752 ret = ripng_outgoing_filter (p, ri);
1753 if (ret < 0)
1754 continue;
paul718e3742002-12-13 20:15:29 +00001755
hassoa94434b2003-05-25 17:10:12 +00001756 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001757 if (ri->routemap[RIPNG_FILTER_OUT])
1758 {
1759 int ret;
1760 struct ripng_info newinfo;
1761
hassoa94434b2003-05-25 17:10:12 +00001762 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001763 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001764 /* the nexthop is :: */
1765 newinfo.metric = aggregate->metric;
1766 newinfo.metric_out = aggregate->metric_out;
1767 newinfo.tag = aggregate->tag;
1768 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001769
1770 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1771 (struct prefix *) p, RMAP_RIPNG,
1772 &newinfo);
1773
1774 if (ret == RMAP_DENYMATCH)
1775 {
1776 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001777 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001778 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001779 continue;
paul718e3742002-12-13 20:15:29 +00001780 }
1781
hassoa94434b2003-05-25 17:10:12 +00001782 aggregate->metric_out = newinfo.metric_out;
1783 aggregate->tag_out = newinfo.tag_out;
1784 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1785 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001786 }
1787
hassoa94434b2003-05-25 17:10:12 +00001788 /* There is no redistribute routemap for the aggregated RTE */
1789
paul718e3742002-12-13 20:15:29 +00001790 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001791 /* XXX, vincent, in order to increase time convergence,
1792 * it should be announced if a child has changed.
1793 */
paul718e3742002-12-13 20:15:29 +00001794 if (route_type == ripng_changed_route)
1795 continue;
1796
hassoa94434b2003-05-25 17:10:12 +00001797 /* Apply offset-list */
1798 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1799 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001800
hassoa94434b2003-05-25 17:10:12 +00001801 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1802 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1803
1804 /* Add RTE to the list */
1805 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001806 }
1807
1808 }
paul718e3742002-12-13 20:15:29 +00001809
hassoa94434b2003-05-25 17:10:12 +00001810 /* Flush the list */
1811 ripng_rte_send(ripng_rte_list, ifp, to);
1812 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001813}
1814
1815/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001816static int
1817ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001818{
1819 /* ripng should be NULL. */
1820 assert (ripng == NULL);
1821
1822 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001823 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001824
1825 /* Default version and timer values. */
1826 ripng->version = RIPNG_V1;
1827 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1828 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1829 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1830 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1831
1832 /* Make buffer. */
1833 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1834 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1835
1836 /* Initialize RIPng routig table. */
1837 ripng->table = route_table_init ();
1838 ripng->route = route_table_init ();
1839 ripng->aggregate = route_table_init ();
1840
1841 /* Make socket. */
1842 ripng->sock = ripng_make_socket ();
1843 if (ripng->sock < 0)
1844 return ripng->sock;
1845
1846 /* Threads. */
1847 ripng_event (RIPNG_READ, ripng->sock);
1848 ripng_event (RIPNG_UPDATE_EVENT, 1);
1849
1850 return 0;
1851}
1852
hassoa94434b2003-05-25 17:10:12 +00001853/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001854int
1855ripng_request (struct interface *ifp)
1856{
1857 struct rte *rte;
1858 struct ripng_packet ripng_packet;
1859
hassoa94434b2003-05-25 17:10:12 +00001860 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1861 if (if_is_loopback(ifp))
1862 return 0;
1863
1864 /* If interface is down, don't send RIP packet. */
1865 if (! if_is_up (ifp))
1866 return 0;
1867
paul718e3742002-12-13 20:15:29 +00001868 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001869 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001870
1871 memset (&ripng_packet, 0, sizeof (ripng_packet));
1872 ripng_packet.command = RIPNG_REQUEST;
1873 ripng_packet.version = RIPNG_V1;
1874 rte = ripng_packet.rte;
1875 rte->metric = RIPNG_METRIC_INFINITY;
1876
1877 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1878 NULL, ifp);
1879}
1880
paul718e3742002-12-13 20:15:29 +00001881
Paul Jakma6ac29a52008-08-15 13:45:30 +01001882static int
paul718e3742002-12-13 20:15:29 +00001883ripng_update_jitter (int time)
1884{
1885 return ((rand () % (time + 1)) - (time / 2));
1886}
1887
1888void
1889ripng_event (enum ripng_event event, int sock)
1890{
paul718e3742002-12-13 20:15:29 +00001891 int jitter = 0;
1892
1893 switch (event)
1894 {
1895 case RIPNG_READ:
1896 if (!ripng->t_read)
1897 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1898 break;
1899 case RIPNG_UPDATE_EVENT:
1900 if (ripng->t_update)
1901 {
1902 thread_cancel (ripng->t_update);
1903 ripng->t_update = NULL;
1904 }
1905 /* Update timer jitter. */
1906 jitter = ripng_update_jitter (ripng->update_time);
1907
1908 ripng->t_update =
1909 thread_add_timer (master, ripng_update, NULL,
1910 sock ? 2 : ripng->update_time + jitter);
1911 break;
1912 case RIPNG_TRIGGERED_UPDATE:
1913 if (ripng->t_triggered_interval)
1914 ripng->trigger = 1;
1915 else if (! ripng->t_triggered_update)
1916 ripng->t_triggered_update =
1917 thread_add_event (master, ripng_triggered_update, NULL, 0);
1918 break;
1919 default:
1920 break;
1921 }
1922}
1923
paul718e3742002-12-13 20:15:29 +00001924
paul718e3742002-12-13 20:15:29 +00001925/* Print out routes update time. */
1926static void
1927ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1928{
paul718e3742002-12-13 20:15:29 +00001929 time_t clock;
1930 struct tm *tm;
1931#define TIME_BUF 25
1932 char timebuf [TIME_BUF];
1933 struct thread *thread;
1934
paul718e3742002-12-13 20:15:29 +00001935 if ((thread = rinfo->t_timeout) != NULL)
1936 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001937 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001938 tm = gmtime (&clock);
1939 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1940 vty_out (vty, "%5s", timebuf);
1941 }
1942 else if ((thread = rinfo->t_garbage_collect) != NULL)
1943 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001944 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001945 tm = gmtime (&clock);
1946 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1947 vty_out (vty, "%5s", timebuf);
1948 }
1949}
1950
Paul Jakma6ac29a52008-08-15 13:45:30 +01001951static char *
hassoa94434b2003-05-25 17:10:12 +00001952ripng_route_subtype_print (struct ripng_info *rinfo)
1953{
1954 static char str[3];
1955 memset(str, 0, 3);
1956
1957 if (rinfo->suppress)
1958 strcat(str, "S");
1959
1960 switch (rinfo->sub_type)
1961 {
1962 case RIPNG_ROUTE_RTE:
1963 strcat(str, "n");
1964 break;
1965 case RIPNG_ROUTE_STATIC:
1966 strcat(str, "s");
1967 break;
1968 case RIPNG_ROUTE_DEFAULT:
1969 strcat(str, "d");
1970 break;
1971 case RIPNG_ROUTE_REDISTRIBUTE:
1972 strcat(str, "r");
1973 break;
1974 case RIPNG_ROUTE_INTERFACE:
1975 strcat(str, "i");
1976 break;
1977 default:
1978 strcat(str, "?");
1979 break;
1980 }
1981
1982 return str;
1983}
1984
paul718e3742002-12-13 20:15:29 +00001985DEFUN (show_ipv6_ripng,
1986 show_ipv6_ripng_cmd,
1987 "show ipv6 ripng",
1988 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001989 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001990 "Show RIPng routes\n")
1991{
1992 struct route_node *rp;
1993 struct ripng_info *rinfo;
1994 struct ripng_aggregate *aggregate;
1995 struct prefix_ipv6 *p;
1996 int len;
1997
hassoa94434b2003-05-25 17:10:12 +00001998 if (! ripng)
1999 return CMD_SUCCESS;
2000
paul718e3742002-12-13 20:15:29 +00002001 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00002002 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2003 "Sub-codes:%s"
2004 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2005 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2006 " Network Next Hop Via Metric Tag Time%s",
2007 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002008 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2009
2010 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2011 {
2012 if ((aggregate = rp->aggregate) != NULL)
2013 {
2014 p = (struct prefix_ipv6 *) &rp->p;
2015
2016#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002017 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002018 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002019 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002020#else
hassoa94434b2003-05-25 17:10:12 +00002021 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002022 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002023#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002024 vty_out (vty, "%s", VTY_NEWLINE);
2025 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002026
hassoa94434b2003-05-25 17:10:12 +00002027 vty_out (vty, "%*s", 28, " ");
2028 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002029 aggregate->tag,
2030 VTY_NEWLINE);
2031 }
2032
2033 if ((rinfo = rp->info) != NULL)
2034 {
2035 p = (struct prefix_ipv6 *) &rp->p;
2036
2037#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002038 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2039 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002040 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002041 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002042 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002043#else
ajsf52d13c2005-10-01 17:38:06 +00002044 len = vty_out (vty, "%c(%s) %s/%d ",
2045 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002046 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002047 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002048#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002049 vty_out (vty, "%s", VTY_NEWLINE);
2050 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002051 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002052
hassoa94434b2003-05-25 17:10:12 +00002053 len = 28 - len;
2054 if (len > 0)
2055 len = vty_out (vty, "%*s", len, " ");
2056
2057 /* from */
2058 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2059 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2060 {
2061 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2062 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2063 {
2064 len = vty_out (vty, "kill");
2065 } else
2066 len = vty_out (vty, "self");
2067
2068 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002069 if (len > 0)
2070 vty_out (vty, "%*s", len, " ");
2071
hassoa94434b2003-05-25 17:10:12 +00002072 vty_out (vty, " %2d %3d ",
2073 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002074
hassoa94434b2003-05-25 17:10:12 +00002075 /* time */
2076 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2077 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2078 {
2079 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002080 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002081 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2082 {
2083 /* poisonous reversed routes (gc) */
2084 ripng_vty_out_uptime (vty, rinfo);
2085 }
paul718e3742002-12-13 20:15:29 +00002086
2087 vty_out (vty, "%s", VTY_NEWLINE);
2088 }
2089 }
2090
2091 return CMD_SUCCESS;
2092}
2093
hassoa94434b2003-05-25 17:10:12 +00002094DEFUN (show_ipv6_ripng_status,
2095 show_ipv6_ripng_status_cmd,
2096 "show ipv6 ripng status",
2097 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002098 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002099 "Show RIPng routes\n"
2100 "IPv6 routing protocol process parameters and statistics\n")
2101{
hasso52dc7ee2004-09-23 19:18:23 +00002102 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002103 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002104
2105 if (! ripng)
2106 return CMD_SUCCESS;
2107
2108 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2109 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2110 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002111 vty_out (vty, " next due in %lu seconds%s",
2112 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002113 VTY_NEWLINE);
2114 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2115 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2116 VTY_NEWLINE);
2117
2118 /* Filtering status show. */
2119 config_show_distribute (vty);
2120
2121 /* Default metric information. */
2122 vty_out (vty, " Default redistribution metric is %d%s",
2123 ripng->default_metric, VTY_NEWLINE);
2124
2125 /* Redistribute information. */
2126 vty_out (vty, " Redistributing:");
2127 ripng_redistribute_write (vty, 0);
2128 vty_out (vty, "%s", VTY_NEWLINE);
2129
2130 vty_out (vty, " Default version control: send version %d,", ripng->version);
2131 vty_out (vty, " receive version %d %s", ripng->version,
2132 VTY_NEWLINE);
2133
2134 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2135
paul1eb8ef22005-04-07 07:30:20 +00002136 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002137 {
2138 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002139
hassoa94434b2003-05-25 17:10:12 +00002140 ri = ifp->info;
2141
2142 if (ri->enable_network || ri->enable_interface)
2143 {
2144
2145 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2146 ripng->version,
2147 ripng->version,
2148 VTY_NEWLINE);
2149 }
2150 }
2151
2152 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2153 ripng_network_write (vty, 0);
2154
2155 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2156 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2157 ripng_peer_display (vty);
2158
2159 return CMD_SUCCESS;
2160}
2161
paul718e3742002-12-13 20:15:29 +00002162DEFUN (router_ripng,
2163 router_ripng_cmd,
2164 "router ripng",
2165 "Enable a routing process\n"
2166 "Make RIPng instance command\n")
2167{
2168 int ret;
2169
2170 vty->node = RIPNG_NODE;
2171
2172 if (!ripng)
2173 {
2174 ret = ripng_create ();
2175
2176 /* Notice to user we couldn't create RIPng. */
2177 if (ret < 0)
2178 {
2179 zlog_warn ("can't create RIPng");
2180 return CMD_WARNING;
2181 }
2182 }
2183
2184 return CMD_SUCCESS;
2185}
2186
hassoa94434b2003-05-25 17:10:12 +00002187DEFUN (no_router_ripng,
2188 no_router_ripng_cmd,
2189 "no router ripng",
2190 NO_STR
2191 "Enable a routing process\n"
2192 "Make RIPng instance command\n")
2193{
2194 if(ripng)
2195 ripng_clean();
2196 return CMD_SUCCESS;
2197}
2198
paul718e3742002-12-13 20:15:29 +00002199DEFUN (ripng_route,
2200 ripng_route_cmd,
2201 "route IPV6ADDR",
2202 "Static route setup\n"
2203 "Set static RIPng route announcement\n")
2204{
2205 int ret;
2206 struct prefix_ipv6 p;
2207 struct route_node *rp;
2208
2209 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2210 if (ret <= 0)
2211 {
2212 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2213 return CMD_WARNING;
2214 }
2215 apply_mask_ipv6 (&p);
2216
2217 rp = route_node_get (ripng->route, (struct prefix *) &p);
2218 if (rp->info)
2219 {
2220 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2221 route_unlock_node (rp);
2222 return CMD_WARNING;
2223 }
2224 rp->info = (void *)1;
2225
hassoa94434b2003-05-25 17:10:12 +00002226 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002227
2228 return CMD_SUCCESS;
2229}
2230
2231DEFUN (no_ripng_route,
2232 no_ripng_route_cmd,
2233 "no route IPV6ADDR",
2234 NO_STR
2235 "Static route setup\n"
2236 "Delete static RIPng route announcement\n")
2237{
2238 int ret;
2239 struct prefix_ipv6 p;
2240 struct route_node *rp;
2241
2242 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2243 if (ret <= 0)
2244 {
2245 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2246 return CMD_WARNING;
2247 }
2248 apply_mask_ipv6 (&p);
2249
2250 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2251 if (! rp)
2252 {
2253 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2254 return CMD_WARNING;
2255 }
2256
2257 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2258 route_unlock_node (rp);
2259
2260 rp->info = NULL;
2261 route_unlock_node (rp);
2262
2263 return CMD_SUCCESS;
2264}
2265
2266DEFUN (ripng_aggregate_address,
2267 ripng_aggregate_address_cmd,
2268 "aggregate-address X:X::X:X/M",
2269 "Set aggregate RIPng route announcement\n"
2270 "Aggregate network\n")
2271{
2272 int ret;
2273 struct prefix p;
2274 struct route_node *node;
2275
2276 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2277 if (ret <= 0)
2278 {
2279 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2280 return CMD_WARNING;
2281 }
2282
2283 /* Check aggregate alredy exist or not. */
2284 node = route_node_get (ripng->aggregate, &p);
2285 if (node->info)
2286 {
2287 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2288 route_unlock_node (node);
2289 return CMD_WARNING;
2290 }
2291 node->info = (void *)1;
2292
2293 ripng_aggregate_add (&p);
2294
2295 return CMD_SUCCESS;
2296}
2297
2298DEFUN (no_ripng_aggregate_address,
2299 no_ripng_aggregate_address_cmd,
2300 "no aggregate-address X:X::X:X/M",
2301 NO_STR
2302 "Delete aggregate RIPng route announcement\n"
2303 "Aggregate network")
2304{
2305 int ret;
2306 struct prefix p;
2307 struct route_node *rn;
2308
2309 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2310 if (ret <= 0)
2311 {
2312 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2313 return CMD_WARNING;
2314 }
2315
2316 rn = route_node_lookup (ripng->aggregate, &p);
2317 if (! rn)
2318 {
2319 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2320 return CMD_WARNING;
2321 }
2322 route_unlock_node (rn);
2323 rn->info = NULL;
2324 route_unlock_node (rn);
2325
2326 ripng_aggregate_delete (&p);
2327
2328 return CMD_SUCCESS;
2329}
2330
2331DEFUN (ripng_default_metric,
2332 ripng_default_metric_cmd,
2333 "default-metric <1-16>",
2334 "Set a metric of redistribute routes\n"
2335 "Default metric\n")
2336{
2337 if (ripng)
2338 {
2339 ripng->default_metric = atoi (argv[0]);
2340 }
2341 return CMD_SUCCESS;
2342}
2343
2344DEFUN (no_ripng_default_metric,
2345 no_ripng_default_metric_cmd,
2346 "no default-metric",
2347 NO_STR
2348 "Set a metric of redistribute routes\n"
2349 "Default metric\n")
2350{
2351 if (ripng)
2352 {
2353 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2354 }
2355 return CMD_SUCCESS;
2356}
2357
2358ALIAS (no_ripng_default_metric,
2359 no_ripng_default_metric_val_cmd,
2360 "no default-metric <1-16>",
2361 NO_STR
2362 "Set a metric of redistribute routes\n"
2363 "Default metric\n")
2364
2365#if 0
2366/* RIPng update timer setup. */
2367DEFUN (ripng_update_timer,
2368 ripng_update_timer_cmd,
2369 "update-timer SECOND",
2370 "Set RIPng update timer in seconds\n"
2371 "Seconds\n")
2372{
2373 unsigned long update;
2374 char *endptr = NULL;
2375
2376 update = strtoul (argv[0], &endptr, 10);
2377 if (update == ULONG_MAX || *endptr != '\0')
2378 {
2379 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2380 return CMD_WARNING;
2381 }
2382
2383 ripng->update_time = update;
2384
2385 ripng_event (RIPNG_UPDATE_EVENT, 0);
2386 return CMD_SUCCESS;
2387}
2388
2389DEFUN (no_ripng_update_timer,
2390 no_ripng_update_timer_cmd,
2391 "no update-timer SECOND",
2392 NO_STR
2393 "Unset RIPng update timer in seconds\n"
2394 "Seconds\n")
2395{
2396 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2397 ripng_event (RIPNG_UPDATE_EVENT, 0);
2398 return CMD_SUCCESS;
2399}
2400
2401/* RIPng timeout timer setup. */
2402DEFUN (ripng_timeout_timer,
2403 ripng_timeout_timer_cmd,
2404 "timeout-timer SECOND",
2405 "Set RIPng timeout timer in seconds\n"
2406 "Seconds\n")
2407{
2408 unsigned long timeout;
2409 char *endptr = NULL;
2410
2411 timeout = strtoul (argv[0], &endptr, 10);
2412 if (timeout == ULONG_MAX || *endptr != '\0')
2413 {
2414 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2415 return CMD_WARNING;
2416 }
2417
2418 ripng->timeout_time = timeout;
2419
2420 return CMD_SUCCESS;
2421}
2422
2423DEFUN (no_ripng_timeout_timer,
2424 no_ripng_timeout_timer_cmd,
2425 "no timeout-timer SECOND",
2426 NO_STR
2427 "Unset RIPng timeout timer in seconds\n"
2428 "Seconds\n")
2429{
2430 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2431 return CMD_SUCCESS;
2432}
2433
2434/* RIPng garbage timer setup. */
2435DEFUN (ripng_garbage_timer,
2436 ripng_garbage_timer_cmd,
2437 "garbage-timer SECOND",
2438 "Set RIPng garbage timer in seconds\n"
2439 "Seconds\n")
2440{
2441 unsigned long garbage;
2442 char *endptr = NULL;
2443
2444 garbage = strtoul (argv[0], &endptr, 10);
2445 if (garbage == ULONG_MAX || *endptr != '\0')
2446 {
2447 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2448 return CMD_WARNING;
2449 }
2450
2451 ripng->garbage_time = garbage;
2452
2453 return CMD_SUCCESS;
2454}
2455
2456DEFUN (no_ripng_garbage_timer,
2457 no_ripng_garbage_timer_cmd,
2458 "no garbage-timer SECOND",
2459 NO_STR
2460 "Unset RIPng garbage timer in seconds\n"
2461 "Seconds\n")
2462{
2463 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2464 return CMD_SUCCESS;
2465}
2466#endif /* 0 */
2467
2468DEFUN (ripng_timers,
2469 ripng_timers_cmd,
2470 "timers basic <0-65535> <0-65535> <0-65535>",
2471 "RIPng timers setup\n"
2472 "Basic timer\n"
2473 "Routing table update timer value in second. Default is 30.\n"
2474 "Routing information timeout timer. Default is 180.\n"
2475 "Garbage collection timer. Default is 120.\n")
2476{
2477 unsigned long update;
2478 unsigned long timeout;
2479 unsigned long garbage;
2480 char *endptr = NULL;
2481
2482 update = strtoul (argv[0], &endptr, 10);
2483 if (update == ULONG_MAX || *endptr != '\0')
2484 {
2485 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2486 return CMD_WARNING;
2487 }
2488
2489 timeout = strtoul (argv[1], &endptr, 10);
2490 if (timeout == ULONG_MAX || *endptr != '\0')
2491 {
2492 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2493 return CMD_WARNING;
2494 }
2495
2496 garbage = strtoul (argv[2], &endptr, 10);
2497 if (garbage == ULONG_MAX || *endptr != '\0')
2498 {
2499 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2500 return CMD_WARNING;
2501 }
2502
2503 /* Set each timer value. */
2504 ripng->update_time = update;
2505 ripng->timeout_time = timeout;
2506 ripng->garbage_time = garbage;
2507
2508 /* Reset update timer thread. */
2509 ripng_event (RIPNG_UPDATE_EVENT, 0);
2510
2511 return CMD_SUCCESS;
2512}
2513
2514DEFUN (no_ripng_timers,
2515 no_ripng_timers_cmd,
2516 "no timers basic",
2517 NO_STR
2518 "RIPng timers setup\n"
2519 "Basic timer\n")
2520{
2521 /* Set each timer value to the default. */
2522 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2523 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2524 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2525
2526 /* Reset update timer thread. */
2527 ripng_event (RIPNG_UPDATE_EVENT, 0);
2528
2529 return CMD_SUCCESS;
2530}
2531
hassoa94434b2003-05-25 17:10:12 +00002532ALIAS (no_ripng_timers,
2533 no_ripng_timers_val_cmd,
2534 "no timers basic <0-65535> <0-65535> <0-65535>",
2535 NO_STR
2536 "RIPng timers setup\n"
2537 "Basic timer\n"
2538 "Routing table update timer value in second. Default is 30.\n"
2539 "Routing information timeout timer. Default is 180.\n"
2540 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002541
2542DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2543 "show ipv6 protocols",
2544 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002545 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002546 "Routing protocol information")
2547{
2548 if (! ripng)
2549 return CMD_SUCCESS;
2550
2551 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2552
2553 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2554 ripng->update_time, 0,
2555 VTY_NEWLINE);
2556
2557 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2558 ripng->timeout_time,
2559 ripng->garbage_time,
2560 VTY_NEWLINE);
2561
2562 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2563 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2564
2565 return CMD_SUCCESS;
2566}
2567
2568/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002569DEFUN (ripng_default_information_originate,
2570 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002571 "default-information originate",
2572 "Default route information\n"
2573 "Distribute default route\n")
2574{
2575 struct prefix_ipv6 p;
2576
hassoa94434b2003-05-25 17:10:12 +00002577 if (! ripng ->default_information) {
2578 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002579
hassoa94434b2003-05-25 17:10:12 +00002580 str2prefix_ipv6 ("::/0", &p);
2581 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2582 }
paul718e3742002-12-13 20:15:29 +00002583
2584 return CMD_SUCCESS;
2585}
2586
paula2c62832003-04-23 17:01:31 +00002587DEFUN (no_ripng_default_information_originate,
2588 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002589 "no default-information originate",
2590 NO_STR
2591 "Default route information\n"
2592 "Distribute default route\n")
2593{
2594 struct prefix_ipv6 p;
2595
hassoa94434b2003-05-25 17:10:12 +00002596 if (ripng->default_information) {
2597 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002598
hassoa94434b2003-05-25 17:10:12 +00002599 str2prefix_ipv6 ("::/0", &p);
2600 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2601 }
paul718e3742002-12-13 20:15:29 +00002602
2603 return CMD_SUCCESS;
2604}
2605
2606/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002607static int
paul718e3742002-12-13 20:15:29 +00002608ripng_config_write (struct vty *vty)
2609{
hassoa94434b2003-05-25 17:10:12 +00002610 int ripng_network_write (struct vty *, int);
2611 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002612 int write = 0;
2613 struct route_node *rp;
2614
2615 if (ripng)
2616 {
2617
2618 /* RIPng router. */
2619 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2620
2621 if (ripng->default_information)
2622 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2623
hassoa94434b2003-05-25 17:10:12 +00002624 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002625
2626 /* RIPng default metric configuration */
2627 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2628 vty_out (vty, " default-metric %d%s",
2629 ripng->default_metric, VTY_NEWLINE);
2630
hassoa94434b2003-05-25 17:10:12 +00002631 ripng_redistribute_write (vty, 1);
2632
2633 /* RIP offset-list configuration. */
2634 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002635
2636 /* RIPng aggregate routes. */
2637 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2638 if (rp->info != NULL)
2639 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002640 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002641 rp->p.prefixlen,
2642
2643 VTY_NEWLINE);
2644
2645 /* RIPng static routes. */
2646 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2647 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002648 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002649 rp->p.prefixlen,
2650 VTY_NEWLINE);
2651
2652 /* RIPng timers configuration. */
2653 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2654 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2655 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2656 {
2657 vty_out (vty, " timers basic %ld %ld %ld%s",
2658 ripng->update_time,
2659 ripng->timeout_time,
2660 ripng->garbage_time,
2661 VTY_NEWLINE);
2662 }
2663#if 0
2664 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2665 vty_out (vty, " update-timer %d%s", ripng->update_time,
2666 VTY_NEWLINE);
2667 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2668 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2669 VTY_NEWLINE);
2670 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2671 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2672 VTY_NEWLINE);
2673#endif /* 0 */
2674
2675 write += config_write_distribute (vty);
2676
2677 write += config_write_if_rmap (vty);
2678
2679 write++;
2680 }
2681 return write;
2682}
2683
2684/* RIPng node structure. */
2685struct cmd_node cmd_ripng_node =
2686{
2687 RIPNG_NODE,
2688 "%s(config-router)# ",
2689 1,
2690};
2691
Paul Jakma6ac29a52008-08-15 13:45:30 +01002692static void
paul718e3742002-12-13 20:15:29 +00002693ripng_distribute_update (struct distribute *dist)
2694{
2695 struct interface *ifp;
2696 struct ripng_interface *ri;
2697 struct access_list *alist;
2698 struct prefix_list *plist;
2699
2700 if (! dist->ifname)
2701 return;
2702
2703 ifp = if_lookup_by_name (dist->ifname);
2704 if (ifp == NULL)
2705 return;
2706
2707 ri = ifp->info;
2708
2709 if (dist->list[DISTRIBUTE_IN])
2710 {
2711 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2712 if (alist)
2713 ri->list[RIPNG_FILTER_IN] = alist;
2714 else
2715 ri->list[RIPNG_FILTER_IN] = NULL;
2716 }
2717 else
2718 ri->list[RIPNG_FILTER_IN] = NULL;
2719
2720 if (dist->list[DISTRIBUTE_OUT])
2721 {
2722 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2723 if (alist)
2724 ri->list[RIPNG_FILTER_OUT] = alist;
2725 else
2726 ri->list[RIPNG_FILTER_OUT] = NULL;
2727 }
2728 else
2729 ri->list[RIPNG_FILTER_OUT] = NULL;
2730
2731 if (dist->prefix[DISTRIBUTE_IN])
2732 {
2733 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2734 if (plist)
2735 ri->prefix[RIPNG_FILTER_IN] = plist;
2736 else
2737 ri->prefix[RIPNG_FILTER_IN] = NULL;
2738 }
2739 else
2740 ri->prefix[RIPNG_FILTER_IN] = NULL;
2741
2742 if (dist->prefix[DISTRIBUTE_OUT])
2743 {
2744 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2745 if (plist)
2746 ri->prefix[RIPNG_FILTER_OUT] = plist;
2747 else
2748 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2749 }
2750 else
2751 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2752}
hassoa94434b2003-05-25 17:10:12 +00002753
paul718e3742002-12-13 20:15:29 +00002754void
2755ripng_distribute_update_interface (struct interface *ifp)
2756{
2757 struct distribute *dist;
2758
2759 dist = distribute_lookup (ifp->name);
2760 if (dist)
2761 ripng_distribute_update (dist);
2762}
2763
2764/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002765static void
hassoc9e52be2004-09-26 16:09:34 +00002766ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002767{
2768 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002769 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002770
paul1eb8ef22005-04-07 07:30:20 +00002771 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2772 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002773}
hassoc9e52be2004-09-26 16:09:34 +00002774
Paul Jakma6ac29a52008-08-15 13:45:30 +01002775static void
hassoc9e52be2004-09-26 16:09:34 +00002776ripng_distribute_update_all_wrapper (struct access_list *notused)
2777{
2778 ripng_distribute_update_all(NULL);
2779}
hassoa94434b2003-05-25 17:10:12 +00002780
2781/* delete all the added ripng routes. */
2782void
2783ripng_clean()
2784{
2785 int i;
2786 struct route_node *rp;
2787 struct ripng_info *rinfo;
2788
2789 if (ripng) {
2790 /* Clear RIPng routes */
2791 for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
2792 if ((rinfo = rp->info) != NULL) {
2793 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2794 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2795 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
2796 &rinfo->nexthop, rinfo->metric);
2797
2798 RIPNG_TIMER_OFF (rinfo->t_timeout);
2799 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2800
2801 rp->info = NULL;
2802 route_unlock_node (rp);
2803
2804 ripng_info_free(rinfo);
2805 }
2806 }
2807
2808 /* Cancel the RIPng timers */
2809 RIPNG_TIMER_OFF (ripng->t_update);
2810 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2811 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2812
2813 /* Cancel the read thread */
2814 if (ripng->t_read) {
2815 thread_cancel (ripng->t_read);
2816 ripng->t_read = NULL;
2817 }
2818
2819 /* Close the RIPng socket */
2820 if (ripng->sock >= 0) {
2821 close(ripng->sock);
2822 ripng->sock = -1;
2823 }
2824
2825 /* Static RIPng route configuration. */
2826 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2827 if (rp->info) {
2828 rp->info = NULL;
2829 route_unlock_node (rp);
2830 }
2831
2832 /* RIPng aggregated prefixes */
2833 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2834 if (rp->info) {
2835 rp->info = NULL;
2836 route_unlock_node (rp);
2837 }
2838
2839 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2840 if (ripng->route_map[i].name)
2841 free (ripng->route_map[i].name);
2842
2843 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2844 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2845 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2846
2847 XFREE (MTYPE_RIPNG, ripng);
2848 ripng = NULL;
2849 } /* if (ripng) */
2850
2851 ripng_clean_network();
2852 ripng_passive_interface_clean ();
2853 ripng_offset_clean ();
2854 ripng_interface_clean ();
2855 ripng_redistribute_clean ();
2856}
2857
2858/* Reset all values to the default settings. */
2859void
2860ripng_reset ()
2861{
2862 /* Call ripd related reset functions. */
2863 ripng_debug_reset ();
2864 ripng_route_map_reset ();
2865
2866 /* Call library reset functions. */
2867 vty_reset ();
2868 access_list_reset ();
2869 prefix_list_reset ();
2870
2871 distribute_list_reset ();
2872
2873 ripng_interface_reset ();
2874
2875 ripng_zclient_reset ();
2876}
paul718e3742002-12-13 20:15:29 +00002877
Paul Jakma6ac29a52008-08-15 13:45:30 +01002878static void
paul718e3742002-12-13 20:15:29 +00002879ripng_if_rmap_update (struct if_rmap *if_rmap)
2880{
2881 struct interface *ifp;
2882 struct ripng_interface *ri;
2883 struct route_map *rmap;
2884
2885 ifp = if_lookup_by_name (if_rmap->ifname);
2886 if (ifp == NULL)
2887 return;
2888
2889 ri = ifp->info;
2890
2891 if (if_rmap->routemap[IF_RMAP_IN])
2892 {
2893 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2894 if (rmap)
2895 ri->routemap[IF_RMAP_IN] = rmap;
2896 else
2897 ri->routemap[IF_RMAP_IN] = NULL;
2898 }
2899 else
2900 ri->routemap[RIPNG_FILTER_IN] = NULL;
2901
2902 if (if_rmap->routemap[IF_RMAP_OUT])
2903 {
2904 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2905 if (rmap)
2906 ri->routemap[IF_RMAP_OUT] = rmap;
2907 else
2908 ri->routemap[IF_RMAP_OUT] = NULL;
2909 }
2910 else
2911 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2912}
2913
2914void
2915ripng_if_rmap_update_interface (struct interface *ifp)
2916{
2917 struct if_rmap *if_rmap;
2918
2919 if_rmap = if_rmap_lookup (ifp->name);
2920 if (if_rmap)
2921 ripng_if_rmap_update (if_rmap);
2922}
2923
Paul Jakma6ac29a52008-08-15 13:45:30 +01002924static void
paul718e3742002-12-13 20:15:29 +00002925ripng_routemap_update_redistribute (void)
2926{
2927 int i;
2928
2929 if (ripng)
2930 {
2931 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2932 {
2933 if (ripng->route_map[i].name)
2934 ripng->route_map[i].map =
2935 route_map_lookup_by_name (ripng->route_map[i].name);
2936 }
2937 }
2938}
2939
Paul Jakma6ac29a52008-08-15 13:45:30 +01002940static void
hasso98b718a2004-10-11 12:57:57 +00002941ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00002942{
2943 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002944 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002945
paul1eb8ef22005-04-07 07:30:20 +00002946 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2947 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002948
2949 ripng_routemap_update_redistribute ();
2950}
2951
2952/* Initialize ripng structure and set commands. */
2953void
2954ripng_init ()
2955{
2956 /* Randomize. */
2957 srand (time (NULL));
2958
2959 /* Install RIPNG_NODE. */
2960 install_node (&cmd_ripng_node, ripng_config_write);
2961
2962 /* Install ripng commands. */
2963 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002964 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002965
2966 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002967 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002968
2969 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002970 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00002971
2972 install_default (RIPNG_NODE);
2973 install_element (RIPNG_NODE, &ripng_route_cmd);
2974 install_element (RIPNG_NODE, &no_ripng_route_cmd);
2975 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
2976 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
2977
2978 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
2979 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
2980 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
2981
2982 install_element (RIPNG_NODE, &ripng_timers_cmd);
2983 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00002984 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00002985#if 0
2986 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2987 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2988 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2989 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2990 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2991 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2992#endif /* 0 */
2993
paula2c62832003-04-23 17:01:31 +00002994 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
2995 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00002996
2997 ripng_if_init ();
2998 ripng_debug_init ();
2999
3000 /* Access list install. */
3001 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003002 access_list_add_hook (ripng_distribute_update_all_wrapper);
3003 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003004
3005 /* Prefix list initialize.*/
3006 prefix_list_init ();
3007 prefix_list_add_hook (ripng_distribute_update_all);
3008 prefix_list_delete_hook (ripng_distribute_update_all);
3009
3010 /* Distribute list install. */
3011 distribute_list_init (RIPNG_NODE);
3012 distribute_list_add_hook (ripng_distribute_update);
3013 distribute_list_delete_hook (ripng_distribute_update);
3014
3015 /* Route-map for interface. */
3016 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003017 ripng_offset_init ();
3018
paul718e3742002-12-13 20:15:29 +00003019 route_map_add_hook (ripng_routemap_update);
3020 route_map_delete_hook (ripng_routemap_update);
3021
hasso0750d212003-05-24 21:41:49 +00003022 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003023 if_rmap_hook_add (ripng_if_rmap_update);
3024 if_rmap_hook_delete (ripng_if_rmap_update);
3025}