Annotation of embedaddon/quagga/zebra/connected.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Address linked list routine.
! 3: * Copyright (C) 1997, 98 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 "prefix.h"
! 26: #include "linklist.h"
! 27: #include "if.h"
! 28: #include "table.h"
! 29: #include "rib.h"
! 30: #include "table.h"
! 31: #include "log.h"
! 32: #include "memory.h"
! 33:
! 34: #include "zebra/zserv.h"
! 35: #include "zebra/redistribute.h"
! 36: #include "zebra/interface.h"
! 37: #include "zebra/connected.h"
! 38: extern struct zebra_t zebrad;
! 39:
! 40: /* withdraw a connected address */
! 41: static void
! 42: connected_withdraw (struct connected *ifc)
! 43: {
! 44: if (! ifc)
! 45: return;
! 46:
! 47: /* Update interface address information to protocol daemon. */
! 48: if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 49: {
! 50: zebra_interface_address_delete_update (ifc->ifp, ifc);
! 51:
! 52: if_subnet_delete (ifc->ifp, ifc);
! 53:
! 54: if (ifc->address->family == AF_INET)
! 55: connected_down_ipv4 (ifc->ifp, ifc);
! 56: #ifdef HAVE_IPV6
! 57: else
! 58: connected_down_ipv6 (ifc->ifp, ifc);
! 59: #endif
! 60:
! 61: UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
! 62: }
! 63:
! 64: if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
! 65: {
! 66: listnode_delete (ifc->ifp->connected, ifc);
! 67: connected_free (ifc);
! 68: }
! 69: }
! 70:
! 71: static void
! 72: connected_announce (struct interface *ifp, struct connected *ifc)
! 73: {
! 74: if (!ifc)
! 75: return;
! 76:
! 77: listnode_add (ifp->connected, ifc);
! 78:
! 79: /* Update interface address information to protocol daemon. */
! 80: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 81: {
! 82: if (ifc->address->family == AF_INET)
! 83: if_subnet_add (ifp, ifc);
! 84:
! 85: SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
! 86:
! 87: zebra_interface_address_add_update (ifp, ifc);
! 88:
! 89: if (if_is_operative(ifp))
! 90: {
! 91: if (ifc->address->family == AF_INET)
! 92: connected_up_ipv4 (ifp, ifc);
! 93: #ifdef HAVE_IPV6
! 94: else
! 95: connected_up_ipv6 (ifp, ifc);
! 96: #endif
! 97: }
! 98: }
! 99: }
! 100:
! 101: /* If same interface address is already exist... */
! 102: struct connected *
! 103: connected_check (struct interface *ifp, struct prefix *p)
! 104: {
! 105: struct connected *ifc;
! 106: struct listnode *node;
! 107:
! 108: for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
! 109: if (prefix_same (ifc->address, p))
! 110: return ifc;
! 111:
! 112: return NULL;
! 113: }
! 114:
! 115: /* Check if two ifc's describe the same address */
! 116: static int
! 117: connected_same (struct connected *ifc1, struct connected *ifc2)
! 118: {
! 119: if (ifc1->ifp != ifc2->ifp)
! 120: return 0;
! 121:
! 122: if (ifc1->destination)
! 123: if (!ifc2->destination)
! 124: return 0;
! 125: if (ifc2->destination)
! 126: if (!ifc1->destination)
! 127: return 0;
! 128:
! 129: if (ifc1->destination && ifc2->destination)
! 130: if (!prefix_same (ifc1->destination, ifc2->destination))
! 131: return 0;
! 132:
! 133: if (ifc1->flags != ifc2->flags)
! 134: return 0;
! 135:
! 136: return 1;
! 137: }
! 138:
! 139: /* Handle implicit withdrawals of addresses, where a system ADDs an address
! 140: * to an interface which already has the same address configured.
! 141: *
! 142: * Returns the struct connected which must be announced to clients,
! 143: * or NULL if nothing to do.
! 144: */
! 145: static struct connected *
! 146: connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
! 147: {
! 148: struct connected *current;
! 149:
! 150: /* Check same connected route. */
! 151: if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
! 152: {
! 153: if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
! 154: SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
! 155:
! 156: /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
! 157: * back an address we have already added.
! 158: */
! 159: if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
! 160: {
! 161: /* nothing to do */
! 162: connected_free (ifc);
! 163: return NULL;
! 164: }
! 165:
! 166: UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
! 167: connected_withdraw (current); /* implicit withdraw - freebsd does this */
! 168: }
! 169: return ifc;
! 170: }
! 171:
! 172: /* Called from if_up(). */
! 173: void
! 174: connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
! 175: {
! 176: struct prefix_ipv4 p;
! 177:
! 178: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 179: return;
! 180:
! 181: PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
! 182:
! 183: /* Apply mask to the network. */
! 184: apply_mask_ipv4 (&p);
! 185:
! 186: /* In case of connected address is 0.0.0.0/0 we treat it tunnel
! 187: address. */
! 188: if (prefix_ipv4_any (&p))
! 189: return;
! 190:
! 191: rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
! 192: RT_TABLE_MAIN, ifp->metric, 0);
! 193:
! 194: rib_update ();
! 195: }
! 196:
! 197: /* Add connected IPv4 route to the interface. */
! 198: void
! 199: connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
! 200: u_char prefixlen, struct in_addr *broad,
! 201: const char *label)
! 202: {
! 203: struct prefix_ipv4 *p;
! 204: struct connected *ifc;
! 205:
! 206: /* Make connected structure. */
! 207: ifc = connected_new ();
! 208: ifc->ifp = ifp;
! 209: ifc->flags = flags;
! 210:
! 211: /* Allocate new connected address. */
! 212: p = prefix_ipv4_new ();
! 213: p->family = AF_INET;
! 214: p->prefix = *addr;
! 215: p->prefixlen = prefixlen;
! 216: ifc->address = (struct prefix *) p;
! 217:
! 218: /* If there is broadcast or peer address. */
! 219: if (broad)
! 220: {
! 221: p = prefix_ipv4_new ();
! 222: p->family = AF_INET;
! 223: p->prefix = *broad;
! 224: p->prefixlen = prefixlen;
! 225: ifc->destination = (struct prefix *) p;
! 226:
! 227: /* validate the destination address */
! 228: if (CONNECTED_PEER(ifc))
! 229: {
! 230: if (IPV4_ADDR_SAME(addr,broad))
! 231: zlog_warn("warning: interface %s has same local and peer "
! 232: "address %s, routing protocols may malfunction",
! 233: ifp->name,inet_ntoa(*addr));
! 234: }
! 235: else
! 236: {
! 237: if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
! 238: {
! 239: char buf[2][INET_ADDRSTRLEN];
! 240: struct in_addr bcalc;
! 241: bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
! 242: zlog_warn("warning: interface %s broadcast addr %s/%d != "
! 243: "calculated %s, routing protocols may malfunction",
! 244: ifp->name,
! 245: inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
! 246: prefixlen,
! 247: inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
! 248: }
! 249: }
! 250:
! 251: }
! 252: else
! 253: {
! 254: if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
! 255: {
! 256: zlog_warn("warning: %s called for interface %s "
! 257: "with peer flag set, but no peer address supplied",
! 258: __func__, ifp->name);
! 259: UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
! 260: }
! 261:
! 262: /* no broadcast or destination address was supplied */
! 263: if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
! 264: zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
! 265: "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
! 266: }
! 267:
! 268: /* Label of this address. */
! 269: if (label)
! 270: ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
! 271:
! 272: /* nothing to do? */
! 273: if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
! 274: return;
! 275:
! 276: connected_announce (ifp, ifc);
! 277: }
! 278:
! 279: void
! 280: connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
! 281: {
! 282: struct prefix_ipv4 p;
! 283:
! 284: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 285: return;
! 286:
! 287: PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
! 288:
! 289: /* Apply mask to the network. */
! 290: apply_mask_ipv4 (&p);
! 291:
! 292: /* In case of connected address is 0.0.0.0/0 we treat it tunnel
! 293: address. */
! 294: if (prefix_ipv4_any (&p))
! 295: return;
! 296:
! 297: /* Same logic as for connected_up_ipv4(): push the changes into the head. */
! 298: rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
! 299:
! 300: rib_update ();
! 301: }
! 302:
! 303: /* Delete connected IPv4 route to the interface. */
! 304: void
! 305: connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
! 306: u_char prefixlen, struct in_addr *broad)
! 307: {
! 308: struct prefix_ipv4 p;
! 309: struct connected *ifc;
! 310:
! 311: memset (&p, 0, sizeof (struct prefix_ipv4));
! 312: p.family = AF_INET;
! 313: p.prefix = *addr;
! 314: p.prefixlen = prefixlen;
! 315:
! 316: ifc = connected_check (ifp, (struct prefix *) &p);
! 317: if (! ifc)
! 318: return;
! 319:
! 320: connected_withdraw (ifc);
! 321:
! 322: rib_update();
! 323: }
! 324:
! 325: #ifdef HAVE_IPV6
! 326: void
! 327: connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
! 328: {
! 329: struct prefix_ipv6 p;
! 330:
! 331: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 332: return;
! 333:
! 334: PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
! 335:
! 336: /* Apply mask to the network. */
! 337: apply_mask_ipv6 (&p);
! 338:
! 339: #if ! defined (MUSICA) && ! defined (LINUX)
! 340: /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
! 341: if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
! 342: return;
! 343: #endif
! 344:
! 345: rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
! 346: ifp->metric, 0);
! 347:
! 348: rib_update ();
! 349: }
! 350:
! 351: /* Add connected IPv6 route to the interface. */
! 352: void
! 353: connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
! 354: u_char prefixlen, struct in6_addr *broad,
! 355: const char *label)
! 356: {
! 357: struct prefix_ipv6 *p;
! 358: struct connected *ifc;
! 359:
! 360: /* Make connected structure. */
! 361: ifc = connected_new ();
! 362: ifc->ifp = ifp;
! 363: ifc->flags = flags;
! 364:
! 365: /* Allocate new connected address. */
! 366: p = prefix_ipv6_new ();
! 367: p->family = AF_INET6;
! 368: IPV6_ADDR_COPY (&p->prefix, addr);
! 369: p->prefixlen = prefixlen;
! 370: ifc->address = (struct prefix *) p;
! 371:
! 372: /* If there is broadcast or peer address. */
! 373: if (broad)
! 374: {
! 375: if (IN6_IS_ADDR_UNSPECIFIED(broad))
! 376: zlog_warn("warning: %s called for interface %s with unspecified "
! 377: "destination address; ignoring!", __func__, ifp->name);
! 378: else
! 379: {
! 380: p = prefix_ipv6_new ();
! 381: p->family = AF_INET6;
! 382: IPV6_ADDR_COPY (&p->prefix, broad);
! 383: p->prefixlen = prefixlen;
! 384: ifc->destination = (struct prefix *) p;
! 385: }
! 386: }
! 387: if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
! 388: {
! 389: zlog_warn("warning: %s called for interface %s "
! 390: "with peer flag set, but no peer address supplied",
! 391: __func__, ifp->name);
! 392: UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
! 393: }
! 394:
! 395: /* Label of this address. */
! 396: if (label)
! 397: ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
! 398:
! 399: if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
! 400: return;
! 401:
! 402: connected_announce (ifp, ifc);
! 403: }
! 404:
! 405: void
! 406: connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
! 407: {
! 408: struct prefix_ipv6 p;
! 409:
! 410: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
! 411: return;
! 412:
! 413: PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
! 414:
! 415: apply_mask_ipv6 (&p);
! 416:
! 417: if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
! 418: return;
! 419:
! 420: rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
! 421:
! 422: rib_update ();
! 423: }
! 424:
! 425: void
! 426: connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
! 427: u_char prefixlen, struct in6_addr *broad)
! 428: {
! 429: struct prefix_ipv6 p;
! 430: struct connected *ifc;
! 431:
! 432: memset (&p, 0, sizeof (struct prefix_ipv6));
! 433: p.family = AF_INET6;
! 434: memcpy (&p.prefix, address, sizeof (struct in6_addr));
! 435: p.prefixlen = prefixlen;
! 436:
! 437: ifc = connected_check (ifp, (struct prefix *) &p);
! 438: if (! ifc)
! 439: return;
! 440:
! 441: connected_withdraw (ifc);
! 442:
! 443: rib_update();
! 444: }
! 445: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>