> 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

Reply via email to