Annotation of embedaddon/pimd/config.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998-2001
! 3: * University of Southern California/Information Sciences Institute.
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. Neither the name of the project nor the names of its contributors
! 15: * may be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: */
! 30: /*
! 31: * Part of this program has been derived from mrouted.
! 32: * The mrouted program is covered by the license in the accompanying file
! 33: * named "LICENSE.mrouted".
! 34: *
! 35: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
! 36: * Leland Stanford Junior University.
! 37: *
! 38: */
! 39:
! 40: #include "defs.h"
! 41:
! 42: #define WARN(fmt, args...) logit(LOG_WARNING, 0, "%s:%u - " fmt, config_file, lineno, ##args)
! 43: #define BAILOUT(msg, arg...) { WARN(msg ", bailing out!", ##arg); return FALSE; }
! 44: #define IGNORING(msg, arg...) { WARN(msg ", ignoring ...", ##arg); continue; }
! 45:
! 46: /* Helper macros */
! 47: #define QUERIER_TIMEOUT(qintv) (IGMP_ROBUSTNESS_VARIABLE * (qintv) + IGMP_QUERY_RESPONSE_INTERVAL / 2)
! 48:
! 49: #define LINE_BUFSIZ 1024 /* Max. line length of the config file */
! 50:
! 51: #define CONF_UNKNOWN -1
! 52: #define CONF_EMPTY 1
! 53: #define CONF_PHYINT 2
! 54: #define CONF_CANDIDATE_RP 3
! 55: #define CONF_RP_ADDRESS 4
! 56: #define CONF_GROUP_PREFIX 5
! 57: #define CONF_BOOTSTRAP_RP 6
! 58: #define CONF_COMPAT_THRESHOLD 7
! 59: #define CONF_SPT_THRESHOLD 8
! 60: #define CONF_DEFAULT_ROUTE_METRIC 9
! 61: #define CONF_DEFAULT_ROUTE_DISTANCE 10
! 62: #define CONF_ALTNET 11
! 63: #define CONF_MASKLEN 12
! 64: #define CONF_SCOPED 13
! 65: #define CONF_IGMP_QUERY_INTERVAL 14
! 66: #define CONF_IGMP_QUERIER_TIMEOUT 15
! 67: #define CONF_HELLO_INTERVAL 16
! 68:
! 69: /*
! 70: * Global settings
! 71: */
! 72: uint16_t pim_timer_hello_interval = PIM_TIMER_HELLO_INTERVAL;
! 73: uint16_t pim_timer_hello_holdtime = PIM_TIMER_HELLO_HOLDTIME;
! 74:
! 75: /*
! 76: * Forward declarations.
! 77: */
! 78: static char *next_word (char **);
! 79: static int parse_phyint (char *s);
! 80: static uint32_t ifname2addr (char *s);
! 81:
! 82: static uint32_t lineno;
! 83: extern struct rp_hold *g_rp_hold;
! 84:
! 85: /*
! 86: * Query the kernel to find network interfaces that are multicast-capable
! 87: * and install them in the uvifs array.
! 88: */
! 89: void config_vifs_from_kernel(void)
! 90: {
! 91: struct ifreq *ifrp, *ifend;
! 92: struct uvif *v;
! 93: vifi_t vifi;
! 94: uint32_t n;
! 95: uint32_t addr, mask, subnet;
! 96: short flags;
! 97: int num_ifreq = 64;
! 98: struct ifconf ifc;
! 99: char *newbuf;
! 100:
! 101: total_interfaces = 0; /* The total number of physical interfaces */
! 102:
! 103: ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
! 104: ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char));
! 105: while (ifc.ifc_buf) {
! 106: if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
! 107: logit(LOG_ERR, errno, "Failed querying kernel network interfaces");
! 108:
! 109: /*
! 110: * If the buffer was large enough to hold all the addresses
! 111: * then break out, otherwise increase the buffer size and
! 112: * try again.
! 113: *
! 114: * The only way to know that we definitely had enough space
! 115: * is to know that there was enough space for at least one
! 116: * more struct ifreq. ???
! 117: */
! 118: if ((num_ifreq * sizeof(struct ifreq)) >= ifc.ifc_len + sizeof(struct ifreq))
! 119: break;
! 120:
! 121: num_ifreq *= 2;
! 122: ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
! 123: newbuf = realloc(ifc.ifc_buf, ifc.ifc_len);
! 124: if (newbuf == NULL)
! 125: free(ifc.ifc_buf);
! 126: ifc.ifc_buf = newbuf;
! 127: }
! 128: if (ifc.ifc_buf == NULL)
! 129: logit(LOG_ERR, 0, "config_vifs_from_kernel() ran out of memory");
! 130:
! 131: ifrp = (struct ifreq *)ifc.ifc_buf;
! 132: ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
! 133: /*
! 134: * Loop through all of the interfaces.
! 135: */
! 136: for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
! 137: struct ifreq ifr;
! 138:
! 139: memset (&ifr, 0, sizeof (ifr));
! 140:
! 141: #ifdef HAVE_SA_LEN
! 142: n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
! 143: if (n < sizeof(*ifrp))
! 144: n = sizeof(*ifrp);
! 145: #else
! 146: n = sizeof(*ifrp);
! 147: #endif /* HAVE_SA_LEN */
! 148:
! 149: /*
! 150: * Ignore any interface for an address family other than IP.
! 151: */
! 152: if (ifrp->ifr_addr.sa_family != AF_INET) {
! 153: total_interfaces++; /* Eventually may have IP address later */
! 154: continue;
! 155: }
! 156:
! 157: addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
! 158:
! 159: /*
! 160: * Need a template to preserve address info that is
! 161: * used below to locate the next entry. (Otherwise,
! 162: * SIOCGIFFLAGS stomps over it because the requests
! 163: * are returned in a union.)
! 164: */
! 165: memcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
! 166:
! 167: /*
! 168: * Ignore loopback interfaces and interfaces that do not
! 169: * support multicast.
! 170: */
! 171: if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
! 172: logit(LOG_ERR, errno, "Failed reading interface flags for phyint %s", ifr.ifr_name);
! 173:
! 174: flags = ifr.ifr_flags;
! 175: if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST)
! 176: continue;
! 177:
! 178: /*
! 179: * Everyone below is a potential vif interface.
! 180: * We don't care if it has wrong configuration or not configured
! 181: * at all.
! 182: */
! 183: total_interfaces++;
! 184:
! 185: /*
! 186: * Ignore any interface whose address and mask do not define a
! 187: * valid subnet number, or whose address is of the form
! 188: * {subnet,0} or {subnet,-1}.
! 189: */
! 190: if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0) {
! 191: if (!(flags & IFF_POINTOPOINT))
! 192: logit(LOG_ERR, errno, "Failed reading interface netmask for phyint %s", ifr.ifr_name);
! 193:
! 194: mask = 0xffffffff;
! 195: } else {
! 196: mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
! 197: }
! 198:
! 199: subnet = addr & mask;
! 200: #ifdef DISABLE_MASKLEN_CHECK
! 201: if (mask != 0xffffffff) {
! 202: #endif
! 203: if ((!inet_valid_subnet(subnet, mask)) || (addr == subnet) || addr == (subnet | ~mask)) {
! 204: if (!(inet_valid_host(addr) && ((mask == htonl(0xfffffffe)) || (flags & IFF_POINTOPOINT)))) {
! 205: logit(LOG_WARNING, 0, "Ignoring %s, has invalid address %s and/or netmask %s",
! 206: ifr.ifr_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(mask, s2, sizeof(s2)));
! 207: continue;
! 208: }
! 209: }
! 210: #ifdef DISABLE_MASKLEN_CHECK
! 211: }
! 212: #endif
! 213:
! 214: /*
! 215: * Ignore any interface that is connected to the same subnet as
! 216: * one already installed in the uvifs array.
! 217: */
! 218: /*
! 219: * TODO: XXX: bug or "feature" is to allow only one interface per
! 220: * subnet?
! 221: */
! 222: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 223: if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
! 224: logit(LOG_DEBUG, 0, "Ignoring %s (%s on subnet %s) (alias for vif#%u?)",
! 225: v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask), vifi);
! 226: break;
! 227: }
! 228: /* we don't care about point-to-point links in same subnet */
! 229: if (flags & IFF_POINTOPOINT)
! 230: continue;
! 231: if (v->uv_flags & VIFF_POINT_TO_POINT)
! 232: continue;
! 233: #if 0
! 234: /*
! 235: * TODO: to allow different interfaces belong to
! 236: * overlapping subnet addresses, use this version instead
! 237: */
! 238: if (((addr & mask ) == v->uv_subnet) && (v->uv_subnetmask == mask)) {
! 239: logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name);
! 240: break;
! 241: }
! 242: #else
! 243: if ((addr & v->uv_subnetmask) == v->uv_subnet || (v->uv_subnet & mask) == subnet) {
! 244: logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name);
! 245: break;
! 246: }
! 247: #endif /* 0 */
! 248: }
! 249: if (vifi != numvifs)
! 250: continue;
! 251:
! 252: /*
! 253: * If there is room in the uvifs array, install this interface.
! 254: */
! 255: if (numvifs == MAXVIFS) {
! 256: logit(LOG_WARNING, 0, "Too many vifs, ignoring %s", ifr.ifr_name);
! 257: continue;
! 258: }
! 259: v = &uvifs[numvifs];
! 260: zero_vif(v, FALSE);
! 261: v->uv_lcl_addr = addr;
! 262: v->uv_subnet = subnet;
! 263: v->uv_subnetmask = mask;
! 264: if (mask != htonl(0xfffffffe))
! 265: v->uv_subnetbcast = subnet | ~mask;
! 266: else
! 267: v->uv_subnetbcast = 0xffffffff;
! 268:
! 269: strlcpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
! 270:
! 271: /*
! 272: * Figure out MTU of interface, needed as a seed value when
! 273: * fragmenting PIM register messages. We should really do
! 274: * a PMTU check on initial PIM register send to a new RP...
! 275: */
! 276: if (ioctl(udp_socket, SIOCGIFMTU, &ifr) < 0)
! 277: v->uv_mtu = 1500;
! 278: else
! 279: v->uv_mtu = ifr.ifr_mtu;
! 280:
! 281: if (flags & IFF_POINTOPOINT) {
! 282: v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
! 283: if (ioctl(udp_socket, SIOCGIFDSTADDR, (char *)&ifr) < 0)
! 284: logit(LOG_ERR, errno, "Failed reading point-to-point address for %s", v->uv_name);
! 285: else
! 286: v->uv_rmt_addr = ((struct sockaddr_in *)(&ifr.ifr_dstaddr))->sin_addr.s_addr;
! 287: } else if (mask == htonl(0xfffffffe)) {
! 288: /*
! 289: * Handle RFC 3021 /31 netmasks as point-to-point links
! 290: */
! 291: v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
! 292: if (addr == subnet)
! 293: v->uv_rmt_addr = addr + htonl(1);
! 294: else
! 295: v->uv_rmt_addr = subnet;
! 296: }
! 297: #ifdef __linux__
! 298: {
! 299: struct ifreq ifridx;
! 300:
! 301: memset(&ifridx, 0, sizeof(ifridx));
! 302: strlcpy(ifridx.ifr_name,v->uv_name, IFNAMSIZ);
! 303: if (ioctl(udp_socket, SIOGIFINDEX, (char *) &ifridx) < 0)
! 304: logit(LOG_ERR, errno, "Failed reading interface index for %s", ifridx.ifr_name);
! 305: v->uv_ifindex = ifridx.ifr_ifindex;
! 306: }
! 307: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 308: logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u-%d - rate %d",
! 309: v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)),
! 310: numvifs, v->uv_ifindex, v->uv_rate_limit);
! 311: } else {
! 312: logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u-%d - rate %d",
! 313: v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask),
! 314: numvifs, v->uv_ifindex, v->uv_rate_limit);
! 315: }
! 316: #else /* !__linux__ */
! 317: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 318: logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u - rate=%d",
! 319: v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)),
! 320: numvifs, v->uv_rate_limit);
! 321: } else {
! 322: logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u - rate %d",
! 323: v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask),
! 324: numvifs, v->uv_rate_limit);
! 325: }
! 326: #endif /* __linux__ */
! 327:
! 328: ++numvifs;
! 329:
! 330: /*
! 331: * If the interface is not yet up, set the vifs_down flag to
! 332: * remind us to check again later.
! 333: */
! 334: if (!(flags & IFF_UP)) {
! 335: v->uv_flags |= VIFF_DOWN;
! 336: vifs_down = TRUE;
! 337: }
! 338: }
! 339: }
! 340:
! 341: static int deprecated(char *word, char *new_word, int code)
! 342: {
! 343: WARN("The %s option is deprecated, replaced with %s", word, new_word);
! 344: WARN("Please update your configuration file!");
! 345:
! 346: return code;
! 347: }
! 348:
! 349: /**
! 350: * parse_option - Convert result of string comparisons into numerics.
! 351: * @input: Pointer to the word
! 352: *
! 353: * This function is called by config_vifs_from_file().
! 354: *
! 355: * Returns:
! 356: * A number corresponding to the code of the word, or %CONF_UNKNOWN.
! 357: */
! 358: static int parse_option(char *word)
! 359: {
! 360: if (EQUAL(word, ""))
! 361: return CONF_EMPTY;
! 362: if (EQUAL(word, "phyint"))
! 363: return CONF_PHYINT;
! 364: if (EQUAL(word, "bsr-candidate"))
! 365: return CONF_BOOTSTRAP_RP;
! 366: if (EQUAL(word, "rp-candidate"))
! 367: return CONF_CANDIDATE_RP;
! 368: if (EQUAL(word, "rp-address"))
! 369: return CONF_RP_ADDRESS;
! 370: if (EQUAL(word, "group-prefix"))
! 371: return CONF_GROUP_PREFIX;
! 372: if (EQUAL(word, "spt-threshold"))
! 373: return CONF_SPT_THRESHOLD;
! 374: if (EQUAL(word, "default-route-metric"))
! 375: return CONF_DEFAULT_ROUTE_METRIC;
! 376: if (EQUAL(word, "default-route-distance"))
! 377: return CONF_DEFAULT_ROUTE_DISTANCE;
! 378: if (EQUAL(word, "igmp-query-interval"))
! 379: return CONF_IGMP_QUERY_INTERVAL;
! 380: if (EQUAL(word, "igmp-querier-timeout"))
! 381: return CONF_IGMP_QUERIER_TIMEOUT;
! 382: if (EQUAL(word, "altnet"))
! 383: return CONF_ALTNET;
! 384: if (EQUAL(word, "masklen"))
! 385: return CONF_MASKLEN;
! 386: if (EQUAL(word, "scoped"))
! 387: return CONF_SCOPED;
! 388: if (EQUAL(word, "hello-interval"))
! 389: return CONF_HELLO_INTERVAL;
! 390:
! 391: /* Compatibility with old config files that use _ instead of - */
! 392: if (EQUAL(word, "cand_bootstrap_router"))
! 393: return CONF_BOOTSTRAP_RP;
! 394: if (EQUAL(word, "cand_rp"))
! 395: return CONF_CANDIDATE_RP;
! 396: if (EQUAL(word, "group_prefix"))
! 397: return CONF_GROUP_PREFIX;
! 398: if (EQUAL(word, "rp_address"))
! 399: return CONF_RP_ADDRESS;
! 400: if (EQUAL(word, "switch_register_threshold"))
! 401: return deprecated(word, "spt-threshold", CONF_COMPAT_THRESHOLD);
! 402: if (EQUAL(word, "switch_data_threshold"))
! 403: return deprecated(word, "spt-threshold", CONF_COMPAT_THRESHOLD);
! 404: if (EQUAL(word, "spt_threshold"))
! 405: return CONF_SPT_THRESHOLD;
! 406: if (EQUAL(word, "default_source_metric"))
! 407: return CONF_DEFAULT_ROUTE_METRIC;
! 408: if (EQUAL(word, "default_source_preference"))
! 409: return CONF_DEFAULT_ROUTE_DISTANCE;
! 410: if (EQUAL(word, "default_igmp_query_interval")) /* compat */
! 411: return CONF_IGMP_QUERY_INTERVAL;
! 412: if (EQUAL(word, "default_igmp_querier_timeout")) /* compat */
! 413: return CONF_IGMP_QUERIER_TIMEOUT;
! 414: if (EQUAL(word, "hello_period"))
! 415: return CONF_HELLO_INTERVAL;
! 416:
! 417: return CONF_UNKNOWN;
! 418: }
! 419:
! 420: /* Check for optional /PREFIXLEN suffix to the address/group */
! 421: static void parse_prefix_len(char *token, uint32_t *len)
! 422: {
! 423: char *masklen = strchr(token, '/');
! 424:
! 425: if (masklen) {
! 426: *masklen = 0;
! 427: masklen++;
! 428: if (!sscanf(masklen, "%u", len)) {
! 429: WARN("Invalid masklen '%s'", masklen);
! 430: *len = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
! 431: }
! 432: }
! 433: }
! 434:
! 435: static void validate_prefix_len(uint32_t *len)
! 436: {
! 437: if (*len > (sizeof(uint32_t) * 8)) {
! 438: *len = (sizeof(uint32_t) * 8);
! 439: } else if (*len < PIM_GROUP_PREFIX_MIN_MASKLEN) {
! 440: WARN("Too small masklen %u. Defaulting to %d", *len, PIM_GROUP_PREFIX_MIN_MASKLEN);
! 441: *len = PIM_GROUP_PREFIX_MIN_MASKLEN;
! 442: }
! 443: }
! 444:
! 445:
! 446: /**
! 447: * parse_phyint - Parse physical interface configuration, if any.
! 448: * @s: String token
! 449: *
! 450: * Syntax:
! 451: * phyint <local-addr | ifname> [disable | enable]
! 452: * [igmpv2 | igmpv3]
! 453: * [dr-priority <1-4294967294>]
! 454: * [ttl-threshold <1-255>]
! 455: * [distance <1-255>] [metric <1-1024>]
! 456: * [altnet <net-addr>/<masklen>]
! 457: * [altnet <net-addr> masklen <masklen>]
! 458: * [scoped <net-addr>/<masklen>]
! 459: * [scoped <net-addr> masklen <masklen>]
! 460: *
! 461: * Returns:
! 462: * %TRUE if the parsing was successful, o.w. %FALSE
! 463: */
! 464: static int parse_phyint(char *s)
! 465: {
! 466: char *w, c;
! 467: uint32_t local, altnet_addr, scoped_addr;
! 468: vifi_t vifi;
! 469: struct uvif *v;
! 470: uint32_t n, altnet_masklen = 0, scoped_masklen = 0;
! 471: struct phaddr *ph;
! 472: struct vif_acl *v_acl;
! 473:
! 474: if (EQUAL((w = next_word(&s)), "")) {
! 475: WARN("Missing phyint address");
! 476: return FALSE;
! 477: }
! 478:
! 479: local = ifname2addr(w);
! 480: if (!local) {
! 481: local = inet_parse(w, 4);
! 482: if (!inet_valid_host(local)) {
! 483: WARN("Invalid phyint address '%s'", w);
! 484: return FALSE;
! 485: }
! 486: }
! 487:
! 488: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 489: if (vifi == numvifs) {
! 490: WARN("phyint %s is not a valid interface", inet_fmt(local, s1, sizeof(s1)));
! 491: return FALSE;
! 492: }
! 493:
! 494: if (local != v->uv_lcl_addr)
! 495: continue;
! 496:
! 497: while (!EQUAL((w = next_word(&s)), "")) {
! 498: if (EQUAL(w, "disable")) {
! 499: v->uv_flags |= VIFF_DISABLED;
! 500: continue;
! 501: }
! 502:
! 503: if (EQUAL(w, "enable")) {
! 504: v->uv_flags &= ~VIFF_DISABLED;
! 505: continue;
! 506: }
! 507:
! 508: if (EQUAL(w, "igmpv2")) {
! 509: v->uv_flags &= ~VIFF_IGMPV1;
! 510: v->uv_flags |= VIFF_IGMPV2;
! 511: continue;
! 512: }
! 513:
! 514: if (EQUAL(w, "igmpv3")) {
! 515: v->uv_flags &= ~VIFF_IGMPV1;
! 516: v->uv_flags &= ~VIFF_IGMPV2;
! 517: continue;
! 518: }
! 519:
! 520: if (EQUAL(w, "altnet")) {
! 521: if (EQUAL((w = next_word(&s)), "")) {
! 522: WARN("Missing ALTNET for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 523: continue;
! 524: }
! 525:
! 526: parse_prefix_len (w, &altnet_masklen);
! 527:
! 528: altnet_addr = ifname2addr(w);
! 529: if (!altnet_addr) {
! 530: altnet_addr = inet_parse(w, 4);
! 531: if (!inet_valid_host(altnet_addr)) {
! 532: WARN("Invalid altnet address '%s'", w);
! 533: return FALSE;
! 534: }
! 535: }
! 536:
! 537: if (EQUAL((w = next_word(&s)), "masklen")) {
! 538: if (EQUAL((w = next_word(&s)), "")) {
! 539: WARN("Missing ALTNET masklen for phyint %s", inet_fmt(local, s1, sizeof (s1)));
! 540: continue;
! 541: }
! 542:
! 543: if (!sscanf(w, "%u", &altnet_masklen)) {
! 544: WARN("Invalid altnet masklen '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 545: continue;
! 546: }
! 547: }
! 548:
! 549: ph = (struct phaddr *)calloc(1, sizeof(struct phaddr));
! 550: if (!ph)
! 551: return FALSE;
! 552:
! 553: if (altnet_masklen) {
! 554: VAL_TO_MASK(ph->pa_subnetmask, altnet_masklen);
! 555: } else {
! 556: ph->pa_subnetmask = v->uv_subnetmask;
! 557: }
! 558:
! 559: ph->pa_subnet = altnet_addr & ph->pa_subnetmask;
! 560: ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
! 561: if (altnet_addr & ~ph->pa_subnetmask)
! 562: WARN("Extra subnet %s/%d has host bits set", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen);
! 563:
! 564: ph->pa_next = v->uv_addrs;
! 565: v->uv_addrs = ph;
! 566: logit(LOG_DEBUG, 0, "ALTNET: %s/%d", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen);
! 567: } /* altnet */
! 568:
! 569: /* scoped mcast groups/masklen */
! 570: if (EQUAL(w, "scoped")) {
! 571: if (EQUAL((w = next_word(&s)), "")) {
! 572: WARN("Missing SCOPED for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 573: continue;
! 574: }
! 575:
! 576: parse_prefix_len (w, &scoped_masklen);
! 577:
! 578: scoped_addr = ifname2addr(w);
! 579: if (!scoped_addr) {
! 580: scoped_addr = inet_parse(w, 4);
! 581: if (!IN_MULTICAST(ntohl(scoped_addr))) {
! 582: WARN("Invalid scoped address '%s'", w);
! 583: return FALSE;
! 584: }
! 585: }
! 586:
! 587: if (EQUAL((w = next_word(&s)), "masklen")) {
! 588: if (EQUAL((w = next_word(&s)), "")) {
! 589: WARN("Missing SCOPED masklen for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 590: continue;
! 591: }
! 592: if (sscanf(w, "%u", &scoped_masklen) != 1) {
! 593: WARN("Invalid scoped masklen '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 594: continue;
! 595: }
! 596: }
! 597:
! 598: /* Invalid config. VAL_TO_MASK() also requires len > 0 or shift op will fail. */
! 599: if (!scoped_masklen) {
! 600: WARN("Too small (0) scoped masklen for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 601: continue;
! 602: }
! 603:
! 604: v_acl = (struct vif_acl *)calloc(1, sizeof(struct vif_acl));
! 605: if (!v_acl)
! 606: return FALSE;
! 607:
! 608: VAL_TO_MASK(v_acl->acl_mask, scoped_masklen);
! 609: v_acl->acl_addr = scoped_addr & v_acl->acl_mask;
! 610: if (scoped_addr & ~v_acl->acl_mask)
! 611: WARN("Boundary spec %s/%d has host bits set", inet_fmt(scoped_addr, s1, sizeof(s1)), scoped_masklen);
! 612:
! 613: v_acl->acl_next = v->uv_acl;
! 614: v->uv_acl = v_acl;
! 615: logit(LOG_DEBUG, 0, "SCOPED %s/%x", inet_fmt(v_acl->acl_addr, s1, sizeof(s1)), v_acl->acl_mask);
! 616: } /* scoped */
! 617:
! 618: if (EQUAL(w, "ttl-threshold") || EQUAL(w, "threshold")) {
! 619: if (EQUAL((w = next_word(&s)), "")) {
! 620: WARN("Missing threshold for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 621: continue;
! 622: }
! 623:
! 624: if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) {
! 625: WARN("Invalid threshold '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 626: continue;
! 627: }
! 628:
! 629: v->uv_threshold = n;
! 630: continue;
! 631: } /* threshold */
! 632:
! 633: if (EQUAL(w, "distance") || EQUAL(w, "preference")) {
! 634: if (EQUAL((w = next_word(&s)), "")) {
! 635: WARN("Missing distance value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 636: continue;
! 637: }
! 638:
! 639: if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) {
! 640: WARN("Invalid distance value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 641: continue;
! 642: }
! 643:
! 644: IF_DEBUG(DEBUG_ASSERT)
! 645: logit(LOG_DEBUG, 0, "Config setting default local preference on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
! 646:
! 647: v->uv_local_pref = n;
! 648: continue;
! 649: }
! 650:
! 651: if (EQUAL(w, "metric")) {
! 652: if (EQUAL((w = next_word(&s)), "")) {
! 653: WARN("Missing metric value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 654: continue;
! 655: }
! 656:
! 657: if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 1024 ) {
! 658: WARN("Invalid metric value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 659: continue;
! 660: }
! 661:
! 662: IF_DEBUG(DEBUG_ASSERT)
! 663: logit(LOG_DEBUG, 0, "Setting default local metric on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
! 664:
! 665: v->uv_local_metric = n;
! 666: continue;
! 667: }
! 668:
! 669: if (EQUAL(w, "dr-priority")) {
! 670: if (EQUAL((w = next_word(&s)), "")) {
! 671: WARN("Missing dr-priority value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
! 672: continue;
! 673: }
! 674:
! 675: if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 4294967294u) {
! 676: WARN("Invalid dr-priority value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
! 677: continue;
! 678: }
! 679:
! 680: IF_DEBUG(DEBUG_PIM_HELLO)
! 681: logit(LOG_DEBUG, 0, "Setting dr-priority on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
! 682:
! 683: v->uv_dr_prio = n;
! 684: continue;
! 685: }
! 686: } /* while(... != "") */
! 687:
! 688: break;
! 689: }
! 690:
! 691: return TRUE;
! 692: }
! 693:
! 694:
! 695: /**
! 696: * parse_rp_candidate - Parse candidate Rendez-Vous Point information.
! 697: * @s: String token
! 698: *
! 699: * Syntax:
! 700: * rp-candidate [address | ifname] [priority <0-255>] [time <10-16383>]
! 701: *
! 702: * Returns:
! 703: * %TRUE if the parsing was successful, o.w. %FALSE
! 704: */
! 705: int parse_rp_candidate(char *s)
! 706: {
! 707: u_int time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
! 708: u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY;
! 709: char *w;
! 710: uint32_t local = INADDR_ANY_N;
! 711:
! 712: cand_rp_flag = FALSE;
! 713: my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
! 714: while (!EQUAL((w = next_word(&s)), "")) {
! 715: if (EQUAL(w, "priority")) {
! 716: if (EQUAL((w = next_word(&s)), "")) {
! 717: WARN("Missing priority, defaulting to %u", w, PIM_DEFAULT_CAND_RP_PRIORITY);
! 718: priority = PIM_DEFAULT_CAND_RP_PRIORITY;
! 719: continue;
! 720: }
! 721:
! 722: if (sscanf(w, "%u", &priority) != 1) {
! 723: WARN("Invalid priority %s, defaulting to %u", w, PIM_DEFAULT_CAND_RP_PRIORITY);
! 724: priority = PIM_DEFAULT_CAND_RP_PRIORITY;
! 725: }
! 726:
! 727: if (priority > PIM_MAX_CAND_RP_PRIORITY) {
! 728: WARN("Too high Cand-RP priority %u, defaulting to %d", priority, PIM_MAX_CAND_RP_PRIORITY);
! 729: priority = PIM_MAX_CAND_RP_PRIORITY;
! 730: }
! 731:
! 732: continue;
! 733: }
! 734:
! 735: if (EQUAL(w, "time")) {
! 736: if (EQUAL((w = next_word(&s)), "")) {
! 737: WARN("Missing Cand-RP announce interval, defaulting to %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD);
! 738: time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
! 739: continue;
! 740: }
! 741:
! 742: if (sscanf(w, "%u", &time) != 1) {
! 743: WARN("Invalid Cand-RP announce interval, defaulting to %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD);
! 744: time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
! 745: continue;
! 746: }
! 747:
! 748: if (time < PIM_MIN_CAND_RP_ADV_PERIOD)
! 749: time = PIM_MIN_CAND_RP_ADV_PERIOD;
! 750:
! 751: if (time > PIM_MAX_CAND_RP_ADV_PERIOD)
! 752: time = PIM_MAX_CAND_RP_ADV_PERIOD;
! 753:
! 754: my_cand_rp_adv_period = time;
! 755: continue;
! 756: }
! 757:
! 758: /* Cand-RP interface or address */
! 759: local = ifname2addr(w);
! 760: if (!local)
! 761: local = inet_parse(w, 4);
! 762:
! 763: if (!inet_valid_host(local)) {
! 764: local = max_local_address();
! 765: WARN("Invalid Cand-RP address '%s', defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
! 766: } else if (local_address(local) == NO_VIF) {
! 767: local = max_local_address();
! 768: WARN("Cand-RP address '%s' is not local, defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
! 769: }
! 770: }
! 771:
! 772: if (local == INADDR_ANY_N) {
! 773: /* If address not provided, use the max. local */
! 774: local = max_local_address();
! 775: }
! 776:
! 777: my_cand_rp_address = local;
! 778: my_cand_rp_priority = priority;
! 779: my_cand_rp_adv_period = time;
! 780: cand_rp_flag = TRUE;
! 781:
! 782: logit(LOG_INFO, 0, "Local Cand-RP address %s, priority %u, interval %u sec",
! 783: inet_fmt(local, s1, sizeof(s1)), priority, time);
! 784:
! 785: return TRUE;
! 786: }
! 787:
! 788:
! 789: /**
! 790: * parse_group_prefix - Parse group-prefix configured information.
! 791: * @s: String token
! 792:
! 793: * Syntax:
! 794: * group-prefix <group>[/<masklen>]
! 795: * <group> [masklen <masklen>]
! 796: *
! 797: * Returns:
! 798: * %TRUE if the parsing was successful, o.w. %FALSE
! 799: */
! 800: int parse_group_prefix(char *s)
! 801: {
! 802: char *w;
! 803: uint32_t group_addr;
! 804: uint32_t masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
! 805:
! 806: w = next_word(&s);
! 807: if (EQUAL(w, "")) {
! 808: WARN("Missing group-prefix address");
! 809: return FALSE;
! 810: }
! 811:
! 812: parse_prefix_len (w, &masklen);
! 813:
! 814: group_addr = inet_parse(w, 4);
! 815: if (!IN_MULTICAST(ntohl(group_addr))) {
! 816: WARN("Group address '%s' is not a valid multicast address", inet_fmt(group_addr, s1, sizeof(s1)));
! 817: return FALSE;
! 818: }
! 819:
! 820: /* Was if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) which Arm GCC 4.4.2 dislikes:
! 821: * --> "config.c:693: warning: promoted ~unsigned is always non-zero"
! 822: * The prefix_cnt_ptr is a uint8_t so it seems this check was to prevent overruns.
! 823: * I've changed the check to see if we've already read 255 entries, if so the cnt
! 824: * is maximized and we need to tell the user. --Joachim Nilsson 2010-01-16 */
! 825: if (*cand_rp_adv_message.prefix_cnt_ptr == 255) {
! 826: WARN("Too many multicast groups configured!");
! 827: return FALSE;
! 828: }
! 829:
! 830: if (EQUAL((w = next_word(&s)), "masklen")) {
! 831: w = next_word(&s);
! 832: if (!sscanf(w, "%u", &masklen))
! 833: masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
! 834: }
! 835:
! 836: validate_prefix_len(&masklen);
! 837:
! 838: PUT_EGADDR(group_addr, (uint8_t)masklen, 0, cand_rp_adv_message.insert_data_ptr);
! 839: (*cand_rp_adv_message.prefix_cnt_ptr)++;
! 840:
! 841: logit(LOG_INFO, 0, "Adding Cand-RP group prefix %s/%d", inet_fmt(group_addr, s1, sizeof(s1)), masklen);
! 842:
! 843: return TRUE;
! 844: }
! 845:
! 846:
! 847: /**
! 848: * parse_bsr_candidate - Parse the candidate BSR configured information.
! 849: * @s: String token
! 850: *
! 851: * Syntax:
! 852: * bsr-candidate [address | ifname] [priority <0-255>]
! 853: */
! 854: int parse_bsr_candidate(char *s)
! 855: {
! 856: char *w;
! 857: uint32_t local = INADDR_ANY_N;
! 858: uint32_t priority = PIM_DEFAULT_BSR_PRIORITY;
! 859:
! 860: cand_bsr_flag = FALSE;
! 861: while (!EQUAL((w = next_word(&s)), "")) {
! 862: if (EQUAL(w, "priority")) {
! 863: if (EQUAL((w = next_word(&s)), "")) {
! 864: WARN("Missing Cand-BSR priority, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
! 865: priority = PIM_DEFAULT_BSR_PRIORITY;
! 866: continue;
! 867: }
! 868:
! 869: if (sscanf(w, "%u", &priority) != 1) {
! 870: WARN("Invalid Cand-BSR priority %s, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
! 871: priority = PIM_DEFAULT_BSR_PRIORITY;
! 872: continue;
! 873: }
! 874:
! 875: if (priority > PIM_MAX_CAND_BSR_PRIORITY) {
! 876: WARN("Too high Cand-BSR priority %u, defaulting to %d", priority, PIM_MAX_CAND_BSR_PRIORITY);
! 877: priority = PIM_MAX_CAND_BSR_PRIORITY;
! 878: }
! 879:
! 880: my_bsr_priority = (uint8_t)priority;
! 881: continue;
! 882: }
! 883:
! 884: /* Cand-BSR interface or address */
! 885: local = ifname2addr(w);
! 886: if (!local)
! 887: local = inet_parse(w, 4);
! 888:
! 889: if (!inet_valid_host(local)) {
! 890: local = max_local_address();
! 891: WARN("Invalid Cand-BSR address '%s', defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
! 892: continue;
! 893: }
! 894:
! 895: if (local_address(local) == NO_VIF) {
! 896: local = max_local_address();
! 897: WARN("Cand-BSR address '%s' is not local, defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
! 898: }
! 899: }
! 900:
! 901: if (local == INADDR_ANY_N) {
! 902: /* If address not provided, use the max. local */
! 903: local = max_local_address();
! 904: }
! 905:
! 906: my_bsr_address = local;
! 907: my_bsr_priority = priority;
! 908: MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, my_bsr_hash_mask);
! 909: cand_bsr_flag = TRUE;
! 910: logit(LOG_INFO, 0, "Local Cand-BSR address %s, priority %u", inet_fmt(local, s1, sizeof(s1)), priority);
! 911:
! 912: return TRUE;
! 913: }
! 914:
! 915: /**
! 916: * parse_rp_address - Parse rp-address config option.
! 917: * @s: String token.
! 918: *
! 919: * This is an extension to the original pimd to add pimd.conf support for static
! 920: * Rendez-Vous Point addresses.
! 921: *
! 922: * The function has been extended by pjf@asn.pl, of Lintrack, to allow specifying
! 923: * multicast group addresses as well.
! 924: *
! 925: * Syntax:
! 926: * rp-address <ADDRESS> [<GROUP>[</LENGTH> masklen <LENGTH>]
! 927: *
! 928: * Returns:
! 929: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 930: */
! 931: int parse_rp_address(char *s)
! 932: {
! 933: char *w;
! 934: uint32_t local = 0xffffff;
! 935: uint32_t group_addr = htonl(INADDR_UNSPEC_GROUP);
! 936: uint32_t masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
! 937: struct rp_hold *rph;
! 938:
! 939: /* next is RP addr */
! 940: w = next_word(&s);
! 941: if (EQUAL(w, "")) {
! 942: logit(LOG_WARNING, 0, "Missing rp-address argument");
! 943: return FALSE;
! 944: }
! 945:
! 946: local = inet_parse(w, 4);
! 947: if (local == 0xffffff) {
! 948: WARN("Invalid rp-address %s", w);
! 949: return FALSE;
! 950: }
! 951:
! 952: /* next is group addr if exist */
! 953: w = next_word(&s);
! 954: if (!EQUAL(w, "")) {
! 955: parse_prefix_len (w, &masklen);
! 956:
! 957: group_addr = inet_parse(w, 4);
! 958: if (!IN_MULTICAST(ntohl(group_addr))) {
! 959: WARN("%s is not a valid multicast address", inet_fmt(group_addr, s1, sizeof(s1)));
! 960: return FALSE;
! 961: }
! 962:
! 963: /* next is prefix or priority if exist */
! 964: while (!EQUAL((w = next_word(&s)), "")) {
! 965: if (EQUAL(w, "masklen")) {
! 966: w = next_word(&s);
! 967: if (!sscanf(w, "%u", &masklen)) {
! 968: WARN("Invalid masklen %s. Defaulting to %d)", w, PIM_GROUP_PREFIX_DEFAULT_MASKLEN);
! 969: masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
! 970: }
! 971: }
! 972:
! 973: /* Unused, but keeping for backwards compatibility for people who
! 974: * may still have this option in their pimd.conf
! 975: * The priority of a static RP is hardcoded to always be 1, see Juniper's
! 976: * configuration or similar sources for reference. */
! 977: if (EQUAL(w, "priority")) {
! 978: w = next_word(&s);
! 979: WARN("The priority of static RP's is, as of pimd 2.2.0, always 1.");
! 980: }
! 981: }
! 982: } else {
! 983: group_addr = htonl(INADDR_UNSPEC_GROUP);
! 984: masklen = PIM_GROUP_PREFIX_MIN_MASKLEN;
! 985: }
! 986:
! 987: validate_prefix_len(&masklen);
! 988:
! 989: rph = calloc(1, sizeof(*rph));
! 990: if (!rph) {
! 991: logit(LOG_WARNING, 0, "Out of memory when parsing rp-address %s",
! 992: inet_fmt(local, s1, sizeof(s1)));
! 993: return FALSE;
! 994: }
! 995:
! 996: rph->address = local;
! 997: rph->group = group_addr;
! 998: VAL_TO_MASK(rph->mask, masklen);
! 999:
! 1000: /* attach at the beginning */
! 1001: rph->next = g_rp_hold;
! 1002: g_rp_hold = rph;
! 1003:
! 1004: logit(LOG_INFO, 0, "Local static RP: %s, group %s/%d",
! 1005: inet_fmt(local, s1, sizeof(s1)), inet_fmt(group_addr, s2, sizeof(s2)), masklen);
! 1006:
! 1007: return TRUE;
! 1008: }
! 1009:
! 1010:
! 1011: /**
! 1012: * parse_compat_threshold - Parse old deprecated pimd.conf thresholds
! 1013: * @line:
! 1014: *
! 1015: * This is a backwards compatible parser for the two older threshold
! 1016: * settings used in pimd prior to v2.2.0. The switchover mechanism has
! 1017: * been completely changed, however, so we simply read the settings as
! 1018: * if they where the same as the new spt-threshold, only converting the
! 1019: * rate argument differently (bps vs kbps). Last line to be read is
! 1020: * what is activated in pimd as spt-threshold.
! 1021: *
! 1022: * Note, previously the parser was very lenient to errors, but since the
! 1023: * default has changed it is much more strict. Any syntax error and pimd
! 1024: * bails out ignoring the line.
! 1025: *
! 1026: * Syntax:
! 1027: * switch_register_threshold [rate <BPS> interval <SEC>]
! 1028: * switch_data_threshold [rate <BPS> interval <SEC>]
! 1029: *
! 1030: * Returns:
! 1031: * When parsing @line is successful, returns %TRUE, otherwise %FALSE.
! 1032: */
! 1033: static int parse_compat_threshold(char *line)
! 1034: {
! 1035: char *w;
! 1036: int rate = -1;
! 1037: int interval = -1;
! 1038:
! 1039: while (!EQUAL((w = next_word(&line)), "")) {
! 1040: if (EQUAL(w, "rate")) {
! 1041: if (EQUAL((w = next_word(&line)), ""))
! 1042: BAILOUT("Missing rate value in compat threshold parser");
! 1043:
! 1044: /* 10 --> 1,000,000,000 == 100 Gbps */
! 1045: if (sscanf(w, "%10d", &rate) != 1)
! 1046: BAILOUT("Invalid rate value %s in compat threshold parser", w);
! 1047:
! 1048: continue;
! 1049: }
! 1050:
! 1051: if (EQUAL(w, "interval")) {
! 1052: if (EQUAL((w = next_word(&line)), ""))
! 1053: IGNORING("Missing interval value in compat threshold parser");
! 1054:
! 1055: /* 5 --> 99,999 ~= 27h */
! 1056: if (sscanf(w, "%5d", &interval) != 1)
! 1057: IGNORING("Invalid interval %s in compat threshold parser", w);
! 1058:
! 1059: continue;
! 1060: }
! 1061: }
! 1062:
! 1063: /* Set polling mode */
! 1064: spt_threshold.mode = SPT_RATE;
! 1065:
! 1066: /* Only accept values if they don't messup for new spt-threshold */
! 1067: if (interval >= TIMER_INTERVAL)
! 1068: spt_threshold.interval = interval;
! 1069:
! 1070: /* Accounting for headers we can approximate 1 byte/s == 10 bits/s (bps) */
! 1071: spt_threshold.bytes = rate * spt_threshold.interval / 10;
! 1072:
! 1073: logit(LOG_INFO, 0, "Compatibility set spt-treshold rate %u kbps with interval %u sec",
! 1074: spt_threshold.bytes, spt_threshold.interval);
! 1075:
! 1076: return TRUE;
! 1077: }
! 1078:
! 1079:
! 1080: /**
! 1081: * parse_hello_interval - Parse and assign the hello interval
! 1082: * @s: Input data
! 1083: *
! 1084: * Syntax:
! 1085: * hello-interval <SEC>
! 1086: *
! 1087: * Returns:
! 1088: * %TRUE if successful, otherwise %FALSE.
! 1089: */
! 1090: int parse_hello_interval(char *s)
! 1091: {
! 1092: char *w;
! 1093: u_int period;
! 1094: u_int holdtime;
! 1095:
! 1096: if (!EQUAL((w = next_word(&s)), "")) {
! 1097: if (sscanf(w, "%u", &period) != 1) {
! 1098: logit(LOG_WARNING, 0, "Invalid hello-interval %s; defaulting to %u", w, PIM_TIMER_HELLO_INTERVAL);
! 1099: period = PIM_TIMER_HELLO_INTERVAL;
! 1100: holdtime = PIM_TIMER_HELLO_HOLDTIME;
! 1101: } else {
! 1102: if (period <= (u_int)(UINT16_MAX / 3.5)) {
! 1103: holdtime = period * 3.5;
! 1104: } else {
! 1105: logit(LOG_WARNING, 0, "Too large hello-interval %s; defaulting to %u", w, PIM_TIMER_HELLO_INTERVAL);
! 1106: period = PIM_TIMER_HELLO_INTERVAL;
! 1107: holdtime = PIM_TIMER_HELLO_HOLDTIME;
! 1108: }
! 1109: }
! 1110: } else {
! 1111: logit(LOG_WARNING, 0, "Missing hello-interval value; defaulting to %u", PIM_TIMER_HELLO_INTERVAL);
! 1112: period = PIM_TIMER_HELLO_INTERVAL;
! 1113: holdtime = PIM_TIMER_HELLO_HOLDTIME;
! 1114: }
! 1115:
! 1116: logit(LOG_INFO, 0, "hello-interval is %u", period);
! 1117: pim_timer_hello_interval = period;
! 1118: pim_timer_hello_holdtime = holdtime;
! 1119:
! 1120: return TRUE;
! 1121: }
! 1122:
! 1123:
! 1124: /**
! 1125: * parse_spt_threshold - Parse spt-threshold option
! 1126: * @s: String token
! 1127: *
! 1128: * This configuration setting replaces the switch_register_threshold and
! 1129: * switch_data_threshold. It is more intuitive and more in line with
! 1130: * what major vendors are also using.
! 1131: *
! 1132: * Note that the rate is in kbps instead of bps, compared to the old
! 1133: * syntax. Both the above parse_compat_threshold() and this function
! 1134: * target the same backend.
! 1135: *
! 1136: * Syntax:
! 1137: * spt-threshold [rate <KBPS> | packets <NUM> | infinity] [interval <SEC>]
! 1138: *
! 1139: * Returns:
! 1140: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 1141: */
! 1142: static int parse_spt_threshold(char *s)
! 1143: {
! 1144: char *w;
! 1145: uint32_t rate = SPT_THRESHOLD_DEFAULT_RATE;
! 1146: uint32_t packets = SPT_THRESHOLD_DEFAULT_PACKETS;
! 1147: uint32_t interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
! 1148: spt_mode_t mode = SPT_THRESHOLD_DEFAULT_MODE;
! 1149:
! 1150: while (!EQUAL((w = next_word(&s)), "")) {
! 1151: if (EQUAL(w, "rate")) {
! 1152: mode = SPT_RATE;
! 1153:
! 1154: if (EQUAL((w = next_word(&s)), "")) {
! 1155: WARN("Missing spt-threshold rate argument, defaulting to %u", SPT_THRESHOLD_DEFAULT_RATE);
! 1156: rate = SPT_THRESHOLD_DEFAULT_RATE;
! 1157: continue;
! 1158: }
! 1159:
! 1160: /* 10 --> 1,000,000,000 == 100 Gbps */
! 1161: if (sscanf(w, "%10u", &rate) != 1) {
! 1162: WARN("Invalid spt-threshold rate %s, defaulting to %u", w, SPT_THRESHOLD_DEFAULT_RATE);
! 1163: rate = SPT_THRESHOLD_DEFAULT_RATE;
! 1164: }
! 1165:
! 1166: continue;
! 1167: }
! 1168:
! 1169: if (EQUAL(w, "interval")) {
! 1170: if (EQUAL((w = next_word(&s)), "")) {
! 1171: WARN("Missing spt-threshold interval; defaulting to %u sec", SPT_THRESHOLD_DEFAULT_INTERVAL);
! 1172: interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
! 1173: continue;
! 1174: }
! 1175:
! 1176: /* 5 --> 99,999 ~= 27h */
! 1177: if (sscanf(w, "%5u", &interval) != 1) {
! 1178: WARN("Invalid spt-threshold interval %s; defaulting to %u sec", w, SPT_THRESHOLD_DEFAULT_INTERVAL);
! 1179: interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
! 1180: }
! 1181:
! 1182: if (interval < TIMER_INTERVAL) {
! 1183: WARN("Too low spt-threshold interval %s; defaulting to %u sec", w, TIMER_INTERVAL);
! 1184: interval = TIMER_INTERVAL;
! 1185: }
! 1186:
! 1187: continue;
! 1188: }
! 1189:
! 1190: if (EQUAL(w, "packets")) {
! 1191: mode = SPT_PACKETS;
! 1192:
! 1193: if (EQUAL((w = next_word(&s)), "")) {
! 1194: WARN("Missing spt-threshold number of packets; defaulting to %u", SPT_THRESHOLD_DEFAULT_PACKETS);
! 1195: packets = SPT_THRESHOLD_DEFAULT_PACKETS;
! 1196: continue;
! 1197: }
! 1198:
! 1199: /* 10 --> 4294967295, which is max of uint32_t */
! 1200: if (sscanf(w, "%10u", &packets) != 1) {
! 1201: WARN("Invalid spt-threshold packets %s; defaulting to %u",
! 1202: w, SPT_THRESHOLD_DEFAULT_PACKETS);
! 1203: packets = SPT_THRESHOLD_DEFAULT_INTERVAL;
! 1204: }
! 1205:
! 1206: continue;
! 1207: }
! 1208:
! 1209: if (EQUAL(w, "infinity")) {
! 1210: mode = SPT_INF;
! 1211: continue;
! 1212: }
! 1213:
! 1214: WARN("Invalid spt-threshold parameter %s; reverting to defaults.", w);
! 1215: mode = SPT_THRESHOLD_DEFAULT_MODE;
! 1216: rate = SPT_THRESHOLD_DEFAULT_RATE;
! 1217: packets = SPT_THRESHOLD_DEFAULT_PACKETS;
! 1218: interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
! 1219: break;
! 1220: }
! 1221:
! 1222: spt_threshold.mode = mode;
! 1223: switch (mode) {
! 1224: case SPT_INF:
! 1225: logit(LOG_INFO, 0, "spt-threshold infinity => RP and lasthop router will never switch to SPT.");
! 1226: break;
! 1227:
! 1228: case SPT_RATE:
! 1229: /* Accounting for headers we can approximate 1 byte/s == 10 bits/s (bps)
! 1230: * Note, in the new spt_threshold setting the rate is in kbps as well! */
! 1231: spt_threshold.bytes = rate * interval / 10 * 1000;
! 1232: spt_threshold.interval = interval;
! 1233: logit(LOG_INFO, 0, "spt-threshold rate %u interval %u", rate, interval);
! 1234: break;
! 1235:
! 1236: case SPT_PACKETS:
! 1237: spt_threshold.packets = packets;
! 1238: spt_threshold.interval = interval;
! 1239: logit(LOG_INFO, 0, "spt-threshold packets %u interval %u", packets, interval);
! 1240: break;
! 1241:
! 1242: }
! 1243:
! 1244: return TRUE;
! 1245: }
! 1246:
! 1247:
! 1248: /**
! 1249: * parse_default_route_metric - Parse default-route-metric option
! 1250: * @s: String token
! 1251: *
! 1252: * Reads and assigns the route metric used for PIM Asserts by default.
! 1253: * This is used if pimd cannot read unicast route metrics from the
! 1254: * OS/kernel.
! 1255: *
! 1256: * Syntax:
! 1257: * default-route-metric <1-1024>
! 1258: *
! 1259: * Default routing protocol distance and route metric statements should
! 1260: * precede all phyint statements in the config file.
! 1261: *
! 1262: * Returns:
! 1263: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 1264: */
! 1265: int parse_default_route_metric(char *s)
! 1266: {
! 1267: char *w;
! 1268: u_int value;
! 1269: vifi_t vifi;
! 1270: struct uvif *v;
! 1271:
! 1272: value = UCAST_DEFAULT_ROUTE_METRIC;
! 1273: if (EQUAL((w = next_word(&s)), "")) {
! 1274: WARN("Missing route metric default; defaulting to %u", UCAST_DEFAULT_ROUTE_METRIC);
! 1275: } else if (sscanf(w, "%u", &value) != 1) {
! 1276: WARN("Invalid route metric default; defaulting to %u", UCAST_DEFAULT_ROUTE_METRIC);
! 1277: value = UCAST_DEFAULT_ROUTE_METRIC;
! 1278: }
! 1279:
! 1280: default_route_metric = value;
! 1281: logit(LOG_INFO, 0, "default-route-metric is %u", value);
! 1282:
! 1283: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
! 1284: v->uv_local_metric = default_route_metric;
! 1285:
! 1286: return TRUE;
! 1287: }
! 1288:
! 1289:
! 1290: /**
! 1291: * parse_default_route_distance - Parse default-route-distance option
! 1292: * @s: String token
! 1293: *
! 1294: * Reads and assigns the default source metric preference, i.e. routing
! 1295: * protocol distance. This is used if pimd cannot read unicast routing
! 1296: * protocol information from the OS/kernel.
! 1297: *
! 1298: * Syntax:
! 1299: * default-route-distance <1-255>
! 1300: *
! 1301: * Default routing protocol distance and route metric statements should
! 1302: * precede all phyint statements in the config file.
! 1303: *
! 1304: * Returns:
! 1305: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 1306: */
! 1307: int parse_default_route_distance(char *s)
! 1308: {
! 1309: char *w;
! 1310: u_int value;
! 1311: vifi_t vifi;
! 1312: struct uvif *v;
! 1313:
! 1314: value = UCAST_DEFAULT_ROUTE_DISTANCE;
! 1315: if (EQUAL((w = next_word(&s)), "")) {
! 1316: WARN("Missing default routing protocol distance; defaulting to %u", UCAST_DEFAULT_ROUTE_DISTANCE);
! 1317: } else if (sscanf(w, "%u", &value) != 1) {
! 1318: WARN("Invalid default routing protocol distance; defaulting to %u", UCAST_DEFAULT_ROUTE_DISTANCE);
! 1319: value = UCAST_DEFAULT_ROUTE_DISTANCE;
! 1320: }
! 1321:
! 1322: default_route_distance = value;
! 1323: logit(LOG_INFO, 0, "default-route-distance is %u", value);
! 1324: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
! 1325: v->uv_local_pref = default_route_distance;
! 1326:
! 1327: return TRUE;
! 1328: }
! 1329:
! 1330: /**
! 1331: * parse_igmp_query_interval - Parse igmp-query-interval option
! 1332: * @s: String token
! 1333: *
! 1334: * Reads and assigns the default IGMP query interval. If the argument
! 1335: * is missing or invalid the parser defaults to %IGMP_QUERY_INTERVAL
! 1336: *
! 1337: * Syntax:
! 1338: * igmp-query-interval <SEC>
! 1339: *
! 1340: * Returns:
! 1341: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 1342: */
! 1343: static int parse_igmp_query_interval(char *s)
! 1344: {
! 1345: char *w;
! 1346: uint32_t value = IGMP_QUERY_INTERVAL;
! 1347:
! 1348: if (EQUAL((w = next_word(&s)), "")) {
! 1349: WARN("Missing argument to igmp-query-interval; defaulting to %u", IGMP_QUERY_INTERVAL);
! 1350: } else if (sscanf(w, "%u", &value) != 1) {
! 1351: WARN("Invalid default igmp-query-interval; defaulting to %u", IGMP_QUERY_INTERVAL);
! 1352: value = IGMP_QUERY_INTERVAL;
! 1353: }
! 1354:
! 1355: igmp_query_interval = value;
! 1356:
! 1357: /* Calculate new querier timeout, or expect config option after this. */
! 1358: igmp_querier_timeout = 0;
! 1359:
! 1360: return TRUE;
! 1361: }
! 1362:
! 1363: /**
! 1364: * parse_igmp_querier_timeout - Parse igmp-querier-timeout option
! 1365: * @s: String token
! 1366: *
! 1367: * Reads and assigns default querier timeout for an active IGMP querier.
! 1368: * This is the time it takes before pimd tries to take over as the
! 1369: * active querier. If the argument is missing or invalid the system
! 1370: * will calculate a fallback based on the query interval.
! 1371: *
! 1372: * Syntax:
! 1373: * igmp-querier-timeout <SEC>
! 1374: *
! 1375: * Returns:
! 1376: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
! 1377: */
! 1378: static int parse_igmp_querier_timeout(char *s)
! 1379: {
! 1380: char *w;
! 1381: uint32_t value = 0;
! 1382: uint32_t recommended = QUERIER_TIMEOUT(igmp_query_interval);
! 1383:
! 1384: if (EQUAL((w = next_word(&s)), "")) {
! 1385: WARN("Missing argument to igmp-querier-timeout!");
! 1386: } else if (sscanf(w, "%u", &value) != 1) {
! 1387: WARN("Invalid default igmp-querier-timeout!");
! 1388: value = 0;
! 1389: }
! 1390:
! 1391: /* Do some sanity checks to prevent invalid configuration and to recommend
! 1392: * better settings, see GitHub issue troglobit/pimd#31 for details. */
! 1393: if (value != 0) {
! 1394: /* 1) Prevent invalid configuration */
! 1395: if (value <= igmp_query_interval) {
! 1396: WARN("IGMP querier timeout %d must be larger than the query interval %d, forcing default!",
! 1397: value, igmp_query_interval);
! 1398: value = recommended;
! 1399: }
! 1400:
! 1401: /* 2) Warn power user of potentially too low setting. */
! 1402: if (value < recommended)
! 1403: WARN("The IGMP querier timeout %d is smaller than the recommended value %d, allowing ...",
! 1404: value, recommended);
! 1405:
! 1406: logit(LOG_WARNING, 0, "Recommended querier timeout = Robustness x query-interval + response-time / 2 = %d x %d + %d / 2 = %d",
! 1407: IGMP_ROBUSTNESS_VARIABLE, igmp_query_interval, IGMP_QUERY_RESPONSE_INTERVAL, recommended);
! 1408: }
! 1409:
! 1410: igmp_querier_timeout = value;
! 1411:
! 1412: return TRUE;
! 1413: }
! 1414:
! 1415: static void fallback_config(void)
! 1416: {
! 1417: char buf[LINE_BUFSIZ], *s = buf;
! 1418:
! 1419: logit(LOG_NOTICE, 0, "Using built-in defaults, including RP/BSR candidate.");
! 1420:
! 1421: snprintf(buf, sizeof(buf), "priority 20 time 30");
! 1422: parse_rp_candidate(s);
! 1423:
! 1424: snprintf(buf, sizeof(buf), "priority 5");
! 1425: parse_bsr_candidate(s);
! 1426: }
! 1427:
! 1428: void config_vifs_from_file(void)
! 1429: {
! 1430: FILE *fp;
! 1431: char linebuf[LINE_BUFSIZ];
! 1432: char *w, *s;
! 1433: int option;
! 1434: uint8_t *data_ptr;
! 1435: int error_flag;
! 1436:
! 1437: error_flag = FALSE;
! 1438: lineno = 0;
! 1439:
! 1440: /* TODO: HARDCODING!!! */
! 1441: cand_rp_adv_message.buffer = calloc(1, 4 + sizeof(pim_encod_uni_addr_t) +
! 1442: 255 * sizeof(pim_encod_grp_addr_t));
! 1443: if (!cand_rp_adv_message.buffer)
! 1444: logit(LOG_ERR, errno, "Ran out of memory in config_vifs_from_file()");
! 1445:
! 1446: cand_rp_adv_message.prefix_cnt_ptr = cand_rp_adv_message.buffer;
! 1447: /* By default, if no group-prefix configured, then prefix_cnt == 0
! 1448: * implies group-prefix = 224.0.0.0 and masklen = 4.
! 1449: */
! 1450: *cand_rp_adv_message.prefix_cnt_ptr = 0;
! 1451: cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
! 1452: /* TODO: XXX: HARDCODING!!! */
! 1453: cand_rp_adv_message.insert_data_ptr += (4 + 6);
! 1454:
! 1455: fp = fopen(config_file, "r");
! 1456: if (!fp) {
! 1457: logit(LOG_WARNING, errno, "Cannot open configuration file %s", config_file);
! 1458: fallback_config();
! 1459: goto nofile;
! 1460: }
! 1461:
! 1462: while (fgets(linebuf, sizeof(linebuf), fp)) {
! 1463: if (strlen(linebuf) >= (LINE_BUFSIZ - 1)) {
! 1464: WARN("Line length must be shorter than %d", LINE_BUFSIZ);
! 1465: error_flag = TRUE;
! 1466: }
! 1467: lineno++;
! 1468:
! 1469: s = linebuf;
! 1470: w = next_word(&s);
! 1471: option = parse_option(w);
! 1472:
! 1473: switch (option) {
! 1474: case CONF_EMPTY:
! 1475: continue;
! 1476: break;
! 1477:
! 1478: case CONF_PHYINT:
! 1479: parse_phyint(s);
! 1480: break;
! 1481:
! 1482: case CONF_CANDIDATE_RP:
! 1483: parse_rp_candidate(s);
! 1484: break;
! 1485:
! 1486: case CONF_RP_ADDRESS:
! 1487: parse_rp_address(s);
! 1488: break;
! 1489:
! 1490: case CONF_GROUP_PREFIX:
! 1491: parse_group_prefix(s);
! 1492: break;
! 1493:
! 1494: case CONF_BOOTSTRAP_RP:
! 1495: parse_bsr_candidate(s);
! 1496: break;
! 1497:
! 1498: case CONF_COMPAT_THRESHOLD:
! 1499: parse_compat_threshold(s);
! 1500: break;
! 1501:
! 1502: case CONF_SPT_THRESHOLD:
! 1503: parse_spt_threshold(s);
! 1504: break;
! 1505:
! 1506: case CONF_DEFAULT_ROUTE_METRIC:
! 1507: parse_default_route_metric(s);
! 1508: break;
! 1509:
! 1510: case CONF_DEFAULT_ROUTE_DISTANCE:
! 1511: parse_default_route_distance(s);
! 1512: break;
! 1513:
! 1514: case CONF_IGMP_QUERY_INTERVAL:
! 1515: parse_igmp_query_interval(s);
! 1516: break;
! 1517:
! 1518: case CONF_IGMP_QUERIER_TIMEOUT:
! 1519: parse_igmp_querier_timeout(s);
! 1520: break;
! 1521:
! 1522: case CONF_HELLO_INTERVAL:
! 1523: parse_hello_interval(s);
! 1524: break;
! 1525:
! 1526: default:
! 1527: logit(LOG_WARNING, 0, "%s:%u - Unknown command '%s'", config_file, lineno, w);
! 1528: error_flag = TRUE;
! 1529: }
! 1530: }
! 1531:
! 1532: fclose(fp);
! 1533:
! 1534: nofile:
! 1535: /* A static RP address is needed for SSM. We use a link-local
! 1536: * address. It is not required to be configured on any interface. */
! 1537: strncpy(linebuf, "169.254.0.1 232.0.0.0/8\n", sizeof(linebuf));
! 1538: s = linebuf;
! 1539: parse_rp_address(s);
! 1540:
! 1541: if (error_flag)
! 1542: logit(LOG_ERR, 0, "%s:%u - Syntax error", config_file, lineno);
! 1543:
! 1544: cand_rp_adv_message.message_size = cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
! 1545: if (cand_rp_flag != FALSE) {
! 1546: /* Prepare the RP info */
! 1547: my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
! 1548:
! 1549: /* TODO: HARDCODING! */
! 1550: data_ptr = cand_rp_adv_message.buffer + 1;
! 1551: PUT_BYTE(my_cand_rp_priority, data_ptr);
! 1552: PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
! 1553: PUT_EUADDR(my_cand_rp_address, data_ptr);
! 1554: }
! 1555:
! 1556: /* If no IGMP querier timeout was set, calculate from query interval */
! 1557: if (!igmp_querier_timeout)
! 1558: igmp_querier_timeout = QUERIER_TIMEOUT(igmp_query_interval);
! 1559:
! 1560: IF_DEBUG(DEBUG_IGMP) {
! 1561: logit(LOG_INFO, 0, "IGMP query interval : %u sec", igmp_query_interval);
! 1562: logit(LOG_INFO, 0, "IGMP querier timeout : %u sec", igmp_querier_timeout);
! 1563: }
! 1564: }
! 1565:
! 1566:
! 1567: static uint32_t ifname2addr(char *s)
! 1568: {
! 1569: vifi_t vifi;
! 1570: struct uvif *v;
! 1571:
! 1572: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 1573: if (!strcmp(v->uv_name, s))
! 1574: return v->uv_lcl_addr;
! 1575: }
! 1576:
! 1577: return 0;
! 1578: }
! 1579:
! 1580: static char *next_word(char **s)
! 1581: {
! 1582: char *w;
! 1583:
! 1584: w = *s;
! 1585: while (*w == ' ' || *w == '\t')
! 1586: w++;
! 1587:
! 1588: *s = w;
! 1589: while (**s != 0) {
! 1590: switch (**s) {
! 1591: case ' ':
! 1592: case '\t':
! 1593: **s = '\0';
! 1594: (*s)++;
! 1595: return w;
! 1596:
! 1597: case '\n':
! 1598: case '#':
! 1599: **s = '\0';
! 1600: return w;
! 1601:
! 1602: default:
! 1603: if (isascii((int)**s) && isupper((int)**s))
! 1604: **s = tolower((int)**s);
! 1605: (*s)++;
! 1606: }
! 1607: }
! 1608:
! 1609: return w;
! 1610: }
! 1611:
! 1612: /**
! 1613: * Local Variables:
! 1614: * version-control: t
! 1615: * indent-tabs-mode: t
! 1616: * c-file-style: "ellemtel"
! 1617: * c-basic-offset: 4
! 1618: * End:
! 1619: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>