Annotation of embedaddon/pimdd/vif.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998 by the University of Southern California.
! 3: * All rights reserved.
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software and
! 6: * its documentation in source and binary forms for lawful
! 7: * purposes and without fee is hereby granted, provided
! 8: * that the above copyright notice appear in all copies and that both
! 9: * the copyright notice and this permission notice appear in supporting
! 10: * documentation, and that any documentation, advertising materials,
! 11: * and other materials related to such distribution and use acknowledge
! 12: * that the software was developed by the University of Southern
! 13: * California and/or Information Sciences Institute.
! 14: * The name of the University of Southern California may not
! 15: * be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
! 19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
! 20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
! 21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
! 22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
! 23: * NON-INFRINGEMENT.
! 24: *
! 25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
! 26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
! 27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
! 28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 29: *
! 30: * Other copyrights might apply to parts of this software and are so
! 31: * noted when applicable.
! 32: */
! 33: /*
! 34: * Questions concerning this software should be directed to
! 35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
! 36: *
! 37: * $Id: vif.c,v 1.6 1998/12/22 21:50:19 kurtw Exp $
! 38: */
! 39: /*
! 40: * Part of this program has been derived from mrouted.
! 41: * The mrouted program is covered by the license in the accompanying file
! 42: * named "LICENSE.mrouted".
! 43: *
! 44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
! 45: * Leland Stanford Junior University.
! 46: *
! 47: */
! 48:
! 49: #include "defs.h"
! 50:
! 51: /*
! 52: * Exported variables.
! 53: */
! 54: struct uvif uvifs[MAXVIFS]; /* array of all virtual interfaces */
! 55: vifi_t numvifs; /* Number of vifs in use */
! 56: int vifs_down; /* 1=>some interfaces are down */
! 57: int phys_vif; /* An enabled vif */
! 58: int udp_socket; /* Since the honkin' kernel doesn't support */
! 59: /* ioctls on raw IP sockets, we need a UDP */
! 60: /* socket as well as our IGMP (raw) socket. */
! 61: /* How dumb. */
! 62: int total_interfaces; /* Number of all interfaces: including the
! 63: * non-configured, but excluding the
! 64: * loopback interface and the non-multicast
! 65: * capable interfaces.
! 66: */
! 67:
! 68: /*
! 69: * Forward declarations.
! 70: */
! 71: static void start_vif __P((vifi_t vifi));
! 72: static void stop_vif __P((vifi_t vifi));
! 73: static void start_all_vifs __P(());
! 74:
! 75:
! 76: void
! 77: init_vifs()
! 78: {
! 79: vifi_t vifi;
! 80: struct uvif *v;
! 81: int enabled_vifs;
! 82:
! 83: numvifs = 0;
! 84: vifs_down = FALSE;
! 85:
! 86: /*
! 87: * Configure the vifs based on the interface configuration of the
! 88: * the kernel and the contents of the configuration file.
! 89: * (Open a UDP socket for ioctl use in the config procedures if
! 90: * the kernel can't handle IOCTL's on the IGMP socket.)
! 91: */
! 92: #ifdef IOCTL_OK_ON_RAW_SOCKET
! 93: udp_socket = igmp_socket;
! 94: #else
! 95: if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
! 96: log(LOG_ERR, errno, "UDP socket");
! 97: #endif
! 98:
! 99: /*
! 100: * Clean up all vifs
! 101: */
! 102: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
! 103: v->uv_flags = 0;
! 104: v->uv_metric = DEFAULT_METRIC;
! 105: v->uv_admetric = 0;
! 106: v->uv_threshold = DEFAULT_THRESHOLD;
! 107: v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
! 108: v->uv_lcl_addr = INADDR_ANY_N;
! 109: v->uv_rmt_addr = INADDR_ANY_N;
! 110: v->uv_dst_addr = INADDR_ANY_N;
! 111: v->uv_subnet = INADDR_ANY_N;
! 112: v->uv_subnetmask = INADDR_ANY_N;
! 113: v->uv_subnetbcast = INADDR_ANY_N;
! 114: strncpy(v->uv_name, "", IFNAMSIZ);
! 115: v->uv_groups = (struct listaddr *)NULL;
! 116: v->uv_dvmrp_neighbors = (struct listaddr *)NULL;
! 117: NBRM_CLRALL(v->uv_nbrmap);
! 118: v->uv_querier = (struct listaddr *)NULL;
! 119: v->uv_igmpv1_warn = 0;
! 120: v->uv_prune_lifetime = 0;
! 121: v->uv_acl = (struct vif_acl *)NULL;
! 122: RESET_TIMER(v->uv_leaf_timer);
! 123: v->uv_addrs = (struct phaddr *)NULL;
! 124: v->uv_filter = (struct vif_filter *)NULL;
! 125: RESET_TIMER(v->uv_pim_hello_timer);
! 126: RESET_TIMER(v->uv_gq_timer);
! 127: v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL;
! 128: v->uv_local_pref = default_source_preference;
! 129: v->uv_local_metric = default_source_metric;
! 130: }
! 131:
! 132: log(LOG_INFO, 0, "Getting vifs from kernel");
! 133: config_vifs_from_kernel();
! 134: log(LOG_INFO, 0, "Getting vifs from %s", configfilename);
! 135: config_vifs_from_file();
! 136:
! 137: /*
! 138: * Quit if there are fewer than two enabled vifs.
! 139: */
! 140: enabled_vifs = 0;
! 141: phys_vif = -1;
! 142:
! 143: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 144: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
! 145: continue;
! 146: if (phys_vif == -1)
! 147: phys_vif = vifi;
! 148: enabled_vifs++;
! 149: }
! 150:
! 151: if (enabled_vifs < 2)
! 152: log(LOG_ERR, 0, "can't forward: %s",
! 153: enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
! 154:
! 155: k_init_pim(igmp_socket); /* Call to kernel to initiliaze structures */
! 156:
! 157: start_all_vifs();
! 158: }
! 159:
! 160:
! 161: static void
! 162: start_all_vifs()
! 163: {
! 164: vifi_t vifi;
! 165: struct uvif *v;
! 166:
! 167: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 168: /* Start vif if not DISABLED or DOWN */
! 169: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) {
! 170: if (v->uv_flags & VIFF_DISABLED)
! 171: log(LOG_INFO, 0,
! 172: "%s is DISABLED; vif #%u out of service",
! 173: v->uv_name, vifi);
! 174: else
! 175: log(LOG_INFO, 0,
! 176: "%s is DOWN; vif #%u out of service",
! 177: v->uv_name, vifi);
! 178: }
! 179: else
! 180: start_vif(vifi);
! 181: }
! 182: }
! 183:
! 184:
! 185:
! 186: /*
! 187: * stop all vifs
! 188: */
! 189: void
! 190: stop_all_vifs()
! 191: {
! 192: vifi_t vifi;
! 193:
! 194: for (vifi = 0; vifi < numvifs; vifi++) {
! 195: stop_vif(vifi);
! 196: }
! 197: }
! 198:
! 199:
! 200: /*
! 201: * Initialize the vif and add to the kernel. The vif can be either
! 202: * physical, tunnel (tunnels will be used in the future
! 203: * when this code becomes PIM multicast boarder router.
! 204: */
! 205: static void
! 206: start_vif(vifi)
! 207: vifi_t vifi;
! 208: {
! 209: struct uvif *v;
! 210: u_int32 src;
! 211:
! 212: v = &uvifs[vifi];
! 213: src = v->uv_lcl_addr;
! 214: /* Initialy no router on any vif */
! 215: v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN;
! 216: SET_TIMER(v->uv_pim_hello_timer, 1 + RANDOM() % PIM_TIMER_HELLO_PERIOD);
! 217: RESET_TIMER(v->uv_gq_timer);
! 218: v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL;
! 219:
! 220: /* Tell kernel to add, i.e. start this vif */
! 221: k_add_vif(igmp_socket, vifi, &uvifs[vifi]);
! 222: log(LOG_INFO, 0, "%s comes up; vif #%u now in service", v->uv_name, vifi);
! 223:
! 224: /*
! 225: * Join the PIM multicast group on the interface.
! 226: */
! 227: k_join(igmp_socket, allpimrouters_group, src);
! 228:
! 229: /*
! 230: * Join the ALL-ROUTERS multicast group on the interface.
! 231: * This allows mtrace requests to loop back if they are run
! 232: * on the multicast router.
! 233: */
! 234: k_join(igmp_socket, allrouters_group, src);
! 235:
! 236: /*
! 237: * Until neighbors are discovered, assume responsibility for sending
! 238: * periodic group membership queries to the subnet. Send the first
! 239: * query.
! 240: */
! 241: v->uv_flags |= VIFF_QUERIER;
! 242: query_groups(v);
! 243:
! 244: /*
! 245: * Send a probe via the new vif to look for neighbors.
! 246: */
! 247: send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME);
! 248: }
! 249:
! 250:
! 251: /*
! 252: * Stop a vif (either physical interface or tunnel).
! 253: * If we are running only PIM we don't have tunnels.
! 254: */
! 255: static void
! 256: stop_vif(vifi)
! 257: vifi_t vifi;
! 258: {
! 259: struct uvif *v;
! 260: struct listaddr *a;
! 261: register pim_nbr_entry_t *n, *next;
! 262: struct vif_acl *acl;
! 263:
! 264: /*
! 265: * TODO: make sure that the kernel viftable is
! 266: * consistent with the daemon table
! 267: */
! 268: v = &uvifs[vifi];
! 269: k_leave(igmp_socket, allpimrouters_group, v->uv_lcl_addr);
! 270: k_leave(igmp_socket, allrouters_group, v->uv_lcl_addr);
! 271: /*
! 272: * Discard all group addresses. (No need to tell kernel;
! 273: * the k_del_vif() call will clean up kernel state.)
! 274: */
! 275: while (v->uv_groups != NULL) {
! 276: a = v->uv_groups;
! 277: v->uv_groups = a->al_next;
! 278: free((char *)a);
! 279: }
! 280:
! 281: /*
! 282: * TODO: inform (eventually) the neighbors I am going down by sending
! 283: * PIM_HELLO with holdtime=0 so someone else should become a DR.
! 284: */
! 285: /* TODO: dummy! Implement it!! Any problems if don't use it? */
! 286: delete_vif_from_mrt(vifi);
! 287:
! 288: /*
! 289: * Delete the interface from the kernel's vif structure.
! 290: */
! 291: k_del_vif(igmp_socket, vifi);
! 292: v->uv_flags = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS )
! 293: | VIFF_DOWN;
! 294: RESET_TIMER(v->uv_pim_hello_timer);
! 295: RESET_TIMER(v->uv_gq_timer);
! 296: for (n = v->uv_pim_neighbors; n != NULL; n = next) {
! 297: next = n->next; /* Free the space for each neighbour */
! 298: free((char *)n);
! 299: }
! 300: v->uv_pim_neighbors = NULL;
! 301:
! 302: /* TODO: currently not used */
! 303: /* The Access Control List (list with the scoped addresses) */
! 304: while (v->uv_acl != NULL) {
! 305: acl = v->uv_acl;
! 306: v->uv_acl = acl->acl_next;
! 307: free((char *)acl);
! 308: }
! 309:
! 310: vifs_down = TRUE;
! 311: log(LOG_INFO, 0,
! 312: "%s goes down; vif #%u out of service", v->uv_name, vifi);
! 313: }
! 314:
! 315:
! 316: /*
! 317: * See if any interfaces have changed from up state to down, or vice versa,
! 318: * including any non-multicast-capable interfaces that are in use as local
! 319: * tunnel end-points. Ignore interfaces that have been administratively
! 320: * disabled.
! 321: */
! 322: void
! 323: check_vif_state()
! 324: {
! 325: register vifi_t vifi;
! 326: register struct uvif *v;
! 327: struct ifreq ifr;
! 328: static int checking_vifs = 0;
! 329:
! 330: /*
! 331: * XXX: TODO: True only for DVMRP?? Check.
! 332: * If we get an error while checking, (e.g. two interfaces go down
! 333: * at once, and we decide to send a prune out one of the failed ones)
! 334: * then don't go into an infinite loop!
! 335: */
! 336: if (checking_vifs)
! 337: return;
! 338:
! 339: vifs_down = FALSE;
! 340: checking_vifs = 1;
! 341: /* TODO: Check all potential interfaces!!! */
! 342: /* Check the physical and tunnels only */
! 343: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 344: if (v->uv_flags & VIFF_DISABLED)
! 345: continue;
! 346:
! 347: strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
! 348: /* get the interface flags */
! 349: if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
! 350: log(LOG_ERR, errno,
! 351: "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
! 352:
! 353: if (v->uv_flags & VIFF_DOWN) {
! 354: if (ifr.ifr_flags & IFF_UP) {
! 355: start_vif(vifi);
! 356: }
! 357: else vifs_down = TRUE;
! 358: }
! 359: else {
! 360: if (!(ifr.ifr_flags & IFF_UP)) {
! 361: log(LOG_NOTICE, 0,
! 362: "%s has gone down; vif #%u taken out of service",
! 363: v->uv_name, vifi);
! 364: stop_vif(vifi);
! 365: vifs_down = TRUE;
! 366: }
! 367: }
! 368: }
! 369: checking_vifs = 0;
! 370: }
! 371:
! 372:
! 373: /*
! 374: * If the source is directly connected to us, find the vif number for
! 375: * the corresponding physical interface (tunnels excluded).
! 376: * Local addresses are excluded.
! 377: * Return the vif number or NO_VIF if not found.
! 378: */
! 379: vifi_t
! 380: find_vif_direct(src)
! 381: u_int32 src;
! 382: {
! 383: vifi_t vifi;
! 384: register struct uvif *v;
! 385: register struct phaddr *p;
! 386:
! 387: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 388: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
! 389: continue;
! 390: if (src == v->uv_lcl_addr)
! 391: return (NO_VIF); /* src is one of our IP addresses */
! 392: if ((src & v->uv_subnetmask) == v->uv_subnet &&
! 393: ((v->uv_subnetmask == 0xffffffff) ||
! 394: (src != v->uv_subnetbcast)))
! 395: return(vifi);
! 396: /* Check the extra subnets for this vif */
! 397: /* TODO: don't think currently pimd can handle extra subnets */
! 398: for (p = v->uv_addrs; p; p = p->pa_next) {
! 399: if ((src & p->pa_subnetmask) == p->pa_subnet &&
! 400: ((p->pa_subnetmask == 0xffffffff) ||
! 401: (src != p->pa_subnetbcast)))
! 402: return(vifi);
! 403: }
! 404: }
! 405: return (NO_VIF);
! 406: }
! 407:
! 408:
! 409: /*
! 410: * Checks if src is local address. If "yes" return the vif index,
! 411: * otherwise return value is NO_VIF.
! 412: */
! 413: vifi_t
! 414: local_address(src)
! 415: u_int32 src;
! 416: {
! 417: vifi_t vifi;
! 418: register struct uvif *v;
! 419:
! 420: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 421: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
! 422: continue;
! 423: if (src != v->uv_lcl_addr)
! 424: continue;
! 425: else
! 426: return(vifi);
! 427: }
! 428: /* Returning NO_VIF means not a local address */
! 429: return (NO_VIF);
! 430: }
! 431:
! 432: /*
! 433: * If the source is directly connected, or is local address,
! 434: * find the vif number for the corresponding physical interface
! 435: * (tunnels excluded).
! 436: * Return the vif number or NO_VIF if not found.
! 437: */
! 438: vifi_t
! 439: find_vif_direct_local(src)
! 440: u_int32 src;
! 441: {
! 442: vifi_t vifi;
! 443: register struct uvif *v;
! 444: register struct phaddr *p;
! 445:
! 446: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 447: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
! 448: continue;
! 449: if (src == v->uv_lcl_addr)
! 450: return (vifi); /* src is one of our IP addresses */
! 451: if ((src & v->uv_subnetmask) == v->uv_subnet &&
! 452: ((v->uv_subnetmask == 0xffffffff) ||
! 453: (src != v->uv_subnetbcast)))
! 454: return(vifi);
! 455: /* Check the extra subnets for this vif */
! 456: /* TODO: don't think currently pimd can handle extra subnets */
! 457: for (p = v->uv_addrs; p; p = p->pa_next) {
! 458: if ((src & p->pa_subnetmask) == p->pa_subnet &&
! 459: ((p->pa_subnetmask == 0xffffffff) ||
! 460: (src != p->pa_subnetbcast)))
! 461: return(vifi);
! 462: }
! 463: }
! 464: return (NO_VIF);
! 465: }
! 466:
! 467: /*
! 468: * Returns the highest address of local vif that is UP and ENABLED.
! 469: */
! 470: u_int32
! 471: max_local_address()
! 472: {
! 473: vifi_t vifi;
! 474: struct uvif *v;
! 475: u_int32 max_address = 0;
! 476:
! 477: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 478: /* Count vif if not DISABLED or DOWN */
! 479: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
! 480: continue;
! 481: if (ntohl(v->uv_lcl_addr) > ntohl(max_address))
! 482: max_address = v->uv_lcl_addr;
! 483: }
! 484: return(max_address);
! 485: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>