Add helpers for parsing masked MAC in format of MAC/MAC and MAC/prefix. In additions to utils that convert MAC into prefix len and in reverse, creating MAC mask from prefix len. This will be used for the extended port_security parsing.
Signed-off-by: Ales Musil <[email protected]> --- v2: Rebase on top of latest main. --- lib/ovn-util.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ovn-util.h | 18 ++++++++++++++++++ tests/ovn.at | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-ovn.c | 22 ++++++++++++++++++++++ 4 files changed, 138 insertions(+) diff --git a/lib/ovn-util.c b/lib/ovn-util.c index 71098d478..c9de6567c 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -1737,3 +1737,52 @@ is_partial_uuid_match(const struct uuid *uuid, const char *match) s2 = strip_leading_zero(s2); return !strncmp(s1, s2, strlen(s2)); } + +/* Parses string 's', which must be a MAC address with an optional mask or + * mask prefix length. Stores the MAC address into '*ea' and the mask prefix + * length into '*len' (if 's' does not contain a mask, all-one-bits + * is assumed). + * + * Returns true if successful, otherwise false and the '*ea' is zeroed out in + * case. */ +bool +eth_addr_parse_masked(const char *s, struct eth_addr *ea, unsigned int *plen) +{ + int n = 0; + + if (!ovs_scan_len(s, &n, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*ea))) { + *ea = eth_addr_zero; + return false; + } + + /* There isn't any mask provided. */ + if (s[n] != '/') { + *plen = 48; + return true; + } + + struct eth_addr mask; + if (ovs_scan_len(s, &n, "/"ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mask))) { + int prefix = eth_addr_get_prefix_len(mask); + if (!eth_addr_equals(mask, eth_addr_create_mask(prefix))) { + *ea = eth_addr_zero; + return false; + } + + *plen = prefix; + return true; + } + + int prefix; + if (ovs_scan_len(s, &n, "/%d", &prefix)) { + if (prefix < 0 || prefix > 48) { + *ea = eth_addr_zero; + return false; + } + *plen = prefix; + return true; + } + + *ea = eth_addr_zero; + return false; +} diff --git a/lib/ovn-util.h b/lib/ovn-util.h index 74931ed29..d256cfbde 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -672,6 +672,24 @@ is_uuid_with_prefix(const char *uuid) return uuid[0] == '0' && (uuid[1] == 'x' || uuid[1] == 'X'); } +static inline struct eth_addr +eth_addr_create_mask(unsigned int len) +{ + struct eth_addr mac; + eth_addr_from_uint64((UINT64_MAX << (48 - len)), &mac); + + return mac; +} + +static inline unsigned int +eth_addr_get_prefix_len(struct eth_addr mac) +{ + uint64_t n = (UINT64_C(0xffff) << 48) | eth_addr_to_uint64(mac); + return 48 - ctz64(n); +} + +bool eth_addr_parse_masked(const char *, struct eth_addr *, unsigned int *); + bool is_partial_uuid_match(const struct uuid *uuid, const char *match); /* Utilities around properly handling exit command. */ diff --git a/tests/ovn.at b/tests/ovn.at index f33d4cfad..034fdd0d8 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -2411,6 +2411,55 @@ check ovstest test-sparse-array add check ovstest test-sparse-array remove-replace AT_CLEANUP +AT_SETUP([Parse MAC]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:xx], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:ff:ff 01:02:03:04:05:06/48 +]) + +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/-1], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/-40], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/49], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/128], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/48], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:ff:ff 01:02:03:04:05:06/48 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/40], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:ff:00 01:02:03:04:05:06/40 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:00/40], [0], [dnl +01:02:03:04:05:00/ff:ff:ff:ff:ff:00 01:02:03:04:05:00/40 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/25], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:80:00:00 01:02:03:04:05:06/25 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:00:00:00/25], [0], [dnl +01:02:03:00:00:00/ff:ff:ff:80:00:00 01:02:03:00:00:00/25 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/0], [0], [dnl +01:02:03:04:05:06/00:00:00:00:00:00 01:02:03:04:05:06/0 +]) + +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:ff:ff:xx], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:ff:0f:00], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/01:02:03:04:05:00], [1]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:ff:ff:00], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:ff:00 01:02:03:04:05:06/40 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:ff:00:00], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:00:00 01:02:03:04:05:06/32 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:00:00:00], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:00:00:00 01:02:03:04:05:06/24 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/ff:ff:ff:ff:ff:f0], [0], [dnl +01:02:03:04:05:06/ff:ff:ff:ff:ff:f0 01:02:03:04:05:06/44 +]) +AT_CHECK([ovstest test-ovn parse-eth-addr 01:02:03:04:05:06/00:00:00:00:00:00], [0], [dnl +01:02:03:04:05:06/00:00:00:00:00:00 01:02:03:04:05:06/0 +]) +AT_CLEANUP + AT_BANNER([OVN end-to-end tests]) OVN_FOR_EACH_NORTHD([ diff --git a/tests/test-ovn.c b/tests/test-ovn.c index fae7e7bd5..5fe1788bb 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1466,6 +1466,22 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) flow_collector_ids_destroy(&collector_ids); exit(ok ? EXIT_SUCCESS : EXIT_FAILURE); } + +static void +test_parse_eth_addr(struct ovs_cmdl_context *ctx) +{ + unsigned int plen; + struct eth_addr mac; + + if (!eth_addr_parse_masked(ctx->argv[1], &mac, &plen)) { + ovs_assert(eth_addr_equals(mac, eth_addr_zero)); + exit(EXIT_FAILURE); + } + + printf(ETH_ADDR_FMT "/" ETH_ADDR_FMT " " ETH_ADDR_FMT "/%u\n", + ETH_ADDR_ARGS(mac), ETH_ADDR_ARGS(eth_addr_create_mask(plen)), + ETH_ADDR_ARGS(mac), plen); +} static unsigned int parse_relops(const char *s) @@ -1552,6 +1568,9 @@ exhaustive N\n\ parse-actions\n\ Parses OVN actions from stdin and prints the equivalent OpenFlow actions\n\ on stdout.\n\ +parse-eth-addr\n\ + Parses masked MAC address from stdin and prints the equivalent MAC/plen \n\ + and MAC/mask to stdout\n\ ", program_name, program_name); exit(EXIT_SUCCESS); @@ -1677,6 +1696,9 @@ test_ovn_main(int argc, char *argv[]) /* Actions. */ {"parse-actions", NULL, 0, 0, test_parse_actions, OVS_RO}, + /* Utils. */ + {"parse-eth-addr", NULL, 1, 1, test_parse_eth_addr, OVS_RO}, + {NULL, NULL, 0, 0, NULL, OVS_RO}, }; struct ovs_cmdl_context ctx; -- 2.52.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
