upcall.cmd = OVS_PACKET_CMD_MISS;
upcall.key = &key;
- upcall.userdata = 0;
- upcall.sample_pool = 0;
- upcall.actions = NULL;
- upcall.actions_len = 0;
dp_upcall(dp, skb, &upcall);
stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
goto out;
len = sizeof(struct ovs_header);
len += nla_total_size(skb->len);
len += nla_total_size(FLOW_BUFSIZE);
- if (upcall_info->userdata)
+ if (upcall_info->cmd == OVS_PACKET_CMD_ACTION)
len += nla_total_size(8);
- if (upcall_info->sample_pool)
- len += nla_total_size(4);
- if (upcall_info->actions_len)
- len += nla_total_size(upcall_info->actions_len);
user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) {
flow_to_nlattrs(upcall_info->key, user_skb);
nla_nest_end(user_skb, nla);
- if (upcall_info->userdata)
- nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA, upcall_info->userdata);
- if (upcall_info->sample_pool)
- nla_put_u32(user_skb, OVS_PACKET_ATTR_SAMPLE_POOL, upcall_info->sample_pool);
- if (upcall_info->actions_len) {
- const struct nlattr *actions = upcall_info->actions;
- u32 actions_len = upcall_info->actions_len;
-
- nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_ACTIONS);
- memcpy(__skb_put(user_skb, actions_len), actions, actions_len);
- nla_nest_end(user_skb, nla);
- }
+ if (upcall_info->cmd == OVS_PACKET_CMD_ACTION)
+ nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA,
+ upcall_info->userdata);
nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len);
if (skb->ip_summed == CHECKSUM_PARTIAL)
return 0;
}
-static int validate_actions(const struct nlattr *attr)
+static int validate_actions(const struct nlattr *attr, int depth);
+
+static int validate_sample(const struct nlattr *attr, int depth)
+{
+ static const struct nla_policy sample_policy[OVS_SAMPLE_ATTR_MAX + 1] =
+ {
+ [OVS_SAMPLE_ATTR_PROBABILITY] = {.type = NLA_U32 },
+ [OVS_SAMPLE_ATTR_ACTIONS] = {.type = NLA_UNSPEC },
+ };
+ struct nlattr *a[OVS_SAMPLE_ATTR_MAX + 1];
+ int error;
+
+ error = nla_parse_nested(a, OVS_SAMPLE_ATTR_MAX, attr, sample_policy);
+ if (error)
+ return error;
+
+ if (!a[OVS_SAMPLE_ATTR_PROBABILITY])
+ return -EINVAL;
+ if (!a[OVS_SAMPLE_ATTR_ACTIONS])
+ return -EINVAL;
+
+ return validate_actions(a[OVS_SAMPLE_ATTR_ACTIONS], (depth + 1));
+}
+
+static int validate_actions(const struct nlattr *attr, int depth)
{
const struct nlattr *a;
- int rem;
+ int rem, err;
+
+ if (depth >= SAMPLE_ACTION_DEPTH)
+ return -EOVERFLOW;
nla_for_each_nested(a, attr, rem) {
static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
};
int type = nla_type(a);
- if (type > OVS_ACTION_ATTR_MAX || nla_len(a) != action_lens[type])
+ /* Match expected attr len for given attr len except for
+ * OVS_ACTION_ATTR_SAMPLE, as it has nested actions list which
+ * is variable size. */
+ if (type > OVS_ACTION_ATTR_MAX ||
+ (nla_len(a) != action_lens[type] &&
+ type != OVS_ACTION_ATTR_SAMPLE))
return -EINVAL;
switch (type) {
return -EINVAL;
break;
+ case OVS_ACTION_ATTR_SAMPLE:
+ err = validate_sample(a, depth);
+ if (err)
+ return err;
+ break;
+
default:
return -EOPNOTSUPP;
}
nla_len(a[OVS_PACKET_ATTR_PACKET]) < ETH_HLEN)
goto err;
- err = validate_actions(a[OVS_PACKET_ATTR_ACTIONS]);
+ err = validate_actions(a[OVS_PACKET_ATTR_ACTIONS], 0);
if (err)
goto err;
/* Validate actions. */
if (a[OVS_FLOW_ATTR_ACTIONS]) {
- error = validate_actions(a[OVS_FLOW_ATTR_ACTIONS]);
+ error = validate_actions(a[OVS_FLOW_ATTR_ACTIONS], 0);
if (error)
goto error;
} else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) {
#endif
[OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
[OVS_DP_ATTR_IPV4_FRAGS] = { .type = NLA_U32 },
- [OVS_DP_ATTR_SAMPLING] = { .type = NLA_U32 },
};
static struct genl_family dp_datapath_genl_family = {
NLA_PUT_U32(skb, OVS_DP_ATTR_IPV4_FRAGS,
dp->drop_frags ? OVS_DP_FRAG_DROP : OVS_DP_FRAG_ZERO);
- if (dp->sflow_probability)
- NLA_PUT_U32(skb, OVS_DP_ATTR_SAMPLING, dp->sflow_probability);
-
return genlmsg_end(skb, ovs_header);
nla_put_failure:
{
if (a[OVS_DP_ATTR_IPV4_FRAGS])
dp->drop_frags = nla_get_u32(a[OVS_DP_ATTR_IPV4_FRAGS]) == OVS_DP_FRAG_DROP;
- if (a[OVS_DP_ATTR_SAMPLING])
- dp->sflow_probability = nla_get_u32(a[OVS_DP_ATTR_SAMPLING]);
}
static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)