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);
+ const struct nlattr *ma, struct ds *ds,
+ bool verbose);
/* Returns one the following for the action with the given OVS_ACTION_ATTR_*
* 'type':
format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
{
static const struct nl_policy ovs_sample_policy[] = {
- [OVS_SAMPLE_ATTR_PROBABILITY] = { .type = NL_A_U32 },
- [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_NESTED }
+ { NL_A_NO_ATTR, 0, 0, false }, /* OVS_SAMPLE_ATTR_UNSPEC */
+ { NL_A_U32, 0, 0, false }, /* OVS_SAMPLE_ATTR_PROBABILITY */
+ { NL_A_NESTED, 0, 0, false }, /* OVS_SAMPLE_ATTR_ACTIONS */
};
struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
double percentage;
format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
{
static const struct nl_policy ovs_userspace_policy[] = {
- [OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
- [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
- .optional = true },
+ { NL_A_NO_ATTR, 0, 0, false }, /* OVS_USERSPACE_ATTR_UNSPEC */
+ { NL_A_U32, 0, 0, false }, /* OVS_USERSPACE_ATTR_PID */
+ { NL_A_UNSPEC, 0, 0, true }, /* OVS_USERSPACE_ATTR_USERDATA */
};
struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
const struct nlattr *userdata_attr;
break;
case OVS_ACTION_ATTR_SET:
ds_put_cstr(ds, "set(");
- format_odp_key_attr(nl_attr_get(a), NULL, ds);
+ format_odp_key_attr(nl_attr_get(a), NULL, ds, true);
ds_put_cstr(ds, ")");
break;
case OVS_ACTION_ATTR_PUSH_VLAN:
nl_msg_end_nested(a, tun_key_ofs);
}
+static bool
+odp_mask_attr_is_wildcard(const struct nlattr *ma)
+{
+ return is_all_zeros(nl_attr_get(ma), nl_attr_get_size(ma));
+}
+
static bool
odp_mask_attr_is_exact(const struct nlattr *ma)
{
static void
format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
- struct ds *ds)
+ struct ds *ds, bool verbose)
{
struct flow_tnl tun_key;
enum ovs_key_attr attr = nl_attr_type(a);
char namebuf[OVS_KEY_ATTR_BUFSIZE];
int expected_len;
+ bool is_exact;
- if (ma && odp_mask_attr_is_exact(ma)) {
- ma = NULL;
- }
+ is_exact = ma ? odp_mask_attr_is_exact(ma) : true;
ds_put_cstr(ds, ovs_key_attr_to_string(attr, namebuf, sizeof namebuf));
case OVS_KEY_ATTR_ENCAP:
if (ma && nl_attr_get_size(ma) && nl_attr_get_size(a)) {
odp_flow_format(nl_attr_get(a), nl_attr_get_size(a),
- nl_attr_get(ma), nl_attr_get_size(ma), ds);
+ nl_attr_get(ma), nl_attr_get_size(ma), ds, verbose);
} else if (nl_attr_get_size(a)) {
- odp_flow_format(nl_attr_get(a), nl_attr_get_size(a), NULL, 0, ds);
+ odp_flow_format(nl_attr_get(a), nl_attr_get_size(a), NULL, 0, ds,
+ verbose);
}
break;
case OVS_KEY_ATTR_PRIORITY:
case OVS_KEY_ATTR_SKB_MARK:
ds_put_format(ds, "%#"PRIx32, nl_attr_get_u32(a));
- if (ma) {
+ if (!is_exact) {
ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
}
break;
memset(&tun_key, 0, sizeof tun_key);
if (odp_tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
ds_put_format(ds, "error");
- } else if (ma) {
+ } else if (!is_exact) {
struct flow_tnl tun_mask;
memset(&tun_mask, 0, sizeof tun_mask);
case OVS_KEY_ATTR_IN_PORT:
ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a));
- if (ma) {
+ if (!is_exact) {
ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
}
break;
case OVS_KEY_ATTR_ETHERNET:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_ethernet *eth_mask = nl_attr_get(ma);
const struct ovs_key_ethernet *eth_key = nl_attr_get(a);
case OVS_KEY_ATTR_VLAN:
{
ovs_be16 vlan_tci = nl_attr_get_be16(a);
- if (ma) {
+ if (!is_exact) {
ovs_be16 mask = nl_attr_get_be16(ma);
- ds_put_format(ds, "vid=%"PRIu16"/%"PRIx16",pcp=%d/0x%x,cfi=%d/%d",
+ ds_put_format(ds, "vid=%"PRIu16"/0x%"PRIx16",pcp=%d/0x%x,cfi=%d/%d",
vlan_tci_to_vid(vlan_tci),
vlan_tci_to_vid(mask),
vlan_tci_to_pcp(vlan_tci),
- vlan_tci_to_vid(mask),
+ vlan_tci_to_pcp(mask),
vlan_tci_to_cfi(vlan_tci),
vlan_tci_to_cfi(mask));
} else {
case OVS_KEY_ATTR_MPLS: {
const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
const struct ovs_key_mpls *mpls_mask = NULL;
- if (ma) {
+ if (!is_exact) {
mpls_mask = nl_attr_get(ma);
}
format_mpls(ds, mpls_key, mpls_mask);
case OVS_KEY_ATTR_ETHERTYPE:
ds_put_format(ds, "0x%04"PRIx16, ntohs(nl_attr_get_be16(a)));
- if (ma) {
+ if (!is_exact) {
ds_put_format(ds, "/0x%04"PRIx16, ntohs(nl_attr_get_be16(ma)));
}
break;
case OVS_KEY_ATTR_IPV4:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_ipv4 *ipv4_key = nl_attr_get(a);
const struct ovs_key_ipv4 *ipv4_mask = nl_attr_get(ma);
break;
case OVS_KEY_ATTR_IPV6:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_ipv6 *ipv6_key, *ipv6_mask;
char src_str[INET6_ADDRSTRLEN];
char dst_str[INET6_ADDRSTRLEN];
break;
case OVS_KEY_ATTR_TCP:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_tcp *tcp_mask = nl_attr_get(ma);
const struct ovs_key_tcp *tcp_key = nl_attr_get(a);
break;
case OVS_KEY_ATTR_UDP:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_udp *udp_mask = nl_attr_get(ma);
const struct ovs_key_udp *udp_key = nl_attr_get(a);
break;
case OVS_KEY_ATTR_ICMP:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_icmp *icmp_mask = nl_attr_get(ma);
const struct ovs_key_icmp *icmp_key = nl_attr_get(a);
break;
case OVS_KEY_ATTR_ICMPV6:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_icmpv6 *icmpv6_mask = nl_attr_get(ma);
const struct ovs_key_icmpv6 *icmpv6_key = nl_attr_get(a);
break;
case OVS_KEY_ATTR_ARP:
- if (ma) {
+ if (!is_exact) {
const struct ovs_key_arp *arp_mask = nl_attr_get(ma);
const struct ovs_key_arp *arp_key = nl_attr_get(a);
break;
case OVS_KEY_ATTR_ND: {
- const struct ovs_key_nd *nd_key, *nd_mask;
+ const struct ovs_key_nd *nd_key, *nd_mask = NULL;
char target[INET6_ADDRSTRLEN];
nd_key = nl_attr_get(a);
- nd_mask = ma ? nl_attr_get(ma) : NULL;
+ if (!is_exact) {
+ nd_mask = nl_attr_get(ma);
+ }
inet_ntop(AF_INET6, nd_key->nd_target, target, sizeof target);
ds_put_format(ds, "target=%s", target);
- if (nd_mask) {
+ if (!is_exact) {
inet_ntop(AF_INET6, nd_mask->nd_target, target, sizeof target);
ds_put_format(ds, "/%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) {
+ if (!is_exact) {
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) {
+ if (!is_exact) {
ds_put_format(ds, "/"ETH_ADDR_FMT,
ETH_ADDR_ARGS(nd_mask->nd_tll));
}
case __OVS_KEY_ATTR_MAX:
default:
format_generic_odp_key(a, ds);
- if (ma) {
+ if (!is_exact) {
ds_put_char(ds, '/');
format_generic_odp_key(ma, ds);
}
ds_put_char(ds, ')');
}
+static struct nlattr *
+generate_all_wildcard_mask(struct ofpbuf *ofp, const struct nlattr *key)
+{
+ const struct nlattr *a;
+ unsigned int left;
+ int type = nl_attr_type(key);
+ int size = nl_attr_get_size(key);
+
+ if (odp_flow_key_attr_len(type) >=0) {
+ memset(nl_msg_put_unspec_uninit(ofp, type, size), 0, size);
+ } else {
+ size_t nested_mask;
+
+ nested_mask = nl_msg_start_nested(ofp, type);
+ NL_ATTR_FOR_EACH(a, left, key, nl_attr_get_size(key)) {
+ generate_all_wildcard_mask(ofp, nl_attr_get(a));
+ }
+ nl_msg_end_nested(ofp, nested_mask);
+ }
+
+ return ofp->base;
+}
+
/* Appends to 'ds' a string representation of the 'key_len' bytes of
* OVS_KEY_ATTR_* attributes in 'key'. If non-null, additionally formats the
* 'mask_len' bytes of 'mask' which apply to 'key'. */
void
odp_flow_format(const struct nlattr *key, size_t key_len,
const struct nlattr *mask, size_t mask_len,
- struct ds *ds)
+ struct ds *ds, bool verbose)
{
if (key_len) {
const struct nlattr *a;
unsigned int left;
bool has_ethtype_key = false;
const struct nlattr *ma = NULL;
+ struct ofpbuf ofp;
+ bool first_field = true;
+ ofpbuf_init(&ofp, 100);
NL_ATTR_FOR_EACH (a, left, key, key_len) {
- if (a != key) {
- ds_put_char(ds, ',');
- }
- if (nl_attr_type(a) == OVS_KEY_ATTR_ETHERTYPE) {
+ bool is_nested_attr;
+ bool is_wildcard = false;
+ int attr_type = nl_attr_type(a);
+
+ if (attr_type == OVS_KEY_ATTR_ETHERTYPE) {
has_ethtype_key = true;
}
+
+ is_nested_attr = (odp_flow_key_attr_len(attr_type) == -2);
+
if (mask && mask_len) {
ma = nl_attr_find__(mask, mask_len, nl_attr_type(a));
+ is_wildcard = ma ? odp_mask_attr_is_wildcard(ma) : true;
}
- format_odp_key_attr(a, ma, ds);
+
+ if (verbose || !is_wildcard || is_nested_attr) {
+ if (is_wildcard && !ma) {
+ ma = generate_all_wildcard_mask(&ofp, a);
+ }
+ if (!first_field) {
+ ds_put_char(ds, ',');
+ }
+ format_odp_key_attr(a, ma, ds, verbose);
+ first_field = false;
+ }
+ ofpbuf_clear(&ofp);
}
+ ofpbuf_uninit(&ofp);
+
if (left) {
int i;
odp_flow_key_format(const struct nlattr *key,
size_t key_len, struct ds *ds)
{
- odp_flow_format(key, key_len, NULL, 0, ds);
+ odp_flow_format(key, key_len, NULL, 0, ds, true);
+}
+
+static void
+put_nd(struct ovs_key_nd* nd_key, const uint8_t *nd_sll,
+ const uint8_t *nd_tll, struct ofpbuf *key)
+{
+ if (nd_sll) {
+ memcpy(nd_key->nd_sll, nd_sll, ETH_ADDR_LEN);
+ }
+
+ if (nd_tll) {
+ memcpy(nd_key->nd_tll, nd_tll, ETH_ADDR_LEN);
+ }
+
+ nl_msg_put_unspec(key, OVS_KEY_ATTR_ND, nd_key, sizeof *nd_key);
}
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)
+put_nd_key(int n, const char *nd_target_s, const uint8_t *nd_sll,
+ const uint8_t *nd_tll, struct ofpbuf *key)
{
struct ovs_key_nd nd_key;
memset(&nd_key, 0, sizeof nd_key);
+
if (inet_pton(AF_INET6, nd_target_s, nd_key.nd_target) != 1) {
return -EINVAL;
}
- if (nd_sll) {
- memcpy(nd_key.nd_sll, nd_sll, ETH_ADDR_LEN);
- }
- if (nd_tll) {
- memcpy(nd_key.nd_tll, nd_tll, ETH_ADDR_LEN);
+
+ put_nd(&nd_key, nd_sll, nd_tll, key);
+ return n;
+}
+
+static int
+put_nd_mask(int n, const char *nd_target_s,
+ const uint8_t *nd_sll, const uint8_t *nd_tll, struct ofpbuf *mask)
+{
+ struct ovs_key_nd nd_mask;
+
+ memset(&nd_mask, 0xff, sizeof nd_mask);
+
+ if (strlen(nd_target_s) != 0 &&
+ inet_pton(AF_INET6, nd_target_s, nd_mask.nd_target) != 1) {
+ return -EINVAL;
}
- nl_msg_put_unspec(key, OVS_KEY_ATTR_ND, &nd_key, sizeof nd_key);
+
+ put_nd(&nd_mask, nd_sll, nd_tll, mask);
return n;
}
uint8_t nd_tll_mask[ETH_ADDR_LEN];
int n = -1;
- 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);
+ nd_target_mask_s[0] = 0;
+ memset(nd_sll_mask, 0xff, sizeof nd_sll_mask);
+ memset(nd_tll_mask, 0xff, sizeof nd_tll_mask);
if (mask && 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);
+ put_nd_mask(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) {
put_nd_key(n, nd_target_s, NULL, NULL, key);
if (mask) {
- put_nd_key(n, nd_target_mask_s, NULL, NULL, mask);
+ put_nd_mask(n, nd_target_mask_s, NULL, NULL, mask);
}
} else if (mask && sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
",sll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
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);
+ put_nd_mask(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) {
put_nd_key(n, nd_target_s, nd_sll, NULL, key);
if (mask) {
- put_nd_key(n, nd_target_mask_s, nd_sll_mask, NULL, mask);
+ put_nd_mask(n, nd_target_mask_s, nd_sll_mask, NULL, mask);
}
} else if (mask && sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
",tll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT")%n",
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);
+ put_nd_mask(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) {
put_nd_key(n, nd_target_s, NULL, nd_tll, key);
if (mask) {
- put_nd_key(n, nd_target_mask_s, NULL, nd_tll_mask, mask);
+ put_nd_mask(n, nd_target_mask_s, NULL, nd_tll_mask, mask);
}
} else if (mask && sscanf(s, "nd(target="IPV6_SCAN_FMT"/"IPV6_SCAN_FMT
",sll="ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT","
&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);
+ put_nd_mask(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),
&& n > 0) {
put_nd_key(n, nd_target_s, nd_sll, nd_tll, key);
if (mask) {
- put_nd_key(n, nd_target_mask_s, nd_sll_mask, nd_tll_mask, mask);
+ put_nd_mask(n, nd_target_mask_s,
+ nd_sll_mask, nd_tll_mask, mask);
}
}
: OVS_FRAG_TYPE_LATER);
}
-/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'.
- * 'flow->in_port' is ignored (since it is likely to be an OpenFlow port
- * number rather than a datapath port number). Instead, if 'odp_in_port'
- * is anything other than OVSP_NONE, it is included in 'buf' as the input
- * port.
- *
- * 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be
- * capable of being expanded to allow for that much space. */
-void
-odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
- uint32_t odp_in_port)
+static uint8_t
+ovs_to_odp_frag_mask(uint8_t nw_frag_mask)
+{
+ uint8_t frag_mask = ~(OVS_FRAG_TYPE_FIRST | OVS_FRAG_TYPE_LATER);
+
+ frag_mask |= (nw_frag_mask & FLOW_NW_FRAG_ANY) ? OVS_FRAG_TYPE_FIRST : 0;
+ frag_mask |= (nw_frag_mask & FLOW_NW_FRAG_LATER) ? OVS_FRAG_TYPE_LATER : 0;
+
+ return frag_mask;
+}
+
+static void
+odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
+ const struct flow *flow, odp_port_t odp_in_port)
{
+ bool is_mask;
struct ovs_key_ethernet *eth_key;
size_t encap;
- if (flow->skb_priority) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
- }
+ /* We assume that if 'data' and 'flow' are not the same, we should
+ * treat 'data' as a mask. */
+ is_mask = (data != flow);
- if (flow->tunnel.ip_dst) {
- tun_key_to_attr(buf, &flow->tunnel);
- }
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority);
- if (flow->skb_mark) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, flow->skb_mark);
+ if (flow->tunnel.ip_dst || is_mask) {
+ tun_key_to_attr(buf, &data->tunnel);
}
- if (odp_in_port != OVSP_NONE) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT, odp_in_port);
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, data->pkt_mark);
+
+ /* Add an ingress port attribute if this is a mask or 'odp_in_port'
+ * is not the magical value "ODPP_NONE". */
+ if (is_mask || odp_in_port != ODPP_NONE) {
+ nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, odp_in_port);
}
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
sizeof *eth_key);
- memcpy(eth_key->eth_src, flow->dl_src, ETH_ADDR_LEN);
- memcpy(eth_key->eth_dst, flow->dl_dst, ETH_ADDR_LEN);
+ memcpy(eth_key->eth_src, data->dl_src, ETH_ADDR_LEN);
+ memcpy(eth_key->eth_dst, data->dl_dst, ETH_ADDR_LEN);
if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN));
- nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, flow->vlan_tci);
+ if (is_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(UINT16_MAX));
+ } else {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN));
+ }
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci);
encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
if (flow->vlan_tci == htons(0)) {
goto unencap;
}
if (ntohs(flow->dl_type) < ETH_TYPE_MIN) {
+ /* For backwards compatibility with kernels that don't support
+ * wildcarding, the following convention is used to encode the
+ * OVS_KEY_ATTR_ETHERTYPE for key and mask:
+ *
+ * key mask matches
+ * -------- -------- -------
+ * >0x5ff 0xffff Specified Ethernet II Ethertype.
+ * >0x5ff 0 Any Ethernet II or non-Ethernet II frame.
+ * <none> 0xffff Any non-Ethernet II frame (except valid
+ * 802.3 SNAP packet with valid eth_type).
+ */
+ if (is_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(UINT16_MAX));
+ }
goto unencap;
}
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, flow->dl_type);
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, data->dl_type);
if (flow->dl_type == htons(ETH_TYPE_IP)) {
struct ovs_key_ipv4 *ipv4_key;
ipv4_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV4,
sizeof *ipv4_key);
- ipv4_key->ipv4_src = flow->nw_src;
- ipv4_key->ipv4_dst = flow->nw_dst;
- ipv4_key->ipv4_proto = flow->nw_proto;
- ipv4_key->ipv4_tos = flow->nw_tos;
- ipv4_key->ipv4_ttl = flow->nw_ttl;
- ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->nw_frag);
+ ipv4_key->ipv4_src = data->nw_src;
+ ipv4_key->ipv4_dst = data->nw_dst;
+ ipv4_key->ipv4_proto = data->nw_proto;
+ ipv4_key->ipv4_tos = data->nw_tos;
+ ipv4_key->ipv4_ttl = data->nw_ttl;
+ ipv4_key->ipv4_frag = is_mask ? ovs_to_odp_frag_mask(data->nw_frag)
+ : ovs_to_odp_frag(data->nw_frag);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
struct ovs_key_ipv6 *ipv6_key;
ipv6_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV6,
sizeof *ipv6_key);
- memcpy(ipv6_key->ipv6_src, &flow->ipv6_src, sizeof ipv6_key->ipv6_src);
- memcpy(ipv6_key->ipv6_dst, &flow->ipv6_dst, sizeof ipv6_key->ipv6_dst);
- ipv6_key->ipv6_label = flow->ipv6_label;
- ipv6_key->ipv6_proto = flow->nw_proto;
- ipv6_key->ipv6_tclass = flow->nw_tos;
- ipv6_key->ipv6_hlimit = flow->nw_ttl;
- ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->nw_frag);
+ memcpy(ipv6_key->ipv6_src, &data->ipv6_src, sizeof ipv6_key->ipv6_src);
+ memcpy(ipv6_key->ipv6_dst, &data->ipv6_dst, sizeof ipv6_key->ipv6_dst);
+ ipv6_key->ipv6_label = data->ipv6_label;
+ ipv6_key->ipv6_proto = data->nw_proto;
+ ipv6_key->ipv6_tclass = data->nw_tos;
+ ipv6_key->ipv6_hlimit = data->nw_ttl;
+ ipv6_key->ipv6_frag = is_mask ? ovs_to_odp_frag_mask(data->nw_frag)
+ : ovs_to_odp_frag(data->nw_frag);
} else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
flow->dl_type == htons(ETH_TYPE_RARP)) {
struct ovs_key_arp *arp_key;
arp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ARP,
sizeof *arp_key);
memset(arp_key, 0, sizeof *arp_key);
- arp_key->arp_sip = flow->nw_src;
- arp_key->arp_tip = flow->nw_dst;
- arp_key->arp_op = htons(flow->nw_proto);
- memcpy(arp_key->arp_sha, flow->arp_sha, ETH_ADDR_LEN);
- memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN);
+ arp_key->arp_sip = data->nw_src;
+ arp_key->arp_tip = data->nw_dst;
+ arp_key->arp_op = htons(data->nw_proto);
+ memcpy(arp_key->arp_sha, data->arp_sha, ETH_ADDR_LEN);
+ memcpy(arp_key->arp_tha, data->arp_tha, ETH_ADDR_LEN);
}
if (flow->mpls_depth) {
mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
sizeof *mpls_key);
- mpls_key->mpls_lse = flow->mpls_lse;
+ mpls_key->mpls_lse = data->mpls_lse;
}
if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
tcp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_TCP,
sizeof *tcp_key);
- tcp_key->tcp_src = flow->tp_src;
- tcp_key->tcp_dst = flow->tp_dst;
+ tcp_key->tcp_src = data->tp_src;
+ tcp_key->tcp_dst = data->tp_dst;
} else if (flow->nw_proto == IPPROTO_UDP) {
struct ovs_key_udp *udp_key;
udp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_UDP,
sizeof *udp_key);
- udp_key->udp_src = flow->tp_src;
- udp_key->udp_dst = flow->tp_dst;
+ udp_key->udp_src = data->tp_src;
+ udp_key->udp_dst = data->tp_dst;
} else if (flow->dl_type == htons(ETH_TYPE_IP)
&& flow->nw_proto == IPPROTO_ICMP) {
struct ovs_key_icmp *icmp_key;
icmp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ICMP,
sizeof *icmp_key);
- icmp_key->icmp_type = ntohs(flow->tp_src);
- icmp_key->icmp_code = ntohs(flow->tp_dst);
+ icmp_key->icmp_type = ntohs(data->tp_src);
+ icmp_key->icmp_code = ntohs(data->tp_dst);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)
&& flow->nw_proto == IPPROTO_ICMPV6) {
struct ovs_key_icmpv6 *icmpv6_key;
icmpv6_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ICMPV6,
sizeof *icmpv6_key);
- icmpv6_key->icmpv6_type = ntohs(flow->tp_src);
- icmpv6_key->icmpv6_code = ntohs(flow->tp_dst);
+ icmpv6_key->icmpv6_type = ntohs(data->tp_src);
+ icmpv6_key->icmpv6_code = ntohs(data->tp_dst);
if (icmpv6_key->icmpv6_type == ND_NEIGHBOR_SOLICIT
|| icmpv6_key->icmpv6_type == ND_NEIGHBOR_ADVERT) {
nd_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ND,
sizeof *nd_key);
- memcpy(nd_key->nd_target, &flow->nd_target,
+ memcpy(nd_key->nd_target, &data->nd_target,
sizeof nd_key->nd_target);
- memcpy(nd_key->nd_sll, flow->arp_sha, ETH_ADDR_LEN);
- memcpy(nd_key->nd_tll, flow->arp_tha, ETH_ADDR_LEN);
+ memcpy(nd_key->nd_sll, data->arp_sha, ETH_ADDR_LEN);
+ memcpy(nd_key->nd_tll, data->arp_tha, ETH_ADDR_LEN);
}
}
}
}
}
+/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'.
+ * 'flow->in_port' is ignored (since it is likely to be an OpenFlow port
+ * number rather than a datapath port number). Instead, if 'odp_in_port'
+ * is anything other than ODPP_NONE, it is included in 'buf' as the input
+ * port.
+ *
+ * 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be
+ * capable of being expanded to allow for that much space. */
+void
+odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
+ odp_port_t odp_in_port)
+{
+ odp_flow_key_from_flow__(buf, flow, flow, odp_in_port);
+}
+
+/* Appends a representation of 'mask' as OVS_KEY_ATTR_* attributes to
+ * 'buf'. 'flow' is used as a template to determine how to interpret
+ * 'mask'. For example, the 'dl_type' of 'mask' describes the mask, but
+ * it doesn't indicate whether the other fields should be interpreted as
+ * ARP, IPv4, IPv6, etc.
+ *
+ * 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be
+ * capable of being expanded to allow for that much space. */
+void
+odp_flow_key_from_mask(struct ofpbuf *buf, const struct flow *mask,
+ const struct flow *flow, uint32_t odp_in_port_mask)
+{
+ odp_flow_key_from_flow__(buf, mask, flow, u32_to_odp(odp_in_port_mask));
+}
+
uint32_t
odp_flow_key_hash(const struct nlattr *key, size_t key_len)
{
BUILD_ASSERT_DECL(!(NLA_ALIGNTO % sizeof(uint32_t)));
- return hash_words((const uint32_t *) key, key_len / sizeof(uint32_t), 0);
+ return hash_words(ALIGNED_CAST(const uint32_t *, key),
+ key_len / sizeof(uint32_t), 0);
}
static void
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK)) {
- flow->skb_mark = nl_attr_get_u32(attrs[OVS_KEY_ATTR_SKB_MARK]);
+ flow->pkt_mark = nl_attr_get_u32(attrs[OVS_KEY_ATTR_SKB_MARK]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK;
}
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) {
- flow->in_port = nl_attr_get_u32(attrs[OVS_KEY_ATTR_IN_PORT]);
+ flow->in_port.odp_port
+ = nl_attr_get_odp_port(attrs[OVS_KEY_ATTR_IN_PORT]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IN_PORT;
} else {
- flow->in_port = OVSP_NONE;
+ flow->in_port.odp_port = ODPP_NONE;
}
/* Ethernet header. */
}
void
-odp_put_skb_mark_action(const uint32_t skb_mark,
+odp_put_pkt_mark_action(const uint32_t pkt_mark,
struct ofpbuf *odp_actions)
{
- commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &skb_mark,
- sizeof(skb_mark));
+ commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &pkt_mark,
+ sizeof(pkt_mark));
}
/* If any of the flow key data that ODP actions can modify are different in
}
static void
-commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
+commit_set_pkt_mark_action(const struct flow *flow, struct flow *base,
struct ofpbuf *odp_actions,
struct flow_wildcards *wc)
{
- if (base->skb_mark == flow->skb_mark) {
+ if (base->pkt_mark == flow->pkt_mark) {
return;
}
- memset(&wc->masks.skb_mark, 0xff, sizeof wc->masks.skb_mark);
- base->skb_mark = flow->skb_mark;
+ memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
+ base->pkt_mark = flow->pkt_mark;
- odp_put_skb_mark_action(base->skb_mark, odp_actions);
+ odp_put_pkt_mark_action(base->pkt_mark, odp_actions);
}
/* If any of the flow key data that ODP actions can modify are different in
* 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
*/
commit_mpls_action(flow, base, odp_actions, wc);
commit_set_priority_action(flow, base, odp_actions, wc);
- commit_set_skb_mark_action(flow, base, odp_actions, wc);
+ commit_set_pkt_mark_action(flow, base, odp_actions, wc);
}