> 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]>
Acked-by: Lorenzo Bianconi <[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 >
_______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
