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