This updates rte_ether_addr_unformat() to accept more types of input. There have been requests to handle Windows and other formats.
Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- Marking this as RFC until unit tests are added. lib/net/rte_ether.c | 78 +++++++++++++++++++++++++++++++++++---------- lib/net/rte_ether.h | 6 ++-- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/lib/net/rte_ether.c b/lib/net/rte_ether.c index 66d9a9d0699a..5250353eb162 100644 --- a/lib/net/rte_ether.c +++ b/lib/net/rte_ether.c @@ -38,7 +38,8 @@ static int8_t get_xdigit(char ch) } /* Convert 00:11:22:33:44:55 to ethernet address */ -static bool get_ether_addr6(const char *s0, struct rte_ether_addr *ea) +static bool get_ether_addr6(const char *s0, struct rte_ether_addr *ea, + const char sep) { const char *s = s0; int i; @@ -50,14 +51,17 @@ static bool get_ether_addr6(const char *s0, struct rte_ether_addr *ea) if (x < 0) return false; - ea->addr_bytes[i] = x << 4; - x = get_xdigit(*s++); - if (x < 0) - return false; - ea->addr_bytes[i] |= x; + ea->addr_bytes[i] = x; + if (*s != sep) { + x = get_xdigit(*s++); + if (x < 0) + return false; + ea->addr_bytes[i] <<= 4; + ea->addr_bytes[i] |= x; + } if (i < RTE_ETHER_ADDR_LEN - 1 && - *s++ != ':') + *s++ != sep) return false; } @@ -66,7 +70,8 @@ static bool get_ether_addr6(const char *s0, struct rte_ether_addr *ea) } /* Convert 0011:2233:4455 to ethernet address */ -static bool get_ether_addr3(const char *s, struct rte_ether_addr *ea) +static bool get_ether_addr3(const char *s, struct rte_ether_addr *ea, + const char sep) { int i, j; @@ -80,12 +85,14 @@ static bool get_ether_addr3(const char *s, struct rte_ether_addr *ea) if (x < 0) return false; w = (w << 4) | x; + if (*s == sep) + break; } ea->addr_bytes[i] = w >> 8; ea->addr_bytes[i + 1] = w & 0xff; if (i < RTE_ETHER_ADDR_LEN - 2 && - *s++ != ':') + *s++ != sep) return false; } @@ -93,17 +100,56 @@ static bool get_ether_addr3(const char *s, struct rte_ether_addr *ea) } /* - * Like ether_aton_r but can handle either - * XX:XX:XX:XX:XX:XX or XXXX:XXXX:XXXX - * and is more restrictive. + * Scan input to see if seperated by dash, colon or period + * Returns seperator and number of matches + * If seperators are mixed will return + */ +static unsigned int get_ether_sep(const char *s, char *sep) +{ + const char seperators[] = "-:."; + unsigned int count = 0; + const char *cp; + + cp = strpbrk(s, seperators); + if (cp == NULL) + return 0; + + *sep = *cp; + do { + ++count; + /* find next instance of seperator */ + cp = strchr(cp + 1, *sep); + } while (cp != NULL); + + return count; +} + +/* + * Be libreal in accepting a wide variety of notational formats + * for MAC address including: + * - Linux format six groups of hexadecimal digits seperated by colon + * - Windows format six groups seperated by hyphen + * - two groups hexadecimal digits */ int rte_ether_unformat_addr(const char *s, struct rte_ether_addr *ea) { - if (get_ether_addr6(s, ea)) - return 0; - if (get_ether_addr3(s, ea)) - return 0; + unsigned int count; + char sep = '\0'; + + count = get_ether_sep(s, &sep); + switch (count) { + case 5: /* i.e 01:23:45:67:89:AB */ + if (get_ether_addr6(s, ea, sep)) + return 0; + break; + case 2: /* i.e 0123.4567.89AB */ + if (get_ether_addr3(s, ea, sep)) + return 0; + break; + default: + break; + } rte_errno = EINVAL; return -1; diff --git a/lib/net/rte_ether.h b/lib/net/rte_ether.h index b35c72c7b0e0..e9a4ba9b5860 100644 --- a/lib/net/rte_ether.h +++ b/lib/net/rte_ether.h @@ -254,8 +254,10 @@ rte_ether_format_addr(char *buf, uint16_t size, * * @param str * A pointer to buffer contains the formatted MAC address. - * The supported formats are: - * XX:XX:XX:XX:XX:XX or XXXX:XXXX:XXXX + * The example formats are: + * XX:XX:XX:XX:XX:XX - Canonical form + * XX-XX-XX-XX-XX-XX - Windows and IEEE 802 + * XXXX:XXXX:XXXX - original DPDK * where XX is a hex digit: 0-9, a-f, or A-F. * @param eth_addr * A pointer to a ether_addr structure. -- 2.39.2