blob: 82e381816ba5d101b915419fff377125f04438d4 [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}
David Lamparter6b0655a2014-06-04 06:53:35 +020098
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;
David Lamparterab90fc02015-03-03 09:07:25 +0100239 struct in6_addr dst = { .s6_addr = { 0 } };
paul718e3742002-12-13 20:15:29 +0000240
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)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000720 rte->metric += ifp->metric ? ifp->metric : 1;
hassoa94434b2003-05-25 17:10:12 +0000721
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;
931
932 rp = route_node_get (ripng->table, (struct prefix *) p);
933 rinfo = rp->info;
934
935 if (rinfo)
936 {
hassoa94434b2003-05-25 17:10:12 +0000937 if (rinfo->type == ZEBRA_ROUTE_CONNECT
938 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
939 && rinfo->metric != RIPNG_METRIC_INFINITY) {
940 route_unlock_node (rp);
941 return;
942 }
943
944 /* Manually configured RIPng route check.
945 * They have the precedence on all the other entries.
946 **/
947 if (rinfo->type == ZEBRA_ROUTE_RIPNG
948 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
949 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
950 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
951 (sub_type != RIPNG_ROUTE_DEFAULT))) {
952 route_unlock_node (rp);
953 return;
954 }
955 }
956
paul718e3742002-12-13 20:15:29 +0000957 RIPNG_TIMER_OFF (rinfo->t_timeout);
958 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
hassoa94434b2003-05-25 17:10:12 +0000959
960 /* Tells the other daemons about the deletion of
961 * this RIPng route
962 **/
963 if (ripng_route_rte (rinfo))
964 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
965 rinfo->metric);
966
967 rp->info = NULL;
968 ripng_info_free (rinfo);
969
paul718e3742002-12-13 20:15:29 +0000970 route_unlock_node (rp);
hassoa94434b2003-05-25 17:10:12 +0000971
paul718e3742002-12-13 20:15:29 +0000972 }
hassoa94434b2003-05-25 17:10:12 +0000973
974 rinfo = ripng_info_new ();
paul718e3742002-12-13 20:15:29 +0000975
976 rinfo->type = type;
977 rinfo->sub_type = sub_type;
978 rinfo->ifindex = ifindex;
979 rinfo->metric = 1;
paul718e3742002-12-13 20:15:29 +0000980 rinfo->rp = rp;
hassoa94434b2003-05-25 17:10:12 +0000981
982 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
983 rinfo->nexthop = *nexthop;
984
985 rinfo->flags |= RIPNG_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000986 rp->info = rinfo;
hassoa94434b2003-05-25 17:10:12 +0000987
988 /* Aggregate check. */
989 ripng_aggregate_increment (rp, rinfo);
990
991 rinfo->flags |= RIPNG_RTF_CHANGED;
992
993 if (IS_RIPNG_DEBUG_EVENT) {
994 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +0000995 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000996 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +0000997 ifindex2ifname(ifindex));
998 else
ajsc6106812004-12-08 19:51:16 +0000999 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001000 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001001 ifindex2ifname(ifindex));
1002 }
1003
1004 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001005}
1006
1007/* Delete redistributed route to RIPng table. */
1008void
1009ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1010 unsigned int ifindex)
1011{
1012 struct route_node *rp;
1013 struct ripng_info *rinfo;
1014
1015 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1016 return;
1017 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1018 return;
1019
1020 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1021
1022 if (rp)
1023 {
1024 rinfo = rp->info;
1025
1026 if (rinfo != NULL
1027 && rinfo->type == type
1028 && rinfo->sub_type == sub_type
1029 && rinfo->ifindex == ifindex)
1030 {
hassoa94434b2003-05-25 17:10:12 +00001031 /* Perform poisoned reverse. */
1032 rinfo->metric = RIPNG_METRIC_INFINITY;
1033 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1034 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001035 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001036
1037 /* Aggregate count decrement. */
1038 ripng_aggregate_decrement (rp, rinfo);
1039
1040 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001041
hassoa94434b2003-05-25 17:10:12 +00001042 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001043 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso3a2ce6a2005-04-08 01:30:51 +00001044 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001045 ifindex2ifname(ifindex));
paul718e3742002-12-13 20:15:29 +00001046
hassoa94434b2003-05-25 17:10:12 +00001047 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001048 }
paul718e3742002-12-13 20:15:29 +00001049 }
1050}
1051
1052/* Withdraw redistributed route. */
1053void
1054ripng_redistribute_withdraw (int type)
1055{
1056 struct route_node *rp;
1057 struct ripng_info *rinfo;
1058
hassoa94434b2003-05-25 17:10:12 +00001059 if (!ripng)
1060 return;
1061
paul718e3742002-12-13 20:15:29 +00001062 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1063 if ((rinfo = rp->info) != NULL)
1064 {
hassoa94434b2003-05-25 17:10:12 +00001065 if ((rinfo->type == type)
1066 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001067 {
hassoa94434b2003-05-25 17:10:12 +00001068 /* Perform poisoned reverse. */
1069 rinfo->metric = RIPNG_METRIC_INFINITY;
1070 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1071 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001072 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001073
hassoa94434b2003-05-25 17:10:12 +00001074 /* Aggregate count decrement. */
1075 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001076
hassoa94434b2003-05-25 17:10:12 +00001077 rinfo->flags |= RIPNG_RTF_CHANGED;
1078
1079 if (IS_RIPNG_DEBUG_EVENT) {
1080 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1081
ajsc6106812004-12-08 19:51:16 +00001082 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001083 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001084 ifindex2ifname(rinfo->ifindex));
1085 }
1086
1087 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001088 }
1089 }
1090}
1091
1092/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001093static void
paul718e3742002-12-13 20:15:29 +00001094ripng_response_process (struct ripng_packet *packet, int size,
1095 struct sockaddr_in6 *from, struct interface *ifp,
1096 int hoplimit)
1097{
1098 caddr_t lim;
1099 struct rte *rte;
1100 struct ripng_nexthop nexthop;
1101
1102 /* RFC2080 2.4.2 Response Messages:
1103 The Response must be ignored if it is not from the RIPng port. */
1104 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1105 {
1106 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001107 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001108 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001109 return;
1110 }
1111
1112 /* The datagram's IPv6 source address should be checked to see
1113 whether the datagram is from a valid neighbor; the source of the
1114 datagram must be a link-local address. */
1115 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1116 {
1117 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001118 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001119 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001120 return;
1121 }
1122
1123 /* It is also worth checking to see whether the response is from one
1124 of the router's own addresses. Interfaces on broadcast networks
1125 may receive copies of their own multicasts immediately. If a
1126 router processes its own output as new input, confusion is likely,
1127 and such datagrams must be ignored. */
1128 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1129 {
1130 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001131 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001132 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001133 return;
1134 }
1135
1136 /* As an additional check, periodic advertisements must have their
1137 hop counts set to 255, and inbound, multicast packets sent from the
1138 RIPng port (i.e. periodic advertisement or triggered update
1139 packets) must be examined to ensure that the hop count is 255. */
1140 if (hoplimit >= 0 && hoplimit != 255)
1141 {
1142 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001143 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001144 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001145 return;
1146 }
1147
hassoa94434b2003-05-25 17:10:12 +00001148 /* Update RIPng peer. */
1149 ripng_peer_update (from, packet->version);
1150
paul718e3742002-12-13 20:15:29 +00001151 /* Reset nexthop. */
1152 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1153 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1154
1155 /* Set RTE pointer. */
1156 rte = packet->rte;
1157
1158 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1159 {
1160 /* First of all, we have to check this RTE is next hop RTE or
1161 not. Next hop RTE is completely different with normal RTE so
1162 we need special treatment. */
1163 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1164 {
1165 ripng_nexthop_rte (rte, from, &nexthop);
1166 continue;
1167 }
1168
1169 /* RTE information validation. */
1170
1171 /* - is the destination prefix valid (e.g., not a multicast
1172 prefix and not a link-local address) A link-local address
1173 should never be present in an RTE. */
1174 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1175 {
1176 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001177 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001178 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001179 continue;
1180 }
1181 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1182 {
1183 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001184 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001185 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001186 continue;
1187 }
1188 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1189 {
1190 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001191 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001192 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001193 continue;
1194 }
1195
1196 /* - is the prefix length valid (i.e., between 0 and 128,
1197 inclusive) */
1198 if (rte->prefixlen > 128)
1199 {
1200 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001201 inet6_ntoa (rte->addr), rte->prefixlen,
1202 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001203 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001204 continue;
1205 }
1206
1207 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1208 if (! (rte->metric >= 1 && rte->metric <= 16))
1209 {
1210 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001211 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001212 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001213 continue;
1214 }
1215
hassoa94434b2003-05-25 17:10:12 +00001216 /* Vincent: XXX Should we compute the direclty reachable nexthop
1217 * for our RIPng network ?
1218 **/
paul718e3742002-12-13 20:15:29 +00001219
1220 /* Routing table updates. */
1221 ripng_route_process (rte, from, &nexthop, ifp);
1222 }
1223}
1224
1225/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001226static void
paul718e3742002-12-13 20:15:29 +00001227ripng_request_process (struct ripng_packet *packet,int size,
1228 struct sockaddr_in6 *from, struct interface *ifp)
1229{
1230 caddr_t lim;
1231 struct rte *rte;
1232 struct prefix_ipv6 p;
1233 struct route_node *rp;
1234 struct ripng_info *rinfo;
1235 struct ripng_interface *ri;
1236
hassoa94434b2003-05-25 17:10:12 +00001237 /* Does not reponse to the requests on the loopback interfaces */
1238 if (if_is_loopback (ifp))
1239 return;
1240
paul718e3742002-12-13 20:15:29 +00001241 /* Check RIPng process is enabled on this interface. */
1242 ri = ifp->info;
1243 if (! ri->running)
1244 return;
1245
1246 /* When passive interface is specified, suppress responses */
1247 if (ri->passive)
1248 return;
1249
hassoa94434b2003-05-25 17:10:12 +00001250 /* RIPng peer update. */
1251 ripng_peer_update (from, packet->version);
1252
paul718e3742002-12-13 20:15:29 +00001253 lim = ((caddr_t) packet) + size;
1254 rte = packet->rte;
1255
1256 /* The Request is processed entry by entry. If there are no
1257 entries, no response is given. */
1258 if (lim == (caddr_t) rte)
1259 return;
1260
1261 /* There is one special case. If there is exactly one entry in the
1262 request, and it has a destination prefix of zero, a prefix length
1263 of zero, and a metric of infinity (i.e., 16), then this is a
1264 request to send the entire routing table. In that case, a call
1265 is made to the output process to send the routing table to the
1266 requesting address/port. */
1267 if (lim == ((caddr_t) (rte + 1)) &&
1268 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1269 rte->prefixlen == 0 &&
1270 rte->metric == RIPNG_METRIC_INFINITY)
1271 {
1272 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001273 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001274 }
1275 else
1276 {
1277 /* Except for this special case, processing is quite simple.
1278 Examine the list of RTEs in the Request one by one. For each
1279 entry, look up the destination in the router's routing
1280 database and, if there is a route, put that route's metric in
1281 the metric field of the RTE. If there is no explicit route
1282 to the specified destination, put infinity in the metric
1283 field. Once all the entries have been filled in, change the
1284 command from Request to Response and send the datagram back
1285 to the requestor. */
1286 memset (&p, 0, sizeof (struct prefix_ipv6));
1287 p.family = AF_INET6;
1288
1289 for (; ((caddr_t) rte) < lim; rte++)
1290 {
1291 p.prefix = rte->addr;
1292 p.prefixlen = rte->prefixlen;
1293 apply_mask_ipv6 (&p);
1294
1295 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1296
1297 if (rp)
1298 {
1299 rinfo = rp->info;
1300 rte->metric = rinfo->metric;
1301 route_unlock_node (rp);
1302 }
1303 else
1304 rte->metric = RIPNG_METRIC_INFINITY;
1305 }
1306 packet->command = RIPNG_RESPONSE;
1307
1308 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1309 }
1310}
1311
1312/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001313static int
paul718e3742002-12-13 20:15:29 +00001314ripng_read (struct thread *thread)
1315{
1316 int len;
1317 int sock;
1318 struct sockaddr_in6 from;
1319 struct ripng_packet *packet;
1320 unsigned int ifindex;
1321 struct interface *ifp;
1322 int hoplimit = -1;
1323
1324 /* Check ripng is active and alive. */
1325 assert (ripng != NULL);
1326 assert (ripng->sock >= 0);
1327
1328 /* Fetch thread data and set read pointer to empty for event
1329 managing. `sock' sould be same as ripng->sock. */
1330 sock = THREAD_FD (thread);
1331 ripng->t_read = NULL;
1332
1333 /* Add myself to the next event. */
1334 ripng_event (RIPNG_READ, sock);
1335
1336 /* Read RIPng packet. */
1337 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1338 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1339 &hoplimit);
1340 if (len < 0)
1341 {
ajs6099b3b2004-11-20 02:06:59 +00001342 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001343 return len;
1344 }
1345
1346 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1347 (4)) must be multiple size of one RTE size (20). */
1348 if (((len - 4) % 20) != 0)
1349 {
1350 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001351 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001352 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001353 return 0;
1354 }
1355
1356 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1357 ifp = if_lookup_by_index (ifindex);
1358
1359 /* RIPng packet received. */
1360 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001361 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001362 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001363 ifp ? ifp->name : "unknown");
1364
1365 /* Logging before packet checking. */
1366 if (IS_RIPNG_DEBUG_RECV)
1367 ripng_packet_dump (packet, len, "RECV");
1368
1369 /* Packet comes from unknown interface. */
1370 if (ifp == NULL)
1371 {
1372 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1373 return 0;
1374 }
1375
1376 /* Packet version mismatch checking. */
1377 if (packet->version != ripng->version)
1378 {
1379 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1380 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001381 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001382 return 0;
1383 }
1384
1385 /* Process RIPng packet. */
1386 switch (packet->command)
1387 {
1388 case RIPNG_REQUEST:
1389 ripng_request_process (packet, len, &from, ifp);
1390 break;
1391 case RIPNG_RESPONSE:
1392 ripng_response_process (packet, len, &from, ifp, hoplimit);
1393 break;
1394 default:
1395 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001396 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001397 break;
1398 }
1399 return 0;
1400}
1401
1402/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001403static void
1404ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001405{
1406 struct route_node *rp;
1407 struct ripng_info *rinfo;
1408
1409 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1410 if ((rinfo = rp->info) != NULL)
1411 if (rinfo->flags & RIPNG_RTF_CHANGED)
1412 rinfo->flags &= ~RIPNG_RTF_CHANGED;
1413}
1414
1415/* Regular update of RIPng route. Send all routing formation to RIPng
1416 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001417static int
paul718e3742002-12-13 20:15:29 +00001418ripng_update (struct thread *t)
1419{
hasso52dc7ee2004-09-23 19:18:23 +00001420 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001421 struct interface *ifp;
1422 struct ripng_interface *ri;
1423
1424 /* Clear update timer thread. */
1425 ripng->t_update = NULL;
1426
1427 /* Logging update event. */
1428 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001429 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001430
1431 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001432 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001433 {
paul718e3742002-12-13 20:15:29 +00001434 ri = ifp->info;
1435
1436 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1437 continue;
1438
1439 if (! ri->running)
1440 continue;
1441
1442 /* When passive interface is specified, suppress announce to the
1443 interface. */
1444 if (ri->passive)
1445 continue;
1446
1447#if RIPNG_ADVANCED
1448 if (ri->ri_send == RIPNG_SEND_OFF)
1449 {
1450 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001451 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001452 "[Event] RIPng send to if %d is suppressed by config",
1453 ifp->ifindex);
1454 continue;
1455 }
1456#endif /* RIPNG_ADVANCED */
1457
hassoa94434b2003-05-25 17:10:12 +00001458 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001459 }
1460
1461 /* Triggered updates may be suppressed if a regular update is due by
1462 the time the triggered update would be sent. */
1463 if (ripng->t_triggered_interval)
1464 {
1465 thread_cancel (ripng->t_triggered_interval);
1466 ripng->t_triggered_interval = NULL;
1467 }
1468 ripng->trigger = 0;
1469
1470 /* Reset flush event. */
1471 ripng_event (RIPNG_UPDATE_EVENT, 0);
1472
1473 return 0;
1474}
1475
1476/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001477static int
paul718e3742002-12-13 20:15:29 +00001478ripng_triggered_interval (struct thread *t)
1479{
1480 ripng->t_triggered_interval = NULL;
1481
1482 if (ripng->trigger)
1483 {
1484 ripng->trigger = 0;
1485 ripng_triggered_update (t);
1486 }
1487 return 0;
1488}
1489
1490/* Execute triggered update. */
1491int
1492ripng_triggered_update (struct thread *t)
1493{
hasso52dc7ee2004-09-23 19:18:23 +00001494 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001495 struct interface *ifp;
1496 struct ripng_interface *ri;
1497 int interval;
1498
1499 ripng->t_triggered_update = NULL;
1500
1501 /* Cancel interval timer. */
1502 if (ripng->t_triggered_interval)
1503 {
1504 thread_cancel (ripng->t_triggered_interval);
1505 ripng->t_triggered_interval = NULL;
1506 }
1507 ripng->trigger = 0;
1508
1509 /* Logging triggered update. */
1510 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001511 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001512
1513 /* Split Horizon processing is done when generating triggered
1514 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001515 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001516 {
paul718e3742002-12-13 20:15:29 +00001517 ri = ifp->info;
1518
1519 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1520 continue;
1521
1522 if (! ri->running)
1523 continue;
1524
1525 /* When passive interface is specified, suppress announce to the
1526 interface. */
1527 if (ri->passive)
1528 continue;
1529
hassoa94434b2003-05-25 17:10:12 +00001530 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001531 }
1532
1533 /* Once all of the triggered updates have been generated, the route
1534 change flags should be cleared. */
1535 ripng_clear_changed_flag ();
1536
1537 /* After a triggered update is sent, a timer should be set for a
1538 random interval between 1 and 5 seconds. If other changes that
1539 would trigger updates occur before the timer expires, a single
1540 update is triggered when the timer expires. */
1541 interval = (random () % 5) + 1;
1542
1543 ripng->t_triggered_interval =
1544 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1545
1546 return 0;
1547}
1548
1549/* Write routing table entry to the stream and return next index of
1550 the routing table entry in the stream. */
1551int
1552ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001553 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001554{
1555 /* RIPng packet header. */
1556 if (num == 0)
1557 {
1558 stream_putc (s, RIPNG_RESPONSE);
1559 stream_putc (s, RIPNG_V1);
1560 stream_putw (s, 0);
1561 }
1562
1563 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001564 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001565 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001566 else
hassoc9e52be2004-09-26 16:09:34 +00001567 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001568 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001569 if (p)
1570 stream_putc (s, p->prefixlen);
1571 else
1572 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001573 stream_putc (s, metric);
1574
1575 return ++num;
1576}
1577
1578/* Send RESPONSE message to specified destination. */
1579void
1580ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001581 int route_type)
paul718e3742002-12-13 20:15:29 +00001582{
1583 int ret;
paul718e3742002-12-13 20:15:29 +00001584 struct route_node *rp;
1585 struct ripng_info *rinfo;
1586 struct ripng_interface *ri;
1587 struct ripng_aggregate *aggregate;
1588 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001589 struct list * ripng_rte_list;
paul718e3742002-12-13 20:15:29 +00001590
hassoa94434b2003-05-25 17:10:12 +00001591 if (IS_RIPNG_DEBUG_EVENT) {
1592 if (to)
ajsc6106812004-12-08 19:51:16 +00001593 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001594 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001595 else
ajsc6106812004-12-08 19:51:16 +00001596 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001597 }
paul718e3742002-12-13 20:15:29 +00001598
paul718e3742002-12-13 20:15:29 +00001599 /* Get RIPng interface. */
1600 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001601
1602 ripng_rte_list = ripng_rte_new();
1603
paul718e3742002-12-13 20:15:29 +00001604 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1605 {
1606 if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
1607 {
hassoa94434b2003-05-25 17:10:12 +00001608 /* If no route-map are applied, the RTE will be these following
1609 * informations.
1610 */
paul718e3742002-12-13 20:15:29 +00001611 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001612 rinfo->metric_out = rinfo->metric;
1613 rinfo->tag_out = rinfo->tag;
1614 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1615 /* In order to avoid some local loops,
1616 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1617 * otherwise set it to 0. The nexthop should not be propagated
1618 * beyond the local broadcast/multicast area in order
1619 * to avoid an IGP multi-level recursive look-up.
1620 */
1621 if (rinfo->ifindex == ifp->ifindex)
1622 rinfo->nexthop_out = rinfo->nexthop;
1623
1624 /* Apply output filters. */
1625 ret = ripng_outgoing_filter (p, ri);
1626 if (ret < 0)
1627 continue;
paul718e3742002-12-13 20:15:29 +00001628
1629 /* Changed route only output. */
1630 if (route_type == ripng_changed_route &&
1631 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1632 continue;
1633
1634 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001635 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1636 {
1637 /* We perform split horizon for RIPng routes. */
1638 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1639 rinfo->ifindex == ifp->ifindex)
1640 continue;
1641 }
paul718e3742002-12-13 20:15:29 +00001642
1643 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001644 rinfo->metric_set = 0;
1645 /* nexthop_out,
1646 * metric_out
1647 * and tag_out are already initialized.
1648 */
paul718e3742002-12-13 20:15:29 +00001649
hassoa94434b2003-05-25 17:10:12 +00001650 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001651 if (ri->routemap[RIPNG_FILTER_OUT])
1652 {
1653 int ret;
paul718e3742002-12-13 20:15:29 +00001654
1655 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1656 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001657 rinfo);
paul718e3742002-12-13 20:15:29 +00001658
1659 if (ret == RMAP_DENYMATCH)
1660 {
1661 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001662 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001663 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001664 continue;
paul718e3742002-12-13 20:15:29 +00001665 }
1666
paul718e3742002-12-13 20:15:29 +00001667 }
1668
hassoa94434b2003-05-25 17:10:12 +00001669 /* Redistribute route-map. */
1670 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001671 {
hassoa94434b2003-05-25 17:10:12 +00001672 int ret;
1673
1674 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1675 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001676 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001677
1678 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001679 {
hassoa94434b2003-05-25 17:10:12 +00001680 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001681 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001682 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001683 continue;
paul718e3742002-12-13 20:15:29 +00001684 }
hassoa94434b2003-05-25 17:10:12 +00001685 }
paul718e3742002-12-13 20:15:29 +00001686
hassoa94434b2003-05-25 17:10:12 +00001687 /* When the route-map does not set metric. */
1688 if (! rinfo->metric_set)
1689 {
1690 /* If the redistribute metric is set. */
1691 if (ripng->route_map[rinfo->type].metric_config
1692 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001693 {
hassoa94434b2003-05-25 17:10:12 +00001694 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1695 }
1696 else
1697 {
1698 /* If the route is not connected or localy generated
1699 one, use default-metric value */
1700 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1701 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001702 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001703 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001704 }
1705 }
1706
hassoa94434b2003-05-25 17:10:12 +00001707 /* Apply offset-list */
1708 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1709 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001710
hassoa94434b2003-05-25 17:10:12 +00001711 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1712 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1713
1714 /* Perform split-horizon with poisoned reverse
1715 * for RIPng routes.
1716 **/
1717 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1718 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1719 rinfo->ifindex == ifp->ifindex)
1720 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1721 }
1722
1723 /* Add RTE to the list */
1724 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001725 }
hassoa94434b2003-05-25 17:10:12 +00001726
1727 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001728 if ((aggregate = rp->aggregate) != NULL &&
1729 aggregate->count > 0 &&
1730 aggregate->suppress == 0)
1731 {
hassoa94434b2003-05-25 17:10:12 +00001732 /* If no route-map are applied, the RTE will be these following
1733 * informations.
1734 */
paul718e3742002-12-13 20:15:29 +00001735 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001736 aggregate->metric_set = 0;
1737 aggregate->metric_out = aggregate->metric;
1738 aggregate->tag_out = aggregate->tag;
1739 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001740
1741 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001742 ret = ripng_outgoing_filter (p, ri);
1743 if (ret < 0)
1744 continue;
paul718e3742002-12-13 20:15:29 +00001745
hassoa94434b2003-05-25 17:10:12 +00001746 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001747 if (ri->routemap[RIPNG_FILTER_OUT])
1748 {
1749 int ret;
1750 struct ripng_info newinfo;
1751
hassoa94434b2003-05-25 17:10:12 +00001752 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001753 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001754 /* the nexthop is :: */
1755 newinfo.metric = aggregate->metric;
1756 newinfo.metric_out = aggregate->metric_out;
1757 newinfo.tag = aggregate->tag;
1758 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001759
1760 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1761 (struct prefix *) p, RMAP_RIPNG,
1762 &newinfo);
1763
1764 if (ret == RMAP_DENYMATCH)
1765 {
1766 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001767 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001768 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001769 continue;
paul718e3742002-12-13 20:15:29 +00001770 }
1771
hassoa94434b2003-05-25 17:10:12 +00001772 aggregate->metric_out = newinfo.metric_out;
1773 aggregate->tag_out = newinfo.tag_out;
1774 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1775 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001776 }
1777
hassoa94434b2003-05-25 17:10:12 +00001778 /* There is no redistribute routemap for the aggregated RTE */
1779
paul718e3742002-12-13 20:15:29 +00001780 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001781 /* XXX, vincent, in order to increase time convergence,
1782 * it should be announced if a child has changed.
1783 */
paul718e3742002-12-13 20:15:29 +00001784 if (route_type == ripng_changed_route)
1785 continue;
1786
hassoa94434b2003-05-25 17:10:12 +00001787 /* Apply offset-list */
1788 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1789 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001790
hassoa94434b2003-05-25 17:10:12 +00001791 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1792 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1793
1794 /* Add RTE to the list */
1795 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001796 }
1797
1798 }
paul718e3742002-12-13 20:15:29 +00001799
hassoa94434b2003-05-25 17:10:12 +00001800 /* Flush the list */
1801 ripng_rte_send(ripng_rte_list, ifp, to);
1802 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001803}
1804
1805/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001806static int
1807ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001808{
1809 /* ripng should be NULL. */
1810 assert (ripng == NULL);
1811
1812 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001813 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001814
1815 /* Default version and timer values. */
1816 ripng->version = RIPNG_V1;
1817 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1818 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1819 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1820 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1821
1822 /* Make buffer. */
1823 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1824 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1825
1826 /* Initialize RIPng routig table. */
1827 ripng->table = route_table_init ();
1828 ripng->route = route_table_init ();
1829 ripng->aggregate = route_table_init ();
1830
1831 /* Make socket. */
1832 ripng->sock = ripng_make_socket ();
1833 if (ripng->sock < 0)
1834 return ripng->sock;
1835
1836 /* Threads. */
1837 ripng_event (RIPNG_READ, ripng->sock);
1838 ripng_event (RIPNG_UPDATE_EVENT, 1);
1839
1840 return 0;
1841}
1842
hassoa94434b2003-05-25 17:10:12 +00001843/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001844int
1845ripng_request (struct interface *ifp)
1846{
1847 struct rte *rte;
1848 struct ripng_packet ripng_packet;
1849
hassoa94434b2003-05-25 17:10:12 +00001850 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1851 if (if_is_loopback(ifp))
1852 return 0;
1853
1854 /* If interface is down, don't send RIP packet. */
1855 if (! if_is_up (ifp))
1856 return 0;
1857
paul718e3742002-12-13 20:15:29 +00001858 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001859 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001860
1861 memset (&ripng_packet, 0, sizeof (ripng_packet));
1862 ripng_packet.command = RIPNG_REQUEST;
1863 ripng_packet.version = RIPNG_V1;
1864 rte = ripng_packet.rte;
1865 rte->metric = RIPNG_METRIC_INFINITY;
1866
1867 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1868 NULL, ifp);
1869}
1870
David Lamparter6b0655a2014-06-04 06:53:35 +02001871
Paul Jakma6ac29a52008-08-15 13:45:30 +01001872static int
paul718e3742002-12-13 20:15:29 +00001873ripng_update_jitter (int time)
1874{
1875 return ((rand () % (time + 1)) - (time / 2));
1876}
1877
1878void
1879ripng_event (enum ripng_event event, int sock)
1880{
paul718e3742002-12-13 20:15:29 +00001881 int jitter = 0;
1882
1883 switch (event)
1884 {
1885 case RIPNG_READ:
1886 if (!ripng->t_read)
1887 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1888 break;
1889 case RIPNG_UPDATE_EVENT:
1890 if (ripng->t_update)
1891 {
1892 thread_cancel (ripng->t_update);
1893 ripng->t_update = NULL;
1894 }
1895 /* Update timer jitter. */
1896 jitter = ripng_update_jitter (ripng->update_time);
1897
1898 ripng->t_update =
1899 thread_add_timer (master, ripng_update, NULL,
1900 sock ? 2 : ripng->update_time + jitter);
1901 break;
1902 case RIPNG_TRIGGERED_UPDATE:
1903 if (ripng->t_triggered_interval)
1904 ripng->trigger = 1;
1905 else if (! ripng->t_triggered_update)
1906 ripng->t_triggered_update =
1907 thread_add_event (master, ripng_triggered_update, NULL, 0);
1908 break;
1909 default:
1910 break;
1911 }
1912}
David Lamparter6b0655a2014-06-04 06:53:35 +02001913
paul718e3742002-12-13 20:15:29 +00001914
paul718e3742002-12-13 20:15:29 +00001915/* Print out routes update time. */
1916static void
1917ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1918{
paul718e3742002-12-13 20:15:29 +00001919 time_t clock;
1920 struct tm *tm;
1921#define TIME_BUF 25
1922 char timebuf [TIME_BUF];
1923 struct thread *thread;
1924
paul718e3742002-12-13 20:15:29 +00001925 if ((thread = rinfo->t_timeout) != NULL)
1926 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001927 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001928 tm = gmtime (&clock);
1929 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1930 vty_out (vty, "%5s", timebuf);
1931 }
1932 else if ((thread = rinfo->t_garbage_collect) != NULL)
1933 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001934 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001935 tm = gmtime (&clock);
1936 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1937 vty_out (vty, "%5s", timebuf);
1938 }
1939}
1940
Paul Jakma6ac29a52008-08-15 13:45:30 +01001941static char *
hassoa94434b2003-05-25 17:10:12 +00001942ripng_route_subtype_print (struct ripng_info *rinfo)
1943{
1944 static char str[3];
1945 memset(str, 0, 3);
1946
1947 if (rinfo->suppress)
1948 strcat(str, "S");
1949
1950 switch (rinfo->sub_type)
1951 {
1952 case RIPNG_ROUTE_RTE:
1953 strcat(str, "n");
1954 break;
1955 case RIPNG_ROUTE_STATIC:
1956 strcat(str, "s");
1957 break;
1958 case RIPNG_ROUTE_DEFAULT:
1959 strcat(str, "d");
1960 break;
1961 case RIPNG_ROUTE_REDISTRIBUTE:
1962 strcat(str, "r");
1963 break;
1964 case RIPNG_ROUTE_INTERFACE:
1965 strcat(str, "i");
1966 break;
1967 default:
1968 strcat(str, "?");
1969 break;
1970 }
1971
1972 return str;
1973}
1974
paul718e3742002-12-13 20:15:29 +00001975DEFUN (show_ipv6_ripng,
1976 show_ipv6_ripng_cmd,
1977 "show ipv6 ripng",
1978 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001979 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001980 "Show RIPng routes\n")
1981{
1982 struct route_node *rp;
1983 struct ripng_info *rinfo;
1984 struct ripng_aggregate *aggregate;
1985 struct prefix_ipv6 *p;
1986 int len;
1987
hassoa94434b2003-05-25 17:10:12 +00001988 if (! ripng)
1989 return CMD_SUCCESS;
1990
paul718e3742002-12-13 20:15:29 +00001991 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00001992 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
1993 "Sub-codes:%s"
1994 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
1995 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
1996 " Network Next Hop Via Metric Tag Time%s",
1997 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00001998 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1999
2000 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2001 {
2002 if ((aggregate = rp->aggregate) != NULL)
2003 {
2004 p = (struct prefix_ipv6 *) &rp->p;
2005
2006#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002007 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002008 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002009 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002010#else
hassoa94434b2003-05-25 17:10:12 +00002011 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002012 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002013#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002014 vty_out (vty, "%s", VTY_NEWLINE);
2015 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002016
hassoa94434b2003-05-25 17:10:12 +00002017 vty_out (vty, "%*s", 28, " ");
2018 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002019 aggregate->tag,
2020 VTY_NEWLINE);
2021 }
2022
2023 if ((rinfo = rp->info) != NULL)
2024 {
2025 p = (struct prefix_ipv6 *) &rp->p;
2026
2027#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002028 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2029 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002030 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002031 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002032 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002033#else
ajsf52d13c2005-10-01 17:38:06 +00002034 len = vty_out (vty, "%c(%s) %s/%d ",
2035 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002036 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002037 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002038#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002039 vty_out (vty, "%s", VTY_NEWLINE);
2040 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002041 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002042
hassoa94434b2003-05-25 17:10:12 +00002043 len = 28 - len;
2044 if (len > 0)
2045 len = vty_out (vty, "%*s", len, " ");
2046
2047 /* from */
2048 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2049 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2050 {
2051 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2052 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2053 {
2054 len = vty_out (vty, "kill");
2055 } else
2056 len = vty_out (vty, "self");
2057
2058 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002059 if (len > 0)
2060 vty_out (vty, "%*s", len, " ");
2061
hassoa94434b2003-05-25 17:10:12 +00002062 vty_out (vty, " %2d %3d ",
2063 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002064
hassoa94434b2003-05-25 17:10:12 +00002065 /* time */
2066 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2067 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2068 {
2069 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002070 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002071 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2072 {
2073 /* poisonous reversed routes (gc) */
2074 ripng_vty_out_uptime (vty, rinfo);
2075 }
paul718e3742002-12-13 20:15:29 +00002076
2077 vty_out (vty, "%s", VTY_NEWLINE);
2078 }
2079 }
2080
2081 return CMD_SUCCESS;
2082}
2083
hassoa94434b2003-05-25 17:10:12 +00002084DEFUN (show_ipv6_ripng_status,
2085 show_ipv6_ripng_status_cmd,
2086 "show ipv6 ripng status",
2087 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002088 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002089 "Show RIPng routes\n"
2090 "IPv6 routing protocol process parameters and statistics\n")
2091{
hasso52dc7ee2004-09-23 19:18:23 +00002092 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002093 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002094
2095 if (! ripng)
2096 return CMD_SUCCESS;
2097
2098 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2099 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2100 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002101 vty_out (vty, " next due in %lu seconds%s",
2102 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002103 VTY_NEWLINE);
2104 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2105 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2106 VTY_NEWLINE);
2107
2108 /* Filtering status show. */
2109 config_show_distribute (vty);
2110
2111 /* Default metric information. */
2112 vty_out (vty, " Default redistribution metric is %d%s",
2113 ripng->default_metric, VTY_NEWLINE);
2114
2115 /* Redistribute information. */
2116 vty_out (vty, " Redistributing:");
2117 ripng_redistribute_write (vty, 0);
2118 vty_out (vty, "%s", VTY_NEWLINE);
2119
2120 vty_out (vty, " Default version control: send version %d,", ripng->version);
2121 vty_out (vty, " receive version %d %s", ripng->version,
2122 VTY_NEWLINE);
2123
2124 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2125
paul1eb8ef22005-04-07 07:30:20 +00002126 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002127 {
2128 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002129
hassoa94434b2003-05-25 17:10:12 +00002130 ri = ifp->info;
2131
2132 if (ri->enable_network || ri->enable_interface)
2133 {
2134
2135 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2136 ripng->version,
2137 ripng->version,
2138 VTY_NEWLINE);
2139 }
2140 }
2141
2142 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2143 ripng_network_write (vty, 0);
2144
2145 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2146 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2147 ripng_peer_display (vty);
2148
2149 return CMD_SUCCESS;
2150}
2151
paul718e3742002-12-13 20:15:29 +00002152DEFUN (router_ripng,
2153 router_ripng_cmd,
2154 "router ripng",
2155 "Enable a routing process\n"
2156 "Make RIPng instance command\n")
2157{
2158 int ret;
2159
2160 vty->node = RIPNG_NODE;
2161
2162 if (!ripng)
2163 {
2164 ret = ripng_create ();
2165
2166 /* Notice to user we couldn't create RIPng. */
2167 if (ret < 0)
2168 {
2169 zlog_warn ("can't create RIPng");
2170 return CMD_WARNING;
2171 }
2172 }
2173
2174 return CMD_SUCCESS;
2175}
2176
hassoa94434b2003-05-25 17:10:12 +00002177DEFUN (no_router_ripng,
2178 no_router_ripng_cmd,
2179 "no router ripng",
2180 NO_STR
2181 "Enable a routing process\n"
2182 "Make RIPng instance command\n")
2183{
2184 if(ripng)
2185 ripng_clean();
2186 return CMD_SUCCESS;
2187}
2188
paul718e3742002-12-13 20:15:29 +00002189DEFUN (ripng_route,
2190 ripng_route_cmd,
2191 "route IPV6ADDR",
2192 "Static route setup\n"
2193 "Set static RIPng route announcement\n")
2194{
2195 int ret;
2196 struct prefix_ipv6 p;
2197 struct route_node *rp;
2198
2199 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2200 if (ret <= 0)
2201 {
2202 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2203 return CMD_WARNING;
2204 }
2205 apply_mask_ipv6 (&p);
2206
2207 rp = route_node_get (ripng->route, (struct prefix *) &p);
2208 if (rp->info)
2209 {
2210 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2211 route_unlock_node (rp);
2212 return CMD_WARNING;
2213 }
2214 rp->info = (void *)1;
2215
hassoa94434b2003-05-25 17:10:12 +00002216 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002217
2218 return CMD_SUCCESS;
2219}
2220
2221DEFUN (no_ripng_route,
2222 no_ripng_route_cmd,
2223 "no route IPV6ADDR",
2224 NO_STR
2225 "Static route setup\n"
2226 "Delete static RIPng route announcement\n")
2227{
2228 int ret;
2229 struct prefix_ipv6 p;
2230 struct route_node *rp;
2231
2232 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2233 if (ret <= 0)
2234 {
2235 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2236 return CMD_WARNING;
2237 }
2238 apply_mask_ipv6 (&p);
2239
2240 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2241 if (! rp)
2242 {
2243 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2244 return CMD_WARNING;
2245 }
2246
2247 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2248 route_unlock_node (rp);
2249
2250 rp->info = NULL;
2251 route_unlock_node (rp);
2252
2253 return CMD_SUCCESS;
2254}
2255
2256DEFUN (ripng_aggregate_address,
2257 ripng_aggregate_address_cmd,
2258 "aggregate-address X:X::X:X/M",
2259 "Set aggregate RIPng route announcement\n"
2260 "Aggregate network\n")
2261{
2262 int ret;
2263 struct prefix p;
2264 struct route_node *node;
2265
2266 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2267 if (ret <= 0)
2268 {
2269 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2270 return CMD_WARNING;
2271 }
2272
2273 /* Check aggregate alredy exist or not. */
2274 node = route_node_get (ripng->aggregate, &p);
2275 if (node->info)
2276 {
2277 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2278 route_unlock_node (node);
2279 return CMD_WARNING;
2280 }
2281 node->info = (void *)1;
2282
2283 ripng_aggregate_add (&p);
2284
2285 return CMD_SUCCESS;
2286}
2287
2288DEFUN (no_ripng_aggregate_address,
2289 no_ripng_aggregate_address_cmd,
2290 "no aggregate-address X:X::X:X/M",
2291 NO_STR
2292 "Delete aggregate RIPng route announcement\n"
2293 "Aggregate network")
2294{
2295 int ret;
2296 struct prefix p;
2297 struct route_node *rn;
2298
2299 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2300 if (ret <= 0)
2301 {
2302 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2303 return CMD_WARNING;
2304 }
2305
2306 rn = route_node_lookup (ripng->aggregate, &p);
2307 if (! rn)
2308 {
2309 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2310 return CMD_WARNING;
2311 }
2312 route_unlock_node (rn);
2313 rn->info = NULL;
2314 route_unlock_node (rn);
2315
2316 ripng_aggregate_delete (&p);
2317
2318 return CMD_SUCCESS;
2319}
2320
2321DEFUN (ripng_default_metric,
2322 ripng_default_metric_cmd,
2323 "default-metric <1-16>",
2324 "Set a metric of redistribute routes\n"
2325 "Default metric\n")
2326{
2327 if (ripng)
2328 {
2329 ripng->default_metric = atoi (argv[0]);
2330 }
2331 return CMD_SUCCESS;
2332}
2333
2334DEFUN (no_ripng_default_metric,
2335 no_ripng_default_metric_cmd,
2336 "no default-metric",
2337 NO_STR
2338 "Set a metric of redistribute routes\n"
2339 "Default metric\n")
2340{
2341 if (ripng)
2342 {
2343 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2344 }
2345 return CMD_SUCCESS;
2346}
2347
2348ALIAS (no_ripng_default_metric,
2349 no_ripng_default_metric_val_cmd,
2350 "no default-metric <1-16>",
2351 NO_STR
2352 "Set a metric of redistribute routes\n"
2353 "Default metric\n")
2354
2355#if 0
2356/* RIPng update timer setup. */
2357DEFUN (ripng_update_timer,
2358 ripng_update_timer_cmd,
2359 "update-timer SECOND",
2360 "Set RIPng update timer in seconds\n"
2361 "Seconds\n")
2362{
2363 unsigned long update;
2364 char *endptr = NULL;
2365
2366 update = strtoul (argv[0], &endptr, 10);
2367 if (update == ULONG_MAX || *endptr != '\0')
2368 {
2369 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2370 return CMD_WARNING;
2371 }
2372
2373 ripng->update_time = update;
2374
2375 ripng_event (RIPNG_UPDATE_EVENT, 0);
2376 return CMD_SUCCESS;
2377}
2378
2379DEFUN (no_ripng_update_timer,
2380 no_ripng_update_timer_cmd,
2381 "no update-timer SECOND",
2382 NO_STR
2383 "Unset RIPng update timer in seconds\n"
2384 "Seconds\n")
2385{
2386 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2387 ripng_event (RIPNG_UPDATE_EVENT, 0);
2388 return CMD_SUCCESS;
2389}
2390
2391/* RIPng timeout timer setup. */
2392DEFUN (ripng_timeout_timer,
2393 ripng_timeout_timer_cmd,
2394 "timeout-timer SECOND",
2395 "Set RIPng timeout timer in seconds\n"
2396 "Seconds\n")
2397{
2398 unsigned long timeout;
2399 char *endptr = NULL;
2400
2401 timeout = strtoul (argv[0], &endptr, 10);
2402 if (timeout == ULONG_MAX || *endptr != '\0')
2403 {
2404 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2405 return CMD_WARNING;
2406 }
2407
2408 ripng->timeout_time = timeout;
2409
2410 return CMD_SUCCESS;
2411}
2412
2413DEFUN (no_ripng_timeout_timer,
2414 no_ripng_timeout_timer_cmd,
2415 "no timeout-timer SECOND",
2416 NO_STR
2417 "Unset RIPng timeout timer in seconds\n"
2418 "Seconds\n")
2419{
2420 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2421 return CMD_SUCCESS;
2422}
2423
2424/* RIPng garbage timer setup. */
2425DEFUN (ripng_garbage_timer,
2426 ripng_garbage_timer_cmd,
2427 "garbage-timer SECOND",
2428 "Set RIPng garbage timer in seconds\n"
2429 "Seconds\n")
2430{
2431 unsigned long garbage;
2432 char *endptr = NULL;
2433
2434 garbage = strtoul (argv[0], &endptr, 10);
2435 if (garbage == ULONG_MAX || *endptr != '\0')
2436 {
2437 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2438 return CMD_WARNING;
2439 }
2440
2441 ripng->garbage_time = garbage;
2442
2443 return CMD_SUCCESS;
2444}
2445
2446DEFUN (no_ripng_garbage_timer,
2447 no_ripng_garbage_timer_cmd,
2448 "no garbage-timer SECOND",
2449 NO_STR
2450 "Unset RIPng garbage timer in seconds\n"
2451 "Seconds\n")
2452{
2453 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2454 return CMD_SUCCESS;
2455}
2456#endif /* 0 */
2457
2458DEFUN (ripng_timers,
2459 ripng_timers_cmd,
2460 "timers basic <0-65535> <0-65535> <0-65535>",
2461 "RIPng timers setup\n"
2462 "Basic timer\n"
2463 "Routing table update timer value in second. Default is 30.\n"
2464 "Routing information timeout timer. Default is 180.\n"
2465 "Garbage collection timer. Default is 120.\n")
2466{
2467 unsigned long update;
2468 unsigned long timeout;
2469 unsigned long garbage;
paul718e3742002-12-13 20:15:29 +00002470
Ulrich Weber69898802011-11-17 21:35:08 +04002471 VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2472 VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2473 VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
paul718e3742002-12-13 20:15:29 +00002474
2475 /* Set each timer value. */
2476 ripng->update_time = update;
2477 ripng->timeout_time = timeout;
2478 ripng->garbage_time = garbage;
2479
2480 /* Reset update timer thread. */
2481 ripng_event (RIPNG_UPDATE_EVENT, 0);
2482
2483 return CMD_SUCCESS;
2484}
2485
2486DEFUN (no_ripng_timers,
2487 no_ripng_timers_cmd,
2488 "no timers basic",
2489 NO_STR
2490 "RIPng timers setup\n"
2491 "Basic timer\n")
2492{
2493 /* Set each timer value to the default. */
2494 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2495 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2496 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2497
2498 /* Reset update timer thread. */
2499 ripng_event (RIPNG_UPDATE_EVENT, 0);
2500
2501 return CMD_SUCCESS;
2502}
2503
hassoa94434b2003-05-25 17:10:12 +00002504ALIAS (no_ripng_timers,
2505 no_ripng_timers_val_cmd,
2506 "no timers basic <0-65535> <0-65535> <0-65535>",
2507 NO_STR
2508 "RIPng timers setup\n"
2509 "Basic timer\n"
2510 "Routing table update timer value in second. Default is 30.\n"
2511 "Routing information timeout timer. Default is 180.\n"
2512 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002513
2514DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2515 "show ipv6 protocols",
2516 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002517 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002518 "Routing protocol information")
2519{
2520 if (! ripng)
2521 return CMD_SUCCESS;
2522
2523 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2524
2525 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2526 ripng->update_time, 0,
2527 VTY_NEWLINE);
2528
2529 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2530 ripng->timeout_time,
2531 ripng->garbage_time,
2532 VTY_NEWLINE);
2533
2534 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2535 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2536
2537 return CMD_SUCCESS;
2538}
2539
2540/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002541DEFUN (ripng_default_information_originate,
2542 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002543 "default-information originate",
2544 "Default route information\n"
2545 "Distribute default route\n")
2546{
2547 struct prefix_ipv6 p;
2548
hassoa94434b2003-05-25 17:10:12 +00002549 if (! ripng ->default_information) {
2550 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002551
hassoa94434b2003-05-25 17:10:12 +00002552 str2prefix_ipv6 ("::/0", &p);
2553 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2554 }
paul718e3742002-12-13 20:15:29 +00002555
2556 return CMD_SUCCESS;
2557}
2558
paula2c62832003-04-23 17:01:31 +00002559DEFUN (no_ripng_default_information_originate,
2560 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002561 "no default-information originate",
2562 NO_STR
2563 "Default route information\n"
2564 "Distribute default route\n")
2565{
2566 struct prefix_ipv6 p;
2567
hassoa94434b2003-05-25 17:10:12 +00002568 if (ripng->default_information) {
2569 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002570
hassoa94434b2003-05-25 17:10:12 +00002571 str2prefix_ipv6 ("::/0", &p);
2572 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2573 }
paul718e3742002-12-13 20:15:29 +00002574
2575 return CMD_SUCCESS;
2576}
2577
2578/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002579static int
paul718e3742002-12-13 20:15:29 +00002580ripng_config_write (struct vty *vty)
2581{
hassoa94434b2003-05-25 17:10:12 +00002582 int ripng_network_write (struct vty *, int);
2583 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002584 int write = 0;
2585 struct route_node *rp;
2586
2587 if (ripng)
2588 {
2589
2590 /* RIPng router. */
2591 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2592
2593 if (ripng->default_information)
2594 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2595
hassoa94434b2003-05-25 17:10:12 +00002596 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002597
2598 /* RIPng default metric configuration */
2599 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2600 vty_out (vty, " default-metric %d%s",
2601 ripng->default_metric, VTY_NEWLINE);
2602
hassoa94434b2003-05-25 17:10:12 +00002603 ripng_redistribute_write (vty, 1);
2604
2605 /* RIP offset-list configuration. */
2606 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002607
2608 /* RIPng aggregate routes. */
2609 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2610 if (rp->info != NULL)
2611 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002612 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002613 rp->p.prefixlen,
2614
2615 VTY_NEWLINE);
2616
2617 /* RIPng static routes. */
2618 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2619 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002620 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002621 rp->p.prefixlen,
2622 VTY_NEWLINE);
2623
2624 /* RIPng timers configuration. */
2625 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2626 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2627 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2628 {
2629 vty_out (vty, " timers basic %ld %ld %ld%s",
2630 ripng->update_time,
2631 ripng->timeout_time,
2632 ripng->garbage_time,
2633 VTY_NEWLINE);
2634 }
2635#if 0
2636 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2637 vty_out (vty, " update-timer %d%s", ripng->update_time,
2638 VTY_NEWLINE);
2639 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2640 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2641 VTY_NEWLINE);
2642 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2643 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2644 VTY_NEWLINE);
2645#endif /* 0 */
2646
2647 write += config_write_distribute (vty);
2648
2649 write += config_write_if_rmap (vty);
2650
2651 write++;
2652 }
2653 return write;
2654}
2655
2656/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002657static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002658{
2659 RIPNG_NODE,
2660 "%s(config-router)# ",
2661 1,
2662};
2663
Paul Jakma6ac29a52008-08-15 13:45:30 +01002664static void
paul718e3742002-12-13 20:15:29 +00002665ripng_distribute_update (struct distribute *dist)
2666{
2667 struct interface *ifp;
2668 struct ripng_interface *ri;
2669 struct access_list *alist;
2670 struct prefix_list *plist;
2671
2672 if (! dist->ifname)
2673 return;
2674
2675 ifp = if_lookup_by_name (dist->ifname);
2676 if (ifp == NULL)
2677 return;
2678
2679 ri = ifp->info;
2680
2681 if (dist->list[DISTRIBUTE_IN])
2682 {
2683 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2684 if (alist)
2685 ri->list[RIPNG_FILTER_IN] = alist;
2686 else
2687 ri->list[RIPNG_FILTER_IN] = NULL;
2688 }
2689 else
2690 ri->list[RIPNG_FILTER_IN] = NULL;
2691
2692 if (dist->list[DISTRIBUTE_OUT])
2693 {
2694 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2695 if (alist)
2696 ri->list[RIPNG_FILTER_OUT] = alist;
2697 else
2698 ri->list[RIPNG_FILTER_OUT] = NULL;
2699 }
2700 else
2701 ri->list[RIPNG_FILTER_OUT] = NULL;
2702
2703 if (dist->prefix[DISTRIBUTE_IN])
2704 {
2705 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2706 if (plist)
2707 ri->prefix[RIPNG_FILTER_IN] = plist;
2708 else
2709 ri->prefix[RIPNG_FILTER_IN] = NULL;
2710 }
2711 else
2712 ri->prefix[RIPNG_FILTER_IN] = NULL;
2713
2714 if (dist->prefix[DISTRIBUTE_OUT])
2715 {
2716 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2717 if (plist)
2718 ri->prefix[RIPNG_FILTER_OUT] = plist;
2719 else
2720 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2721 }
2722 else
2723 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2724}
hassoa94434b2003-05-25 17:10:12 +00002725
paul718e3742002-12-13 20:15:29 +00002726void
2727ripng_distribute_update_interface (struct interface *ifp)
2728{
2729 struct distribute *dist;
2730
2731 dist = distribute_lookup (ifp->name);
2732 if (dist)
2733 ripng_distribute_update (dist);
2734}
2735
2736/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002737static void
hassoc9e52be2004-09-26 16:09:34 +00002738ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002739{
2740 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002741 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002742
paul1eb8ef22005-04-07 07:30:20 +00002743 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2744 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002745}
hassoc9e52be2004-09-26 16:09:34 +00002746
Paul Jakma6ac29a52008-08-15 13:45:30 +01002747static void
hassoc9e52be2004-09-26 16:09:34 +00002748ripng_distribute_update_all_wrapper (struct access_list *notused)
2749{
2750 ripng_distribute_update_all(NULL);
2751}
David Lamparter6b0655a2014-06-04 06:53:35 +02002752
hassoa94434b2003-05-25 17:10:12 +00002753/* delete all the added ripng routes. */
2754void
2755ripng_clean()
2756{
2757 int i;
2758 struct route_node *rp;
2759 struct ripng_info *rinfo;
2760
2761 if (ripng) {
2762 /* Clear RIPng routes */
2763 for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
2764 if ((rinfo = rp->info) != NULL) {
2765 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2766 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2767 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
2768 &rinfo->nexthop, rinfo->metric);
2769
2770 RIPNG_TIMER_OFF (rinfo->t_timeout);
2771 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2772
2773 rp->info = NULL;
2774 route_unlock_node (rp);
2775
2776 ripng_info_free(rinfo);
2777 }
2778 }
2779
2780 /* Cancel the RIPng timers */
2781 RIPNG_TIMER_OFF (ripng->t_update);
2782 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2783 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2784
2785 /* Cancel the read thread */
2786 if (ripng->t_read) {
2787 thread_cancel (ripng->t_read);
2788 ripng->t_read = NULL;
2789 }
2790
2791 /* Close the RIPng socket */
2792 if (ripng->sock >= 0) {
2793 close(ripng->sock);
2794 ripng->sock = -1;
2795 }
2796
2797 /* Static RIPng route configuration. */
2798 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2799 if (rp->info) {
2800 rp->info = NULL;
2801 route_unlock_node (rp);
2802 }
2803
2804 /* RIPng aggregated prefixes */
2805 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2806 if (rp->info) {
2807 rp->info = NULL;
2808 route_unlock_node (rp);
2809 }
2810
2811 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2812 if (ripng->route_map[i].name)
2813 free (ripng->route_map[i].name);
2814
2815 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2816 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2817 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2818
2819 XFREE (MTYPE_RIPNG, ripng);
2820 ripng = NULL;
2821 } /* if (ripng) */
2822
2823 ripng_clean_network();
2824 ripng_passive_interface_clean ();
2825 ripng_offset_clean ();
2826 ripng_interface_clean ();
2827 ripng_redistribute_clean ();
2828}
2829
2830/* Reset all values to the default settings. */
2831void
2832ripng_reset ()
2833{
2834 /* Call ripd related reset functions. */
2835 ripng_debug_reset ();
2836 ripng_route_map_reset ();
2837
2838 /* Call library reset functions. */
2839 vty_reset ();
2840 access_list_reset ();
2841 prefix_list_reset ();
2842
2843 distribute_list_reset ();
2844
2845 ripng_interface_reset ();
2846
2847 ripng_zclient_reset ();
2848}
paul718e3742002-12-13 20:15:29 +00002849
Paul Jakma6ac29a52008-08-15 13:45:30 +01002850static void
paul718e3742002-12-13 20:15:29 +00002851ripng_if_rmap_update (struct if_rmap *if_rmap)
2852{
2853 struct interface *ifp;
2854 struct ripng_interface *ri;
2855 struct route_map *rmap;
2856
2857 ifp = if_lookup_by_name (if_rmap->ifname);
2858 if (ifp == NULL)
2859 return;
2860
2861 ri = ifp->info;
2862
2863 if (if_rmap->routemap[IF_RMAP_IN])
2864 {
2865 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2866 if (rmap)
2867 ri->routemap[IF_RMAP_IN] = rmap;
2868 else
2869 ri->routemap[IF_RMAP_IN] = NULL;
2870 }
2871 else
2872 ri->routemap[RIPNG_FILTER_IN] = NULL;
2873
2874 if (if_rmap->routemap[IF_RMAP_OUT])
2875 {
2876 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2877 if (rmap)
2878 ri->routemap[IF_RMAP_OUT] = rmap;
2879 else
2880 ri->routemap[IF_RMAP_OUT] = NULL;
2881 }
2882 else
2883 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2884}
2885
2886void
2887ripng_if_rmap_update_interface (struct interface *ifp)
2888{
2889 struct if_rmap *if_rmap;
2890
2891 if_rmap = if_rmap_lookup (ifp->name);
2892 if (if_rmap)
2893 ripng_if_rmap_update (if_rmap);
2894}
2895
Paul Jakma6ac29a52008-08-15 13:45:30 +01002896static void
paul718e3742002-12-13 20:15:29 +00002897ripng_routemap_update_redistribute (void)
2898{
2899 int i;
2900
2901 if (ripng)
2902 {
2903 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2904 {
2905 if (ripng->route_map[i].name)
2906 ripng->route_map[i].map =
2907 route_map_lookup_by_name (ripng->route_map[i].name);
2908 }
2909 }
2910}
2911
Paul Jakma6ac29a52008-08-15 13:45:30 +01002912static void
hasso98b718a2004-10-11 12:57:57 +00002913ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00002914{
2915 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002916 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002917
paul1eb8ef22005-04-07 07:30:20 +00002918 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2919 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002920
2921 ripng_routemap_update_redistribute ();
2922}
2923
2924/* Initialize ripng structure and set commands. */
2925void
2926ripng_init ()
2927{
2928 /* Randomize. */
2929 srand (time (NULL));
2930
2931 /* Install RIPNG_NODE. */
2932 install_node (&cmd_ripng_node, ripng_config_write);
2933
2934 /* Install ripng commands. */
2935 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002936 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002937
2938 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002939 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002940
2941 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002942 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00002943
2944 install_default (RIPNG_NODE);
2945 install_element (RIPNG_NODE, &ripng_route_cmd);
2946 install_element (RIPNG_NODE, &no_ripng_route_cmd);
2947 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
2948 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
2949
2950 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
2951 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
2952 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
2953
2954 install_element (RIPNG_NODE, &ripng_timers_cmd);
2955 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00002956 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00002957#if 0
2958 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2959 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2960 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2961 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2962 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2963 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2964#endif /* 0 */
2965
paula2c62832003-04-23 17:01:31 +00002966 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
2967 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00002968
2969 ripng_if_init ();
2970 ripng_debug_init ();
2971
2972 /* Access list install. */
2973 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00002974 access_list_add_hook (ripng_distribute_update_all_wrapper);
2975 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00002976
2977 /* Prefix list initialize.*/
2978 prefix_list_init ();
2979 prefix_list_add_hook (ripng_distribute_update_all);
2980 prefix_list_delete_hook (ripng_distribute_update_all);
2981
2982 /* Distribute list install. */
2983 distribute_list_init (RIPNG_NODE);
2984 distribute_list_add_hook (ripng_distribute_update);
2985 distribute_list_delete_hook (ripng_distribute_update);
2986
2987 /* Route-map for interface. */
2988 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00002989 ripng_offset_init ();
2990
paul718e3742002-12-13 20:15:29 +00002991 route_map_add_hook (ripng_routemap_update);
2992 route_map_delete_hook (ripng_routemap_update);
2993
hasso0750d212003-05-24 21:41:49 +00002994 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00002995 if_rmap_hook_add (ripng_if_rmap_update);
2996 if_rmap_hook_delete (ripng_if_rmap_update);
2997}