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