static void str_to_mac(const char *str, uint8_t mac[6]) { if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) != ETH_ADDR_SCAN_COUNT) { ovs_fatal(0, "invalid mac address %s", str); } }
/* Parses 'str' as an Ethernet address into 'mac'. * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ char * OVS_WARN_UNUSED_RESULT str_to_mac(const char *str, struct eth_addr *mac) { if (!ovs_scan(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*mac))) { return xasprintf("invalid mac address %s", str); } return NULL; }
/* Returns true if specified address specifies a dynamic address, * supporting the following formats: * * "dynamic": * Both MAC and IP are to be allocated dynamically. * * "xx:xx:xx:xx:xx:xx dynamic": * Use specified MAC address, but allocate an IP address * dynamically. */ bool is_dynamic_lsp_address(const char *address) { struct eth_addr ea; int n; return (!strcmp(address, "dynamic") || (ovs_scan(address, ETH_ADDR_SCAN_FMT" dynamic%n", ETH_ADDR_SCAN_ARGS(ea), &n) && address[n] == '\0')); }
bool eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN]) { if (sscanf(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea)) == ETH_ADDR_SCAN_COUNT) { return true; } else { memset(ea, 0, ETH_ADDR_LEN); return false; } }
/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which * should be of the format "MAC [IP1 IP2 ..] .." where IPn should be a * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and * 'ipv6_addrs' fields of 'laddrs'. There may be additional content in * 'address' after "MAC [IP1 IP2 .. ]". The value of 'ofs' that is * returned indicates the offset where that additional content begins. * * Returns true if at least 'MAC' is found in 'address', false otherwise. * * The caller must call destroy_lport_addresses(). */ bool extract_addresses(const char *address, struct lport_addresses *laddrs, int *ofs) { memset(laddrs, 0, sizeof *laddrs); const char *buf = address; const char *const start = buf; int buf_index = 0; const char *buf_end = buf + strlen(address); if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(laddrs->ea))) { laddrs->ea = eth_addr_zero; *ofs = 0; return false; } snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs->ea)); ovs_be32 ip4; struct in6_addr ip6; unsigned int plen; char *error; /* Loop through the buffer and extract the IPv4/IPv6 addresses * and store in the 'laddrs'. Break the loop if invalid data is found. */ buf += buf_index; while (buf < buf_end) { buf_index = 0; error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen); if (!error) { add_ipv4_netaddr(laddrs, ip4, plen); buf += buf_index; continue; } free(error); error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen); if (!error) { add_ipv6_netaddr(laddrs, ip6, plen); } else { free(error); break; } buf += buf_index; } *ofs = buf - start; return true; }
/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and * 'ipv6_addrs' fields of 'laddrs'. * * Return true if at least 'MAC' is found in 'address', false otherwise. * * The caller must call destroy_lport_addresses(). */ bool extract_lsp_addresses(const char *address, struct lport_addresses *laddrs) { memset(laddrs, 0, sizeof *laddrs); const char *buf = address; int buf_index = 0; const char *buf_end = buf + strlen(address); if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(laddrs->ea))) { laddrs->ea = eth_addr_zero; return false; } snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs->ea)); ovs_be32 ip4; struct in6_addr ip6; unsigned int plen; char *error; /* Loop through the buffer and extract the IPv4/IPv6 addresses * and store in the 'laddrs'. Break the loop if invalid data is found. */ buf += buf_index; while (buf < buf_end) { buf_index = 0; error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen); if (!error) { add_ipv4_netaddr(laddrs, ip4, plen); buf += buf_index; continue; } free(error); error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen); if (!error) { add_ipv6_netaddr(laddrs, ip6, plen); } else { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address); free(error); break; } buf += buf_index; } return true; }
static const char * lex_parse_integer__(const char *p, struct lex_token *token) { lex_token_init(token); token->type = LEX_T_INTEGER; memset(&token->value, 0, sizeof token->value); const char *start = p; const char *end = start; while (isalnum((unsigned char) *end) || *end == ':' || (*end == '.' && end[1] != '.')) { end++; } size_t len = end - start; int n; struct eth_addr mac; if (!len) { lex_error(token, "Integer constant expected."); } else if (len == 17 && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) && n == len) { token->value.mac = mac; token->format = LEX_F_ETHERNET; } else if (start + strspn(start, "0123456789") == end) { if (p[0] == '0' && len > 1) { lex_error(token, "Decimal constants must not have leading zeros."); } else { unsigned long long int integer; char *tail; errno = 0; integer = strtoull(p, &tail, 10); if (tail != end || errno == ERANGE) { lex_error(token, "Decimal constants must be less than 2**64."); } else { token->value.integer = htonll(integer); token->format = LEX_F_DECIMAL; } } } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (len > 2) { lex_parse_hex_integer(start + 2, len - 2, token); } else { lex_error(token, "Hex digits expected following 0%c.", p[1]); } } else if (len < INET6_ADDRSTRLEN) { char copy[INET6_ADDRSTRLEN]; memcpy(copy, p, len); copy[len] = '\0'; if (ip_parse(copy, &token->value.ipv4)) { token->format = LEX_F_IPV4; } else if (ipv6_parse(copy, &token->value.ipv6)) { token->format = LEX_F_IPV6; } else { lex_error(token, "Invalid numeric constant."); } } else { lex_error(token, "Invalid numeric constant."); } ovs_assert(token->type == LEX_T_INTEGER || token->type == LEX_T_ERROR); return end; }
static const char * lex_parse_integer__(const char *p, struct lex_token *token) { lex_token_init(token); token->type = LEX_T_INTEGER; memset(&token->value, 0, sizeof token->value); /* Find the extent of an "integer" token, which can be in decimal or * hexadecimal, or an Ethernet address or IPv4 or IPv6 address, as 'start' * through 'end'. * * Special cases we handle here are: * * - The ellipsis token "..", used as e.g. 123..456. A doubled dot * is never valid syntax as part of an "integer", so we stop if * we encounter two dots in a row. * * - Syntax like 1.2.3.4:1234 to indicate an IPv4 address followed by a * port number should be considered three tokens: 1.2.3.4 : 1234. * The obvious approach is to allow just dots or just colons within a * given integer, but that would disallow IPv4-mapped IPv6 addresses, * e.g. ::ffff:192.0.2.128. However, even in those addresses, a * colon never follows a dot, so we stop if we encounter a colon * after a dot. * * (There is no corresponding way to parse an IPv6 address followed * by a port number: ::1:2:3:4:1234 is unavoidably ambiguous.) */ const char *start = p; const char *end = start; bool saw_dot = false; while (isalnum((unsigned char) *end) || (*end == ':' && !saw_dot) || (*end == '.' && end[1] != '.')) { if (*end == '.') { saw_dot = true; } end++; } size_t len = end - start; int n; struct eth_addr mac; if (!len) { lex_error(token, "Integer constant expected."); } else if (len == 17 && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) && n == len) { token->value.mac = mac; token->format = LEX_F_ETHERNET; } else if (start + strspn(start, "0123456789") == end) { if (p[0] == '0' && len > 1) { lex_error(token, "Decimal constants must not have leading zeros."); } else { unsigned long long int integer; char *tail; errno = 0; integer = strtoull(p, &tail, 10); if (tail != end || errno == ERANGE) { lex_error(token, "Decimal constants must be less than 2**64."); } else { token->value.integer = htonll(integer); token->format = LEX_F_DECIMAL; } } } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (len > 2) { lex_parse_hex_integer(start + 2, len - 2, token); } else { lex_error(token, "Hex digits expected following 0%c.", p[1]); } } else if (len < INET6_ADDRSTRLEN) { char copy[INET6_ADDRSTRLEN]; memcpy(copy, p, len); copy[len] = '\0'; if (ip_parse(copy, &token->value.ipv4)) { token->format = LEX_F_IPV4; } else if (ipv6_parse(copy, &token->value.ipv6)) { token->format = LEX_F_IPV6; } else { lex_error(token, "Invalid numeric constant."); } } else { lex_error(token, "Invalid numeric constant."); } ovs_assert(token->type == LEX_T_INTEGER || token->type == LEX_T_ERROR); return end; }