blob: d416255c2fea0cb35e2e1dbf687c8fedb67f4936 [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;
Stephen Hemminger6d0732c2011-09-28 14:23:35 +0400120#ifdef IPTOS_PREC_INTERNETCONTROL
121 ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
122 if (ret < 0)
123 return ret;
124#endif
paul718e3742002-12-13 20:15:29 +0000125 ret = setsockopt_ipv6_multicast_hops (sock, 255);
126 if (ret < 0)
127 return ret;
128 ret = setsockopt_ipv6_multicast_loop (sock, 0);
129 if (ret < 0)
130 return ret;
131 ret = setsockopt_ipv6_hoplimit (sock, 1);
132 if (ret < 0)
133 return ret;
134
135 memset (&ripaddr, 0, sizeof (ripaddr));
136 ripaddr.sin6_family = AF_INET6;
137#ifdef SIN6_LEN
138 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
139#endif /* SIN6_LEN */
140 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
141
paul27d47aa2003-11-17 09:04:53 +0000142 if (ripngd_privs.change (ZPRIVS_RAISE))
143 zlog_err ("ripng_make_socket: could not raise privs");
144
paul718e3742002-12-13 20:15:29 +0000145 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
146 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000147 {
ajs6099b3b2004-11-20 02:06:59 +0000148 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000149 if (ripngd_privs.change (ZPRIVS_LOWER))
150 zlog_err ("ripng_make_socket: could not lower privs");
151 return ret;
152 }
153 if (ripngd_privs.change (ZPRIVS_LOWER))
154 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000155 return sock;
156}
157
158/* Send RIPng packet. */
159int
160ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
161 struct interface *ifp)
162{
163 int ret;
164 struct msghdr msg;
165 struct iovec iov;
166 struct cmsghdr *cmsgptr;
167 char adata [256];
168 struct in6_pktinfo *pkt;
169 struct sockaddr_in6 addr;
170
hassoa94434b2003-05-25 17:10:12 +0000171 if (IS_RIPNG_DEBUG_SEND) {
172 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000173 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000174 zlog_debug (" send interface %s", ifp->name);
175 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000176 }
paul718e3742002-12-13 20:15:29 +0000177
178 memset (&addr, 0, sizeof (struct sockaddr_in6));
179 addr.sin6_family = AF_INET6;
180#ifdef SIN6_LEN
181 addr.sin6_len = sizeof (struct sockaddr_in6);
182#endif /* SIN6_LEN */
183 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
184
185 /* When destination is specified. */
186 if (to != NULL)
187 {
188 addr.sin6_addr = to->sin6_addr;
189 addr.sin6_port = to->sin6_port;
190 }
191 else
192 {
193 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
194 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
195 }
196
197 msg.msg_name = (void *) &addr;
198 msg.msg_namelen = sizeof (struct sockaddr_in6);
199 msg.msg_iov = &iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = (void *) adata;
202 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
203
204 iov.iov_base = buf;
205 iov.iov_len = bufsize;
206
207 cmsgptr = (struct cmsghdr *)adata;
208 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
209 cmsgptr->cmsg_level = IPPROTO_IPV6;
210 cmsgptr->cmsg_type = IPV6_PKTINFO;
211
212 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
213 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
214 pkt->ipi6_ifindex = ifp->ifindex;
215
216 ret = sendmsg (ripng->sock, &msg, 0);
217
hassoa94434b2003-05-25 17:10:12 +0000218 if (ret < 0) {
219 if (to)
220 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000221 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000222 else
ajs6099b3b2004-11-20 02:06:59 +0000223 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000224 }
paul718e3742002-12-13 20:15:29 +0000225
226 return ret;
227}
228
229/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100230static int
paul718e3742002-12-13 20:15:29 +0000231ripng_recv_packet (int sock, u_char *buf, int bufsize,
232 struct sockaddr_in6 *from, unsigned int *ifindex,
233 int *hoplimit)
234{
235 int ret;
236 struct msghdr msg;
237 struct iovec iov;
238 struct cmsghdr *cmsgptr;
239 struct in6_addr dst;
240
241 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
242 point I can't determine size of cmsghdr */
243 char adata[1024];
244
245 /* Fill in message and iovec. */
246 msg.msg_name = (void *) from;
247 msg.msg_namelen = sizeof (struct sockaddr_in6);
248 msg.msg_iov = &iov;
249 msg.msg_iovlen = 1;
250 msg.msg_control = (void *) adata;
251 msg.msg_controllen = sizeof adata;
252 iov.iov_base = buf;
253 iov.iov_len = bufsize;
254
255 /* If recvmsg fail return minus value. */
256 ret = recvmsg (sock, &msg, 0);
257 if (ret < 0)
258 return ret;
259
ajsb99760a2005-01-04 16:24:43 +0000260 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000261 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
262 {
263 /* I want interface index which this packet comes from. */
264 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265 cmsgptr->cmsg_type == IPV6_PKTINFO)
266 {
267 struct in6_pktinfo *ptr;
268
269 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270 *ifindex = ptr->ipi6_ifindex;
271 dst = ptr->ipi6_addr;
272
273 if (*ifindex == 0)
274 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275 }
276
277 /* Incoming packet's multicast hop limit. */
278 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemminger5eb9d112009-12-10 15:52:33 +0300280 {
281 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282 *hoplimit = *phoplimit;
283 }
paul718e3742002-12-13 20:15:29 +0000284 }
285
286 /* Hoplimit check shold be done when destination address is
287 multicast address. */
288 if (! IN6_IS_ADDR_MULTICAST (&dst))
289 *hoplimit = -1;
290
291 return ret;
292}
293
294/* Dump rip packet */
295void
hasso7a1d5832004-10-08 06:32:23 +0000296ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000297{
298 caddr_t lim;
299 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000300 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000301
302 /* Set command string. */
303 if (packet->command == RIPNG_REQUEST)
304 command_str = "request";
305 else if (packet->command == RIPNG_RESPONSE)
306 command_str = "response";
307 else
308 command_str = "unknown";
309
310 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000311 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000312 sndrcv, command_str, packet->version, size);
313
314 /* Dump each routing table entry. */
315 rte = packet->rte;
316
317 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318 {
319 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000320 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000321 else
ajsc6106812004-12-08 19:51:16 +0000322 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000323 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000324 rte->metric, ntohs (rte->tag));
325 }
326}
327
328/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100329static void
paul718e3742002-12-13 20:15:29 +0000330ripng_nexthop_rte (struct rte *rte,
331 struct sockaddr_in6 *from,
332 struct ripng_nexthop *nexthop)
333{
334 char buf[INET6_BUFSIZ];
335
336 /* Logging before checking RTE. */
337 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000338 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000339 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000340
341 /* RFC2080 2.1.1 Next Hop:
342 The route tag and prefix length in the next hop RTE must be
343 set to zero on sending and ignored on receiption. */
344 if (ntohs (rte->tag) != 0)
345 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000346 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000347
348 if (rte->prefixlen != 0)
349 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000350 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000351
352 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353 next hop RTE indicates that the next hop address should be the
354 originator of the RIPng advertisement. An address specified as a
355 next hop must be a link-local address. */
356 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357 {
358 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359 memset (&nexthop->address, 0, sizeof (struct in6_addr));
360 return;
361 }
362
363 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364 {
365 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367 return;
368 }
369
370 /* The purpose of the next hop RTE is to eliminate packets being
371 routed through extra hops in the system. It is particularly useful
372 when RIPng is not being run on all of the routers on a network.
373 Note that next hop RTE is "advisory". That is, if the provided
374 information is ignored, a possibly sub-optimal, but absolutely
375 valid, route may be taken. If the received next hop address is not
376 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
377 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000378 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000379 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382 memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384 return;
385}
386
387/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100388static int
paul718e3742002-12-13 20:15:29 +0000389ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390{
paul1eb8ef22005-04-07 07:30:20 +0000391 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000392 struct connected *connected;
393 struct prefix *p;
394
paul1eb8ef22005-04-07 07:30:20 +0000395 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396 {
397 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000398
paul1eb8ef22005-04-07 07:30:20 +0000399 if (p->family == AF_INET6 &&
400 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402 return 1;
403 }
paul718e3742002-12-13 20:15:29 +0000404 return 0;
405}
406
407/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100408static int
paul718e3742002-12-13 20:15:29 +0000409ripng_garbage_collect (struct thread *t)
410{
411 struct ripng_info *rinfo;
412 struct route_node *rp;
413
414 rinfo = THREAD_ARG (t);
415 rinfo->t_garbage_collect = NULL;
416
417 /* Off timeout timer. */
418 RIPNG_TIMER_OFF (rinfo->t_timeout);
419
420 /* Get route_node pointer. */
421 rp = rinfo->rp;
422
paul718e3742002-12-13 20:15:29 +0000423 /* Unlock route_node. */
424 rp->info = NULL;
425 route_unlock_node (rp);
426
427 /* Free RIPng routing information. */
428 ripng_info_free (rinfo);
429
430 return 0;
431}
432
433/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100434static int
paul718e3742002-12-13 20:15:29 +0000435ripng_timeout (struct thread *t)
436{
437 struct ripng_info *rinfo;
438 struct route_node *rp;
439
440 rinfo = THREAD_ARG (t);
441 rinfo->t_timeout = NULL;
442
443 /* Get route_node pointer. */
444 rp = rinfo->rp;
445
446 /* - The garbage-collection timer is set for 120 seconds. */
447 RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
448 ripng->garbage_time);
449
hassoa94434b2003-05-25 17:10:12 +0000450 /* Delete this route from the kernel. */
451 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
452 rinfo->ifindex);
paul718e3742002-12-13 20:15:29 +0000453 /* - The metric for the route is set to 16 (infinity). This causes
454 the route to be removed from service. */
455 rinfo->metric = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +0000456 rinfo->flags &= ~RIPNG_RTF_FIB;
457
458 /* Aggregate count decrement. */
459 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +0000460
461 /* - The route change flag is to indicate that this entry has been
462 changed. */
463 rinfo->flags |= RIPNG_RTF_CHANGED;
464
465 /* - The output process is signalled to trigger a response. */
466 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
467
468 return 0;
469}
470
Paul Jakma6ac29a52008-08-15 13:45:30 +0100471static void
paul718e3742002-12-13 20:15:29 +0000472ripng_timeout_update (struct ripng_info *rinfo)
473{
474 if (rinfo->metric != RIPNG_METRIC_INFINITY)
475 {
476 RIPNG_TIMER_OFF (rinfo->t_timeout);
477 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
478 }
479}
480
Paul Jakma6ac29a52008-08-15 13:45:30 +0100481static int
hassoa94434b2003-05-25 17:10:12 +0000482ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
483{
484 struct distribute *dist;
485 struct access_list *alist;
486 struct prefix_list *plist;
487
488 /* Input distribute-list filtering. */
489 if (ri->list[RIPNG_FILTER_IN])
490 {
491 if (access_list_apply (ri->list[RIPNG_FILTER_IN],
492 (struct prefix *) p) == FILTER_DENY)
493 {
494 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000495 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000496 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000497 return -1;
498 }
499 }
500 if (ri->prefix[RIPNG_FILTER_IN])
501 {
502 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
503 (struct prefix *) p) == PREFIX_DENY)
504 {
505 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000506 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000507 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000508 return -1;
509 }
510 }
511
512 /* All interface filter check. */
513 dist = distribute_lookup (NULL);
514 if (dist)
515 {
516 if (dist->list[DISTRIBUTE_IN])
517 {
518 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
519
520 if (alist)
521 {
522 if (access_list_apply (alist,
523 (struct prefix *) p) == FILTER_DENY)
524 {
525 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000526 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000527 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000528 return -1;
529 }
530 }
531 }
532 if (dist->prefix[DISTRIBUTE_IN])
533 {
534 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
535
536 if (plist)
537 {
538 if (prefix_list_apply (plist,
539 (struct prefix *) p) == PREFIX_DENY)
540 {
541 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000542 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000543 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000544 return -1;
545 }
546 }
547 }
548 }
549 return 0;
550}
551
Paul Jakma6ac29a52008-08-15 13:45:30 +0100552static int
hassoa94434b2003-05-25 17:10:12 +0000553ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
554{
555 struct distribute *dist;
556 struct access_list *alist;
557 struct prefix_list *plist;
558
559 if (ri->list[RIPNG_FILTER_OUT])
560 {
561 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
562 (struct prefix *) p) == FILTER_DENY)
563 {
564 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000565 zlog_debug ("%s/%d is filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000566 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000567 return -1;
568 }
569 }
570 if (ri->prefix[RIPNG_FILTER_OUT])
571 {
572 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
573 (struct prefix *) p) == PREFIX_DENY)
574 {
575 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000576 zlog_debug ("%s/%d is filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000577 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000578 return -1;
579 }
580 }
581
582 /* All interface filter check. */
583 dist = distribute_lookup (NULL);
584 if (dist)
585 {
586 if (dist->list[DISTRIBUTE_OUT])
587 {
588 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
589
590 if (alist)
591 {
592 if (access_list_apply (alist,
593 (struct prefix *) p) == FILTER_DENY)
594 {
595 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000596 zlog_debug ("%s/%d filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000597 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000598 return -1;
599 }
600 }
601 }
602 if (dist->prefix[DISTRIBUTE_OUT])
603 {
604 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
605
606 if (plist)
607 {
608 if (prefix_list_apply (plist,
609 (struct prefix *) p) == PREFIX_DENY)
610 {
611 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000612 zlog_debug ("%s/%d filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000613 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000614 return -1;
615 }
616 }
617 }
618 }
619 return 0;
620}
621
paul718e3742002-12-13 20:15:29 +0000622/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100623static void
paul718e3742002-12-13 20:15:29 +0000624ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
625 struct ripng_nexthop *ripng_nexthop,
626 struct interface *ifp)
627{
hassoa94434b2003-05-25 17:10:12 +0000628 int ret;
paul718e3742002-12-13 20:15:29 +0000629 struct prefix_ipv6 p;
630 struct route_node *rp;
631 struct ripng_info *rinfo;
632 struct ripng_interface *ri;
633 struct in6_addr *nexthop;
634 u_char oldmetric;
635 int same = 0;
636
637 /* Make prefix structure. */
638 memset (&p, 0, sizeof (struct prefix_ipv6));
639 p.family = AF_INET6;
640 /* p.prefix = rte->addr; */
641 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
642 p.prefixlen = rte->prefixlen;
643
644 /* Make sure mask is applied. */
645 /* XXX We have to check the prefix is valid or not before call
646 apply_mask_ipv6. */
647 apply_mask_ipv6 (&p);
648
649 /* Apply input filters. */
650 ri = ifp->info;
651
hassoa94434b2003-05-25 17:10:12 +0000652 ret = ripng_incoming_filter (&p, ri);
653 if (ret < 0)
654 return;
paul718e3742002-12-13 20:15:29 +0000655
656 /* Modify entry. */
657 if (ri->routemap[RIPNG_FILTER_IN])
658 {
659 int ret;
660 struct ripng_info newinfo;
661
paul41ce9262003-04-19 15:54:03 +0000662 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +0000663 newinfo.type = ZEBRA_ROUTE_RIPNG;
664 newinfo.sub_type = RIPNG_ROUTE_RTE;
665 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
666 newinfo.nexthop = ripng_nexthop->address;
667 else
668 newinfo.nexthop = from->sin6_addr;
669 newinfo.from = from->sin6_addr;
670 newinfo.ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000671 newinfo.metric = rte->metric;
hassoa94434b2003-05-25 17:10:12 +0000672 newinfo.metric_out = rte->metric; /* XXX */
673 newinfo.tag = ntohs(rte->tag); /* XXX */
paul718e3742002-12-13 20:15:29 +0000674
675 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
676 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
677
678 if (ret == RMAP_DENYMATCH)
679 {
680 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000681 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000682 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000683 return;
684 }
685
hassoa94434b2003-05-25 17:10:12 +0000686 /* Get back the object */
687 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
688 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
689 /* the nexthop get changed by the routemap */
690 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
691 ripng_nexthop->address = newinfo.nexthop;
692 else
693 ripng_nexthop->address = in6addr_any;
694 }
695 } else {
696 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
697 /* the nexthop get changed by the routemap */
698 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
699 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
700 ripng_nexthop->address = newinfo.nexthop;
701 }
702 }
703 }
704 rte->tag = htons(newinfo.tag_out); /* XXX */
705 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000706 }
707
hassoa94434b2003-05-25 17:10:12 +0000708 /* Once the entry has been validated, update the metric by
709 * adding the cost of the network on wich the message
710 * arrived. If the result is greater than infinity, use infinity
711 * (RFC2453 Sec. 3.9.2)
712 **/
713
714 /* Zebra ripngd can handle offset-list in. */
715 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
716
717 /* If offset-list does not modify the metric use interface's
718 * one. */
719 if (! ret)
720 rte->metric += ifp->metric;
721
722 if (rte->metric > RIPNG_METRIC_INFINITY)
723 rte->metric = RIPNG_METRIC_INFINITY;
724
paul718e3742002-12-13 20:15:29 +0000725 /* Set nexthop pointer. */
726 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
727 nexthop = &ripng_nexthop->address;
728 else
729 nexthop = &from->sin6_addr;
730
731 /* Lookup RIPng routing table. */
732 rp = route_node_get (ripng->table, (struct prefix *) &p);
733
hassoa94434b2003-05-25 17:10:12 +0000734 /* Sanity check */
735 rinfo = rp->info;
736 if (rinfo)
737 {
738 /* Redistributed route check. */
739 if (rinfo->type != ZEBRA_ROUTE_RIPNG
740 && rinfo->metric != RIPNG_METRIC_INFINITY)
741 return;
742
743 /* Local static route. */
744 if (rinfo->type == ZEBRA_ROUTE_RIPNG
745 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
746 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
747 && rinfo->metric != RIPNG_METRIC_INFINITY)
748 return;
749 }
750
paul718e3742002-12-13 20:15:29 +0000751 if (rp->info == NULL)
752 {
753 /* Now, check to see whether there is already an explicit route
754 for the destination prefix. If there is no such route, add
755 this route to the routing table, unless the metric is
756 infinity (there is no point in adding a route which
757 unusable). */
758 if (rte->metric != RIPNG_METRIC_INFINITY)
759 {
760 rinfo = ripng_info_new ();
761
762 /* - Setting the destination prefix and length to those in
763 the RTE. */
764 rp->info = rinfo;
765 rinfo->rp = rp;
766
767 /* - Setting the metric to the newly calculated metric (as
768 described above). */
769 rinfo->metric = rte->metric;
770 rinfo->tag = ntohs (rte->tag);
771
772 /* - Set the next hop address to be the address of the router
773 from which the datagram came or the next hop address
774 specified by a next hop RTE. */
775 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
776 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
777 rinfo->ifindex = ifp->ifindex;
778
779 /* - Initialize the timeout for the route. If the
780 garbage-collection timer is running for this route, stop it. */
781 ripng_timeout_update (rinfo);
782
783 /* - Set the route change flag. */
784 rinfo->flags |= RIPNG_RTF_CHANGED;
785
786 /* - Signal the output process to trigger an update (see section
787 2.5). */
788 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
789
790 /* Finally, route goes into the kernel. */
791 rinfo->type = ZEBRA_ROUTE_RIPNG;
792 rinfo->sub_type = RIPNG_ROUTE_RTE;
793
hassodeba3552005-08-27 06:19:39 +0000794 ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex,
795 rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000796 rinfo->flags |= RIPNG_RTF_FIB;
797
798 /* Aggregate check. */
799 ripng_aggregate_increment (rp, rinfo);
800 }
801 }
802 else
803 {
804 rinfo = rp->info;
805
806 /* If there is an existing route, compare the next hop address
807 to the address of the router from which the datagram came.
808 If this datagram is from the same router as the existing
809 route, reinitialize the timeout. */
810 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
811 && (rinfo->ifindex == ifp->ifindex));
812
813 if (same)
814 ripng_timeout_update (rinfo);
815
816 /* Next, compare the metrics. If the datagram is from the same
817 router as the existing route, and the new metric is different
818 than the old one; or, if the new metric is lower than the old
819 one; do the following actions: */
820 if ((same && rinfo->metric != rte->metric) ||
821 rte->metric < rinfo->metric)
822 {
823 /* - Adopt the route from the datagram. That is, put the
824 new metric in, and adjust the next hop address (if
825 necessary). */
826 oldmetric = rinfo->metric;
827 rinfo->metric = rte->metric;
828 rinfo->tag = ntohs (rte->tag);
hassoa94434b2003-05-25 17:10:12 +0000829 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
830 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000831
hassoa94434b2003-05-25 17:10:12 +0000832 /* Should a new route to this network be established
833 while the garbage-collection timer is running, the
834 new route will replace the one that is about to be
835 deleted. In this case the garbage-collection timer
836 must be cleared. */
837
838 if (oldmetric == RIPNG_METRIC_INFINITY &&
839 rinfo->metric < RIPNG_METRIC_INFINITY)
840 {
841 rinfo->type = ZEBRA_ROUTE_RIPNG;
842 rinfo->sub_type = RIPNG_ROUTE_RTE;
843
844 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
845
846 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
hassodeba3552005-08-27 06:19:39 +0000847 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
hassoa94434b2003-05-25 17:10:12 +0000848
hassodeba3552005-08-27 06:19:39 +0000849 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
hassoa94434b2003-05-25 17:10:12 +0000850 rinfo->flags |= RIPNG_RTF_FIB;
851
852 /* The aggregation counter needs to be updated because
853 the prefixes, which are into the gc, have been
854 removed from the aggregator (see ripng_timout). */
855 ripng_aggregate_increment (rp, rinfo);
856 }
857
858 /* Update nexthop and/or metric value. */
859 if (oldmetric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +0000860 {
861 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
hassodeba3552005-08-27 06:19:39 +0000862 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000863 rinfo->flags |= RIPNG_RTF_FIB;
864
hassoa94434b2003-05-25 17:10:12 +0000865 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
866 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000867 }
paul718e3742002-12-13 20:15:29 +0000868
869 /* - Set the route change flag and signal the output process
870 to trigger an update. */
871 rinfo->flags |= RIPNG_RTF_CHANGED;
872 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
873
874 /* - If the new metric is infinity, start the deletion
875 process (described above); */
876 if (rinfo->metric == RIPNG_METRIC_INFINITY)
877 {
878 /* If the new metric is infinity, the deletion process
879 begins for the route, which is no longer used for
880 routing packets. Note that the deletion process is
881 started only when the metric is first set to
882 infinity. If the metric was already infinity, then a
883 new deletion process is not started. */
884 if (oldmetric != RIPNG_METRIC_INFINITY)
885 {
886 /* - The garbage-collection timer is set for 120 seconds. */
887 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
888 ripng_garbage_collect, ripng->garbage_time);
889 RIPNG_TIMER_OFF (rinfo->t_timeout);
890
891 /* - The metric for the route is set to 16
892 (infinity). This causes the route to be removed
893 from service.*/
hassoa94434b2003-05-25 17:10:12 +0000894 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
895 rinfo->flags &= ~RIPNG_RTF_FIB;
896
897 /* Aggregate count decrement. */
898 ripng_aggregate_decrement (rp, rinfo);
899
paul718e3742002-12-13 20:15:29 +0000900 /* - The route change flag is to indicate that this
901 entry has been changed. */
902 /* - The output process is signalled to trigger a
903 response. */
904 ; /* Above processes are already done previously. */
905 }
906 }
907 else
908 {
909 /* otherwise, re-initialize the timeout. */
910 ripng_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000911 }
912 }
913 /* Unlock tempolary lock of the route. */
914 route_unlock_node (rp);
915 }
916}
917
918/* Add redistributed route to RIPng table. */
919void
920ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +0000921 unsigned int ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000922{
923 struct route_node *rp;
924 struct ripng_info *rinfo;
925
926 /* Redistribute route */
927 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
928 return;
929 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
930 return;
hassoa94434b2003-05-25 17:10:12 +0000931#if defined (MUSICA) || defined (LINUX)
932 /* XXX As long as the RIPng redistribution is applied to all the connected
933 * routes, one needs to filter the ::/96 prefixes.
934 * However it could be a wanted case, it will be removed soon.
935 */
936 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
937 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
938 return;
939#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +0000940
941 rp = route_node_get (ripng->table, (struct prefix *) p);
942 rinfo = rp->info;
943
944 if (rinfo)
945 {
hassoa94434b2003-05-25 17:10:12 +0000946 if (rinfo->type == ZEBRA_ROUTE_CONNECT
947 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
948 && rinfo->metric != RIPNG_METRIC_INFINITY) {
949 route_unlock_node (rp);
950 return;
951 }
952
953 /* Manually configured RIPng route check.
954 * They have the precedence on all the other entries.
955 **/
956 if (rinfo->type == ZEBRA_ROUTE_RIPNG
957 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
958 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
959 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
960 (sub_type != RIPNG_ROUTE_DEFAULT))) {
961 route_unlock_node (rp);
962 return;
963 }
964 }
965
paul718e3742002-12-13 20:15:29 +0000966 RIPNG_TIMER_OFF (rinfo->t_timeout);
967 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
hassoa94434b2003-05-25 17:10:12 +0000968
969 /* Tells the other daemons about the deletion of
970 * this RIPng route
971 **/
972 if (ripng_route_rte (rinfo))
973 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
974 rinfo->metric);
975
976 rp->info = NULL;
977 ripng_info_free (rinfo);
978
paul718e3742002-12-13 20:15:29 +0000979 route_unlock_node (rp);
hassoa94434b2003-05-25 17:10:12 +0000980
paul718e3742002-12-13 20:15:29 +0000981 }
hassoa94434b2003-05-25 17:10:12 +0000982
983 rinfo = ripng_info_new ();
paul718e3742002-12-13 20:15:29 +0000984
985 rinfo->type = type;
986 rinfo->sub_type = sub_type;
987 rinfo->ifindex = ifindex;
988 rinfo->metric = 1;
paul718e3742002-12-13 20:15:29 +0000989 rinfo->rp = rp;
hassoa94434b2003-05-25 17:10:12 +0000990
991 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
992 rinfo->nexthop = *nexthop;
993
994 rinfo->flags |= RIPNG_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000995 rp->info = rinfo;
hassoa94434b2003-05-25 17:10:12 +0000996
997 /* Aggregate check. */
998 ripng_aggregate_increment (rp, rinfo);
999
1000 rinfo->flags |= RIPNG_RTF_CHANGED;
1001
1002 if (IS_RIPNG_DEBUG_EVENT) {
1003 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +00001004 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001005 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001006 ifindex2ifname(ifindex));
1007 else
ajsc6106812004-12-08 19:51:16 +00001008 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001009 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001010 ifindex2ifname(ifindex));
1011 }
1012
1013 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001014}
1015
1016/* Delete redistributed route to RIPng table. */
1017void
1018ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1019 unsigned int ifindex)
1020{
1021 struct route_node *rp;
1022 struct ripng_info *rinfo;
1023
1024 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1025 return;
1026 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1027 return;
hassoa94434b2003-05-25 17:10:12 +00001028#if defined (MUSICA) || defined (LINUX)
1029 /* XXX As long as the RIPng redistribution is applied to all the connected
1030 * routes, one needs to filter the ::/96 prefixes.
1031 * However it could be a wanted case, it will be removed soon.
1032 */
1033 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
1034 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
1035 return;
1036#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +00001037
1038 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1039
1040 if (rp)
1041 {
1042 rinfo = rp->info;
1043
1044 if (rinfo != NULL
1045 && rinfo->type == type
1046 && rinfo->sub_type == sub_type
1047 && rinfo->ifindex == ifindex)
1048 {
hassoa94434b2003-05-25 17:10:12 +00001049 /* Perform poisoned reverse. */
1050 rinfo->metric = RIPNG_METRIC_INFINITY;
1051 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1052 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001053 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001054
1055 /* Aggregate count decrement. */
1056 ripng_aggregate_decrement (rp, rinfo);
1057
1058 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001059
hassoa94434b2003-05-25 17:10:12 +00001060 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001061 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso3a2ce6a2005-04-08 01:30:51 +00001062 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001063 ifindex2ifname(ifindex));
paul718e3742002-12-13 20:15:29 +00001064
hassoa94434b2003-05-25 17:10:12 +00001065 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001066 }
paul718e3742002-12-13 20:15:29 +00001067 }
1068}
1069
1070/* Withdraw redistributed route. */
1071void
1072ripng_redistribute_withdraw (int type)
1073{
1074 struct route_node *rp;
1075 struct ripng_info *rinfo;
1076
hassoa94434b2003-05-25 17:10:12 +00001077 if (!ripng)
1078 return;
1079
paul718e3742002-12-13 20:15:29 +00001080 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1081 if ((rinfo = rp->info) != NULL)
1082 {
hassoa94434b2003-05-25 17:10:12 +00001083 if ((rinfo->type == type)
1084 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001085 {
hassoa94434b2003-05-25 17:10:12 +00001086 /* Perform poisoned reverse. */
1087 rinfo->metric = RIPNG_METRIC_INFINITY;
1088 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1089 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001090 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001091
hassoa94434b2003-05-25 17:10:12 +00001092 /* Aggregate count decrement. */
1093 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001094
hassoa94434b2003-05-25 17:10:12 +00001095 rinfo->flags |= RIPNG_RTF_CHANGED;
1096
1097 if (IS_RIPNG_DEBUG_EVENT) {
1098 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1099
ajsc6106812004-12-08 19:51:16 +00001100 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001101 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001102 ifindex2ifname(rinfo->ifindex));
1103 }
1104
1105 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001106 }
1107 }
1108}
1109
1110/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001111static void
paul718e3742002-12-13 20:15:29 +00001112ripng_response_process (struct ripng_packet *packet, int size,
1113 struct sockaddr_in6 *from, struct interface *ifp,
1114 int hoplimit)
1115{
1116 caddr_t lim;
1117 struct rte *rte;
1118 struct ripng_nexthop nexthop;
1119
1120 /* RFC2080 2.4.2 Response Messages:
1121 The Response must be ignored if it is not from the RIPng port. */
1122 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1123 {
1124 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001125 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001126 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001127 return;
1128 }
1129
1130 /* The datagram's IPv6 source address should be checked to see
1131 whether the datagram is from a valid neighbor; the source of the
1132 datagram must be a link-local address. */
1133 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1134 {
1135 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001136 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001137 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001138 return;
1139 }
1140
1141 /* It is also worth checking to see whether the response is from one
1142 of the router's own addresses. Interfaces on broadcast networks
1143 may receive copies of their own multicasts immediately. If a
1144 router processes its own output as new input, confusion is likely,
1145 and such datagrams must be ignored. */
1146 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1147 {
1148 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001149 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001150 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001151 return;
1152 }
1153
1154 /* As an additional check, periodic advertisements must have their
1155 hop counts set to 255, and inbound, multicast packets sent from the
1156 RIPng port (i.e. periodic advertisement or triggered update
1157 packets) must be examined to ensure that the hop count is 255. */
1158 if (hoplimit >= 0 && hoplimit != 255)
1159 {
1160 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001161 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001162 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001163 return;
1164 }
1165
hassoa94434b2003-05-25 17:10:12 +00001166 /* Update RIPng peer. */
1167 ripng_peer_update (from, packet->version);
1168
paul718e3742002-12-13 20:15:29 +00001169 /* Reset nexthop. */
1170 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1171 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1172
1173 /* Set RTE pointer. */
1174 rte = packet->rte;
1175
1176 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1177 {
1178 /* First of all, we have to check this RTE is next hop RTE or
1179 not. Next hop RTE is completely different with normal RTE so
1180 we need special treatment. */
1181 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1182 {
1183 ripng_nexthop_rte (rte, from, &nexthop);
1184 continue;
1185 }
1186
1187 /* RTE information validation. */
1188
1189 /* - is the destination prefix valid (e.g., not a multicast
1190 prefix and not a link-local address) A link-local address
1191 should never be present in an RTE. */
1192 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1193 {
1194 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001195 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001196 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001197 continue;
1198 }
1199 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1200 {
1201 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001202 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001203 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001204 continue;
1205 }
1206 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1207 {
1208 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001209 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001210 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001211 continue;
1212 }
1213
1214 /* - is the prefix length valid (i.e., between 0 and 128,
1215 inclusive) */
1216 if (rte->prefixlen > 128)
1217 {
1218 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001219 inet6_ntoa (rte->addr), rte->prefixlen,
1220 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001221 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001222 continue;
1223 }
1224
1225 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1226 if (! (rte->metric >= 1 && rte->metric <= 16))
1227 {
1228 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001229 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001230 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001231 continue;
1232 }
1233
hassoa94434b2003-05-25 17:10:12 +00001234 /* Vincent: XXX Should we compute the direclty reachable nexthop
1235 * for our RIPng network ?
1236 **/
paul718e3742002-12-13 20:15:29 +00001237
1238 /* Routing table updates. */
1239 ripng_route_process (rte, from, &nexthop, ifp);
1240 }
1241}
1242
1243/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001244static void
paul718e3742002-12-13 20:15:29 +00001245ripng_request_process (struct ripng_packet *packet,int size,
1246 struct sockaddr_in6 *from, struct interface *ifp)
1247{
1248 caddr_t lim;
1249 struct rte *rte;
1250 struct prefix_ipv6 p;
1251 struct route_node *rp;
1252 struct ripng_info *rinfo;
1253 struct ripng_interface *ri;
1254
hassoa94434b2003-05-25 17:10:12 +00001255 /* Does not reponse to the requests on the loopback interfaces */
1256 if (if_is_loopback (ifp))
1257 return;
1258
paul718e3742002-12-13 20:15:29 +00001259 /* Check RIPng process is enabled on this interface. */
1260 ri = ifp->info;
1261 if (! ri->running)
1262 return;
1263
1264 /* When passive interface is specified, suppress responses */
1265 if (ri->passive)
1266 return;
1267
hassoa94434b2003-05-25 17:10:12 +00001268 /* RIPng peer update. */
1269 ripng_peer_update (from, packet->version);
1270
paul718e3742002-12-13 20:15:29 +00001271 lim = ((caddr_t) packet) + size;
1272 rte = packet->rte;
1273
1274 /* The Request is processed entry by entry. If there are no
1275 entries, no response is given. */
1276 if (lim == (caddr_t) rte)
1277 return;
1278
1279 /* There is one special case. If there is exactly one entry in the
1280 request, and it has a destination prefix of zero, a prefix length
1281 of zero, and a metric of infinity (i.e., 16), then this is a
1282 request to send the entire routing table. In that case, a call
1283 is made to the output process to send the routing table to the
1284 requesting address/port. */
1285 if (lim == ((caddr_t) (rte + 1)) &&
1286 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1287 rte->prefixlen == 0 &&
1288 rte->metric == RIPNG_METRIC_INFINITY)
1289 {
1290 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001291 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001292 }
1293 else
1294 {
1295 /* Except for this special case, processing is quite simple.
1296 Examine the list of RTEs in the Request one by one. For each
1297 entry, look up the destination in the router's routing
1298 database and, if there is a route, put that route's metric in
1299 the metric field of the RTE. If there is no explicit route
1300 to the specified destination, put infinity in the metric
1301 field. Once all the entries have been filled in, change the
1302 command from Request to Response and send the datagram back
1303 to the requestor. */
1304 memset (&p, 0, sizeof (struct prefix_ipv6));
1305 p.family = AF_INET6;
1306
1307 for (; ((caddr_t) rte) < lim; rte++)
1308 {
1309 p.prefix = rte->addr;
1310 p.prefixlen = rte->prefixlen;
1311 apply_mask_ipv6 (&p);
1312
1313 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1314
1315 if (rp)
1316 {
1317 rinfo = rp->info;
1318 rte->metric = rinfo->metric;
1319 route_unlock_node (rp);
1320 }
1321 else
1322 rte->metric = RIPNG_METRIC_INFINITY;
1323 }
1324 packet->command = RIPNG_RESPONSE;
1325
1326 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1327 }
1328}
1329
1330/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001331static int
paul718e3742002-12-13 20:15:29 +00001332ripng_read (struct thread *thread)
1333{
1334 int len;
1335 int sock;
1336 struct sockaddr_in6 from;
1337 struct ripng_packet *packet;
1338 unsigned int ifindex;
1339 struct interface *ifp;
1340 int hoplimit = -1;
1341
1342 /* Check ripng is active and alive. */
1343 assert (ripng != NULL);
1344 assert (ripng->sock >= 0);
1345
1346 /* Fetch thread data and set read pointer to empty for event
1347 managing. `sock' sould be same as ripng->sock. */
1348 sock = THREAD_FD (thread);
1349 ripng->t_read = NULL;
1350
1351 /* Add myself to the next event. */
1352 ripng_event (RIPNG_READ, sock);
1353
1354 /* Read RIPng packet. */
1355 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1356 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1357 &hoplimit);
1358 if (len < 0)
1359 {
ajs6099b3b2004-11-20 02:06:59 +00001360 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001361 return len;
1362 }
1363
1364 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1365 (4)) must be multiple size of one RTE size (20). */
1366 if (((len - 4) % 20) != 0)
1367 {
1368 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001369 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001370 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001371 return 0;
1372 }
1373
1374 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1375 ifp = if_lookup_by_index (ifindex);
1376
1377 /* RIPng packet received. */
1378 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001379 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001380 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001381 ifp ? ifp->name : "unknown");
1382
1383 /* Logging before packet checking. */
1384 if (IS_RIPNG_DEBUG_RECV)
1385 ripng_packet_dump (packet, len, "RECV");
1386
1387 /* Packet comes from unknown interface. */
1388 if (ifp == NULL)
1389 {
1390 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1391 return 0;
1392 }
1393
1394 /* Packet version mismatch checking. */
1395 if (packet->version != ripng->version)
1396 {
1397 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1398 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001399 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001400 return 0;
1401 }
1402
1403 /* Process RIPng packet. */
1404 switch (packet->command)
1405 {
1406 case RIPNG_REQUEST:
1407 ripng_request_process (packet, len, &from, ifp);
1408 break;
1409 case RIPNG_RESPONSE:
1410 ripng_response_process (packet, len, &from, ifp, hoplimit);
1411 break;
1412 default:
1413 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001414 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001415 break;
1416 }
1417 return 0;
1418}
1419
1420/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001421static void
1422ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001423{
1424 struct route_node *rp;
1425 struct ripng_info *rinfo;
1426
1427 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1428 if ((rinfo = rp->info) != NULL)
1429 if (rinfo->flags & RIPNG_RTF_CHANGED)
1430 rinfo->flags &= ~RIPNG_RTF_CHANGED;
1431}
1432
1433/* Regular update of RIPng route. Send all routing formation to RIPng
1434 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001435static int
paul718e3742002-12-13 20:15:29 +00001436ripng_update (struct thread *t)
1437{
hasso52dc7ee2004-09-23 19:18:23 +00001438 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001439 struct interface *ifp;
1440 struct ripng_interface *ri;
1441
1442 /* Clear update timer thread. */
1443 ripng->t_update = NULL;
1444
1445 /* Logging update event. */
1446 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001447 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001448
1449 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001450 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001451 {
paul718e3742002-12-13 20:15:29 +00001452 ri = ifp->info;
1453
1454 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1455 continue;
1456
1457 if (! ri->running)
1458 continue;
1459
1460 /* When passive interface is specified, suppress announce to the
1461 interface. */
1462 if (ri->passive)
1463 continue;
1464
1465#if RIPNG_ADVANCED
1466 if (ri->ri_send == RIPNG_SEND_OFF)
1467 {
1468 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001469 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001470 "[Event] RIPng send to if %d is suppressed by config",
1471 ifp->ifindex);
1472 continue;
1473 }
1474#endif /* RIPNG_ADVANCED */
1475
hassoa94434b2003-05-25 17:10:12 +00001476 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001477 }
1478
1479 /* Triggered updates may be suppressed if a regular update is due by
1480 the time the triggered update would be sent. */
1481 if (ripng->t_triggered_interval)
1482 {
1483 thread_cancel (ripng->t_triggered_interval);
1484 ripng->t_triggered_interval = NULL;
1485 }
1486 ripng->trigger = 0;
1487
1488 /* Reset flush event. */
1489 ripng_event (RIPNG_UPDATE_EVENT, 0);
1490
1491 return 0;
1492}
1493
1494/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001495static int
paul718e3742002-12-13 20:15:29 +00001496ripng_triggered_interval (struct thread *t)
1497{
1498 ripng->t_triggered_interval = NULL;
1499
1500 if (ripng->trigger)
1501 {
1502 ripng->trigger = 0;
1503 ripng_triggered_update (t);
1504 }
1505 return 0;
1506}
1507
1508/* Execute triggered update. */
1509int
1510ripng_triggered_update (struct thread *t)
1511{
hasso52dc7ee2004-09-23 19:18:23 +00001512 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001513 struct interface *ifp;
1514 struct ripng_interface *ri;
1515 int interval;
1516
1517 ripng->t_triggered_update = NULL;
1518
1519 /* Cancel interval timer. */
1520 if (ripng->t_triggered_interval)
1521 {
1522 thread_cancel (ripng->t_triggered_interval);
1523 ripng->t_triggered_interval = NULL;
1524 }
1525 ripng->trigger = 0;
1526
1527 /* Logging triggered update. */
1528 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001529 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001530
1531 /* Split Horizon processing is done when generating triggered
1532 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001533 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001534 {
paul718e3742002-12-13 20:15:29 +00001535 ri = ifp->info;
1536
1537 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1538 continue;
1539
1540 if (! ri->running)
1541 continue;
1542
1543 /* When passive interface is specified, suppress announce to the
1544 interface. */
1545 if (ri->passive)
1546 continue;
1547
hassoa94434b2003-05-25 17:10:12 +00001548 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001549 }
1550
1551 /* Once all of the triggered updates have been generated, the route
1552 change flags should be cleared. */
1553 ripng_clear_changed_flag ();
1554
1555 /* After a triggered update is sent, a timer should be set for a
1556 random interval between 1 and 5 seconds. If other changes that
1557 would trigger updates occur before the timer expires, a single
1558 update is triggered when the timer expires. */
1559 interval = (random () % 5) + 1;
1560
1561 ripng->t_triggered_interval =
1562 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1563
1564 return 0;
1565}
1566
1567/* Write routing table entry to the stream and return next index of
1568 the routing table entry in the stream. */
1569int
1570ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001571 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001572{
1573 /* RIPng packet header. */
1574 if (num == 0)
1575 {
1576 stream_putc (s, RIPNG_RESPONSE);
1577 stream_putc (s, RIPNG_V1);
1578 stream_putw (s, 0);
1579 }
1580
1581 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001582 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001583 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001584 else
hassoc9e52be2004-09-26 16:09:34 +00001585 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001586 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001587 if (p)
1588 stream_putc (s, p->prefixlen);
1589 else
1590 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001591 stream_putc (s, metric);
1592
1593 return ++num;
1594}
1595
1596/* Send RESPONSE message to specified destination. */
1597void
1598ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001599 int route_type)
paul718e3742002-12-13 20:15:29 +00001600{
1601 int ret;
paul718e3742002-12-13 20:15:29 +00001602 struct route_node *rp;
1603 struct ripng_info *rinfo;
1604 struct ripng_interface *ri;
1605 struct ripng_aggregate *aggregate;
1606 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001607 struct list * ripng_rte_list;
paul718e3742002-12-13 20:15:29 +00001608
hassoa94434b2003-05-25 17:10:12 +00001609 if (IS_RIPNG_DEBUG_EVENT) {
1610 if (to)
ajsc6106812004-12-08 19:51:16 +00001611 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001612 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001613 else
ajsc6106812004-12-08 19:51:16 +00001614 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001615 }
paul718e3742002-12-13 20:15:29 +00001616
paul718e3742002-12-13 20:15:29 +00001617 /* Get RIPng interface. */
1618 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001619
1620 ripng_rte_list = ripng_rte_new();
1621
paul718e3742002-12-13 20:15:29 +00001622 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1623 {
1624 if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
1625 {
hassoa94434b2003-05-25 17:10:12 +00001626 /* If no route-map are applied, the RTE will be these following
1627 * informations.
1628 */
paul718e3742002-12-13 20:15:29 +00001629 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001630 rinfo->metric_out = rinfo->metric;
1631 rinfo->tag_out = rinfo->tag;
1632 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1633 /* In order to avoid some local loops,
1634 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1635 * otherwise set it to 0. The nexthop should not be propagated
1636 * beyond the local broadcast/multicast area in order
1637 * to avoid an IGP multi-level recursive look-up.
1638 */
1639 if (rinfo->ifindex == ifp->ifindex)
1640 rinfo->nexthop_out = rinfo->nexthop;
1641
1642 /* Apply output filters. */
1643 ret = ripng_outgoing_filter (p, ri);
1644 if (ret < 0)
1645 continue;
paul718e3742002-12-13 20:15:29 +00001646
1647 /* Changed route only output. */
1648 if (route_type == ripng_changed_route &&
1649 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1650 continue;
1651
1652 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001653 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1654 {
1655 /* We perform split horizon for RIPng routes. */
1656 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1657 rinfo->ifindex == ifp->ifindex)
1658 continue;
1659 }
paul718e3742002-12-13 20:15:29 +00001660
1661 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001662 rinfo->metric_set = 0;
1663 /* nexthop_out,
1664 * metric_out
1665 * and tag_out are already initialized.
1666 */
paul718e3742002-12-13 20:15:29 +00001667
hassoa94434b2003-05-25 17:10:12 +00001668 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001669 if (ri->routemap[RIPNG_FILTER_OUT])
1670 {
1671 int ret;
paul718e3742002-12-13 20:15:29 +00001672
1673 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1674 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001675 rinfo);
paul718e3742002-12-13 20:15:29 +00001676
1677 if (ret == RMAP_DENYMATCH)
1678 {
1679 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001680 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001681 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001682 continue;
paul718e3742002-12-13 20:15:29 +00001683 }
1684
paul718e3742002-12-13 20:15:29 +00001685 }
1686
hassoa94434b2003-05-25 17:10:12 +00001687 /* Redistribute route-map. */
1688 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001689 {
hassoa94434b2003-05-25 17:10:12 +00001690 int ret;
1691
1692 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1693 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001694 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001695
1696 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001697 {
hassoa94434b2003-05-25 17:10:12 +00001698 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001699 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001700 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001701 continue;
paul718e3742002-12-13 20:15:29 +00001702 }
hassoa94434b2003-05-25 17:10:12 +00001703 }
paul718e3742002-12-13 20:15:29 +00001704
hassoa94434b2003-05-25 17:10:12 +00001705 /* When the route-map does not set metric. */
1706 if (! rinfo->metric_set)
1707 {
1708 /* If the redistribute metric is set. */
1709 if (ripng->route_map[rinfo->type].metric_config
1710 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001711 {
hassoa94434b2003-05-25 17:10:12 +00001712 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1713 }
1714 else
1715 {
1716 /* If the route is not connected or localy generated
1717 one, use default-metric value */
1718 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1719 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001720 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001721 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001722 }
1723 }
1724
hassoa94434b2003-05-25 17:10:12 +00001725 /* Apply offset-list */
1726 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1727 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001728
hassoa94434b2003-05-25 17:10:12 +00001729 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1730 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1731
1732 /* Perform split-horizon with poisoned reverse
1733 * for RIPng routes.
1734 **/
1735 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1736 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1737 rinfo->ifindex == ifp->ifindex)
1738 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1739 }
1740
1741 /* Add RTE to the list */
1742 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001743 }
hassoa94434b2003-05-25 17:10:12 +00001744
1745 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001746 if ((aggregate = rp->aggregate) != NULL &&
1747 aggregate->count > 0 &&
1748 aggregate->suppress == 0)
1749 {
hassoa94434b2003-05-25 17:10:12 +00001750 /* If no route-map are applied, the RTE will be these following
1751 * informations.
1752 */
paul718e3742002-12-13 20:15:29 +00001753 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001754 aggregate->metric_set = 0;
1755 aggregate->metric_out = aggregate->metric;
1756 aggregate->tag_out = aggregate->tag;
1757 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001758
1759 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001760 ret = ripng_outgoing_filter (p, ri);
1761 if (ret < 0)
1762 continue;
paul718e3742002-12-13 20:15:29 +00001763
hassoa94434b2003-05-25 17:10:12 +00001764 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001765 if (ri->routemap[RIPNG_FILTER_OUT])
1766 {
1767 int ret;
1768 struct ripng_info newinfo;
1769
hassoa94434b2003-05-25 17:10:12 +00001770 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001771 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001772 /* the nexthop is :: */
1773 newinfo.metric = aggregate->metric;
1774 newinfo.metric_out = aggregate->metric_out;
1775 newinfo.tag = aggregate->tag;
1776 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001777
1778 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1779 (struct prefix *) p, RMAP_RIPNG,
1780 &newinfo);
1781
1782 if (ret == RMAP_DENYMATCH)
1783 {
1784 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001785 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001786 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001787 continue;
paul718e3742002-12-13 20:15:29 +00001788 }
1789
hassoa94434b2003-05-25 17:10:12 +00001790 aggregate->metric_out = newinfo.metric_out;
1791 aggregate->tag_out = newinfo.tag_out;
1792 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1793 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001794 }
1795
hassoa94434b2003-05-25 17:10:12 +00001796 /* There is no redistribute routemap for the aggregated RTE */
1797
paul718e3742002-12-13 20:15:29 +00001798 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001799 /* XXX, vincent, in order to increase time convergence,
1800 * it should be announced if a child has changed.
1801 */
paul718e3742002-12-13 20:15:29 +00001802 if (route_type == ripng_changed_route)
1803 continue;
1804
hassoa94434b2003-05-25 17:10:12 +00001805 /* Apply offset-list */
1806 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1807 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001808
hassoa94434b2003-05-25 17:10:12 +00001809 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1810 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1811
1812 /* Add RTE to the list */
1813 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001814 }
1815
1816 }
paul718e3742002-12-13 20:15:29 +00001817
hassoa94434b2003-05-25 17:10:12 +00001818 /* Flush the list */
1819 ripng_rte_send(ripng_rte_list, ifp, to);
1820 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001821}
1822
1823/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001824static int
1825ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001826{
1827 /* ripng should be NULL. */
1828 assert (ripng == NULL);
1829
1830 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001831 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001832
1833 /* Default version and timer values. */
1834 ripng->version = RIPNG_V1;
1835 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1836 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1837 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1838 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1839
1840 /* Make buffer. */
1841 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1842 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1843
1844 /* Initialize RIPng routig table. */
1845 ripng->table = route_table_init ();
1846 ripng->route = route_table_init ();
1847 ripng->aggregate = route_table_init ();
1848
1849 /* Make socket. */
1850 ripng->sock = ripng_make_socket ();
1851 if (ripng->sock < 0)
1852 return ripng->sock;
1853
1854 /* Threads. */
1855 ripng_event (RIPNG_READ, ripng->sock);
1856 ripng_event (RIPNG_UPDATE_EVENT, 1);
1857
1858 return 0;
1859}
1860
hassoa94434b2003-05-25 17:10:12 +00001861/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001862int
1863ripng_request (struct interface *ifp)
1864{
1865 struct rte *rte;
1866 struct ripng_packet ripng_packet;
1867
hassoa94434b2003-05-25 17:10:12 +00001868 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1869 if (if_is_loopback(ifp))
1870 return 0;
1871
1872 /* If interface is down, don't send RIP packet. */
1873 if (! if_is_up (ifp))
1874 return 0;
1875
paul718e3742002-12-13 20:15:29 +00001876 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001877 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001878
1879 memset (&ripng_packet, 0, sizeof (ripng_packet));
1880 ripng_packet.command = RIPNG_REQUEST;
1881 ripng_packet.version = RIPNG_V1;
1882 rte = ripng_packet.rte;
1883 rte->metric = RIPNG_METRIC_INFINITY;
1884
1885 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1886 NULL, ifp);
1887}
1888
paul718e3742002-12-13 20:15:29 +00001889
Paul Jakma6ac29a52008-08-15 13:45:30 +01001890static int
paul718e3742002-12-13 20:15:29 +00001891ripng_update_jitter (int time)
1892{
1893 return ((rand () % (time + 1)) - (time / 2));
1894}
1895
1896void
1897ripng_event (enum ripng_event event, int sock)
1898{
paul718e3742002-12-13 20:15:29 +00001899 int jitter = 0;
1900
1901 switch (event)
1902 {
1903 case RIPNG_READ:
1904 if (!ripng->t_read)
1905 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1906 break;
1907 case RIPNG_UPDATE_EVENT:
1908 if (ripng->t_update)
1909 {
1910 thread_cancel (ripng->t_update);
1911 ripng->t_update = NULL;
1912 }
1913 /* Update timer jitter. */
1914 jitter = ripng_update_jitter (ripng->update_time);
1915
1916 ripng->t_update =
1917 thread_add_timer (master, ripng_update, NULL,
1918 sock ? 2 : ripng->update_time + jitter);
1919 break;
1920 case RIPNG_TRIGGERED_UPDATE:
1921 if (ripng->t_triggered_interval)
1922 ripng->trigger = 1;
1923 else if (! ripng->t_triggered_update)
1924 ripng->t_triggered_update =
1925 thread_add_event (master, ripng_triggered_update, NULL, 0);
1926 break;
1927 default:
1928 break;
1929 }
1930}
1931
paul718e3742002-12-13 20:15:29 +00001932
paul718e3742002-12-13 20:15:29 +00001933/* Print out routes update time. */
1934static void
1935ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1936{
paul718e3742002-12-13 20:15:29 +00001937 time_t clock;
1938 struct tm *tm;
1939#define TIME_BUF 25
1940 char timebuf [TIME_BUF];
1941 struct thread *thread;
1942
paul718e3742002-12-13 20:15:29 +00001943 if ((thread = rinfo->t_timeout) != NULL)
1944 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001945 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001946 tm = gmtime (&clock);
1947 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1948 vty_out (vty, "%5s", timebuf);
1949 }
1950 else if ((thread = rinfo->t_garbage_collect) != NULL)
1951 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001952 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001953 tm = gmtime (&clock);
1954 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1955 vty_out (vty, "%5s", timebuf);
1956 }
1957}
1958
Paul Jakma6ac29a52008-08-15 13:45:30 +01001959static char *
hassoa94434b2003-05-25 17:10:12 +00001960ripng_route_subtype_print (struct ripng_info *rinfo)
1961{
1962 static char str[3];
1963 memset(str, 0, 3);
1964
1965 if (rinfo->suppress)
1966 strcat(str, "S");
1967
1968 switch (rinfo->sub_type)
1969 {
1970 case RIPNG_ROUTE_RTE:
1971 strcat(str, "n");
1972 break;
1973 case RIPNG_ROUTE_STATIC:
1974 strcat(str, "s");
1975 break;
1976 case RIPNG_ROUTE_DEFAULT:
1977 strcat(str, "d");
1978 break;
1979 case RIPNG_ROUTE_REDISTRIBUTE:
1980 strcat(str, "r");
1981 break;
1982 case RIPNG_ROUTE_INTERFACE:
1983 strcat(str, "i");
1984 break;
1985 default:
1986 strcat(str, "?");
1987 break;
1988 }
1989
1990 return str;
1991}
1992
paul718e3742002-12-13 20:15:29 +00001993DEFUN (show_ipv6_ripng,
1994 show_ipv6_ripng_cmd,
1995 "show ipv6 ripng",
1996 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001997 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001998 "Show RIPng routes\n")
1999{
2000 struct route_node *rp;
2001 struct ripng_info *rinfo;
2002 struct ripng_aggregate *aggregate;
2003 struct prefix_ipv6 *p;
2004 int len;
2005
hassoa94434b2003-05-25 17:10:12 +00002006 if (! ripng)
2007 return CMD_SUCCESS;
2008
paul718e3742002-12-13 20:15:29 +00002009 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00002010 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2011 "Sub-codes:%s"
2012 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2013 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2014 " Network Next Hop Via Metric Tag Time%s",
2015 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002016 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2017
2018 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2019 {
2020 if ((aggregate = rp->aggregate) != NULL)
2021 {
2022 p = (struct prefix_ipv6 *) &rp->p;
2023
2024#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002025 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002026 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002027 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002028#else
hassoa94434b2003-05-25 17:10:12 +00002029 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002030 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002031#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002032 vty_out (vty, "%s", VTY_NEWLINE);
2033 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002034
hassoa94434b2003-05-25 17:10:12 +00002035 vty_out (vty, "%*s", 28, " ");
2036 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002037 aggregate->tag,
2038 VTY_NEWLINE);
2039 }
2040
2041 if ((rinfo = rp->info) != NULL)
2042 {
2043 p = (struct prefix_ipv6 *) &rp->p;
2044
2045#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002046 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2047 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002048 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002049 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002050 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002051#else
ajsf52d13c2005-10-01 17:38:06 +00002052 len = vty_out (vty, "%c(%s) %s/%d ",
2053 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002054 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002055 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002056#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002057 vty_out (vty, "%s", VTY_NEWLINE);
2058 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002059 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002060
hassoa94434b2003-05-25 17:10:12 +00002061 len = 28 - len;
2062 if (len > 0)
2063 len = vty_out (vty, "%*s", len, " ");
2064
2065 /* from */
2066 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2067 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2068 {
2069 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2070 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2071 {
2072 len = vty_out (vty, "kill");
2073 } else
2074 len = vty_out (vty, "self");
2075
2076 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002077 if (len > 0)
2078 vty_out (vty, "%*s", len, " ");
2079
hassoa94434b2003-05-25 17:10:12 +00002080 vty_out (vty, " %2d %3d ",
2081 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002082
hassoa94434b2003-05-25 17:10:12 +00002083 /* time */
2084 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2085 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2086 {
2087 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002088 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002089 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2090 {
2091 /* poisonous reversed routes (gc) */
2092 ripng_vty_out_uptime (vty, rinfo);
2093 }
paul718e3742002-12-13 20:15:29 +00002094
2095 vty_out (vty, "%s", VTY_NEWLINE);
2096 }
2097 }
2098
2099 return CMD_SUCCESS;
2100}
2101
hassoa94434b2003-05-25 17:10:12 +00002102DEFUN (show_ipv6_ripng_status,
2103 show_ipv6_ripng_status_cmd,
2104 "show ipv6 ripng status",
2105 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002106 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002107 "Show RIPng routes\n"
2108 "IPv6 routing protocol process parameters and statistics\n")
2109{
hasso52dc7ee2004-09-23 19:18:23 +00002110 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002111 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002112
2113 if (! ripng)
2114 return CMD_SUCCESS;
2115
2116 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2117 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2118 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002119 vty_out (vty, " next due in %lu seconds%s",
2120 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002121 VTY_NEWLINE);
2122 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2123 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2124 VTY_NEWLINE);
2125
2126 /* Filtering status show. */
2127 config_show_distribute (vty);
2128
2129 /* Default metric information. */
2130 vty_out (vty, " Default redistribution metric is %d%s",
2131 ripng->default_metric, VTY_NEWLINE);
2132
2133 /* Redistribute information. */
2134 vty_out (vty, " Redistributing:");
2135 ripng_redistribute_write (vty, 0);
2136 vty_out (vty, "%s", VTY_NEWLINE);
2137
2138 vty_out (vty, " Default version control: send version %d,", ripng->version);
2139 vty_out (vty, " receive version %d %s", ripng->version,
2140 VTY_NEWLINE);
2141
2142 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2143
paul1eb8ef22005-04-07 07:30:20 +00002144 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002145 {
2146 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002147
hassoa94434b2003-05-25 17:10:12 +00002148 ri = ifp->info;
2149
2150 if (ri->enable_network || ri->enable_interface)
2151 {
2152
2153 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2154 ripng->version,
2155 ripng->version,
2156 VTY_NEWLINE);
2157 }
2158 }
2159
2160 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2161 ripng_network_write (vty, 0);
2162
2163 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2164 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2165 ripng_peer_display (vty);
2166
2167 return CMD_SUCCESS;
2168}
2169
paul718e3742002-12-13 20:15:29 +00002170DEFUN (router_ripng,
2171 router_ripng_cmd,
2172 "router ripng",
2173 "Enable a routing process\n"
2174 "Make RIPng instance command\n")
2175{
2176 int ret;
2177
2178 vty->node = RIPNG_NODE;
2179
2180 if (!ripng)
2181 {
2182 ret = ripng_create ();
2183
2184 /* Notice to user we couldn't create RIPng. */
2185 if (ret < 0)
2186 {
2187 zlog_warn ("can't create RIPng");
2188 return CMD_WARNING;
2189 }
2190 }
2191
2192 return CMD_SUCCESS;
2193}
2194
hassoa94434b2003-05-25 17:10:12 +00002195DEFUN (no_router_ripng,
2196 no_router_ripng_cmd,
2197 "no router ripng",
2198 NO_STR
2199 "Enable a routing process\n"
2200 "Make RIPng instance command\n")
2201{
2202 if(ripng)
2203 ripng_clean();
2204 return CMD_SUCCESS;
2205}
2206
paul718e3742002-12-13 20:15:29 +00002207DEFUN (ripng_route,
2208 ripng_route_cmd,
2209 "route IPV6ADDR",
2210 "Static route setup\n"
2211 "Set static RIPng route announcement\n")
2212{
2213 int ret;
2214 struct prefix_ipv6 p;
2215 struct route_node *rp;
2216
2217 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2218 if (ret <= 0)
2219 {
2220 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2221 return CMD_WARNING;
2222 }
2223 apply_mask_ipv6 (&p);
2224
2225 rp = route_node_get (ripng->route, (struct prefix *) &p);
2226 if (rp->info)
2227 {
2228 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2229 route_unlock_node (rp);
2230 return CMD_WARNING;
2231 }
2232 rp->info = (void *)1;
2233
hassoa94434b2003-05-25 17:10:12 +00002234 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002235
2236 return CMD_SUCCESS;
2237}
2238
2239DEFUN (no_ripng_route,
2240 no_ripng_route_cmd,
2241 "no route IPV6ADDR",
2242 NO_STR
2243 "Static route setup\n"
2244 "Delete static RIPng route announcement\n")
2245{
2246 int ret;
2247 struct prefix_ipv6 p;
2248 struct route_node *rp;
2249
2250 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2251 if (ret <= 0)
2252 {
2253 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2254 return CMD_WARNING;
2255 }
2256 apply_mask_ipv6 (&p);
2257
2258 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2259 if (! rp)
2260 {
2261 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2262 return CMD_WARNING;
2263 }
2264
2265 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2266 route_unlock_node (rp);
2267
2268 rp->info = NULL;
2269 route_unlock_node (rp);
2270
2271 return CMD_SUCCESS;
2272}
2273
2274DEFUN (ripng_aggregate_address,
2275 ripng_aggregate_address_cmd,
2276 "aggregate-address X:X::X:X/M",
2277 "Set aggregate RIPng route announcement\n"
2278 "Aggregate network\n")
2279{
2280 int ret;
2281 struct prefix p;
2282 struct route_node *node;
2283
2284 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2285 if (ret <= 0)
2286 {
2287 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2288 return CMD_WARNING;
2289 }
2290
2291 /* Check aggregate alredy exist or not. */
2292 node = route_node_get (ripng->aggregate, &p);
2293 if (node->info)
2294 {
2295 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2296 route_unlock_node (node);
2297 return CMD_WARNING;
2298 }
2299 node->info = (void *)1;
2300
2301 ripng_aggregate_add (&p);
2302
2303 return CMD_SUCCESS;
2304}
2305
2306DEFUN (no_ripng_aggregate_address,
2307 no_ripng_aggregate_address_cmd,
2308 "no aggregate-address X:X::X:X/M",
2309 NO_STR
2310 "Delete aggregate RIPng route announcement\n"
2311 "Aggregate network")
2312{
2313 int ret;
2314 struct prefix p;
2315 struct route_node *rn;
2316
2317 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2318 if (ret <= 0)
2319 {
2320 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2321 return CMD_WARNING;
2322 }
2323
2324 rn = route_node_lookup (ripng->aggregate, &p);
2325 if (! rn)
2326 {
2327 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2328 return CMD_WARNING;
2329 }
2330 route_unlock_node (rn);
2331 rn->info = NULL;
2332 route_unlock_node (rn);
2333
2334 ripng_aggregate_delete (&p);
2335
2336 return CMD_SUCCESS;
2337}
2338
2339DEFUN (ripng_default_metric,
2340 ripng_default_metric_cmd,
2341 "default-metric <1-16>",
2342 "Set a metric of redistribute routes\n"
2343 "Default metric\n")
2344{
2345 if (ripng)
2346 {
2347 ripng->default_metric = atoi (argv[0]);
2348 }
2349 return CMD_SUCCESS;
2350}
2351
2352DEFUN (no_ripng_default_metric,
2353 no_ripng_default_metric_cmd,
2354 "no default-metric",
2355 NO_STR
2356 "Set a metric of redistribute routes\n"
2357 "Default metric\n")
2358{
2359 if (ripng)
2360 {
2361 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2362 }
2363 return CMD_SUCCESS;
2364}
2365
2366ALIAS (no_ripng_default_metric,
2367 no_ripng_default_metric_val_cmd,
2368 "no default-metric <1-16>",
2369 NO_STR
2370 "Set a metric of redistribute routes\n"
2371 "Default metric\n")
2372
2373#if 0
2374/* RIPng update timer setup. */
2375DEFUN (ripng_update_timer,
2376 ripng_update_timer_cmd,
2377 "update-timer SECOND",
2378 "Set RIPng update timer in seconds\n"
2379 "Seconds\n")
2380{
2381 unsigned long update;
2382 char *endptr = NULL;
2383
2384 update = strtoul (argv[0], &endptr, 10);
2385 if (update == ULONG_MAX || *endptr != '\0')
2386 {
2387 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2388 return CMD_WARNING;
2389 }
2390
2391 ripng->update_time = update;
2392
2393 ripng_event (RIPNG_UPDATE_EVENT, 0);
2394 return CMD_SUCCESS;
2395}
2396
2397DEFUN (no_ripng_update_timer,
2398 no_ripng_update_timer_cmd,
2399 "no update-timer SECOND",
2400 NO_STR
2401 "Unset RIPng update timer in seconds\n"
2402 "Seconds\n")
2403{
2404 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2405 ripng_event (RIPNG_UPDATE_EVENT, 0);
2406 return CMD_SUCCESS;
2407}
2408
2409/* RIPng timeout timer setup. */
2410DEFUN (ripng_timeout_timer,
2411 ripng_timeout_timer_cmd,
2412 "timeout-timer SECOND",
2413 "Set RIPng timeout timer in seconds\n"
2414 "Seconds\n")
2415{
2416 unsigned long timeout;
2417 char *endptr = NULL;
2418
2419 timeout = strtoul (argv[0], &endptr, 10);
2420 if (timeout == ULONG_MAX || *endptr != '\0')
2421 {
2422 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2423 return CMD_WARNING;
2424 }
2425
2426 ripng->timeout_time = timeout;
2427
2428 return CMD_SUCCESS;
2429}
2430
2431DEFUN (no_ripng_timeout_timer,
2432 no_ripng_timeout_timer_cmd,
2433 "no timeout-timer SECOND",
2434 NO_STR
2435 "Unset RIPng timeout timer in seconds\n"
2436 "Seconds\n")
2437{
2438 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2439 return CMD_SUCCESS;
2440}
2441
2442/* RIPng garbage timer setup. */
2443DEFUN (ripng_garbage_timer,
2444 ripng_garbage_timer_cmd,
2445 "garbage-timer SECOND",
2446 "Set RIPng garbage timer in seconds\n"
2447 "Seconds\n")
2448{
2449 unsigned long garbage;
2450 char *endptr = NULL;
2451
2452 garbage = strtoul (argv[0], &endptr, 10);
2453 if (garbage == ULONG_MAX || *endptr != '\0')
2454 {
2455 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2456 return CMD_WARNING;
2457 }
2458
2459 ripng->garbage_time = garbage;
2460
2461 return CMD_SUCCESS;
2462}
2463
2464DEFUN (no_ripng_garbage_timer,
2465 no_ripng_garbage_timer_cmd,
2466 "no garbage-timer SECOND",
2467 NO_STR
2468 "Unset RIPng garbage timer in seconds\n"
2469 "Seconds\n")
2470{
2471 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2472 return CMD_SUCCESS;
2473}
2474#endif /* 0 */
2475
2476DEFUN (ripng_timers,
2477 ripng_timers_cmd,
2478 "timers basic <0-65535> <0-65535> <0-65535>",
2479 "RIPng timers setup\n"
2480 "Basic timer\n"
2481 "Routing table update timer value in second. Default is 30.\n"
2482 "Routing information timeout timer. Default is 180.\n"
2483 "Garbage collection timer. Default is 120.\n")
2484{
2485 unsigned long update;
2486 unsigned long timeout;
2487 unsigned long garbage;
2488 char *endptr = NULL;
2489
2490 update = strtoul (argv[0], &endptr, 10);
2491 if (update == ULONG_MAX || *endptr != '\0')
2492 {
2493 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2494 return CMD_WARNING;
2495 }
2496
2497 timeout = strtoul (argv[1], &endptr, 10);
2498 if (timeout == ULONG_MAX || *endptr != '\0')
2499 {
2500 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2501 return CMD_WARNING;
2502 }
2503
2504 garbage = strtoul (argv[2], &endptr, 10);
2505 if (garbage == ULONG_MAX || *endptr != '\0')
2506 {
2507 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2508 return CMD_WARNING;
2509 }
2510
2511 /* Set each timer value. */
2512 ripng->update_time = update;
2513 ripng->timeout_time = timeout;
2514 ripng->garbage_time = garbage;
2515
2516 /* Reset update timer thread. */
2517 ripng_event (RIPNG_UPDATE_EVENT, 0);
2518
2519 return CMD_SUCCESS;
2520}
2521
2522DEFUN (no_ripng_timers,
2523 no_ripng_timers_cmd,
2524 "no timers basic",
2525 NO_STR
2526 "RIPng timers setup\n"
2527 "Basic timer\n")
2528{
2529 /* Set each timer value to the default. */
2530 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2531 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2532 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2533
2534 /* Reset update timer thread. */
2535 ripng_event (RIPNG_UPDATE_EVENT, 0);
2536
2537 return CMD_SUCCESS;
2538}
2539
hassoa94434b2003-05-25 17:10:12 +00002540ALIAS (no_ripng_timers,
2541 no_ripng_timers_val_cmd,
2542 "no timers basic <0-65535> <0-65535> <0-65535>",
2543 NO_STR
2544 "RIPng timers setup\n"
2545 "Basic timer\n"
2546 "Routing table update timer value in second. Default is 30.\n"
2547 "Routing information timeout timer. Default is 180.\n"
2548 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002549
2550DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2551 "show ipv6 protocols",
2552 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002553 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002554 "Routing protocol information")
2555{
2556 if (! ripng)
2557 return CMD_SUCCESS;
2558
2559 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2560
2561 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2562 ripng->update_time, 0,
2563 VTY_NEWLINE);
2564
2565 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2566 ripng->timeout_time,
2567 ripng->garbage_time,
2568 VTY_NEWLINE);
2569
2570 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2571 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2572
2573 return CMD_SUCCESS;
2574}
2575
2576/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002577DEFUN (ripng_default_information_originate,
2578 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002579 "default-information originate",
2580 "Default route information\n"
2581 "Distribute default route\n")
2582{
2583 struct prefix_ipv6 p;
2584
hassoa94434b2003-05-25 17:10:12 +00002585 if (! ripng ->default_information) {
2586 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002587
hassoa94434b2003-05-25 17:10:12 +00002588 str2prefix_ipv6 ("::/0", &p);
2589 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2590 }
paul718e3742002-12-13 20:15:29 +00002591
2592 return CMD_SUCCESS;
2593}
2594
paula2c62832003-04-23 17:01:31 +00002595DEFUN (no_ripng_default_information_originate,
2596 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002597 "no default-information originate",
2598 NO_STR
2599 "Default route information\n"
2600 "Distribute default route\n")
2601{
2602 struct prefix_ipv6 p;
2603
hassoa94434b2003-05-25 17:10:12 +00002604 if (ripng->default_information) {
2605 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002606
hassoa94434b2003-05-25 17:10:12 +00002607 str2prefix_ipv6 ("::/0", &p);
2608 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2609 }
paul718e3742002-12-13 20:15:29 +00002610
2611 return CMD_SUCCESS;
2612}
2613
2614/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002615static int
paul718e3742002-12-13 20:15:29 +00002616ripng_config_write (struct vty *vty)
2617{
hassoa94434b2003-05-25 17:10:12 +00002618 int ripng_network_write (struct vty *, int);
2619 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002620 int write = 0;
2621 struct route_node *rp;
2622
2623 if (ripng)
2624 {
2625
2626 /* RIPng router. */
2627 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2628
2629 if (ripng->default_information)
2630 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2631
hassoa94434b2003-05-25 17:10:12 +00002632 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002633
2634 /* RIPng default metric configuration */
2635 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2636 vty_out (vty, " default-metric %d%s",
2637 ripng->default_metric, VTY_NEWLINE);
2638
hassoa94434b2003-05-25 17:10:12 +00002639 ripng_redistribute_write (vty, 1);
2640
2641 /* RIP offset-list configuration. */
2642 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002643
2644 /* RIPng aggregate routes. */
2645 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2646 if (rp->info != NULL)
2647 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002648 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002649 rp->p.prefixlen,
2650
2651 VTY_NEWLINE);
2652
2653 /* RIPng static routes. */
2654 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2655 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002656 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002657 rp->p.prefixlen,
2658 VTY_NEWLINE);
2659
2660 /* RIPng timers configuration. */
2661 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2662 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2663 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2664 {
2665 vty_out (vty, " timers basic %ld %ld %ld%s",
2666 ripng->update_time,
2667 ripng->timeout_time,
2668 ripng->garbage_time,
2669 VTY_NEWLINE);
2670 }
2671#if 0
2672 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2673 vty_out (vty, " update-timer %d%s", ripng->update_time,
2674 VTY_NEWLINE);
2675 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2676 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2677 VTY_NEWLINE);
2678 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2679 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2680 VTY_NEWLINE);
2681#endif /* 0 */
2682
2683 write += config_write_distribute (vty);
2684
2685 write += config_write_if_rmap (vty);
2686
2687 write++;
2688 }
2689 return write;
2690}
2691
2692/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002693static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002694{
2695 RIPNG_NODE,
2696 "%s(config-router)# ",
2697 1,
2698};
2699
Paul Jakma6ac29a52008-08-15 13:45:30 +01002700static void
paul718e3742002-12-13 20:15:29 +00002701ripng_distribute_update (struct distribute *dist)
2702{
2703 struct interface *ifp;
2704 struct ripng_interface *ri;
2705 struct access_list *alist;
2706 struct prefix_list *plist;
2707
2708 if (! dist->ifname)
2709 return;
2710
2711 ifp = if_lookup_by_name (dist->ifname);
2712 if (ifp == NULL)
2713 return;
2714
2715 ri = ifp->info;
2716
2717 if (dist->list[DISTRIBUTE_IN])
2718 {
2719 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2720 if (alist)
2721 ri->list[RIPNG_FILTER_IN] = alist;
2722 else
2723 ri->list[RIPNG_FILTER_IN] = NULL;
2724 }
2725 else
2726 ri->list[RIPNG_FILTER_IN] = NULL;
2727
2728 if (dist->list[DISTRIBUTE_OUT])
2729 {
2730 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2731 if (alist)
2732 ri->list[RIPNG_FILTER_OUT] = alist;
2733 else
2734 ri->list[RIPNG_FILTER_OUT] = NULL;
2735 }
2736 else
2737 ri->list[RIPNG_FILTER_OUT] = NULL;
2738
2739 if (dist->prefix[DISTRIBUTE_IN])
2740 {
2741 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2742 if (plist)
2743 ri->prefix[RIPNG_FILTER_IN] = plist;
2744 else
2745 ri->prefix[RIPNG_FILTER_IN] = NULL;
2746 }
2747 else
2748 ri->prefix[RIPNG_FILTER_IN] = NULL;
2749
2750 if (dist->prefix[DISTRIBUTE_OUT])
2751 {
2752 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2753 if (plist)
2754 ri->prefix[RIPNG_FILTER_OUT] = plist;
2755 else
2756 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2757 }
2758 else
2759 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2760}
hassoa94434b2003-05-25 17:10:12 +00002761
paul718e3742002-12-13 20:15:29 +00002762void
2763ripng_distribute_update_interface (struct interface *ifp)
2764{
2765 struct distribute *dist;
2766
2767 dist = distribute_lookup (ifp->name);
2768 if (dist)
2769 ripng_distribute_update (dist);
2770}
2771
2772/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002773static void
hassoc9e52be2004-09-26 16:09:34 +00002774ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002775{
2776 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002777 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002778
paul1eb8ef22005-04-07 07:30:20 +00002779 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2780 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002781}
hassoc9e52be2004-09-26 16:09:34 +00002782
Paul Jakma6ac29a52008-08-15 13:45:30 +01002783static void
hassoc9e52be2004-09-26 16:09:34 +00002784ripng_distribute_update_all_wrapper (struct access_list *notused)
2785{
2786 ripng_distribute_update_all(NULL);
2787}
hassoa94434b2003-05-25 17:10:12 +00002788
2789/* delete all the added ripng routes. */
2790void
2791ripng_clean()
2792{
2793 int i;
2794 struct route_node *rp;
2795 struct ripng_info *rinfo;
2796
2797 if (ripng) {
2798 /* Clear RIPng routes */
2799 for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
2800 if ((rinfo = rp->info) != NULL) {
2801 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2802 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2803 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
2804 &rinfo->nexthop, rinfo->metric);
2805
2806 RIPNG_TIMER_OFF (rinfo->t_timeout);
2807 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2808
2809 rp->info = NULL;
2810 route_unlock_node (rp);
2811
2812 ripng_info_free(rinfo);
2813 }
2814 }
2815
2816 /* Cancel the RIPng timers */
2817 RIPNG_TIMER_OFF (ripng->t_update);
2818 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2819 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2820
2821 /* Cancel the read thread */
2822 if (ripng->t_read) {
2823 thread_cancel (ripng->t_read);
2824 ripng->t_read = NULL;
2825 }
2826
2827 /* Close the RIPng socket */
2828 if (ripng->sock >= 0) {
2829 close(ripng->sock);
2830 ripng->sock = -1;
2831 }
2832
2833 /* Static RIPng route configuration. */
2834 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2835 if (rp->info) {
2836 rp->info = NULL;
2837 route_unlock_node (rp);
2838 }
2839
2840 /* RIPng aggregated prefixes */
2841 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2842 if (rp->info) {
2843 rp->info = NULL;
2844 route_unlock_node (rp);
2845 }
2846
2847 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2848 if (ripng->route_map[i].name)
2849 free (ripng->route_map[i].name);
2850
2851 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2852 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2853 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2854
2855 XFREE (MTYPE_RIPNG, ripng);
2856 ripng = NULL;
2857 } /* if (ripng) */
2858
2859 ripng_clean_network();
2860 ripng_passive_interface_clean ();
2861 ripng_offset_clean ();
2862 ripng_interface_clean ();
2863 ripng_redistribute_clean ();
2864}
2865
2866/* Reset all values to the default settings. */
2867void
2868ripng_reset ()
2869{
2870 /* Call ripd related reset functions. */
2871 ripng_debug_reset ();
2872 ripng_route_map_reset ();
2873
2874 /* Call library reset functions. */
2875 vty_reset ();
2876 access_list_reset ();
2877 prefix_list_reset ();
2878
2879 distribute_list_reset ();
2880
2881 ripng_interface_reset ();
2882
2883 ripng_zclient_reset ();
2884}
paul718e3742002-12-13 20:15:29 +00002885
Paul Jakma6ac29a52008-08-15 13:45:30 +01002886static void
paul718e3742002-12-13 20:15:29 +00002887ripng_if_rmap_update (struct if_rmap *if_rmap)
2888{
2889 struct interface *ifp;
2890 struct ripng_interface *ri;
2891 struct route_map *rmap;
2892
2893 ifp = if_lookup_by_name (if_rmap->ifname);
2894 if (ifp == NULL)
2895 return;
2896
2897 ri = ifp->info;
2898
2899 if (if_rmap->routemap[IF_RMAP_IN])
2900 {
2901 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2902 if (rmap)
2903 ri->routemap[IF_RMAP_IN] = rmap;
2904 else
2905 ri->routemap[IF_RMAP_IN] = NULL;
2906 }
2907 else
2908 ri->routemap[RIPNG_FILTER_IN] = NULL;
2909
2910 if (if_rmap->routemap[IF_RMAP_OUT])
2911 {
2912 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2913 if (rmap)
2914 ri->routemap[IF_RMAP_OUT] = rmap;
2915 else
2916 ri->routemap[IF_RMAP_OUT] = NULL;
2917 }
2918 else
2919 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2920}
2921
2922void
2923ripng_if_rmap_update_interface (struct interface *ifp)
2924{
2925 struct if_rmap *if_rmap;
2926
2927 if_rmap = if_rmap_lookup (ifp->name);
2928 if (if_rmap)
2929 ripng_if_rmap_update (if_rmap);
2930}
2931
Paul Jakma6ac29a52008-08-15 13:45:30 +01002932static void
paul718e3742002-12-13 20:15:29 +00002933ripng_routemap_update_redistribute (void)
2934{
2935 int i;
2936
2937 if (ripng)
2938 {
2939 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2940 {
2941 if (ripng->route_map[i].name)
2942 ripng->route_map[i].map =
2943 route_map_lookup_by_name (ripng->route_map[i].name);
2944 }
2945 }
2946}
2947
Paul Jakma6ac29a52008-08-15 13:45:30 +01002948static void
hasso98b718a2004-10-11 12:57:57 +00002949ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00002950{
2951 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002952 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002953
paul1eb8ef22005-04-07 07:30:20 +00002954 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2955 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002956
2957 ripng_routemap_update_redistribute ();
2958}
2959
2960/* Initialize ripng structure and set commands. */
2961void
2962ripng_init ()
2963{
2964 /* Randomize. */
2965 srand (time (NULL));
2966
2967 /* Install RIPNG_NODE. */
2968 install_node (&cmd_ripng_node, ripng_config_write);
2969
2970 /* Install ripng commands. */
2971 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002972 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002973
2974 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002975 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002976
2977 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002978 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00002979
2980 install_default (RIPNG_NODE);
2981 install_element (RIPNG_NODE, &ripng_route_cmd);
2982 install_element (RIPNG_NODE, &no_ripng_route_cmd);
2983 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
2984 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
2985
2986 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
2987 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
2988 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
2989
2990 install_element (RIPNG_NODE, &ripng_timers_cmd);
2991 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00002992 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00002993#if 0
2994 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2995 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2996 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2997 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2998 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2999 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3000#endif /* 0 */
3001
paula2c62832003-04-23 17:01:31 +00003002 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3003 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00003004
3005 ripng_if_init ();
3006 ripng_debug_init ();
3007
3008 /* Access list install. */
3009 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003010 access_list_add_hook (ripng_distribute_update_all_wrapper);
3011 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003012
3013 /* Prefix list initialize.*/
3014 prefix_list_init ();
3015 prefix_list_add_hook (ripng_distribute_update_all);
3016 prefix_list_delete_hook (ripng_distribute_update_all);
3017
3018 /* Distribute list install. */
3019 distribute_list_init (RIPNG_NODE);
3020 distribute_list_add_hook (ripng_distribute_update);
3021 distribute_list_delete_hook (ripng_distribute_update);
3022
3023 /* Route-map for interface. */
3024 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003025 ripng_offset_init ();
3026
paul718e3742002-12-13 20:15:29 +00003027 route_map_add_hook (ripng_routemap_update);
3028 route_map_delete_hook (ripng_routemap_update);
3029
hasso0750d212003-05-24 21:41:49 +00003030 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003031 if_rmap_hook_add (ripng_if_rmap_update);
3032 if_rmap_hook_delete (ripng_if_rmap_update);
3033}