On Thu, Feb 12, 2026 at 1:00 PM Dumitru Ceara <[email protected]> wrote:
> On 2/11/26 10:37 AM, Ales Musil wrote: > > 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. > > > > Acked-by: Dumitru Ceara <[email protected]> > > Acked-by: Lorenzo Bianconi <[email protected]> > > Signed-off-by: Ales Musil <[email protected]> > > --- > > v4: Rebase on top of latest main. > > v5: Rebase on top of latest main. > > Add Dumitru's ack. > > Add Lorenzo's ack. > > v6: Rebase on top of latest main. > > v7: Rebase on top of latest main. > > v8: Rebase on top of latest main. > > Address small nit from Dumitru. > > --- > > Hi Ales, > > > 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 8a065e3c2..46b837c02 100644 > > --- a/lib/ovn-util.c > > +++ b/lib/ovn-util.c > > @@ -1762,3 +1762,52 @@ shuffled_range(size_t n) > > > > return indices; > > } > > + > > +/* 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) > > I guess we both forgot about this in v6-v8, the comment talks about > 'len' but the argument is called 'plen': > > https://mail.openvswitch.org/pipermail/ovs-dev/2026-February/430065.html > > With that addressed: > Acked-by: Dumitru Ceara <[email protected]> > > Thanks, > Dumitru > > > +{ > > + 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 0ba0d1c26..402a7b155 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 802e6d0da..c2d113f8e 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -2443,6 +2443,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 e88d3d45e..3c89eeba0 100644 > > --- a/tests/test-ovn.c > > +++ b/tests/test-ovn.c > > @@ -1474,6 +1474,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) > > @@ -1560,6 +1576,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); > > @@ -1685,6 +1704,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; > > Thank you Lorenzo and Dumitru, I took care of the nit and merged this into main. Regards, Ales _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
