return -1;
}
+/* Returns a string form of 'attr'. The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'namebuf'. 'bufsize'
+ * should be at least OVS_KEY_ATTR_BUFSIZE. */
+enum { OVS_KEY_ATTR_BUFSIZE = 3 + INT_STRLEN(unsigned int) + 1 };
static const char *
-ovs_key_attr_to_string(enum ovs_key_attr attr)
+ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
{
- static char unknown_attr[3 + INT_STRLEN(unsigned int) + 1];
-
switch (attr) {
case OVS_KEY_ATTR_UNSPEC: return "unspec";
case OVS_KEY_ATTR_ENCAP: return "encap";
case __OVS_KEY_ATTR_MAX:
default:
- snprintf(unknown_attr, sizeof unknown_attr, "key%u",
- (unsigned int) attr);
- return unknown_attr;
+ snprintf(namebuf, bufsize, "key%u", (unsigned int) attr);
+ return namebuf;
}
}
switch (type) {
case OVS_ACTION_ATTR_OUTPUT:
- ds_put_format(ds, "%"PRIu16, nl_attr_get_u32(a));
+ ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a));
break;
case OVS_ACTION_ATTR_USERSPACE:
format_odp_userspace_action(ds, a);
return -1;
}
-static enum odp_key_fitness
-tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
+enum odp_key_fitness
+odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
{
unsigned int left;
const struct nlattr *a;
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;
- ds_put_cstr(ds, ovs_key_attr_to_string(attr));
+ 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)",
case OVS_KEY_ATTR_TUNNEL:
memset(&tun_key, 0, sizeof tun_key);
- if (tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
+ if (odp_tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
ds_put_format(ds, "(error)");
} else {
ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
ds_init(&s);
for (i = 0; i < 64; i++) {
if (attrs & (UINT64_C(1) << i)) {
- ds_put_format(&s, " %s", ovs_key_attr_to_string(i));
+ char namebuf[OVS_KEY_ATTR_BUFSIZE];
+
+ ds_put_format(&s, " %s",
+ ovs_key_attr_to_string(i, namebuf, sizeof namebuf));
}
}
if (out_of_range_attr) {
int expected_len = odp_flow_key_attr_len(type);
if (len != expected_len && expected_len >= 0) {
+ char namebuf[OVS_KEY_ATTR_BUFSIZE];
+
VLOG_ERR_RL(&rl, "attribute %s has length %zu but should have "
- "length %d", ovs_key_attr_to_string(type),
+ "length %d", ovs_key_attr_to_string(type, namebuf,
+ sizeof namebuf),
len, expected_len);
return false;
}
*out_of_range_attrp = type;
} else {
if (present_attrs & (UINT64_C(1) << type)) {
+ char namebuf[OVS_KEY_ATTR_BUFSIZE];
+
VLOG_ERR_RL(&rl, "duplicate %s attribute in flow key",
- ovs_key_attr_to_string(type));
+ ovs_key_attr_to_string(type,
+ namebuf, sizeof namebuf));
return false;
}
enum odp_key_fitness fitness;
ovs_be16 tci;
- /* Calulate fitness of outer attributes. */
+ /* Calculate fitness of outer attributes. */
expected_attrs |= ((UINT64_C(1) << OVS_KEY_ATTR_VLAN) |
(UINT64_C(1) << OVS_KEY_ATTR_ENCAP));
fitness = check_expectations(present_attrs, out_of_range_attr,
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUNNEL)) {
enum odp_key_fitness res;
- res = tun_key_from_attr(attrs[OVS_KEY_ATTR_TUNNEL], &flow->tunnel);
+ res = odp_tun_key_from_attr(attrs[OVS_KEY_ATTR_TUNNEL], &flow->tunnel);
if (res == ODP_FIT_ERROR) {
return ODP_FIT_ERROR;
} else if (res == ODP_FIT_PERFECT) {
static void
commit_set_ether_addr_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions,
+ struct flow_wildcards *wc)
{
struct ovs_key_ethernet eth_key;
return;
}
+ memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+ memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+
memcpy(base->dl_src, flow->dl_src, ETH_ADDR_LEN);
memcpy(base->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
static void
commit_vlan_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
if (base->vlan_tci == flow->vlan_tci) {
return;
}
+ memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+
if (base->vlan_tci & htons(VLAN_CFI)) {
nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN);
}
static void
commit_mpls_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
if (flow->mpls_lse == base->mpls_lse &&
flow->mpls_depth == base->mpls_depth) {
return;
}
+ memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+
if (flow->mpls_depth < base->mpls_depth) {
if (base->mpls_depth - flow->mpls_depth > 1) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
static void
commit_set_ipv4_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
struct ovs_key_ipv4 ipv4_key;
return;
}
+ memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+ memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+ memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+ memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+ memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+
ipv4_key.ipv4_src = base->nw_src = flow->nw_src;
ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst;
ipv4_key.ipv4_tos = base->nw_tos = flow->nw_tos;
static void
commit_set_ipv6_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
struct ovs_key_ipv6 ipv6_key;
return;
}
+ memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
+ memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
+ memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
+ memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+ memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+ memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+
base->ipv6_src = flow->ipv6_src;
memcpy(&ipv6_key.ipv6_src, &base->ipv6_src, sizeof(ipv6_key.ipv6_src));
base->ipv6_dst = flow->ipv6_dst;
static void
commit_set_nw_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
/* Check if flow really have an IP header. */
if (!flow->nw_proto) {
}
if (base->dl_type == htons(ETH_TYPE_IP)) {
- commit_set_ipv4_action(flow, base, odp_actions);
+ commit_set_ipv4_action(flow, base, odp_actions, wc);
} else if (base->dl_type == htons(ETH_TYPE_IPV6)) {
- commit_set_ipv6_action(flow, base, odp_actions);
+ commit_set_ipv6_action(flow, base, odp_actions, wc);
}
}
static void
commit_set_port_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
if (!is_ip_any(base) || (!base->tp_src && !base->tp_dst)) {
return;
return;
}
+ memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+ memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+
if (flow->nw_proto == IPPROTO_TCP) {
struct ovs_key_tcp port_key;
static void
commit_set_priority_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions,
+ struct flow_wildcards *wc)
{
if (base->skb_priority == flow->skb_priority) {
return;
}
+
+ memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
base->skb_priority = flow->skb_priority;
commit_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY,
static void
commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions,
+ struct flow_wildcards *wc)
{
if (base->skb_mark == flow->skb_mark) {
return;
}
+
+ memset(&wc->masks.skb_mark, 0xff, sizeof wc->masks.skb_mark);
base->skb_mark = flow->skb_mark;
odp_put_skb_mark_action(base->skb_mark, odp_actions);
* 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
* key from 'base' into 'flow', and then changes 'base' the same way. Does not
* commit set_tunnel actions. Users should call commit_odp_tunnel_action()
- * in addition to this function if needed. */
+ * in addition to this function if needed. Sets fields in 'wc' that are
+ * used as part of the action. */
void
commit_odp_actions(const struct flow *flow, struct flow *base,
- struct ofpbuf *odp_actions)
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
- commit_set_ether_addr_action(flow, base, odp_actions);
- commit_vlan_action(flow, base, odp_actions);
- commit_set_nw_action(flow, base, odp_actions);
- commit_set_port_action(flow, base, odp_actions);
- /* Commiting MPLS actions should occur after committing nw and port
+ commit_set_ether_addr_action(flow, base, odp_actions, wc);
+ commit_vlan_action(flow, base, odp_actions, wc);
+ commit_set_nw_action(flow, base, odp_actions, wc);
+ commit_set_port_action(flow, base, odp_actions, wc);
+ /* Committing MPLS actions should occur after committing nw and port
* actions. This is because committing MPLS actions may alter a packet so
* that it is no longer IP and thus nw and port actions are no longer valid.
*/
- commit_mpls_action(flow, base, odp_actions);
- commit_set_priority_action(flow, base, odp_actions);
- commit_set_skb_mark_action(flow, base, odp_actions);
+ 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);
}