Annotation of embedaddon/quagga/ripngd/ripng_interface.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Interface related function for RIPng.
! 3: * Copyright (C) 1998 Kunihiro Ishiguro
! 4: *
! 5: * This file is part of GNU Zebra.
! 6: *
! 7: * GNU Zebra is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2, or (at your option) any
! 10: * later version.
! 11: *
! 12: * GNU Zebra is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 15: * General Public License for more details.
! 16: *
! 17: * You should have received a copy of the GNU General Public License
! 18: * along with GNU Zebra; see the file COPYING. If not, write to the Free
! 19: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 20: * 02111-1307, USA.
! 21: */
! 22:
! 23: #include <zebra.h>
! 24:
! 25: #include "linklist.h"
! 26: #include "if.h"
! 27: #include "prefix.h"
! 28: #include "memory.h"
! 29: #include "network.h"
! 30: #include "filter.h"
! 31: #include "log.h"
! 32: #include "stream.h"
! 33: #include "zclient.h"
! 34: #include "command.h"
! 35: #include "table.h"
! 36: #include "thread.h"
! 37: #include "privs.h"
! 38:
! 39: #include "ripngd/ripngd.h"
! 40: #include "ripngd/ripng_debug.h"
! 41:
! 42: /* If RFC2133 definition is used. */
! 43: #ifndef IPV6_JOIN_GROUP
! 44: #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
! 45: #endif
! 46: #ifndef IPV6_LEAVE_GROUP
! 47: #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
! 48: #endif
! 49:
! 50: extern struct zebra_privs_t ripngd_privs;
! 51:
! 52: /* Static utility function. */
! 53: static void ripng_enable_apply (struct interface *);
! 54: static void ripng_passive_interface_apply (struct interface *);
! 55: static int ripng_enable_if_lookup (const char *);
! 56: static int ripng_enable_network_lookup2 (struct connected *);
! 57: static void ripng_enable_apply_all (void);
! 58:
! 59: /* Join to the all rip routers multicast group. */
! 60: static int
! 61: ripng_multicast_join (struct interface *ifp)
! 62: {
! 63: int ret;
! 64: struct ipv6_mreq mreq;
! 65: int save_errno;
! 66:
! 67: if (if_is_up (ifp) && if_is_multicast (ifp)) {
! 68: memset (&mreq, 0, sizeof (mreq));
! 69: inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
! 70: mreq.ipv6mr_interface = ifp->ifindex;
! 71:
! 72: /*
! 73: * NetBSD 1.6.2 requires root to join groups on gif(4).
! 74: * While this is bogus, privs are available and easy to use
! 75: * for this call as a workaround.
! 76: */
! 77: if (ripngd_privs.change (ZPRIVS_RAISE))
! 78: zlog_err ("ripng_multicast_join: could not raise privs");
! 79:
! 80: ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
! 81: (char *) &mreq, sizeof (mreq));
! 82: save_errno = errno;
! 83:
! 84: if (ripngd_privs.change (ZPRIVS_LOWER))
! 85: zlog_err ("ripng_multicast_join: could not lower privs");
! 86:
! 87: if (ret < 0 && save_errno == EADDRINUSE)
! 88: {
! 89: /*
! 90: * Group is already joined. This occurs due to sloppy group
! 91: * management, in particular declining to leave the group on
! 92: * an interface that has just gone down.
! 93: */
! 94: zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name);
! 95: return 0; /* not an error */
! 96: }
! 97:
! 98: if (ret < 0)
! 99: zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s",
! 100: safe_strerror (save_errno));
! 101:
! 102: if (IS_RIPNG_DEBUG_EVENT)
! 103: zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name);
! 104:
! 105: if (ret < 0)
! 106: return -1;
! 107: }
! 108: return 0;
! 109: }
! 110:
! 111: /* Leave from the all rip routers multicast group. */
! 112: static int
! 113: ripng_multicast_leave (struct interface *ifp)
! 114: {
! 115: int ret;
! 116: struct ipv6_mreq mreq;
! 117:
! 118: if (if_is_up (ifp) && if_is_multicast (ifp)) {
! 119: memset (&mreq, 0, sizeof (mreq));
! 120: inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
! 121: mreq.ipv6mr_interface = ifp->ifindex;
! 122:
! 123: ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
! 124: (char *) &mreq, sizeof (mreq));
! 125: if (ret < 0)
! 126: zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno));
! 127:
! 128: if (IS_RIPNG_DEBUG_EVENT)
! 129: zlog_debug ("RIPng %s leave from all-rip-routers multicast group",
! 130: ifp->name);
! 131:
! 132: if (ret < 0)
! 133: return -1;
! 134: }
! 135:
! 136: return 0;
! 137: }
! 138:
! 139: /* How many link local IPv6 address could be used on the interface ? */
! 140: static int
! 141: ripng_if_ipv6_lladdress_check (struct interface *ifp)
! 142: {
! 143: struct listnode *nn;
! 144: struct connected *connected;
! 145: int count = 0;
! 146:
! 147: for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected))
! 148: {
! 149: struct prefix *p;
! 150: p = connected->address;
! 151:
! 152: if ((p->family == AF_INET6) &&
! 153: IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6))
! 154: count++;
! 155: }
! 156:
! 157: return count;
! 158: }
! 159:
! 160: static int
! 161: ripng_if_down (struct interface *ifp)
! 162: {
! 163: struct route_node *rp;
! 164: struct ripng_info *rinfo;
! 165: struct ripng_interface *ri;
! 166:
! 167: if (ripng)
! 168: {
! 169: for (rp = route_top (ripng->table); rp; rp = route_next (rp))
! 170: if ((rinfo = rp->info) != NULL)
! 171: {
! 172: /* Routes got through this interface. */
! 173: if (rinfo->ifindex == ifp->ifindex
! 174: && rinfo->type == ZEBRA_ROUTE_RIPNG
! 175: && rinfo->sub_type == RIPNG_ROUTE_RTE)
! 176: {
! 177: ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
! 178: &rinfo->nexthop,
! 179: rinfo->ifindex);
! 180:
! 181: ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
! 182: (struct prefix_ipv6 *)&rp->p,
! 183: rinfo->ifindex);
! 184: }
! 185: else
! 186: {
! 187: /* All redistributed routes got through this interface,
! 188: * but the static and system ones are kept. */
! 189: if ((rinfo->ifindex == ifp->ifindex) &&
! 190: (rinfo->type != ZEBRA_ROUTE_STATIC) &&
! 191: (rinfo->type != ZEBRA_ROUTE_SYSTEM))
! 192: ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
! 193: (struct prefix_ipv6 *) &rp->p,
! 194: rinfo->ifindex);
! 195: }
! 196: }
! 197: }
! 198:
! 199: ri = ifp->info;
! 200:
! 201: if (ri->running)
! 202: {
! 203: if (IS_RIPNG_DEBUG_EVENT)
! 204: zlog_debug ("turn off %s", ifp->name);
! 205:
! 206: /* Leave from multicast group. */
! 207: ripng_multicast_leave (ifp);
! 208:
! 209: ri->running = 0;
! 210: }
! 211:
! 212: return 0;
! 213: }
! 214:
! 215: /* Inteface link up message processing. */
! 216: int
! 217: ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length)
! 218: {
! 219: struct stream *s;
! 220: struct interface *ifp;
! 221:
! 222: /* zebra_interface_state_read() updates interface structure in iflist. */
! 223: s = zclient->ibuf;
! 224: ifp = zebra_interface_state_read (s);
! 225:
! 226: if (ifp == NULL)
! 227: return 0;
! 228:
! 229: if (IS_RIPNG_DEBUG_ZEBRA)
! 230: zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d",
! 231: ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
! 232: ifp->metric, ifp->mtu6);
! 233:
! 234: /* Check if this interface is RIPng enabled or not. */
! 235: ripng_enable_apply (ifp);
! 236:
! 237: /* Check for a passive interface. */
! 238: ripng_passive_interface_apply (ifp);
! 239:
! 240: /* Apply distribute list to the all interface. */
! 241: ripng_distribute_update_interface (ifp);
! 242:
! 243: return 0;
! 244: }
! 245:
! 246: /* Inteface link down message processing. */
! 247: int
! 248: ripng_interface_down (int command, struct zclient *zclient,
! 249: zebra_size_t length)
! 250: {
! 251: struct stream *s;
! 252: struct interface *ifp;
! 253:
! 254: /* zebra_interface_state_read() updates interface structure in iflist. */
! 255: s = zclient->ibuf;
! 256: ifp = zebra_interface_state_read (s);
! 257:
! 258: if (ifp == NULL)
! 259: return 0;
! 260:
! 261: ripng_if_down (ifp);
! 262:
! 263: if (IS_RIPNG_DEBUG_ZEBRA)
! 264: zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d",
! 265: ifp->name, ifp->ifindex,
! 266: (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6);
! 267:
! 268: return 0;
! 269: }
! 270:
! 271: /* Inteface addition message from zebra. */
! 272: int
! 273: ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length)
! 274: {
! 275: struct interface *ifp;
! 276:
! 277: ifp = zebra_interface_add_read (zclient->ibuf);
! 278:
! 279: if (IS_RIPNG_DEBUG_ZEBRA)
! 280: zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d",
! 281: ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
! 282: ifp->metric, ifp->mtu6);
! 283:
! 284: /* Check is this interface is RIP enabled or not.*/
! 285: ripng_enable_apply (ifp);
! 286:
! 287: /* Apply distribute list to the interface. */
! 288: ripng_distribute_update_interface (ifp);
! 289:
! 290: /* Check interface routemap. */
! 291: ripng_if_rmap_update_interface (ifp);
! 292:
! 293: return 0;
! 294: }
! 295:
! 296: int
! 297: ripng_interface_delete (int command, struct zclient *zclient,
! 298: zebra_size_t length)
! 299: {
! 300: struct interface *ifp;
! 301: struct stream *s;
! 302:
! 303: s = zclient->ibuf;
! 304: /* zebra_interface_state_read() updates interface structure in iflist */
! 305: ifp = zebra_interface_state_read(s);
! 306:
! 307: if (ifp == NULL)
! 308: return 0;
! 309:
! 310: if (if_is_up (ifp)) {
! 311: ripng_if_down(ifp);
! 312: }
! 313:
! 314: zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
! 315: ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
! 316: ifp->metric, ifp->mtu6);
! 317:
! 318: /* To support pseudo interface do not free interface structure. */
! 319: /* if_delete(ifp); */
! 320: ifp->ifindex = IFINDEX_INTERNAL;
! 321:
! 322: return 0;
! 323: }
! 324:
! 325: void
! 326: ripng_interface_clean (void)
! 327: {
! 328: struct listnode *node, *nnode;
! 329: struct interface *ifp;
! 330: struct ripng_interface *ri;
! 331:
! 332: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
! 333: {
! 334: ri = ifp->info;
! 335:
! 336: ri->enable_network = 0;
! 337: ri->enable_interface = 0;
! 338: ri->running = 0;
! 339:
! 340: if (ri->t_wakeup)
! 341: {
! 342: thread_cancel (ri->t_wakeup);
! 343: ri->t_wakeup = NULL;
! 344: }
! 345: }
! 346: }
! 347:
! 348: void
! 349: ripng_interface_reset (void)
! 350: {
! 351: struct listnode *node;
! 352: struct interface *ifp;
! 353: struct ripng_interface *ri;
! 354:
! 355: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 356: {
! 357: ri = ifp->info;
! 358:
! 359: ri->enable_network = 0;
! 360: ri->enable_interface = 0;
! 361: ri->running = 0;
! 362:
! 363: ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
! 364: ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
! 365:
! 366: ri->list[RIPNG_FILTER_IN] = NULL;
! 367: ri->list[RIPNG_FILTER_OUT] = NULL;
! 368:
! 369: ri->prefix[RIPNG_FILTER_IN] = NULL;
! 370: ri->prefix[RIPNG_FILTER_OUT] = NULL;
! 371:
! 372: if (ri->t_wakeup)
! 373: {
! 374: thread_cancel (ri->t_wakeup);
! 375: ri->t_wakeup = NULL;
! 376: }
! 377:
! 378: ri->passive = 0;
! 379: }
! 380: }
! 381:
! 382: static void
! 383: ripng_apply_address_add (struct connected *ifc) {
! 384: struct prefix_ipv6 address;
! 385: struct prefix *p;
! 386:
! 387: if (!ripng)
! 388: return;
! 389:
! 390: if (! if_is_up(ifc->ifp))
! 391: return;
! 392:
! 393: p = ifc->address;
! 394:
! 395: memset (&address, 0, sizeof (address));
! 396: address.family = p->family;
! 397: address.prefix = p->u.prefix6;
! 398: address.prefixlen = p->prefixlen;
! 399: apply_mask_ipv6(&address);
! 400:
! 401: /* Check if this interface is RIP enabled or not
! 402: or Check if this address's prefix is RIP enabled */
! 403: if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) ||
! 404: (ripng_enable_network_lookup2(ifc) >= 0))
! 405: ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
! 406: &address, ifc->ifp->ifindex, NULL);
! 407:
! 408: }
! 409:
! 410: int
! 411: ripng_interface_address_add (int command, struct zclient *zclient,
! 412: zebra_size_t length)
! 413: {
! 414: struct connected *c;
! 415: struct prefix *p;
! 416:
! 417: c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
! 418: zclient->ibuf);
! 419:
! 420: if (c == NULL)
! 421: return 0;
! 422:
! 423: p = c->address;
! 424:
! 425: if (p->family == AF_INET6)
! 426: {
! 427: struct ripng_interface *ri = c->ifp->info;
! 428:
! 429: if (IS_RIPNG_DEBUG_ZEBRA)
! 430: zlog_debug ("RIPng connected address %s/%d add",
! 431: inet6_ntoa(p->u.prefix6),
! 432: p->prefixlen);
! 433:
! 434: /* Check is this prefix needs to be redistributed. */
! 435: ripng_apply_address_add(c);
! 436:
! 437: /* Let's try once again whether the interface could be activated */
! 438: if (!ri->running) {
! 439: /* Check if this interface is RIP enabled or not.*/
! 440: ripng_enable_apply (c->ifp);
! 441:
! 442: /* Apply distribute list to the interface. */
! 443: ripng_distribute_update_interface (c->ifp);
! 444:
! 445: /* Check interface routemap. */
! 446: ripng_if_rmap_update_interface (c->ifp);
! 447: }
! 448:
! 449: }
! 450:
! 451: return 0;
! 452: }
! 453:
! 454: static void
! 455: ripng_apply_address_del (struct connected *ifc) {
! 456: struct prefix_ipv6 address;
! 457: struct prefix *p;
! 458:
! 459: if (!ripng)
! 460: return;
! 461:
! 462: if (! if_is_up(ifc->ifp))
! 463: return;
! 464:
! 465: p = ifc->address;
! 466:
! 467: memset (&address, 0, sizeof (address));
! 468: address.family = p->family;
! 469: address.prefix = p->u.prefix6;
! 470: address.prefixlen = p->prefixlen;
! 471: apply_mask_ipv6(&address);
! 472:
! 473: ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
! 474: &address, ifc->ifp->ifindex);
! 475: }
! 476:
! 477: int
! 478: ripng_interface_address_delete (int command, struct zclient *zclient,
! 479: zebra_size_t length)
! 480: {
! 481: struct connected *ifc;
! 482: struct prefix *p;
! 483: char buf[INET6_ADDRSTRLEN];
! 484:
! 485: ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
! 486: zclient->ibuf);
! 487:
! 488: if (ifc)
! 489: {
! 490: p = ifc->address;
! 491:
! 492: if (p->family == AF_INET6)
! 493: {
! 494: if (IS_RIPNG_DEBUG_ZEBRA)
! 495: zlog_debug ("RIPng connected address %s/%d delete",
! 496: inet_ntop (AF_INET6, &p->u.prefix6, buf,
! 497: INET6_ADDRSTRLEN),
! 498: p->prefixlen);
! 499:
! 500: /* Check wether this prefix needs to be removed. */
! 501: ripng_apply_address_del(ifc);
! 502: }
! 503: connected_free (ifc);
! 504: }
! 505:
! 506: return 0;
! 507: }
! 508:
! 509: /* RIPng enable interface vector. */
! 510: vector ripng_enable_if;
! 511:
! 512: /* RIPng enable network table. */
! 513: struct route_table *ripng_enable_network;
! 514:
! 515: /* Lookup RIPng enable network. */
! 516: /* Check wether the interface has at least a connected prefix that
! 517: * is within the ripng_enable_network table. */
! 518: static int
! 519: ripng_enable_network_lookup_if (struct interface *ifp)
! 520: {
! 521: struct listnode *node;
! 522: struct connected *connected;
! 523: struct prefix_ipv6 address;
! 524:
! 525: for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
! 526: {
! 527: struct prefix *p;
! 528: struct route_node *node;
! 529:
! 530: p = connected->address;
! 531:
! 532: if (p->family == AF_INET6)
! 533: {
! 534: address.family = AF_INET6;
! 535: address.prefix = p->u.prefix6;
! 536: address.prefixlen = IPV6_MAX_BITLEN;
! 537:
! 538: node = route_node_match (ripng_enable_network,
! 539: (struct prefix *)&address);
! 540: if (node)
! 541: {
! 542: route_unlock_node (node);
! 543: return 1;
! 544: }
! 545: }
! 546: }
! 547: return -1;
! 548: }
! 549:
! 550: /* Check wether connected is within the ripng_enable_network table. */
! 551: static int
! 552: ripng_enable_network_lookup2 (struct connected *connected)
! 553: {
! 554: struct prefix_ipv6 address;
! 555: struct prefix *p;
! 556:
! 557: p = connected->address;
! 558:
! 559: if (p->family == AF_INET6) {
! 560: struct route_node *node;
! 561:
! 562: address.family = p->family;
! 563: address.prefix = p->u.prefix6;
! 564: address.prefixlen = IPV6_MAX_BITLEN;
! 565:
! 566: /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */
! 567: node = route_node_match (ripng_enable_network,
! 568: (struct prefix *)&address);
! 569:
! 570: if (node) {
! 571: route_unlock_node (node);
! 572: return 1;
! 573: }
! 574: }
! 575:
! 576: return -1;
! 577: }
! 578:
! 579: /* Add RIPng enable network. */
! 580: static int
! 581: ripng_enable_network_add (struct prefix *p)
! 582: {
! 583: struct route_node *node;
! 584:
! 585: node = route_node_get (ripng_enable_network, p);
! 586:
! 587: if (node->info)
! 588: {
! 589: route_unlock_node (node);
! 590: return -1;
! 591: }
! 592: else
! 593: node->info = (char *) "enabled";
! 594:
! 595: /* XXX: One should find a better solution than a generic one */
! 596: ripng_enable_apply_all();
! 597:
! 598: return 1;
! 599: }
! 600:
! 601: /* Delete RIPng enable network. */
! 602: static int
! 603: ripng_enable_network_delete (struct prefix *p)
! 604: {
! 605: struct route_node *node;
! 606:
! 607: node = route_node_lookup (ripng_enable_network, p);
! 608: if (node)
! 609: {
! 610: node->info = NULL;
! 611:
! 612: /* Unlock info lock. */
! 613: route_unlock_node (node);
! 614:
! 615: /* Unlock lookup lock. */
! 616: route_unlock_node (node);
! 617:
! 618: return 1;
! 619: }
! 620: return -1;
! 621: }
! 622:
! 623: /* Lookup function. */
! 624: static int
! 625: ripng_enable_if_lookup (const char *ifname)
! 626: {
! 627: unsigned int i;
! 628: char *str;
! 629:
! 630: for (i = 0; i < vector_active (ripng_enable_if); i++)
! 631: if ((str = vector_slot (ripng_enable_if, i)) != NULL)
! 632: if (strcmp (str, ifname) == 0)
! 633: return i;
! 634: return -1;
! 635: }
! 636:
! 637: /* Add interface to ripng_enable_if. */
! 638: static int
! 639: ripng_enable_if_add (const char *ifname)
! 640: {
! 641: int ret;
! 642:
! 643: ret = ripng_enable_if_lookup (ifname);
! 644: if (ret >= 0)
! 645: return -1;
! 646:
! 647: vector_set (ripng_enable_if, strdup (ifname));
! 648:
! 649: ripng_enable_apply_all();
! 650:
! 651: return 1;
! 652: }
! 653:
! 654: /* Delete interface from ripng_enable_if. */
! 655: static int
! 656: ripng_enable_if_delete (const char *ifname)
! 657: {
! 658: int index;
! 659: char *str;
! 660:
! 661: index = ripng_enable_if_lookup (ifname);
! 662: if (index < 0)
! 663: return -1;
! 664:
! 665: str = vector_slot (ripng_enable_if, index);
! 666: free (str);
! 667: vector_unset (ripng_enable_if, index);
! 668:
! 669: ripng_enable_apply_all();
! 670:
! 671: return 1;
! 672: }
! 673:
! 674: /* Wake up interface. */
! 675: static int
! 676: ripng_interface_wakeup (struct thread *t)
! 677: {
! 678: struct interface *ifp;
! 679: struct ripng_interface *ri;
! 680:
! 681: /* Get interface. */
! 682: ifp = THREAD_ARG (t);
! 683:
! 684: ri = ifp->info;
! 685: ri->t_wakeup = NULL;
! 686:
! 687: /* Join to multicast group. */
! 688: if (ripng_multicast_join (ifp) < 0) {
! 689: zlog_err ("multicast join failed, interface %s not running", ifp->name);
! 690: return 0;
! 691: }
! 692:
! 693: /* Set running flag. */
! 694: ri->running = 1;
! 695:
! 696: /* Send RIP request to the interface. */
! 697: ripng_request (ifp);
! 698:
! 699: return 0;
! 700: }
! 701:
! 702: static void
! 703: ripng_connect_set (struct interface *ifp, int set)
! 704: {
! 705: struct listnode *node, *nnode;
! 706: struct connected *connected;
! 707: struct prefix_ipv6 address;
! 708:
! 709: for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
! 710: {
! 711: struct prefix *p;
! 712: p = connected->address;
! 713:
! 714: if (p->family != AF_INET6)
! 715: continue;
! 716:
! 717: address.family = AF_INET6;
! 718: address.prefix = p->u.prefix6;
! 719: address.prefixlen = p->prefixlen;
! 720: apply_mask_ipv6 (&address);
! 721:
! 722: if (set) {
! 723: /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
! 724: if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) ||
! 725: (ripng_enable_network_lookup2(connected) >= 0))
! 726: ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
! 727: &address, connected->ifp->ifindex, NULL);
! 728: } else {
! 729: ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
! 730: &address, connected->ifp->ifindex);
! 731: if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT))
! 732: ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE,
! 733: &address, connected->ifp->ifindex, NULL);
! 734: }
! 735: }
! 736: }
! 737:
! 738: /* Check RIPng is enabed on this interface. */
! 739: void
! 740: ripng_enable_apply (struct interface *ifp)
! 741: {
! 742: int ret;
! 743: struct ripng_interface *ri = NULL;
! 744:
! 745: /* Check interface. */
! 746: if (! if_is_up (ifp))
! 747: return;
! 748:
! 749: ri = ifp->info;
! 750:
! 751: /* Is this interface a candidate for RIPng ? */
! 752: ret = ripng_enable_network_lookup_if (ifp);
! 753:
! 754: /* If the interface is matched. */
! 755: if (ret > 0)
! 756: ri->enable_network = 1;
! 757: else
! 758: ri->enable_network = 0;
! 759:
! 760: /* Check interface name configuration. */
! 761: ret = ripng_enable_if_lookup (ifp->name);
! 762: if (ret >= 0)
! 763: ri->enable_interface = 1;
! 764: else
! 765: ri->enable_interface = 0;
! 766:
! 767: /* any candidate interface MUST have a link-local IPv6 address */
! 768: if ((! ripng_if_ipv6_lladdress_check (ifp)) &&
! 769: (ri->enable_network || ri->enable_interface)) {
! 770: ri->enable_network = 0;
! 771: ri->enable_interface = 0;
! 772: zlog_warn("Interface %s does not have any link-local address",
! 773: ifp->name);
! 774: }
! 775:
! 776: /* Update running status of the interface. */
! 777: if (ri->enable_network || ri->enable_interface)
! 778: {
! 779: {
! 780: if (IS_RIPNG_DEBUG_EVENT)
! 781: zlog_debug ("RIPng turn on %s", ifp->name);
! 782:
! 783: /* Add interface wake up thread. */
! 784: if (! ri->t_wakeup)
! 785: ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
! 786: ifp, 1);
! 787:
! 788: ripng_connect_set (ifp, 1);
! 789: }
! 790: }
! 791: else
! 792: {
! 793: if (ri->running)
! 794: {
! 795: /* Might as well clean up the route table as well
! 796: * ripng_if_down sets to 0 ri->running, and displays "turn off %s"
! 797: **/
! 798: ripng_if_down(ifp);
! 799:
! 800: ripng_connect_set (ifp, 0);
! 801: }
! 802: }
! 803: }
! 804:
! 805: /* Set distribute list to all interfaces. */
! 806: static void
! 807: ripng_enable_apply_all (void)
! 808: {
! 809: struct interface *ifp;
! 810: struct listnode *node;
! 811:
! 812: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 813: ripng_enable_apply (ifp);
! 814: }
! 815:
! 816: /* Clear all network and neighbor configuration */
! 817: void
! 818: ripng_clean_network ()
! 819: {
! 820: unsigned int i;
! 821: char *str;
! 822: struct route_node *rn;
! 823:
! 824: /* ripng_enable_network */
! 825: for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn))
! 826: if (rn->info) {
! 827: rn->info = NULL;
! 828: route_unlock_node(rn);
! 829: }
! 830:
! 831: /* ripng_enable_if */
! 832: for (i = 0; i < vector_active (ripng_enable_if); i++)
! 833: if ((str = vector_slot (ripng_enable_if, i)) != NULL) {
! 834: free (str);
! 835: vector_slot (ripng_enable_if, i) = NULL;
! 836: }
! 837: }
! 838:
! 839: /* Vector to store passive-interface name. */
! 840: vector Vripng_passive_interface;
! 841:
! 842: /* Utility function for looking up passive interface settings. */
! 843: static int
! 844: ripng_passive_interface_lookup (const char *ifname)
! 845: {
! 846: unsigned int i;
! 847: char *str;
! 848:
! 849: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
! 850: if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
! 851: if (strcmp (str, ifname) == 0)
! 852: return i;
! 853: return -1;
! 854: }
! 855:
! 856: void
! 857: ripng_passive_interface_apply (struct interface *ifp)
! 858: {
! 859: int ret;
! 860: struct ripng_interface *ri;
! 861:
! 862: ri = ifp->info;
! 863:
! 864: ret = ripng_passive_interface_lookup (ifp->name);
! 865: if (ret < 0)
! 866: ri->passive = 0;
! 867: else
! 868: ri->passive = 1;
! 869: }
! 870:
! 871: static void
! 872: ripng_passive_interface_apply_all (void)
! 873: {
! 874: struct interface *ifp;
! 875: struct listnode *node;
! 876:
! 877: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 878: ripng_passive_interface_apply (ifp);
! 879: }
! 880:
! 881: /* Passive interface. */
! 882: static int
! 883: ripng_passive_interface_set (struct vty *vty, const char *ifname)
! 884: {
! 885: if (ripng_passive_interface_lookup (ifname) >= 0)
! 886: return CMD_WARNING;
! 887:
! 888: vector_set (Vripng_passive_interface, strdup (ifname));
! 889:
! 890: ripng_passive_interface_apply_all ();
! 891:
! 892: return CMD_SUCCESS;
! 893: }
! 894:
! 895: static int
! 896: ripng_passive_interface_unset (struct vty *vty, const char *ifname)
! 897: {
! 898: int i;
! 899: char *str;
! 900:
! 901: i = ripng_passive_interface_lookup (ifname);
! 902: if (i < 0)
! 903: return CMD_WARNING;
! 904:
! 905: str = vector_slot (Vripng_passive_interface, i);
! 906: free (str);
! 907: vector_unset (Vripng_passive_interface, i);
! 908:
! 909: ripng_passive_interface_apply_all ();
! 910:
! 911: return CMD_SUCCESS;
! 912: }
! 913:
! 914: /* Free all configured RIP passive-interface settings. */
! 915: void
! 916: ripng_passive_interface_clean (void)
! 917: {
! 918: unsigned int i;
! 919: char *str;
! 920:
! 921: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
! 922: if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
! 923: {
! 924: free (str);
! 925: vector_slot (Vripng_passive_interface, i) = NULL;
! 926: }
! 927: ripng_passive_interface_apply_all ();
! 928: }
! 929:
! 930: /* Write RIPng enable network and interface to the vty. */
! 931: int
! 932: ripng_network_write (struct vty *vty, int config_mode)
! 933: {
! 934: unsigned int i;
! 935: const char *ifname;
! 936: struct route_node *node;
! 937: char buf[BUFSIZ];
! 938:
! 939: /* Write enable network. */
! 940: for (node = route_top (ripng_enable_network); node; node = route_next (node))
! 941: if (node->info)
! 942: {
! 943: struct prefix *p = &node->p;
! 944: vty_out (vty, "%s%s/%d%s",
! 945: config_mode ? " network " : " ",
! 946: inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
! 947: p->prefixlen,
! 948: VTY_NEWLINE);
! 949:
! 950: }
! 951:
! 952: /* Write enable interface. */
! 953: for (i = 0; i < vector_active (ripng_enable_if); i++)
! 954: if ((ifname = vector_slot (ripng_enable_if, i)) != NULL)
! 955: vty_out (vty, "%s%s%s",
! 956: config_mode ? " network " : " ",
! 957: ifname,
! 958: VTY_NEWLINE);
! 959:
! 960: /* Write passive interface. */
! 961: if (config_mode)
! 962: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
! 963: if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
! 964: vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
! 965:
! 966: return 0;
! 967: }
! 968:
! 969: /* RIPng enable on specified interface or matched network. */
! 970: DEFUN (ripng_network,
! 971: ripng_network_cmd,
! 972: "network IF_OR_ADDR",
! 973: "RIPng enable on specified interface or network.\n"
! 974: "Interface or address")
! 975: {
! 976: int ret;
! 977: struct prefix p;
! 978:
! 979: ret = str2prefix (argv[0], &p);
! 980:
! 981: /* Given string is IPv6 network or interface name. */
! 982: if (ret)
! 983: ret = ripng_enable_network_add (&p);
! 984: else
! 985: ret = ripng_enable_if_add (argv[0]);
! 986:
! 987: if (ret < 0)
! 988: {
! 989: vty_out (vty, "There is same network configuration %s%s", argv[0],
! 990: VTY_NEWLINE);
! 991: return CMD_WARNING;
! 992: }
! 993:
! 994: return CMD_SUCCESS;
! 995: }
! 996:
! 997: /* RIPng enable on specified interface or matched network. */
! 998: DEFUN (no_ripng_network,
! 999: no_ripng_network_cmd,
! 1000: "no network IF_OR_ADDR",
! 1001: NO_STR
! 1002: "RIPng enable on specified interface or network.\n"
! 1003: "Interface or address")
! 1004: {
! 1005: int ret;
! 1006: struct prefix p;
! 1007:
! 1008: ret = str2prefix (argv[0], &p);
! 1009:
! 1010: /* Given string is interface name. */
! 1011: if (ret)
! 1012: ret = ripng_enable_network_delete (&p);
! 1013: else
! 1014: ret = ripng_enable_if_delete (argv[0]);
! 1015:
! 1016: if (ret < 0)
! 1017: {
! 1018: vty_out (vty, "can't find network %s%s", argv[0],
! 1019: VTY_NEWLINE);
! 1020: return CMD_WARNING;
! 1021: }
! 1022:
! 1023: return CMD_SUCCESS;
! 1024: }
! 1025:
! 1026: DEFUN (ipv6_ripng_split_horizon,
! 1027: ipv6_ripng_split_horizon_cmd,
! 1028: "ipv6 ripng split-horizon",
! 1029: IPV6_STR
! 1030: "Routing Information Protocol\n"
! 1031: "Perform split horizon\n")
! 1032: {
! 1033: struct interface *ifp;
! 1034: struct ripng_interface *ri;
! 1035:
! 1036: ifp = vty->index;
! 1037: ri = ifp->info;
! 1038:
! 1039: ri->split_horizon = RIPNG_SPLIT_HORIZON;
! 1040: return CMD_SUCCESS;
! 1041: }
! 1042:
! 1043: DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
! 1044: ipv6_ripng_split_horizon_poisoned_reverse_cmd,
! 1045: "ipv6 ripng split-horizon poisoned-reverse",
! 1046: IPV6_STR
! 1047: "Routing Information Protocol\n"
! 1048: "Perform split horizon\n"
! 1049: "With poisoned-reverse\n")
! 1050: {
! 1051: struct interface *ifp;
! 1052: struct ripng_interface *ri;
! 1053:
! 1054: ifp = vty->index;
! 1055: ri = ifp->info;
! 1056:
! 1057: ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
! 1058: return CMD_SUCCESS;
! 1059: }
! 1060:
! 1061: DEFUN (no_ipv6_ripng_split_horizon,
! 1062: no_ipv6_ripng_split_horizon_cmd,
! 1063: "no ipv6 ripng split-horizon",
! 1064: NO_STR
! 1065: IPV6_STR
! 1066: "Routing Information Protocol\n"
! 1067: "Perform split horizon\n")
! 1068: {
! 1069: struct interface *ifp;
! 1070: struct ripng_interface *ri;
! 1071:
! 1072: ifp = vty->index;
! 1073: ri = ifp->info;
! 1074:
! 1075: ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
! 1076: return CMD_SUCCESS;
! 1077: }
! 1078:
! 1079: ALIAS (no_ipv6_ripng_split_horizon,
! 1080: no_ipv6_ripng_split_horizon_poisoned_reverse_cmd,
! 1081: "no ipv6 ripng split-horizon poisoned-reverse",
! 1082: NO_STR
! 1083: IPV6_STR
! 1084: "Routing Information Protocol\n"
! 1085: "Perform split horizon\n"
! 1086: "With poisoned-reverse\n")
! 1087:
! 1088: DEFUN (ripng_passive_interface,
! 1089: ripng_passive_interface_cmd,
! 1090: "passive-interface IFNAME",
! 1091: "Suppress routing updates on an interface\n"
! 1092: "Interface name\n")
! 1093: {
! 1094: return ripng_passive_interface_set (vty, argv[0]);
! 1095: }
! 1096:
! 1097: DEFUN (no_ripng_passive_interface,
! 1098: no_ripng_passive_interface_cmd,
! 1099: "no passive-interface IFNAME",
! 1100: NO_STR
! 1101: "Suppress routing updates on an interface\n"
! 1102: "Interface name\n")
! 1103: {
! 1104: return ripng_passive_interface_unset (vty, argv[0]);
! 1105: }
! 1106:
! 1107: static struct ripng_interface *
! 1108: ri_new (void)
! 1109: {
! 1110: struct ripng_interface *ri;
! 1111: ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
! 1112:
! 1113: /* Set default split-horizon behavior. If the interface is Frame
! 1114: Relay or SMDS is enabled, the default value for split-horizon is
! 1115: off. But currently Zebra does detect Frame Relay or SMDS
! 1116: interface. So all interface is set to split horizon. */
! 1117: ri->split_horizon_default = RIPNG_SPLIT_HORIZON;
! 1118: ri->split_horizon = ri->split_horizon_default;
! 1119:
! 1120: return ri;
! 1121: }
! 1122:
! 1123: static int
! 1124: ripng_if_new_hook (struct interface *ifp)
! 1125: {
! 1126: ifp->info = ri_new ();
! 1127: return 0;
! 1128: }
! 1129:
! 1130: /* Called when interface structure deleted. */
! 1131: static int
! 1132: ripng_if_delete_hook (struct interface *ifp)
! 1133: {
! 1134: XFREE (MTYPE_IF, ifp->info);
! 1135: ifp->info = NULL;
! 1136: return 0;
! 1137: }
! 1138:
! 1139: /* Configuration write function for ripngd. */
! 1140: static int
! 1141: interface_config_write (struct vty *vty)
! 1142: {
! 1143: struct listnode *node;
! 1144: struct interface *ifp;
! 1145: struct ripng_interface *ri;
! 1146: int write = 0;
! 1147:
! 1148: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 1149: {
! 1150: ri = ifp->info;
! 1151:
! 1152: /* Do not display the interface if there is no
! 1153: * configuration about it.
! 1154: **/
! 1155: if ((!ifp->desc) &&
! 1156: (ri->split_horizon == ri->split_horizon_default))
! 1157: continue;
! 1158:
! 1159: vty_out (vty, "interface %s%s", ifp->name,
! 1160: VTY_NEWLINE);
! 1161: if (ifp->desc)
! 1162: vty_out (vty, " description %s%s", ifp->desc,
! 1163: VTY_NEWLINE);
! 1164:
! 1165: /* Split horizon. */
! 1166: if (ri->split_horizon != ri->split_horizon_default)
! 1167: {
! 1168: switch (ri->split_horizon) {
! 1169: case RIPNG_SPLIT_HORIZON:
! 1170: vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE);
! 1171: break;
! 1172: case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
! 1173: vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s",
! 1174: VTY_NEWLINE);
! 1175: break;
! 1176: case RIPNG_NO_SPLIT_HORIZON:
! 1177: default:
! 1178: vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE);
! 1179: break;
! 1180: }
! 1181: }
! 1182:
! 1183: vty_out (vty, "!%s", VTY_NEWLINE);
! 1184:
! 1185: write++;
! 1186: }
! 1187: return write;
! 1188: }
! 1189:
! 1190: /* ripngd's interface node. */
! 1191: static struct cmd_node interface_node =
! 1192: {
! 1193: INTERFACE_NODE,
! 1194: "%s(config-if)# ",
! 1195: 1 /* VTYSH */
! 1196: };
! 1197:
! 1198: /* Initialization of interface. */
! 1199: void
! 1200: ripng_if_init ()
! 1201: {
! 1202: /* Interface initialize. */
! 1203: iflist = list_new ();
! 1204: if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
! 1205: if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook);
! 1206:
! 1207: /* RIPng enable network init. */
! 1208: ripng_enable_network = route_table_init ();
! 1209:
! 1210: /* RIPng enable interface init. */
! 1211: ripng_enable_if = vector_init (1);
! 1212:
! 1213: /* RIPng passive interface. */
! 1214: Vripng_passive_interface = vector_init (1);
! 1215:
! 1216: /* Install interface node. */
! 1217: install_node (&interface_node, interface_config_write);
! 1218:
! 1219: /* Install commands. */
! 1220: install_element (CONFIG_NODE, &interface_cmd);
! 1221: install_element (CONFIG_NODE, &no_interface_cmd);
! 1222: install_default (INTERFACE_NODE);
! 1223: install_element (INTERFACE_NODE, &interface_desc_cmd);
! 1224: install_element (INTERFACE_NODE, &no_interface_desc_cmd);
! 1225:
! 1226: install_element (RIPNG_NODE, &ripng_network_cmd);
! 1227: install_element (RIPNG_NODE, &no_ripng_network_cmd);
! 1228: install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
! 1229: install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
! 1230:
! 1231: install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
! 1232: install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
! 1233: install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
! 1234: install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd);
! 1235: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>