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);
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;
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;
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));
- if (!ma) {
+ is_wildcard = ma ? odp_mask_attr_is_wildcard(ma) : true;
+ }
+
+ 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;
}
- format_odp_key_attr(a, ma, ds);
ofpbuf_clear(&ofp);
}
ofpbuf_uninit(&ofp);
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
: OVS_FRAG_TYPE_LATER);
}
+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)
* treat 'data' as a mask. */
is_mask = (data != flow);
- if (flow->skb_priority) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority);
- }
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority);
- if (flow->tunnel.ip_dst) {
+ if (flow->tunnel.ip_dst || is_mask) {
tun_key_to_attr(buf, &data->tunnel);
}
- if (flow->skb_mark) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, data->skb_mark);
- }
+ 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". */
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 = ovs_to_odp_frag(data->nw_frag);
+ 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->ipv6_proto = data->nw_proto;
ipv6_key->ipv6_tclass = data->nw_tos;
ipv6_key->ipv6_hlimit = data->nw_ttl;
- ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->nw_frag);
+ 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;
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;
}
}
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);
}