[ovs-dev] [megaflow v3 2/2] ovs-dpctl: Add mega flow support
Ethan Jackson
ethan at nicira.com
Wed Jun 12 00:39:04 UTC 2013
This doesn't constitute a review but two things
s/cerata/create
Do we really need the --mega option? Seems like that would be a
reasonable default given that the most important implementations will
be running megaflows.
Ethan
On Tue, Jun 11, 2013 at 4:45 PM, Andy Zhou <azhou at nicira.com> wrote:
> Added --mega option to ovs-dpctl command to allow mega flow to be
> specified and displayed. ovs-dpctl tool is mainly used as debugging
> tool.
>
> This patch also implements the low level user space routines to send
> and receive mega flow netlink messages. Those netlink support
> routines are required for forthcoming user space mega flow patches.
>
> Ethan contributed current version of ovs-dpctl mega flow output
> function.
>
> Co-authored-by: Ethan Jackson <ethan at nicira.com>
> Signed-off-by: Ethan Jackson <ethan at nicira.com>
> Signed-off-by: Andy Zhou <azhou at nicira.com>
>
> ---
> v1->v2
> Integrated Ethan's patch on ovs-dpctl mega flow output.
> Add Ethan as a co-author for this patch.
>
> v2->v3
> Rebase to head to make review easier.
> ovs-dpctl: Add mask input for tunnel configurations.
> ---
> lib/dpif-linux.c | 19 +
> lib/dpif-netdev.c | 6 +
> lib/dpif-provider.h | 1 +
> lib/dpif.c | 9 +
> lib/dpif.h | 4 +
> lib/netdev-dummy.c | 2 +-
> lib/odp-util.c | 1218 +++++++++++++++++++++++++++++++++++++++++-----
> lib/odp-util.h | 11 +-
> ofproto/ofproto-dpif.c | 17 +-
> tests/test-odp.c | 4 +-
> utilities/ovs-dpctl.8.in | 8 +
> utilities/ovs-dpctl.c | 44 +-
> 12 files changed, 1194 insertions(+), 149 deletions(-)
>
> diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
> index 1383b58..a084c3b 100644
> --- a/lib/dpif-linux.c
> +++ b/lib/dpif-linux.c
> @@ -105,6 +105,8 @@ struct dpif_linux_flow {
> * the Netlink version of the command, even if actions_len is zero. */
> const struct nlattr *key; /* OVS_FLOW_ATTR_KEY. */
> size_t key_len;
> + const struct nlattr *mask; /* OVS_FLOW_ATTR_KEY. */
> + size_t mask_len;
> const struct nlattr *actions; /* OVS_FLOW_ATTR_ACTIONS. */
> size_t actions_len;
> const struct ovs_flow_stats *stats; /* OVS_FLOW_ATTR_STATS. */
> @@ -807,6 +809,8 @@ dpif_linux_init_flow_put(struct dpif *dpif_, const struct dpif_flow_put *put,
> request->dp_ifindex = dpif->dp_ifindex;
> request->key = put->key;
> request->key_len = put->key_len;
> + request->mask = put->mask;
> + request->mask_len = put->mask_len;
> /* Ensure that OVS_FLOW_ATTR_ACTIONS will always be included. */
> request->actions = (put->actions
> ? put->actions
> @@ -901,6 +905,7 @@ dpif_linux_flow_dump_start(const struct dpif *dpif_, void **statep)
> static int
> dpif_linux_flow_dump_next(const struct dpif *dpif_ OVS_UNUSED, void *state_,
> const struct nlattr **key, size_t *key_len,
> + const struct nlattr **mask, size_t *mask_len,
> const struct nlattr **actions, size_t *actions_len,
> const struct dpif_flow_stats **stats)
> {
> @@ -941,6 +946,10 @@ dpif_linux_flow_dump_next(const struct dpif *dpif_ OVS_UNUSED, void *state_,
> *key = state->flow.key;
> *key_len = state->flow.key_len;
> }
> + if (mask) {
> + *mask = state->flow.mask;
> + *mask_len = state->flow.mask ? state->flow.mask_len: 0;
> + }
> if (stats) {
> dpif_linux_flow_get_stats(&state->flow, &state->stats);
> *stats = &state->stats;
> @@ -1832,6 +1841,7 @@ dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *flow,
> {
> static const struct nl_policy ovs_flow_policy[] = {
> [OVS_FLOW_ATTR_KEY] = { .type = NL_A_NESTED },
> + [OVS_FLOW_ATTR_MASK] = { .type = NL_A_NESTED, .optional = true },
> [OVS_FLOW_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
> [OVS_FLOW_ATTR_STATS] = { NL_POLICY_FOR(struct ovs_flow_stats),
> .optional = true },
> @@ -1863,6 +1873,11 @@ dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *flow,
> flow->dp_ifindex = ovs_header->dp_ifindex;
> flow->key = nl_attr_get(a[OVS_FLOW_ATTR_KEY]);
> flow->key_len = nl_attr_get_size(a[OVS_FLOW_ATTR_KEY]);
> +
> + if (a[OVS_FLOW_ATTR_MASK]) {
> + flow->mask = nl_attr_get(a[OVS_FLOW_ATTR_MASK]);
> + flow->mask_len = nl_attr_get_size(a[OVS_FLOW_ATTR_MASK]);
> + }
> if (a[OVS_FLOW_ATTR_ACTIONS]) {
> flow->actions = nl_attr_get(a[OVS_FLOW_ATTR_ACTIONS]);
> flow->actions_len = nl_attr_get_size(a[OVS_FLOW_ATTR_ACTIONS]);
> @@ -1898,6 +1913,10 @@ dpif_linux_flow_to_ofpbuf(const struct dpif_linux_flow *flow,
> nl_msg_put_unspec(buf, OVS_FLOW_ATTR_KEY, flow->key, flow->key_len);
> }
>
> + if (flow->mask_len) {
> + nl_msg_put_unspec(buf, OVS_FLOW_ATTR_MASK, flow->mask, flow->mask_len);
> + }
> +
> if (flow->actions || flow->actions_len) {
> nl_msg_put_unspec(buf, OVS_FLOW_ATTR_ACTIONS,
> flow->actions, flow->actions_len);
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 52aedb6..5a54627 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -879,6 +879,7 @@ dpif_netdev_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep)
> static int
> dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_,
> const struct nlattr **key, size_t *key_len,
> + const struct nlattr **mask, size_t *mask_len,
> const struct nlattr **actions, size_t *actions_len,
> const struct dpif_flow_stats **stats)
> {
> @@ -904,6 +905,11 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_,
> *key_len = buf.size;
> }
>
> + if (mask) {
> + *mask = NULL;
> + *mask_len = 0;
> + }
> +
> if (actions) {
> free(state->actions);
> state->actions = xmemdup(flow->actions, flow->actions_len);
> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
> index bea822f..0ee0843 100644
> --- a/lib/dpif-provider.h
> +++ b/lib/dpif-provider.h
> @@ -292,6 +292,7 @@ struct dpif_class {
> * 'flow_dump_next' or 'flow_dump_done' for 'state'. */
> int (*flow_dump_next)(const struct dpif *dpif, void *state,
> const struct nlattr **key, size_t *key_len,
> + const struct nlattr **mask, size_t *mask_len,
> const struct nlattr **actions, size_t *actions_len,
> const struct dpif_flow_stats **stats);
>
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 6aa52d5..f90b02d 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -854,6 +854,7 @@ dpif_flow_put__(struct dpif *dpif, const struct dpif_flow_put *put)
> int
> dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
> const struct nlattr *key, size_t key_len,
> + const struct nlattr *mask, size_t mask_len,
> const struct nlattr *actions, size_t actions_len,
> struct dpif_flow_stats *stats)
> {
> @@ -862,6 +863,8 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
> put.flags = flags;
> put.key = key;
> put.key_len = key_len;
> + put.mask = mask;
> + put.mask_len = mask_len;
> put.actions = actions;
> put.actions_len = actions_len;
> put.stats = stats;
> @@ -937,6 +940,7 @@ dpif_flow_dump_start(struct dpif_flow_dump *dump, const struct dpif *dpif)
> bool
> dpif_flow_dump_next(struct dpif_flow_dump *dump,
> const struct nlattr **key, size_t *key_len,
> + const struct nlattr **mask, size_t *mask_len,
> const struct nlattr **actions, size_t *actions_len,
> const struct dpif_flow_stats **stats)
> {
> @@ -946,6 +950,7 @@ dpif_flow_dump_next(struct dpif_flow_dump *dump,
> if (!error) {
> error = dpif->dpif_class->flow_dump_next(dpif, dump->state,
> key, key_len,
> + mask, mask_len,
> actions, actions_len,
> stats);
> if (error) {
> @@ -957,6 +962,10 @@ dpif_flow_dump_next(struct dpif_flow_dump *dump,
> *key = NULL;
> *key_len = 0;
> }
> + if (mask) {
> + *mask = NULL;
> + *mask_len = 0;
> + }
> if (actions) {
> *actions = NULL;
> *actions_len = 0;
> diff --git a/lib/dpif.h b/lib/dpif.h
> index fd05b2f..d7b73eb 100644
> --- a/lib/dpif.h
> +++ b/lib/dpif.h
> @@ -447,6 +447,7 @@ enum dpif_flow_put_flags {
> int dpif_flow_flush(struct dpif *);
> int dpif_flow_put(struct dpif *, enum dpif_flow_put_flags,
> const struct nlattr *key, size_t key_len,
> + const struct nlattr *mask, size_t mask_len,
> const struct nlattr *actions, size_t actions_len,
> struct dpif_flow_stats *);
> int dpif_flow_del(struct dpif *,
> @@ -464,6 +465,7 @@ struct dpif_flow_dump {
> void dpif_flow_dump_start(struct dpif_flow_dump *, const struct dpif *);
> bool dpif_flow_dump_next(struct dpif_flow_dump *,
> const struct nlattr **key, size_t *key_len,
> + const struct nlattr **mask, size_t *mask_len,
> const struct nlattr **actions, size_t *actions_len,
> const struct dpif_flow_stats **);
> int dpif_flow_dump_done(struct dpif_flow_dump *);
> @@ -492,6 +494,8 @@ struct dpif_flow_put {
> enum dpif_flow_put_flags flags; /* DPIF_FP_*. */
> const struct nlattr *key; /* Flow to put. */
> size_t key_len; /* Length of 'key' in bytes. */
> + const struct nlattr *mask; /* Mega flow mask to put. */
> + size_t mask_len; /* Length of 'mask' in bytes. */
> const struct nlattr *actions; /* Actions to perform on flow. */
> size_t actions_len; /* Length of 'actions' in bytes. */
>
> diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
> index 3e2187e..1424932 100644
> --- a/lib/netdev-dummy.c
> +++ b/lib/netdev-dummy.c
> @@ -623,7 +623,7 @@ eth_from_packet_or_flow(const char *s)
> * settle for parsing a datapath key for now.
> */
> ofpbuf_init(&odp_key, 0);
> - error = odp_flow_key_from_string(s, NULL, &odp_key);
> + error = odp_micro_flow_key_from_string(s, NULL, &odp_key);
> if (error) {
> ofpbuf_uninit(&odp_key);
> return NULL;
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index acd1a9d..6f4eb96 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -50,7 +50,10 @@ static const char *delimiters = ", \t\r\n";
>
> static int parse_odp_key_attr(const char *, const struct simap *port_names,
> struct ofpbuf *);
> -static void format_odp_key_attr(const struct nlattr *a, struct ds *ds);
> +static int parse_odp_key_mask_attr(const char *, const struct simap *port_names,
> + struct ofpbuf *, struct ofpbuf *);
> +static void format_odp_key_attr(const struct nlattr *a,
> + const struct nlattr *ma, struct ds *ds);
>
> /* Returns one the following for the action with the given OVS_ACTION_ATTR_*
> * 'type':
> @@ -378,7 +381,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
> break;
> case OVS_ACTION_ATTR_SET:
> ds_put_cstr(ds, "set(");
> - format_odp_key_attr(nl_attr_get(a), ds);
> + format_odp_key_attr(nl_attr_get(a), NULL, ds);
> ds_put_cstr(ds, ")");
> break;
> case OVS_ACTION_ATTR_PUSH_VLAN:
> @@ -747,10 +750,11 @@ format_generic_odp_key(const struct nlattr *a, struct ds *ds)
>
> unspec = nl_attr_get(a);
> for (i = 0; i < len; i++) {
> - ds_put_char(ds, i ? ' ': '(');
> + if (i) {
> + ds_put_char(ds, ' ');
> + }
> ds_put_format(ds, "%02x", unspec[i]);
> }
> - ds_put_char(ds, ')');
> }
> }
>
> @@ -876,55 +880,95 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key)
> }
>
> static void
> -format_odp_key_attr(const struct nlattr *a, struct ds *ds)
> +format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
> + struct ds *ds)
> {
> - const struct ovs_key_ethernet *eth_key;
> - const struct ovs_key_ipv4 *ipv4_key;
> - const struct ovs_key_ipv6 *ipv6_key;
> - const struct ovs_key_tcp *tcp_key;
> - const struct ovs_key_udp *udp_key;
> - const struct ovs_key_icmp *icmp_key;
> - const struct ovs_key_icmpv6 *icmpv6_key;
> - const struct ovs_key_arp *arp_key;
> - const struct ovs_key_nd *nd_key;
> struct flow_tnl tun_key;
> enum ovs_key_attr attr = nl_attr_type(a);
> char namebuf[OVS_KEY_ATTR_BUFSIZE];
> int expected_len;
>
> + if (ma) {
> + const uint8_t *ma_bytes = nl_attr_get(ma);
> + bool is_exact = true;
> + size_t i;
> +
> + for (i = 0; i < nl_attr_get_size(ma); i++) {
> + if (ma_bytes[i] != 0xff) {
> + is_exact = false;
> + break;
> + }
> + }
> + ma = is_exact ? NULL : ma;
> + }
> +
> ds_put_cstr(ds, ovs_key_attr_to_string(attr, namebuf, sizeof namebuf));
> +
> expected_len = odp_flow_key_attr_len(nl_attr_type(a));
> if (expected_len != -2 && nl_attr_get_size(a) != expected_len) {
> - ds_put_format(ds, "(bad length %zu, expected %d)",
> + ds_put_format(ds, "(bad length %zu, expected %d)(",
> nl_attr_get_size(a),
> odp_flow_key_attr_len(nl_attr_type(a)));
> format_generic_odp_key(a, ds);
> + if (ma) {
> + ds_put_char(ds, '/');
> + format_generic_odp_key(ma, ds);
> + }
> + ds_put_char(ds, ')');
> return;
> }
>
> + ds_put_char(ds, '(');
> switch (attr) {
> case OVS_KEY_ATTR_ENCAP:
> - ds_put_cstr(ds, "(");
> - if (nl_attr_get_size(a)) {
> + if (ma && nl_attr_get_size(ma) && nl_attr_get_size(a)) {
> + odp_mega_flow_format(nl_attr_get(a), nl_attr_get_size(a),
> + nl_attr_get(ma), nl_attr_get_size(ma),
> + ds);
> + } else if (nl_attr_get_size(a)) {
> odp_flow_key_format(nl_attr_get(a), nl_attr_get_size(a), ds);
> }
> - ds_put_char(ds, ')');
> break;
>
> case OVS_KEY_ATTR_PRIORITY:
> - ds_put_format(ds, "(%#"PRIx32")", nl_attr_get_u32(a));
> + ds_put_format(ds, "%#"PRIx32, nl_attr_get_u32(a));
> + if (ma) {
> + ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
> + }
> break;
>
> case OVS_KEY_ATTR_SKB_MARK:
> - ds_put_format(ds, "(%#"PRIx32")", nl_attr_get_u32(a));
> + ds_put_format(ds, "%#"PRIx32, nl_attr_get_u32(a));
> + if (ma) {
> + ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
> + }
> break;
>
> case OVS_KEY_ATTR_TUNNEL:
> memset(&tun_key, 0, sizeof tun_key);
> if (odp_tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
> - ds_put_format(ds, "(error)");
> + ds_put_format(ds, "error");
> + } else if (ma) {
> + struct flow_tnl tun_mask;
> +
> + odp_tun_key_from_attr(ma, &tun_mask);
> +
> + ds_put_format(ds, "tun_id=%#"PRIx64"/%#"PRIx64
> + ",src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
> + ",tos=%#"PRIx8"/%#"PRIx8",ttl=%"PRIu8"/%#"PRIx8
> + ",flags(",
> + ntohll(tun_key.tun_id), ntohll(tun_mask.tun_id),
> + IP_ARGS(tun_key.ip_src), IP_ARGS(tun_mask.ip_src),
> + IP_ARGS(tun_key.ip_dst), IP_ARGS(tun_mask.ip_dst),
> + tun_key.ip_tos, tun_mask.ip_tos,
> + tun_key.ip_ttl, tun_mask.ip_ttl);
> +
> + format_flags(ds, flow_tun_flag_to_string,
> + (uint32_t) tun_key.flags, ',');
> + ds_put_format(ds, "/%#"PRIx16, tun_mask.flags);
> + ds_put_char(ds, ')');
> } else {
> - ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
> + ds_put_format(ds, "tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
> "tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
> ntohll(tun_key.tun_id),
> IP_ARGS(tun_key.ip_src),
> @@ -933,117 +977,261 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
>
> format_flags(ds, flow_tun_flag_to_string,
> (uint32_t) tun_key.flags, ',');
> - ds_put_format(ds, "))");
> + ds_put_char(ds, ')');
> }
> break;
>
> case OVS_KEY_ATTR_IN_PORT:
> - ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a));
> + ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a));
> + if (ma) {
> + ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
> + }
> break;
>
> case OVS_KEY_ATTR_ETHERNET:
> - eth_key = nl_attr_get(a);
> - ds_put_format(ds, "(src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT")",
> - ETH_ADDR_ARGS(eth_key->eth_src),
> - ETH_ADDR_ARGS(eth_key->eth_dst));
> + if (ma) {
> + const struct ovs_key_ethernet *eth_mask = nl_attr_get(ma);
> + const struct ovs_key_ethernet *eth_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src="ETH_ADDR_FMT"/"ETH_ADDR_FMT
> + ",dst="ETH_ADDR_FMT"/"ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(eth_key->eth_src),
> + ETH_ADDR_ARGS(eth_mask->eth_src),
> + ETH_ADDR_ARGS(eth_key->eth_dst),
> + ETH_ADDR_ARGS(eth_mask->eth_dst));
> + } else {
> + const struct ovs_key_ethernet *eth_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(eth_key->eth_src),
> + ETH_ADDR_ARGS(eth_key->eth_dst));
> + }
> break;
>
> case OVS_KEY_ATTR_VLAN:
> - ds_put_char(ds, '(');
> format_vlan_tci(ds, nl_attr_get_be16(a));
> - ds_put_char(ds, ')');
> + if (ma) {
> + ds_put_format(ds, "/%#"PRIx16, nl_attr_get_u16(ma));
> + }
> break;
>
> case OVS_KEY_ATTR_MPLS: {
> const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
> - ds_put_char(ds, '(');
> format_mpls_lse(ds, mpls_key->mpls_lse);
> - ds_put_char(ds, ')');
> + if (ma) {
> + ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
> + }
> break;
> }
>
> case OVS_KEY_ATTR_ETHERTYPE:
> - ds_put_format(ds, "(0x%04"PRIx16")",
> - ntohs(nl_attr_get_be16(a)));
> + ds_put_format(ds, "0x%04"PRIx16, ntohs(nl_attr_get_be16(a)));
> + if (ma) {
> + ds_put_format(ds, "/0x%04"PRIx16, ntohs(nl_attr_get_be16(ma)));
> + }
> break;
>
> case OVS_KEY_ATTR_IPV4:
> - ipv4_key = nl_attr_get(a);
> - ds_put_format(ds, "(src="IP_FMT",dst="IP_FMT",proto=%"PRIu8
> - ",tos=%#"PRIx8",ttl=%"PRIu8",frag=%s)",
> - IP_ARGS(ipv4_key->ipv4_src),
> - IP_ARGS(ipv4_key->ipv4_dst),
> - ipv4_key->ipv4_proto, ipv4_key->ipv4_tos,
> - ipv4_key->ipv4_ttl,
> - ovs_frag_type_to_string(ipv4_key->ipv4_frag));
> + if (ma) {
> + const struct ovs_key_ipv4 *ipv4_key = nl_attr_get(a);
> + const struct ovs_key_ipv4 *ipv4_mask = nl_attr_get(ma);
> +
> + ds_put_format(ds, "src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
> + ",proto=%"PRIu8"/%#"PRIx8",tos=%#"PRIx8"/%#"PRIx8
> + ",ttl=%"PRIu8"/%#"PRIx8",frag=%s/%#"PRIx8,
> + IP_ARGS(ipv4_key->ipv4_src),
> + IP_ARGS(ipv4_mask->ipv4_src),
> + IP_ARGS(ipv4_key->ipv4_dst),
> + IP_ARGS(ipv4_mask->ipv4_dst),
> + ipv4_key->ipv4_proto, ipv4_mask->ipv4_proto,
> + ipv4_key->ipv4_tos, ipv4_mask->ipv4_tos,
> + ipv4_key->ipv4_ttl, ipv4_mask->ipv4_ttl,
> + ovs_frag_type_to_string(ipv4_key->ipv4_frag),
> + ipv4_mask->ipv4_frag);
> + } else {
> + const struct ovs_key_ipv4 *ipv4_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src="IP_FMT",dst="IP_FMT",proto=%"PRIu8
> + ",tos=%#"PRIx8",ttl=%"PRIu8",frag=%s",
> + IP_ARGS(ipv4_key->ipv4_src),
> + IP_ARGS(ipv4_key->ipv4_dst),
> + ipv4_key->ipv4_proto, ipv4_key->ipv4_tos,
> + ipv4_key->ipv4_ttl,
> + ovs_frag_type_to_string(ipv4_key->ipv4_frag));
> + }
> break;
>
> - case OVS_KEY_ATTR_IPV6: {
> - char src_str[INET6_ADDRSTRLEN];
> - char dst_str[INET6_ADDRSTRLEN];
> + case OVS_KEY_ATTR_IPV6:
> + if (ma) {
> + const struct ovs_key_ipv6 *ipv6_key, *ipv6_mask;
> + char src_str[INET6_ADDRSTRLEN];
> + char dst_str[INET6_ADDRSTRLEN];
> + char src_mask[INET6_ADDRSTRLEN];
> + char dst_mask[INET6_ADDRSTRLEN];
> +
> + ipv6_key = nl_attr_get(a);
> + inet_ntop(AF_INET6, ipv6_key->ipv6_src, src_str, sizeof src_str);
> + inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
> +
> + ipv6_mask = nl_attr_get(ma);
> + inet_ntop(AF_INET6, ipv6_mask->ipv6_src, src_str, sizeof src_str);
> + inet_ntop(AF_INET6, ipv6_mask->ipv6_dst, dst_str, sizeof dst_str);
> +
> + ds_put_format(ds, "src=%s/%s,dst=%s/%s,label=%#"PRIx32"/%#"PRIx32
> + ",proto=%"PRIu8"/%#"PRIx8",tclass=%#"PRIx8"/%#"PRIx8
> + ",hlimit=%"PRIu8"/%#"PRIx8",frag=%s/%#"PRIx8,
> + src_str, src_mask, dst_str, dst_mask,
> + ntohl(ipv6_key->ipv6_label),
> + ntohl(ipv6_mask->ipv6_label),
> + ipv6_key->ipv6_proto, ipv6_mask->ipv6_proto,
> + ipv6_key->ipv6_tclass, ipv6_mask->ipv6_tclass,
> + ipv6_key->ipv6_hlimit, ipv6_mask->ipv6_hlimit,
> + ovs_frag_type_to_string(ipv6_key->ipv6_frag),
> + ipv6_mask->ipv6_frag);
> + } else {
> + const struct ovs_key_ipv6 *ipv6_key;
> + char src_str[INET6_ADDRSTRLEN];
> + char dst_str[INET6_ADDRSTRLEN];
>
> - ipv6_key = nl_attr_get(a);
> - inet_ntop(AF_INET6, ipv6_key->ipv6_src, src_str, sizeof src_str);
> - inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
> + ipv6_key = nl_attr_get(a);
> + inet_ntop(AF_INET6, ipv6_key->ipv6_src, src_str, sizeof src_str);
> + inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
>
> - ds_put_format(ds, "(src=%s,dst=%s,label=%#"PRIx32",proto=%"PRIu8
> - ",tclass=%#"PRIx8",hlimit=%"PRIu8",frag=%s)",
> - src_str, dst_str, ntohl(ipv6_key->ipv6_label),
> - ipv6_key->ipv6_proto, ipv6_key->ipv6_tclass,
> - ipv6_key->ipv6_hlimit,
> - ovs_frag_type_to_string(ipv6_key->ipv6_frag));
> + ds_put_format(ds, "src=%s,dst=%s,label=%#"PRIx32",proto=%"PRIu8
> + ",tclass=%#"PRIx8",hlimit=%"PRIu8",frag=%s",
> + src_str, dst_str, ntohl(ipv6_key->ipv6_label),
> + ipv6_key->ipv6_proto, ipv6_key->ipv6_tclass,
> + ipv6_key->ipv6_hlimit,
> + ovs_frag_type_to_string(ipv6_key->ipv6_frag));
> + }
> break;
> - }
>
> case OVS_KEY_ATTR_TCP:
> - tcp_key = nl_attr_get(a);
> - ds_put_format(ds, "(src=%"PRIu16",dst=%"PRIu16")",
> - ntohs(tcp_key->tcp_src), ntohs(tcp_key->tcp_dst));
> + if (ma) {
> + const struct ovs_key_tcp *tcp_mask = nl_attr_get(ma);
> + const struct ovs_key_tcp *tcp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
> + ",dst=%"PRIu16"/%#"PRIx16,
> + ntohs(tcp_key->tcp_src), ntohs(tcp_mask->tcp_src),
> + ntohs(tcp_key->tcp_dst), ntohs(tcp_mask->tcp_dst));
> + } else {
> + const struct ovs_key_tcp *tcp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src=%"PRIu16",dst=%"PRIu16,
> + ntohs(tcp_key->tcp_src), ntohs(tcp_key->tcp_dst));
> + }
> break;
>
> case OVS_KEY_ATTR_UDP:
> - udp_key = nl_attr_get(a);
> - ds_put_format(ds, "(src=%"PRIu16",dst=%"PRIu16")",
> - ntohs(udp_key->udp_src), ntohs(udp_key->udp_dst));
> + if (ma) {
> + const struct ovs_key_udp *udp_mask = nl_attr_get(ma);
> + const struct ovs_key_udp *udp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
> + ",dst=%"PRIu16"/%#"PRIx16,
> + ntohs(udp_key->udp_src), ntohs(udp_mask->udp_src),
> + ntohs(udp_key->udp_dst), ntohs(udp_mask->udp_dst));
> + } else {
> + const struct ovs_key_udp *udp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "src=%"PRIu16",dst=%"PRIu16,
> + ntohs(udp_key->udp_src), ntohs(udp_key->udp_dst));
> + }
> break;
>
> case OVS_KEY_ATTR_ICMP:
> - icmp_key = nl_attr_get(a);
> - ds_put_format(ds, "(type=%"PRIu8",code=%"PRIu8")",
> - icmp_key->icmp_type, icmp_key->icmp_code);
> + if (ma) {
> + const struct ovs_key_icmp *icmp_mask = nl_attr_get(ma);
> + const struct ovs_key_icmp *icmp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "type=%"PRIu8"/%#"PRIx8",code=%"PRIu8"/%#"PRIx8,
> + icmp_key->icmp_type, icmp_mask->icmp_type,
> + icmp_key->icmp_code, icmp_mask->icmp_code);
> + } else {
> + const struct ovs_key_icmp *icmp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "type=%"PRIu8",code=%"PRIu8,
> + icmp_key->icmp_type, icmp_key->icmp_code);
> + }
> break;
>
> case OVS_KEY_ATTR_ICMPV6:
> - icmpv6_key = nl_attr_get(a);
> - ds_put_format(ds, "(type=%"PRIu8",code=%"PRIu8")",
> - icmpv6_key->icmpv6_type, icmpv6_key->icmpv6_code);
> + if (ma) {
> + const struct ovs_key_icmpv6 *icmpv6_mask = nl_attr_get(ma);
> + const struct ovs_key_icmpv6 *icmpv6_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "type=%"PRIu8"/%#"PRIx8",code=%"PRIu8"/%#"PRIx8,
> + icmpv6_key->icmpv6_type, icmpv6_mask->icmpv6_type,
> + icmpv6_key->icmpv6_code, icmpv6_mask->icmpv6_code);
> + } else {
> + const struct ovs_key_icmpv6 *icmpv6_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "type=%"PRIu8",code=%"PRIu8,
> + icmpv6_key->icmpv6_type, icmpv6_key->icmpv6_code);
> + }
> break;
>
> case OVS_KEY_ATTR_ARP:
> - arp_key = nl_attr_get(a);
> - ds_put_format(ds, "(sip="IP_FMT",tip="IP_FMT",op=%"PRIu16","
> - "sha="ETH_ADDR_FMT",tha="ETH_ADDR_FMT")",
> - IP_ARGS(arp_key->arp_sip), IP_ARGS(arp_key->arp_tip),
> - ntohs(arp_key->arp_op), ETH_ADDR_ARGS(arp_key->arp_sha),
> - ETH_ADDR_ARGS(arp_key->arp_tha));
> + if (ma) {
> + const struct ovs_key_arp *arp_mask = nl_attr_get(ma);
> + const struct ovs_key_arp *arp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "sip="IP_FMT"/"IP_FMT",tip="IP_FMT"/"IP_FMT
> + ",op=%"PRIu16"/%#"PRIx16
> + ",sha="ETH_ADDR_FMT"/"ETH_ADDR_FMT
> + ",tha="ETH_ADDR_FMT"/"ETH_ADDR_FMT,
> + IP_ARGS(arp_key->arp_sip),
> + IP_ARGS(arp_mask->arp_sip),
> + IP_ARGS(arp_key->arp_tip),
> + IP_ARGS(arp_mask->arp_tip),
> + ntohs(arp_key->arp_op), ntohs(arp_mask->arp_op),
> + ETH_ADDR_ARGS(arp_key->arp_sha),
> + ETH_ADDR_ARGS(arp_mask->arp_sha),
> + ETH_ADDR_ARGS(arp_key->arp_tha),
> + ETH_ADDR_ARGS(arp_mask->arp_tha));
> + } else {
> + const struct ovs_key_arp *arp_key = nl_attr_get(a);
> +
> + ds_put_format(ds, "sip="IP_FMT",tip="IP_FMT",op=%"PRIu16","
> + "sha="ETH_ADDR_FMT",tha="ETH_ADDR_FMT,
> + IP_ARGS(arp_key->arp_sip), IP_ARGS(arp_key->arp_tip),
> + ntohs(arp_key->arp_op),
> + ETH_ADDR_ARGS(arp_key->arp_sha),
> + ETH_ADDR_ARGS(arp_key->arp_tha));
> + }
> break;
>
> case OVS_KEY_ATTR_ND: {
> + const struct ovs_key_nd *nd_key, *nd_mask;
> char target[INET6_ADDRSTRLEN];
>
> nd_key = nl_attr_get(a);
> + nd_mask = ma ? nl_attr_get(ma) : NULL;
> +
> inet_ntop(AF_INET6, nd_key->nd_target, target, sizeof target);
> + ds_put_format(ds, "target=%s", target);
> + if (nd_mask) {
> + inet_ntop(AF_INET6, nd_mask->nd_target, target, sizeof target);
> + ds_put_format(ds, "/%s", target);
> + }
>
> - ds_put_format(ds, "(target=%s", target);
> if (!eth_addr_is_zero(nd_key->nd_sll)) {
> ds_put_format(ds, ",sll="ETH_ADDR_FMT,
> ETH_ADDR_ARGS(nd_key->nd_sll));
> + if (nd_mask) {
> + ds_put_format(ds, "/"ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(nd_mask->nd_sll));
> + }
> }
> if (!eth_addr_is_zero(nd_key->nd_tll)) {
> ds_put_format(ds, ",tll="ETH_ADDR_FMT,
> ETH_ADDR_ARGS(nd_key->nd_tll));
> + if (nd_mask) {
> + ds_put_format(ds, "/"ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(nd_mask->nd_tll));
> + }
> }
> - ds_put_char(ds, ')');
> break;
> }
>
> @@ -1051,24 +1239,39 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
> case __OVS_KEY_ATTR_MAX:
> default:
> format_generic_odp_key(a, ds);
> + if (ma) {
> + ds_put_char(ds, '/');
> + format_generic_odp_key(ma, ds);
> + }
> break;
> }
> + ds_put_char(ds, ')');
> }
>
> /* Appends to 'ds' a string representation of the 'key_len' bytes of
> - * OVS_KEY_ATTR_* attributes in 'key'. */
> + * OVS_KEY_ATTR_* attributes in 'key'. If non-null, additionally formats the
> + * 'mask_len' bytes of 'mask' which apply to 'key'. */
> void
> -odp_flow_key_format(const struct nlattr *key, size_t key_len, struct ds *ds)
> +odp_mega_flow_format(const struct nlattr *key, size_t key_len,
> + const struct nlattr *mask, size_t mask_len,
> + struct ds *ds)
> {
> if (key_len) {
> const struct nlattr *a;
> unsigned int left;
>
> NL_ATTR_FOR_EACH (a, left, key, key_len) {
> + const struct nlattr *ma = NULL;
> +
> if (a != key) {
> ds_put_char(ds, ',');
> }
> - format_odp_key_attr(a, ds);
> +
> + if (mask && mask_len) {
> + ma = nl_attr_find__(mask, mask_len, nl_attr_type(a));
> + }
> +
> + format_odp_key_attr(a, ma, ds);
> }
> if (left) {
> int i;
> @@ -1087,6 +1290,14 @@ odp_flow_key_format(const struct nlattr *key, size_t key_len, struct ds *ds)
> }
> }
>
> +/* Appends to 'ds' a string representation of the 'key_len' bytes of
> + * OVS_KEY_ATTR_* attributes in 'key'. */
> +void
> +odp_flow_key_format(const struct nlattr *key, size_t key_len, struct ds *ds)
> +{
> + odp_mega_flow_format(key, key_len, NULL, 0, ds);
> +}
> +
> static int
> put_nd_key(int n, const char *nd_target_s,
> const uint8_t *nd_sll, const uint8_t *nd_tll, struct ofpbuf *key)
> @@ -1132,8 +1343,8 @@ mpls_lse_from_components(int mpls_label, int mpls_tc, int mpls_ttl, int mpls_bos
> }
>
> static int
> -parse_odp_key_attr(const char *s, const struct simap *port_names,
> - struct ofpbuf *key)
> +parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
> + struct ofpbuf *key, struct ofpbuf *mask)
> {
> /* Many of the sscanf calls in this function use oversized destination
> * fields because some sscanf() implementations truncate the range of %i
> @@ -1147,31 +1358,79 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
>
> {
> unsigned long long int priority;
> + unsigned long long int priority_mask;
> int n = -1;
>
> - if (sscanf(s, "skb_priority(%llx)%n", &priority, &n) > 0 && n > 0) {
> + if (sscanf(s, "skb_priority(%llx/%llx)%n", &priority,
> + &priority_mask, &n) > 0 && n > 0) {
> nl_msg_put_u32(key, OVS_KEY_ATTR_PRIORITY, priority);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_PRIORITY, priority_mask);
> + return n;
> + } else if (sscanf(s, "skb_priority(%llx)%n",
> + &priority, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_PRIORITY, priority);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_PRIORITY, 0xffffffff);
> return n;
> }
> }
>
> {
> unsigned long long int mark;
> + unsigned long long int mark_mask;
> int n = -1;
>
> - if (sscanf(s, "skb_mark(%llx)%n", &mark, &n) > 0 && n > 0) {
> + if (sscanf(s, "skb_mark(%llx/%llx)%n", &mark,
> + &mark_mask, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_SKB_MARK, mark);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_SKB_MARK, mark_mask);
> + return n;
> + } else if (sscanf(s, "skb_mark(%llx)%n", &mark, &n) > 0 && n > 0) {
> nl_msg_put_u32(key, OVS_KEY_ATTR_SKB_MARK, mark);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_SKB_MARK, 0xffffffff);
> return n;
> }
> }
>
> {
> char tun_id_s[32];
> - int tos, ttl;
> - struct flow_tnl tun_key;
> + int tos, tos_mask, ttl, ttl_mask;
> + struct flow_tnl tun_key, tun_key_mask;
> int n = -1;
>
> if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
> + "src="IP_SCAN_FMT"/"IP_SCAN_FMT",dst="IP_SCAN_FMT
> + "/"IP_SCAN_FMT",tos=%i/%x,ttl=%i/%x,flags%n",
> + tun_id_s,
> + IP_SCAN_ARGS(&tun_key.ip_src),
> + IP_SCAN_ARGS(&tun_key_mask.ip_src),
> + IP_SCAN_ARGS(&tun_key.ip_dst),
> + IP_SCAN_ARGS(&tun_key_mask.ip_dst),
> + &tos, &tos_mask, &ttl, &ttl_mask,
> + &n) > 0 && n > 0) {
> + int res;
> + uint32_t flags;
> +
> + tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0));
> + tun_key.ip_tos = tos;
> + tun_key_mask.ip_tos = tos_mask;
> + tun_key.ip_ttl = ttl;
> + tun_key_mask.ip_ttl = ttl_mask;
> + res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
> + tun_key.flags = (uint16_t) flags;
> + tun_key_mask.flags = (uint16_t) 0xffff;
> +
> + if (res < 0) {
> + return res;
> + }
> + n += res;
> + if (s[n] != ')') {
> + return -EINVAL;
> + }
> + n++;
> + tun_key_to_attr(key, &tun_key);
> + tun_key_to_attr(mask, &tun_key_mask);
> + return n;
> + } else if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
> "src="IP_SCAN_FMT",dst="IP_SCAN_FMT
> ",tos=%i,ttl=%i,flags%n", tun_id_s,
> IP_SCAN_ARGS(&tun_key.ip_src),
> @@ -1195,20 +1454,31 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> }
> n++;
> tun_key_to_attr(key, &tun_key);
> +
> + memset(&tun_key, 0xff, sizeof tun_key);
> + tun_key_to_attr(mask, &tun_key);
> return n;
> }
> }
>
> {
> unsigned long long int in_port;
> + unsigned long long int in_port_mask;
> int n = -1;
>
> - if (sscanf(s, "in_port(%lli)%n", &in_port, &n) > 0 && n > 0) {
> + if (sscanf(s, "in_port(%lli/%llx)%n", &in_port,
> + &in_port_mask, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, in_port);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_IN_PORT, in_port_mask);
> + return n;
> + } else if (sscanf(s, "in_port(%lli)%n", &in_port, &n) > 0 && n > 0) {
> nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, in_port);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_IN_PORT, 0xffffffff);
> return n;
> }
> }
>
> +
> if (port_names && !strncmp(s, "in_port(", 8)) {
> const char *name;
> const struct simap_node *node;
> @@ -1219,20 +1489,39 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> node = simap_find_len(port_names, name, name_len);
> if (node) {
> nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, node->data);
> + nl_msg_put_u32(mask, OVS_KEY_ATTR_IN_PORT, 0xffffffff);
> return 8 + name_len + 1;
> }
> }
>
> {
> struct ovs_key_ethernet eth_key;
> + struct ovs_key_ethernet eth_key_mask;
> int n = -1;
>
> if (sscanf(s,
> + "eth(src="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT","
> + "dst="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
> + ETH_ADDR_SCAN_ARGS(eth_key.eth_src),
> + ETH_ADDR_SCAN_ARGS(eth_key_mask.eth_src),
> + ETH_ADDR_SCAN_ARGS(eth_key.eth_dst),
> + ETH_ADDR_SCAN_ARGS(eth_key_mask.eth_dst), &n) > 0 && n > 0) {
> +
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ETHERNET,
> + ð_key, sizeof eth_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ETHERNET,
> + ð_key_mask, sizeof eth_key_mask);
> + return n;
> + } else if (sscanf(s,
> "eth(src="ETH_ADDR_SCAN_FMT",dst="ETH_ADDR_SCAN_FMT")%n",
> ETH_ADDR_SCAN_ARGS(eth_key.eth_src),
> ETH_ADDR_SCAN_ARGS(eth_key.eth_dst), &n) > 0 && n > 0) {
> nl_msg_put_unspec(key, OVS_KEY_ATTR_ETHERNET,
> ð_key, sizeof eth_key);
> +
> + memset(ð_key, 0xff, sizeof eth_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ETHERNET,
> + ð_key, sizeof eth_key);
> return n;
> }
> }
> @@ -1241,32 +1530,57 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> uint16_t vid;
> int pcp;
> int cfi;
> + unsigned long long int vlan_mask;
> int n = -1;
>
> - if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i)%n", &vid, &pcp, &n) > 0
> - && n > 0)) {
> + if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i)/%llx%n",
> + &vid, &pcp, &vlan_mask, &n) > 0 && n > 0)) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> + htons((vid << VLAN_VID_SHIFT) |
> + (pcp << VLAN_PCP_SHIFT) |
> + VLAN_CFI));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_VLAN, htons(vlan_mask));
> + return n;
> + } else if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i)%n",
> + &vid, &pcp, &n) > 0 && n > 0)) {
> nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> htons((vid << VLAN_VID_SHIFT) |
> (pcp << VLAN_PCP_SHIFT) |
> VLAN_CFI));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_VLAN, htons(0xffff));
> + return n;
> + } else if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i,cfi=%i)/%llx%n",
> + &vid, &pcp, &cfi, &vlan_mask, &n) > 0 && n > 0)) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> + htons((vid << VLAN_VID_SHIFT) |
> + (pcp << VLAN_PCP_SHIFT) |
> + (cfi ? VLAN_CFI : 0)));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_VLAN, htons(vlan_mask));
> return n;
> } else if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i,cfi=%i)%n",
> - &vid, &pcp, &cfi, &n) > 0
> - && n > 0)) {
> + &vid, &pcp, &cfi, &n) > 0 && n > 0)) {
> nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> htons((vid << VLAN_VID_SHIFT) |
> (pcp << VLAN_PCP_SHIFT) |
> (cfi ? VLAN_CFI : 0)));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_VLAN, htons(0xffff));
> return n;
> }
> }
>
> {
> int eth_type;
> + unsigned long long int eth_type_mask;
> int n = -1;
>
> - if (sscanf(s, "eth_type(%i)%n", ð_type, &n) > 0 && n > 0) {
> + if (sscanf(s, "eth_type(%i/%llx)%n",
> + ð_type, ð_type_mask, &n) > 0 && n > 0) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_ETHERTYPE, htons(eth_type));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_ETHERTYPE, htons(eth_type_mask));
> + return n;
> + } else if (sscanf(s, "eth_type(%i)%n", ð_type, &n) > 0 && n > 0) {
> nl_msg_put_be16(key, OVS_KEY_ATTR_ETHERTYPE, htons(eth_type));
> + nl_msg_put_be16(mask, OVS_KEY_ATTR_ETHERTYPE, htons(0xffff));
> return n;
> }
> }
> @@ -1287,17 +1601,54 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> }
> }
>
> +
> {
> - ovs_be32 ipv4_src;
> - ovs_be32 ipv4_dst;
> + ovs_be32 ipv4_src, ipv4_src_mask;
> + ovs_be32 ipv4_dst, ipv4_dst_mask;
> int ipv4_proto;
> + unsigned long long int ipv4_proto_mask;
> int ipv4_tos;
> + unsigned long long int ipv4_tos_mask;
> int ipv4_ttl;
> + unsigned long long int ipv4_ttl_mask;
> char frag[8];
> + unsigned long long int ipv4_frag_mask;
> enum ovs_frag_type ipv4_frag;
> int n = -1;
>
> - if (sscanf(s, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT","
> + if (sscanf(s, "ipv4(src="IP_SCAN_FMT"/"IP_SCAN_FMT","
> + "dst="IP_SCAN_FMT"/"IP_SCAN_FMT","
> + "proto=%i/%llx,tos=%i/%llx,ttl=%i/%llx,"
> + "frag=%7[a-z]/%llx)%n",
> + IP_SCAN_ARGS(&ipv4_src), IP_SCAN_ARGS(&ipv4_src_mask),
> + IP_SCAN_ARGS(&ipv4_dst), IP_SCAN_ARGS(&ipv4_dst_mask),
> + &ipv4_proto, &ipv4_proto_mask,
> + &ipv4_tos, &ipv4_tos_mask, &ipv4_ttl, &ipv4_ttl_mask,
> + frag, &ipv4_frag_mask, &n) > 0
> + && n > 0
> + && ovs_frag_type_from_string(frag, &ipv4_frag)) {
> + struct ovs_key_ipv4 ipv4_key;
> + struct ovs_key_ipv4 ipv4_mask;
> +
> + ipv4_key.ipv4_src = ipv4_src;
> + ipv4_key.ipv4_dst = ipv4_dst;
> + ipv4_key.ipv4_proto = ipv4_proto;
> + ipv4_key.ipv4_tos = ipv4_tos;
> + ipv4_key.ipv4_ttl = ipv4_ttl;
> + ipv4_key.ipv4_frag = ipv4_frag;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4,
> + &ipv4_key, sizeof ipv4_key);
> +
> + ipv4_mask.ipv4_src = ipv4_src_mask;
> + ipv4_mask.ipv4_dst = ipv4_dst_mask;
> + ipv4_mask.ipv4_proto = ipv4_proto_mask;
> + ipv4_mask.ipv4_tos = ipv4_tos_mask;
> + ipv4_mask.ipv4_ttl = ipv4_ttl_mask;
> + ipv4_mask.ipv4_frag = ipv4_frag_mask;
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_IPV4,
> + &ipv4_mask, sizeof ipv4_mask);
> + return n;
> + } else if (sscanf(s, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT","
> "proto=%i,tos=%i,ttl=%i,frag=%7[a-z])%n",
> IP_SCAN_ARGS(&ipv4_src), IP_SCAN_ARGS(&ipv4_dst),
> &ipv4_proto, &ipv4_tos, &ipv4_ttl, frag, &n) > 0
> @@ -1313,22 +1664,68 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> ipv4_key.ipv4_frag = ipv4_frag;
> nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4,
> &ipv4_key, sizeof ipv4_key);
> +
> + memset(&ipv4_key, 0xff, sizeof ipv4_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_IPV4,
> + &ipv4_key, sizeof ipv4_key);
> return n;
> }
> }
>
> {
> char ipv6_src_s[IPV6_SCAN_LEN + 1];
> + char ipv6_src_mask_s[IPV6_SCAN_LEN + 1];
> char ipv6_dst_s[IPV6_SCAN_LEN + 1];
> + char ipv6_dst_mask_s[IPV6_SCAN_LEN + 1];
> int ipv6_label;
> + unsigned long long int ipv6_label_mask;
> int ipv6_proto;
> + unsigned long long int ipv6_proto_mask;
> int ipv6_tclass;
> + unsigned long long int ipv6_tclass_mask;
> int ipv6_hlimit;
> + unsigned long long int ipv6_hlimit_mask;
> char frag[8];
> enum ovs_frag_type ipv6_frag;
> + unsigned long long int ipv6_frag_mask;
> int n = -1;
>
> - if (sscanf(s, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT","
> + if (sscanf(s, "ipv6(src="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT",dst="
> + IPV6_SCAN_FMT"/"IPV6_SCAN_FMT","
> + "label=%i/%llx,proto=%i/%llx,tclass=%i/%llx,"
> + "hlimit=%i/%llx,frag=%7[a-z]/%llx)%n",
> + ipv6_src_s, ipv6_src_mask_s, ipv6_dst_s, ipv6_dst_mask_s,
> + &ipv6_label, &ipv6_label_mask, &ipv6_proto,
> + &ipv6_proto_mask, &ipv6_tclass, &ipv6_tclass_mask,
> + &ipv6_hlimit, &ipv6_hlimit_mask, frag,
> + &ipv6_frag_mask, &n) > 0
> + && n > 0
> + && ovs_frag_type_from_string(frag, &ipv6_frag)) {
> + struct ovs_key_ipv6 ipv6_key;
> + struct ovs_key_ipv6 ipv6_mask;
> +
> + if (inet_pton(AF_INET6, ipv6_src_s, &ipv6_key.ipv6_src) != 1 ||
> + inet_pton(AF_INET6, ipv6_dst_s, &ipv6_key.ipv6_dst) != 1) {
> + return -EINVAL;
> + }
> + ipv6_key.ipv6_label = htonl(ipv6_label);
> + ipv6_key.ipv6_proto = ipv6_proto;
> + ipv6_key.ipv6_tclass = ipv6_tclass;
> + ipv6_key.ipv6_hlimit = ipv6_hlimit;
> + ipv6_key.ipv6_frag = ipv6_frag;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV6,
> + &ipv6_key, sizeof ipv6_key);
> +
> + ipv6_mask.ipv6_label = htonl(ipv6_label_mask);
> + ipv6_mask.ipv6_proto = ipv6_proto_mask;
> + ipv6_mask.ipv6_tclass = ipv6_tclass_mask;
> + ipv6_mask.ipv6_hlimit = ipv6_hlimit_mask;
> + ipv6_mask.ipv6_frag = ipv6_frag_mask;
> + memset(&ipv6_key, 0xff, sizeof ipv6_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_IPV6,
> + &ipv6_mask, sizeof ipv6_mask);
> + return n;
> + } else if (sscanf(s, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT","
> "label=%i,proto=%i,tclass=%i,hlimit=%i,frag=%7[a-z])%n",
> ipv6_src_s, ipv6_dst_s, &ipv6_label,
> &ipv6_proto, &ipv6_tclass, &ipv6_hlimit, frag, &n) > 0
> @@ -1354,15 +1751,36 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> {
> int tcp_src;
> int tcp_dst;
> + unsigned long long int tcp_src_mask;
> + unsigned long long int tcp_dst_mask;
> int n = -1;
>
> - if (sscanf(s, "tcp(src=%i,dst=%i)%n",&tcp_src, &tcp_dst, &n) > 0
> + if (sscanf(s, "tcp(src=%i/%llx,dst=%i/%llx)%n",
> + &tcp_src, &tcp_src_mask, &tcp_dst, &tcp_dst_mask, &n) > 0
> + && n > 0) {
> + struct ovs_key_tcp tcp_key;
> + struct ovs_key_tcp tcp_mask;
> +
> + tcp_key.tcp_src = htons(tcp_src);
> + tcp_key.tcp_dst = htons(tcp_dst);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_TCP, &tcp_key, sizeof tcp_key);
> +
> + tcp_mask.tcp_src = htons(tcp_src_mask);
> + tcp_mask.tcp_dst = htons(tcp_dst_mask);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_TCP,
> + &tcp_mask, sizeof tcp_mask);
> + return n;
> + } else if (sscanf(s, "tcp(src=%i,dst=%i)%n",&tcp_src, &tcp_dst, &n) > 0
> && n > 0) {
> struct ovs_key_tcp tcp_key;
>
> tcp_key.tcp_src = htons(tcp_src);
> tcp_key.tcp_dst = htons(tcp_dst);
> nl_msg_put_unspec(key, OVS_KEY_ATTR_TCP, &tcp_key, sizeof tcp_key);
> +
> + memset(&tcp_key, 0xff, sizeof tcp_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_TCP,
> + &tcp_key, sizeof tcp_key);
> return n;
> }
> }
> @@ -1370,8 +1788,26 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> {
> int udp_src;
> int udp_dst;
> + unsigned long long int udp_src_mask;
> + unsigned long long int udp_dst_mask;
> int n = -1;
>
> + if (sscanf(s, "udp(src=%i/%llx,dst=%i/%llx)%n",
> + &udp_src, &udp_src_mask,
> + &udp_dst, &udp_dst_mask, &n) > 0 && n > 0) {
> + struct ovs_key_udp udp_key;
> + struct ovs_key_udp udp_mask;
> +
> + udp_key.udp_src = htons(udp_src);
> + udp_key.udp_dst = htons(udp_dst);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_UDP, &udp_key, sizeof udp_key);
> +
> + udp_mask.udp_src = htons(udp_src_mask);
> + udp_mask.udp_dst = htons(udp_dst_mask);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_UDP,
> + &udp_mask, sizeof udp_mask);
> + return n;
> + }
> if (sscanf(s, "udp(src=%i,dst=%i)%n", &udp_src, &udp_dst, &n) > 0
> && n > 0) {
> struct ovs_key_udp udp_key;
> @@ -1379,6 +1815,9 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> udp_key.udp_src = htons(udp_src);
> udp_key.udp_dst = htons(udp_dst);
> nl_msg_put_unspec(key, OVS_KEY_ATTR_UDP, &udp_key, sizeof udp_key);
> +
> + memset(&udp_key, 0xff, sizeof udp_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_UDP, &udp_key, sizeof udp_key);
> return n;
> }
> }
> @@ -1386,9 +1825,27 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> {
> int icmp_type;
> int icmp_code;
> + unsigned long long int icmp_type_mask;
> + unsigned long long int icmp_code_mask;
> int n = -1;
>
> - if (sscanf(s, "icmp(type=%i,code=%i)%n",
> + if (sscanf(s, "icmp(type=%i/%llx,code=%i/%llx)%n",
> + &icmp_type, &icmp_type_mask,
> + &icmp_code, &icmp_code_mask, &n) > 0 && n > 0) {
> + struct ovs_key_icmp icmp_key;
> + struct ovs_key_icmp icmp_mask;
> +
> + icmp_key.icmp_type = icmp_type;
> + icmp_key.icmp_code = icmp_code;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMP,
> + &icmp_key, sizeof icmp_key);
> +
> + icmp_mask.icmp_type = icmp_type_mask;
> + icmp_mask.icmp_code = icmp_code_mask;
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ICMP,
> + &icmp_mask, sizeof icmp_mask);
> + return n;
> + } else if (sscanf(s, "icmp(type=%i,code=%i)%n",
> &icmp_type, &icmp_code, &n) > 0
> && n > 0) {
> struct ovs_key_icmp icmp_key;
> @@ -1397,32 +1854,87 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> icmp_key.icmp_code = icmp_code;
> nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMP,
> &icmp_key, sizeof icmp_key);
> + memset(&icmp_key, 0xff, sizeof icmp_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ICMP, &icmp_key,
> + sizeof icmp_key);
> return n;
> }
> }
>
> {
> struct ovs_key_icmpv6 icmpv6_key;
> + struct ovs_key_icmpv6 icmpv6_mask;
> + unsigned long long int icmpv6_type_mask;
> + unsigned long long int icmpv6_code_mask;
> int n = -1;
>
> - if (sscanf(s, "icmpv6(type=%"SCNi8",code=%"SCNi8")%n",
> + if (sscanf(s, "icmpv6(type=%"SCNi8"/%llx,code=%"SCNi8"/%llx)%n",
> + &icmpv6_key.icmpv6_type, &icmpv6_type_mask,
> + &icmpv6_key.icmpv6_code, &icmpv6_code_mask, &n) > 0
> + && n > 0) {
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMPV6,
> + &icmpv6_key, sizeof icmpv6_key);
> +
> + icmpv6_mask.icmpv6_type = icmpv6_type_mask;
> + icmpv6_mask.icmpv6_code = icmpv6_code_mask;
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ICMPV6, &icmpv6_mask,
> + sizeof icmpv6_mask);
> + return n;
> + } else if (sscanf(s, "icmpv6(type=%"SCNi8",code=%"SCNi8")%n",
> &icmpv6_key.icmpv6_type, &icmpv6_key.icmpv6_code,&n) > 0
> && n > 0) {
> nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMPV6,
> &icmpv6_key, sizeof icmpv6_key);
> +
> + memset(&icmpv6_key, 0xff, sizeof icmpv6_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ICMPV6, &icmpv6_key,
> + sizeof icmpv6_key);
> return n;
> }
> }
>
> {
> - ovs_be32 arp_sip;
> - ovs_be32 arp_tip;
> + ovs_be32 arp_sip, arp_sip_mask;
> + ovs_be32 arp_tip, arp_tip_mask;
> int arp_op;
> + unsigned long long int arp_op_mask;
> uint8_t arp_sha[ETH_ADDR_LEN];
> + uint8_t arp_sha_mask[ETH_ADDR_LEN];
> uint8_t arp_tha[ETH_ADDR_LEN];
> + uint8_t arp_tha_mask[ETH_ADDR_LEN];
> int n = -1;
>
> - if (sscanf(s, "arp(sip="IP_SCAN_FMT",tip="IP_SCAN_FMT","
> + if (sscanf(s, "arp(sip="IP_SCAN_FMT"/"IP_SCAN_FMT","
> + "tip="IP_SCAN_FMT"/"IP_SCAN_FMT","
> + "op=%i/%llx,sha="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT","
> + "tha="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
> + IP_SCAN_ARGS(&arp_sip), IP_SCAN_ARGS(&arp_sip_mask),
> + IP_SCAN_ARGS(&arp_tip), IP_SCAN_ARGS(&arp_tip_mask),
> + &arp_op, &arp_op_mask,
> + ETH_ADDR_SCAN_ARGS(arp_sha),
> + ETH_ADDR_SCAN_ARGS(arp_sha_mask),
> + ETH_ADDR_SCAN_ARGS(arp_tha),
> + ETH_ADDR_SCAN_ARGS(arp_tha_mask), &n) > 0 && n > 0) {
> + struct ovs_key_arp arp_key;
> + struct ovs_key_arp arp_mask;
> +
> + memset(&arp_key, 0, sizeof arp_key);
> + arp_key.arp_sip = arp_sip;
> + arp_key.arp_tip = arp_tip;
> + arp_key.arp_op = htons(arp_op);
> + memcpy(arp_key.arp_sha, arp_sha, ETH_ADDR_LEN);
> + memcpy(arp_key.arp_tha, arp_tha, ETH_ADDR_LEN);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ARP, &arp_key, sizeof arp_key);
> +
> + arp_mask.arp_sip = arp_sip_mask;
> + arp_mask.arp_tip = arp_tip_mask;
> + arp_mask.arp_op = htons(arp_op_mask);
> + memcpy(arp_mask.arp_sha, arp_sha_mask, ETH_ADDR_LEN);
> + memcpy(arp_mask.arp_tha, arp_tha_mask, ETH_ADDR_LEN);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ARP,
> + &arp_mask, sizeof arp_mask);
> + return n;
> + } else if (sscanf(s, "arp(sip="IP_SCAN_FMT",tip="IP_SCAN_FMT","
> "op=%i,sha="ETH_ADDR_SCAN_FMT",tha="ETH_ADDR_SCAN_FMT")%n",
> IP_SCAN_ARGS(&arp_sip),
> IP_SCAN_ARGS(&arp_tip),
> @@ -1438,44 +1950,88 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> memcpy(arp_key.arp_sha, arp_sha, ETH_ADDR_LEN);
> memcpy(arp_key.arp_tha, arp_tha, ETH_ADDR_LEN);
> nl_msg_put_unspec(key, OVS_KEY_ATTR_ARP, &arp_key, sizeof arp_key);
> +
> + memset(&arp_key, 0xff, sizeof arp_key);
> + nl_msg_put_unspec(mask, OVS_KEY_ATTR_ARP, &arp_key, sizeof arp_key);
> return n;
> }
> }
>
> {
> char nd_target_s[IPV6_SCAN_LEN + 1];
> + char nd_target_mask_s[IPV6_SCAN_LEN + 1];
> uint8_t nd_sll[ETH_ADDR_LEN];
> + uint8_t nd_sll_mask[ETH_ADDR_LEN];
> uint8_t nd_tll[ETH_ADDR_LEN];
> + uint8_t nd_tll_mask[ETH_ADDR_LEN];
> int n = -1;
>
> - if (sscanf(s, "nd(target="IPV6_SCAN_FMT")%n",
> + memset(&nd_target_mask_s[0], 0xff, sizeof nd_target_s);
> + memset(&nd_sll_mask[0], 0xff, sizeof nd_sll);
> + memset(&nd_tll_mask [0], 0xff, sizeof nd_tll);
> +
> + if (sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT")%n",
> + nd_target_s, nd_target_mask_s, &n) > 0 && n > 0) {
> + put_nd_key(n, nd_target_s, NULL, NULL, key);
> + put_nd_key(n, nd_target_mask_s, NULL, NULL, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT")%n",
> nd_target_s, &n) > 0 && n > 0) {
> - return put_nd_key(n, nd_target_s, NULL, NULL, key);
> - }
> - if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT")%n",
> + put_nd_key(n, nd_target_s, NULL, NULL, key);
> + put_nd_key(n, nd_target_mask_s, NULL, NULL, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
> + ",sll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, nd_target_mask_s,
> + ETH_ADDR_SCAN_ARGS(nd_sll),
> + ETH_ADDR_SCAN_ARGS(nd_sll_mask), &n) > 0 && n > 0) {
> + put_nd_key(n, nd_target_s, nd_sll, NULL, key);
> + put_nd_key(n, nd_target_mask_s, nd_sll_mask, NULL, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT")%n",
> nd_target_s, ETH_ADDR_SCAN_ARGS(nd_sll), &n) > 0
> && n > 0) {
> - return put_nd_key(n, nd_target_s, nd_sll, NULL, key);
> - }
> - if (sscanf(s, "nd(target="IPV6_SCAN_FMT",tll="ETH_ADDR_SCAN_FMT")%n",
> + put_nd_key(n, nd_target_s, nd_sll, NULL, key);
> + put_nd_key(n, nd_target_mask_s, nd_sll_mask, NULL, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
> + ",tll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, nd_target_mask_s,
> + ETH_ADDR_SCAN_ARGS(nd_tll),
> + ETH_ADDR_SCAN_ARGS(nd_tll_mask), &n) > 0 && n > 0) {
> + put_nd_key(n, nd_target_s, NULL, nd_tll, key);
> + put_nd_key(n, nd_target_mask_s, NULL, nd_tll_mask, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT",tll="ETH_ADDR_SCAN_FMT")%n",
> nd_target_s, ETH_ADDR_SCAN_ARGS(nd_tll), &n) > 0
> && n > 0) {
> - return put_nd_key(n, nd_target_s, NULL, nd_tll, key);
> - }
> - if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT","
> + put_nd_key(n, nd_target_s, NULL, nd_tll, key);
> + put_nd_key(n, nd_target_mask_s, NULL, nd_tll_mask, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
> + ",sll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT","
> + "tll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, nd_target_mask_s,
> + ETH_ADDR_SCAN_ARGS(nd_sll), ETH_ADDR_SCAN_ARGS(nd_sll_mask),
> + ETH_ADDR_SCAN_ARGS(nd_tll), ETH_ADDR_SCAN_ARGS(nd_tll_mask),
> + &n) > 0
> + && n > 0) {
> + put_nd_key(n, nd_target_s, nd_sll, nd_tll, key);
> + put_nd_key(n, nd_target_mask_s, nd_sll_mask, nd_tll_mask, mask);
> + } else if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT","
> "tll="ETH_ADDR_SCAN_FMT")%n",
> nd_target_s, ETH_ADDR_SCAN_ARGS(nd_sll),
> ETH_ADDR_SCAN_ARGS(nd_tll), &n) > 0
> && n > 0) {
> - return put_nd_key(n, nd_target_s, nd_sll, nd_tll, key);
> + put_nd_key(n, nd_target_s, nd_sll, nd_tll, key);
> + put_nd_key(n, nd_target_mask_s, nd_sll_mask, nd_tll_mask, mask);
> }
> +
> + if (n != -1)
> + return n;
> +
> }
>
> if (!strncmp(s, "encap(", 6)) {
> const char *start = s;
> - size_t encap;
> + size_t encap, encap_mask;
>
> encap = nl_msg_start_nested(key, OVS_KEY_ATTR_ENCAP);
> + encap_mask = nl_msg_start_nested(mask, OVS_KEY_ATTR_ENCAP);
>
> s += 6;
> for (;;) {
> @@ -1488,7 +2044,7 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> break;
> }
>
> - retval = parse_odp_key_attr(s, port_names, key);
> + retval = parse_odp_key_mask_attr(s, port_names, key, mask);
> if (retval < 0) {
> return retval;
> }
> @@ -1497,6 +2053,7 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> s++;
>
> nl_msg_end_nested(key, encap);
> + nl_msg_end_nested(mask, encap_mask);
>
> return s - start;
> }
> @@ -1504,25 +2061,398 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
> return -EINVAL;
> }
>
> -/* Parses the string representation of a datapath flow key, in the
> - * format output by odp_flow_key_format(). Returns 0 if successful,
> - * otherwise a positive errno value. On success, the flow key is
> - * appended to 'key' as a series of Netlink attributes. On failure, no
> - * data is appended to 'key'. Either way, 'key''s data might be
> - * reallocated.
> - *
> - * If 'port_names' is nonnull, it points to an simap that maps from a port name
> - * to a port number. (Port names may be used instead of port numbers in
> - * in_port.)
> - *
> - * On success, the attributes appended to 'key' are individually syntactically
> - * valid, but they may not be valid as a sequence. 'key' might, for example,
> - * have duplicated keys. odp_flow_key_to_flow() will detect those errors. */
> -int
> -odp_flow_key_from_string(const char *s, const struct simap *port_names,
> - struct ofpbuf *key)
> -{
> - const size_t old_size = key->size;
> +static int
> +parse_odp_key_attr(const char *s, const struct simap *port_names,
> + struct ofpbuf *key)
> +{
> + /* Many of the sscanf calls in this function use oversized destination
> + * fields because some sscanf() implementations truncate the range of %i
> + * directives, so that e.g. "%"SCNi16 interprets input of "0xfedc" as a
> + * value of 0x7fff. The other alternatives are to allow only a single
> + * radix (e.g. decimal or hexadecimal) or to write more sophisticated
> + * parsers.
> + *
> + * The tun_id parser has to use an alternative approach because there is no
> + * type larger than 64 bits. */
> +
> + {
> + unsigned long long int priority;
> + int n = -1;
> +
> + if (sscanf(s, "skb_priority(%llx)%n", &priority, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_PRIORITY, priority);
> + return n;
> + }
> + }
> +
> + {
> + unsigned long long int mark;
> + int n = -1;
> +
> + if (sscanf(s, "skb_mark(%llx)%n", &mark, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_SKB_MARK, mark);
> + return n;
> + }
> + }
> +
> + {
> + char tun_id_s[32];
> + int tos, ttl;
> + struct flow_tnl tun_key;
> + int n = -1;
> +
> + if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
> + "src="IP_SCAN_FMT",dst="IP_SCAN_FMT
> + ",tos=%i,ttl=%i,flags%n", tun_id_s,
> + IP_SCAN_ARGS(&tun_key.ip_src),
> + IP_SCAN_ARGS(&tun_key.ip_dst), &tos, &ttl,
> + &n) > 0 && n > 0) {
> + int res;
> + uint32_t flags;
> +
> + tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0));
> + tun_key.ip_tos = tos;
> + tun_key.ip_ttl = ttl;
> + res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
> + tun_key.flags = (uint16_t) flags;
> +
> + if (res < 0) {
> + return res;
> + }
> + n += res;
> + if (s[n] != ')') {
> + return -EINVAL;
> + }
> + n++;
> + tun_key_to_attr(key, &tun_key);
> + return n;
> + }
> + }
> +
> + {
> + unsigned long long int in_port;
> + int n = -1;
> +
> + if (sscanf(s, "in_port(%lli)%n", &in_port, &n) > 0 && n > 0) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, in_port);
> + return n;
> + }
> + }
> +
> + if (port_names && !strncmp(s, "in_port(", 8)) {
> + const char *name;
> + const struct simap_node *node;
> + int name_len;
> +
> + name = s + 8;
> + name_len = strcspn(s, ")");
> + node = simap_find_len(port_names, name, name_len);
> + if (node) {
> + nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, node->data);
> + return 8 + name_len + 1;
> + }
> + }
> +
> + {
> + int label, tc, ttl, bos;
> + int n = -1;
> +
> + if (sscanf(s, "mpls(label=%"SCNi32",tc=%i,ttl=%i,bos=%i)%n",
> + &label, &tc, &ttl, &bos, &n) > 0 &&
> + n > 0) {
> + struct ovs_key_mpls *mpls;
> +
> + mpls = nl_msg_put_unspec_uninit(key, OVS_KEY_ATTR_MPLS,
> + sizeof *mpls);
> + mpls->mpls_lse = mpls_lse_from_components(label, tc, ttl, bos);
> + return n;
> + }
> + }
> +
> + {
> + struct ovs_key_ethernet eth_key;
> + int n = -1;
> +
> + if (sscanf(s,
> + "eth(src="ETH_ADDR_SCAN_FMT",dst="ETH_ADDR_SCAN_FMT")%n",
> + ETH_ADDR_SCAN_ARGS(eth_key.eth_src),
> + ETH_ADDR_SCAN_ARGS(eth_key.eth_dst), &n) > 0 && n > 0) {
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ETHERNET,
> + ð_key, sizeof eth_key);
> + return n;
> + }
> + }
> +
> + {
> + uint16_t vid;
> + int pcp;
> + int cfi;
> + int n = -1;
> +
> + if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i)%n", &vid, &pcp, &n) > 0
> + && n > 0)) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> + htons((vid << VLAN_VID_SHIFT) |
> + (pcp << VLAN_PCP_SHIFT) |
> + VLAN_CFI));
> + return n;
> + } else if ((sscanf(s, "vlan(vid=%"SCNi16",pcp=%i,cfi=%i)%n",
> + &vid, &pcp, &cfi, &n) > 0
> + && n > 0)) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_VLAN,
> + htons((vid << VLAN_VID_SHIFT) |
> + (pcp << VLAN_PCP_SHIFT) |
> + (cfi ? VLAN_CFI : 0)));
> + return n;
> + }
> + }
> +
> + {
> + int eth_type;
> + int n = -1;
> +
> + if (sscanf(s, "eth_type(%i)%n", ð_type, &n) > 0 && n > 0) {
> + nl_msg_put_be16(key, OVS_KEY_ATTR_ETHERTYPE, htons(eth_type));
> + return n;
> + }
> + }
> +
> + {
> + ovs_be32 ipv4_src;
> + ovs_be32 ipv4_dst;
> + int ipv4_proto;
> + int ipv4_tos;
> + int ipv4_ttl;
> + char frag[8];
> + enum ovs_frag_type ipv4_frag;
> + int n = -1;
> +
> + if (sscanf(s, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT","
> + "proto=%i,tos=%i,ttl=%i,frag=%7[a-z])%n",
> + IP_SCAN_ARGS(&ipv4_src), IP_SCAN_ARGS(&ipv4_dst),
> + &ipv4_proto, &ipv4_tos, &ipv4_ttl, frag, &n) > 0
> + && n > 0
> + && ovs_frag_type_from_string(frag, &ipv4_frag)) {
> + struct ovs_key_ipv4 ipv4_key;
> +
> + ipv4_key.ipv4_src = ipv4_src;
> + ipv4_key.ipv4_dst = ipv4_dst;
> + ipv4_key.ipv4_proto = ipv4_proto;
> + ipv4_key.ipv4_tos = ipv4_tos;
> + ipv4_key.ipv4_ttl = ipv4_ttl;
> + ipv4_key.ipv4_frag = ipv4_frag;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4,
> + &ipv4_key, sizeof ipv4_key);
> + return n;
> + }
> + }
> +
> + {
> + char ipv6_src_s[IPV6_SCAN_LEN + 1];
> + char ipv6_dst_s[IPV6_SCAN_LEN + 1];
> + int ipv6_label;
> + int ipv6_proto;
> + int ipv6_tclass;
> + int ipv6_hlimit;
> + char frag[8];
> + enum ovs_frag_type ipv6_frag;
> + int n = -1;
> +
> + if (sscanf(s, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT","
> + "label=%i,proto=%i,tclass=%i,hlimit=%i,frag=%7[a-z])%n",
> + ipv6_src_s, ipv6_dst_s, &ipv6_label,
> + &ipv6_proto, &ipv6_tclass, &ipv6_hlimit, frag, &n) > 0
> + && n > 0
> + && ovs_frag_type_from_string(frag, &ipv6_frag)) {
> + struct ovs_key_ipv6 ipv6_key;
> +
> + if (inet_pton(AF_INET6, ipv6_src_s, &ipv6_key.ipv6_src) != 1 ||
> + inet_pton(AF_INET6, ipv6_dst_s, &ipv6_key.ipv6_dst) != 1) {
> + return -EINVAL;
> + }
> + ipv6_key.ipv6_label = htonl(ipv6_label);
> + ipv6_key.ipv6_proto = ipv6_proto;
> + ipv6_key.ipv6_tclass = ipv6_tclass;
> + ipv6_key.ipv6_hlimit = ipv6_hlimit;
> + ipv6_key.ipv6_frag = ipv6_frag;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV6,
> + &ipv6_key, sizeof ipv6_key);
> + return n;
> + }
> + }
> +
> + {
> + int tcp_src;
> + int tcp_dst;
> + int n = -1;
> +
> + if (sscanf(s, "tcp(src=%i,dst=%i)%n",&tcp_src, &tcp_dst, &n) > 0
> + && n > 0) {
> + struct ovs_key_tcp tcp_key;
> +
> + tcp_key.tcp_src = htons(tcp_src);
> + tcp_key.tcp_dst = htons(tcp_dst);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_TCP, &tcp_key, sizeof tcp_key);
> + return n;
> + }
> + }
> +
> + {
> + int udp_src;
> + int udp_dst;
> + int n = -1;
> +
> + if (sscanf(s, "udp(src=%i,dst=%i)%n", &udp_src, &udp_dst, &n) > 0
> + && n > 0) {
> + struct ovs_key_udp udp_key;
> +
> + udp_key.udp_src = htons(udp_src);
> + udp_key.udp_dst = htons(udp_dst);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_UDP, &udp_key, sizeof udp_key);
> + return n;
> + }
> + }
> +
> + {
> + int icmp_type;
> + int icmp_code;
> + int n = -1;
> +
> + if (sscanf(s, "icmp(type=%i,code=%i)%n",
> + &icmp_type, &icmp_code, &n) > 0
> + && n > 0) {
> + struct ovs_key_icmp icmp_key;
> +
> + icmp_key.icmp_type = icmp_type;
> + icmp_key.icmp_code = icmp_code;
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMP,
> + &icmp_key, sizeof icmp_key);
> + return n;
> + }
> + }
> +
> + {
> + struct ovs_key_icmpv6 icmpv6_key;
> + int n = -1;
> +
> + if (sscanf(s, "icmpv6(type=%"SCNi8",code=%"SCNi8")%n",
> + &icmpv6_key.icmpv6_type, &icmpv6_key.icmpv6_code,&n) > 0
> + && n > 0) {
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ICMPV6,
> + &icmpv6_key, sizeof icmpv6_key);
> + return n;
> + }
> + }
> +
> + {
> + ovs_be32 arp_sip;
> + ovs_be32 arp_tip;
> + int arp_op;
> + uint8_t arp_sha[ETH_ADDR_LEN];
> + uint8_t arp_tha[ETH_ADDR_LEN];
> + int n = -1;
> +
> + if (sscanf(s, "arp(sip="IP_SCAN_FMT",tip="IP_SCAN_FMT","
> + "op=%i,sha="ETH_ADDR_SCAN_FMT",tha="ETH_ADDR_SCAN_FMT")%n",
> + IP_SCAN_ARGS(&arp_sip),
> + IP_SCAN_ARGS(&arp_tip),
> + &arp_op,
> + ETH_ADDR_SCAN_ARGS(arp_sha),
> + ETH_ADDR_SCAN_ARGS(arp_tha), &n) > 0 && n > 0) {
> + struct ovs_key_arp arp_key;
> +
> + memset(&arp_key, 0, sizeof arp_key);
> + arp_key.arp_sip = arp_sip;
> + arp_key.arp_tip = arp_tip;
> + arp_key.arp_op = htons(arp_op);
> + memcpy(arp_key.arp_sha, arp_sha, ETH_ADDR_LEN);
> + memcpy(arp_key.arp_tha, arp_tha, ETH_ADDR_LEN);
> + nl_msg_put_unspec(key, OVS_KEY_ATTR_ARP, &arp_key, sizeof arp_key);
> + return n;
> + }
> + }
> +
> + {
> + char nd_target_s[IPV6_SCAN_LEN + 1];
> + uint8_t nd_sll[ETH_ADDR_LEN];
> + uint8_t nd_tll[ETH_ADDR_LEN];
> + int n = -1;
> +
> + if (sscanf(s, "nd(target="IPV6_SCAN_FMT")%n",
> + nd_target_s, &n) > 0 && n > 0) {
> + return put_nd_key(n, nd_target_s, NULL, NULL, key);
> + }
> + if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, ETH_ADDR_SCAN_ARGS(nd_sll), &n) > 0
> + && n > 0) {
> + return put_nd_key(n, nd_target_s, nd_sll, NULL, key);
> + }
> + if (sscanf(s, "nd(target="IPV6_SCAN_FMT",tll="ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, ETH_ADDR_SCAN_ARGS(nd_tll), &n) > 0
> + && n > 0) {
> + return put_nd_key(n, nd_target_s, NULL, nd_tll, key);
> + }
> + if (sscanf(s, "nd(target="IPV6_SCAN_FMT",sll="ETH_ADDR_SCAN_FMT","
> + "tll="ETH_ADDR_SCAN_FMT")%n",
> + nd_target_s, ETH_ADDR_SCAN_ARGS(nd_sll),
> + ETH_ADDR_SCAN_ARGS(nd_tll), &n) > 0
> + && n > 0) {
> + return put_nd_key(n, nd_target_s, nd_sll, nd_tll, key);
> + }
> + }
> +
> + if (!strncmp(s, "encap(", 6)) {
> + const char *start = s;
> + size_t encap;
> +
> + encap = nl_msg_start_nested(key, OVS_KEY_ATTR_ENCAP);
> +
> + s += 6;
> + for (;;) {
> + int retval;
> +
> + s += strspn(s, ", \t\r\n");
> + if (!*s) {
> + return -EINVAL;
> + } else if (*s == ')') {
> + break;
> + }
> +
> + retval = parse_odp_key_attr(s, port_names, key);
> + if (retval < 0) {
> + return retval;
> + }
> + s += retval;
> + }
> + s++;
> +
> + nl_msg_end_nested(key, encap);
> +
> + return s - start;
> + }
> +
> + return -EINVAL;
> +}
> +
> +/* Parses the string representation of a datapath flow key, in the
> + * format output by odp_flow_key_format(). Returns 0 if successful,
> + * otherwise a positive errno value. On success, the flow key is
> + * appended to 'key' as a series of Netlink attributes. On failure, no
> + * data is appended to 'key'. Either way, 'key''s data might be
> + * reallocated.
> + *
> + * If 'port_names' is nonnull, it points to an simap that maps from a port name
> + * to a port number. (Port names may be used instead of port numbers in
> + * in_port.)
> + *
> + * On success, the attributes appended to 'key' are individually syntactically
> + * valid, but they may not be valid as a sequence. 'key' might, for example,
> + * have duplicated keys. odp_flow_key_to_flow() will detect those errors. */
> +int
> +odp_micro_flow_key_from_string(const char *s, const struct simap *port_names,
> + struct ofpbuf *key)
> +{
> + const size_t old_size = key->size;
> for (;;) {
> int retval;
>
> @@ -1542,6 +2472,30 @@ odp_flow_key_from_string(const char *s, const struct simap *port_names,
> return 0;
> }
>
> +int
> +odp_mega_flow_from_string(const char *s, const struct simap *port_names,
> + struct ofpbuf *key, struct ofpbuf *mask)
> +{
> + const size_t old_size = key->size;
> + for (;;) {
> + int retval;
> +
> + s += strspn(s, delimiters);
> + if (!*s) {
> + return 0;
> + }
> +
> + retval = parse_odp_key_mask_attr(s, port_names, key, mask);
> + if (retval < 0) {
> + key->size = old_size;
> + return -retval;
> + }
> + s += retval;
> + }
> +
> + return 0;
> +}
> +
> static uint8_t
> ovs_to_odp_frag(uint8_t nw_frag)
> {
> diff --git a/lib/odp-util.h b/lib/odp-util.h
> index 6213418..37027f8 100644
> --- a/lib/odp-util.h
> +++ b/lib/odp-util.h
> @@ -90,9 +90,16 @@ struct odputil_keybuf {
> enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *,
> struct flow_tnl *);
>
> +void odp_mega_flow_format(const struct nlattr *key, size_t key_len,
> + const struct nlattr *mask, size_t mask_len,
> + struct ds *);
> void odp_flow_key_format(const struct nlattr *, size_t, struct ds *);
> -int odp_flow_key_from_string(const char *s, const struct simap *port_names,
> - struct ofpbuf *);
> +int odp_micro_flow_key_from_string(const char *s,
> + const struct simap *port_names,
> + struct ofpbuf *);
> +int odp_mega_flow_from_string(const char *s,
> + const struct simap *port_names,
> + struct ofpbuf *, struct ofpbuf *);
>
> void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *,
> uint32_t odp_in_port);
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index eb2c7e0..755a193 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -3804,6 +3804,8 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
> put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
> put->key = miss->key;
> put->key_len = miss->key_len;
> + put->mask = NULL;
> + put->mask_len = 0;
> if (want_path == SF_FAST_PATH) {
> put->actions = facet->xout.odp_actions.data;
> put->actions_len = facet->xout.odp_actions.size;
> @@ -4054,7 +4056,8 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
> hmap_insert(&backer->drop_keys, &drop_key->hmap_node,
> hash_bytes(drop_key->key, drop_key->key_len, 0));
> dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY,
> - drop_key->key, drop_key->key_len, NULL, 0, NULL);
> + drop_key->key, drop_key->key_len,
> + NULL, 0, NULL, 0, NULL);
> }
> continue;
> }
> @@ -4450,7 +4453,8 @@ update_stats(struct dpif_backer *backer)
> size_t key_len;
>
> dpif_flow_dump_start(&dump, backer->dpif);
> - while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) {
> + while (dpif_flow_dump_next(&dump, &key, &key_len,
> + NULL, NULL, NULL, NULL, &stats)) {
> struct subfacet *subfacet;
> uint32_t key_hash;
>
> @@ -5352,8 +5356,9 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions,
> &actions, &actions_len);
> }
>
> - ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key,
> - subfacet->key_len, actions, actions_len, stats);
> + ret = dpif_flow_put(ofproto->backer->dpif, flags, subfacet->key,
> + subfacet->key_len, NULL, 0,
> + actions, actions_len, stats);
>
> if (stats) {
> subfacet_reset_dp_stats(subfacet, stats);
> @@ -8007,10 +8012,10 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
> }
>
> /* Parse the flow and determine whether a datapath or
> - * bridge is specified. If function odp_flow_key_from_string()
> + * bridge is specified. If function odp_micro_flow_key_from_string()
> * returns 0, the flow is a odp_flow. If function
> * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
> - if (!odp_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) {
> + if (!odp_micro_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) {
> /* If the odp_flow is the second argument,
> * the datapath name is the first argument. */
> if (argc == 3) {
> diff --git a/tests/test-odp.c b/tests/test-odp.c
> index 268a105..962d62b 100644
> --- a/tests/test-odp.c
> +++ b/tests/test-odp.c
> @@ -42,9 +42,9 @@ parse_keys(void)
>
> /* Convert string to OVS DP key. */
> ofpbuf_init(&odp_key, 0);
> - error = odp_flow_key_from_string(ds_cstr(&in), NULL, &odp_key);
> + error = odp_micro_flow_key_from_string(ds_cstr(&in), NULL, &odp_key);
> if (error) {
> - printf("odp_flow_key_from_string: error\n");
> + printf("odp_micro_flow_key_from_string: error\n");
> goto next;
> }
>
> diff --git a/utilities/ovs-dpctl.8.in b/utilities/ovs-dpctl.8.in
> index 2b0036c..c31ddcf 100644
> --- a/utilities/ovs-dpctl.8.in
> +++ b/utilities/ovs-dpctl.8.in
> @@ -165,6 +165,14 @@ Limits \fBovs\-dpctl\fR runtime to approximately \fIsecs\fR seconds. If
> the timeout expires, \fBovs\-dpctl\fR will exit with a \fBSIGALRM\fR
> signal.
> .
> +.IP "\fB\-a\fR"
> +.IQ "\fB\-\-micro\fR"
> +Causes the add-flow, mod-flow, or del-flow commands to interpret \fIflow\fR as a micro flow. All fields needs to be fully specified with exact values.
> +.
> +.IP "\fB\-o\fR"
> +.IQ "\fB\-\-mega\fR"
> +Causes the add-flow, mod-flow, or del-flow commands to interpret \fIflow\fR as a mega flow. Flow key fields can be specified either with a value, interpreted as a exact match, or in the form of value/mask. Mask value needs be specified in Hexadecimal. Omitted key fields are interpreted as wildcarded fields. This is the default setting.
> +.
> .so lib/vlog.man
> .so lib/common.man
> .
> diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
> index 54505e8..4e29b6d 100644
> --- a/utilities/ovs-dpctl.c
> +++ b/utilities/ovs-dpctl.c
> @@ -66,6 +66,8 @@ static bool may_create;
> * the option itself. */
> static int verbosity;
>
> +static bool mega_flow = true;
> +
> static const struct command all_commands[];
>
> static void usage(void) NO_RETURN;
> @@ -97,6 +99,8 @@ parse_options(int argc, char *argv[])
> {"timeout", required_argument, NULL, 't'},
> {"help", no_argument, NULL, 'h'},
> {"version", no_argument, NULL, 'V'},
> + {"mega", no_argument, NULL, 'a'},
> + {"micro", no_argument, NULL, 'o'},
> VLOG_LONG_OPTIONS,
> {NULL, 0, NULL, 0},
> };
> @@ -141,6 +145,14 @@ parse_options(int argc, char *argv[])
> case 'h':
> usage();
>
> + case 'a':
> + mega_flow = true;
> + break;
> +
> + case 'o':
> + mega_flow = false;
> + break;
> +
> case 'V':
> ovs_print_version(0, 0);
> exit(EXIT_SUCCESS);
> @@ -185,6 +197,9 @@ usage(void)
> "\nOptions for mod-flow:\n"
> " --may-create create flow if it doesn't exist\n"
> " --clear reset existing stats to zero\n"
> + "\nOptions for add-flow/mod-flow/del-flow:\n"
> + " --mega create a meag flow \n"
> + " --micro cerata a micro flow \n"
> "\nOther options:\n"
> " -t, --timeout=SECS give up after SECS seconds\n"
> " -h, --help display this help message\n"
> @@ -743,9 +758,11 @@ dpctl_dump_flows(int argc, char *argv[])
> const struct nlattr *actions;
> struct dpif_flow_dump dump;
> const struct nlattr *key;
> + const struct nlattr *mask;
> size_t actions_len;
> struct dpif *dpif;
> size_t key_len;
> + size_t mask_len;
> struct ds ds;
> char *name;
>
> @@ -756,10 +773,12 @@ dpctl_dump_flows(int argc, char *argv[])
> ds_init(&ds);
> dpif_flow_dump_start(&dump, dpif);
> while (dpif_flow_dump_next(&dump, &key, &key_len,
> + &mask, &mask_len,
> &actions, &actions_len, &stats)) {
> ds_clear(&ds);
> - odp_flow_key_format(key, key_len, &ds);
> + odp_mega_flow_format(key, key_len, mask, mask_len, &ds);
> ds_put_cstr(&ds, ", ");
> +
> dpif_flow_stats_format(stats, &ds);
> ds_put_cstr(&ds, ", actions:");
> format_odp_actions(&ds, actions, actions_len);
> @@ -778,26 +797,39 @@ dpctl_put_flow(int argc, char *argv[], enum dpif_flow_put_flags flags)
> struct dpif_flow_stats stats;
> struct ofpbuf actions;
> struct ofpbuf key;
> + struct ofpbuf mask;
> struct dpif *dpif;
> + struct ds s;
> char *dp_name;
>
> + ds_init(&s);
> ofpbuf_init(&key, 0);
> - run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
> + ofpbuf_init(&mask, 0);
> + if (mega_flow) {
> + run(odp_mega_flow_from_string(key_s, NULL, &key, &mask),
> + "parsing mega flow key");
> + } else {
> + run(odp_micro_flow_key_from_string(key_s, NULL, &key),
> + "parsing micro flow key");
> +
> + }
>
> ofpbuf_init(&actions, 0);
> run(odp_actions_from_string(actions_s, NULL, &actions), "parsing actions");
>
> - dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp();
> + dp_name = argc == 4 ? xstrdup(argv[1]) : get_one_dp();
> run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
> free(dp_name);
>
> run(dpif_flow_put(dpif, flags,
> key.data, key.size,
> + mask.size == 0 ? NULL : mask.data, mask.size,
> actions.data, actions.size,
> print_statistics ? &stats : NULL),
> "updating flow table");
>
> ofpbuf_uninit(&key);
> + ofpbuf_uninit(&mask);
> ofpbuf_uninit(&actions);
>
> if (print_statistics) {
> @@ -842,7 +874,7 @@ dpctl_del_flow(int argc, char *argv[])
> char *dp_name;
>
> ofpbuf_init(&key, 0);
> - run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
> + run(odp_micro_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
>
> dp_name = argc == 2 ? xstrdup(argv[1]) : get_one_dp();
> run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
> @@ -1032,8 +1064,8 @@ dpctl_normalize_actions(int argc, char *argv[])
>
> /* Parse flow key. */
> ofpbuf_init(&keybuf, 0);
> - run(odp_flow_key_from_string(argv[1], &port_names, &keybuf),
> - "odp_flow_key_from_string");
> + run(odp_micro_flow_key_from_string(argv[1], &port_names, &keybuf),
> + "odp_micro_flow_key_from_string");
>
> ds_clear(&s);
> odp_flow_key_format(keybuf.data, keybuf.size, &s);
> --
> 1.7.9.5
>
More information about the dev
mailing list