Annotation of embedaddon/pimd/config.c, revision 1.1.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>