Commit 05da5898 authored by Jarno Rajahalme's avatar Jarno Rajahalme Committed by Pravin B Shelar

openvswitch: Add support for OVS_FLOW_ATTR_PROBE.

This new flag is useful for suppressing error logging while probing
for datapath features using flow commands.  For backwards
compatibility reasons the commands are executed normally, but error
logging is suppressed.
Signed-off-by: default avatarJarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: default avatarPravin B Shelar <pshelar@nicira.com>
parent 12eb18f7
...@@ -457,6 +457,8 @@ enum ovs_flow_attr { ...@@ -457,6 +457,8 @@ enum ovs_flow_attr {
OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */ OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */ OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
OVS_FLOW_ATTR_MASK, /* Sequence of OVS_KEY_ATTR_* attributes. */ OVS_FLOW_ATTR_MASK, /* Sequence of OVS_KEY_ATTR_* attributes. */
OVS_FLOW_ATTR_PROBE, /* Flow operation is a feature probe, error
* logging should be suppressed. */
__OVS_FLOW_ATTR_MAX __OVS_FLOW_ATTR_MAX
}; };
......
...@@ -526,6 +526,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) ...@@ -526,6 +526,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
struct vport *input_vport; struct vport *input_vport;
int len; int len;
int err; int err;
bool log = !a[OVS_FLOW_ATTR_PROBE];
err = -EINVAL; err = -EINVAL;
if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
...@@ -559,12 +560,12 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) ...@@ -559,12 +560,12 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
goto err_kfree_skb; goto err_kfree_skb;
err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet, err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet,
&flow->key); &flow->key, log);
if (err) if (err)
goto err_flow_free; goto err_flow_free;
err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS], err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS],
&flow->key, &acts); &flow->key, &acts, log);
if (err) if (err)
goto err_flow_free; goto err_flow_free;
...@@ -855,15 +856,16 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -855,15 +856,16 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
struct sw_flow_actions *acts; struct sw_flow_actions *acts;
struct sw_flow_match match; struct sw_flow_match match;
int error; int error;
bool log = !a[OVS_FLOW_ATTR_PROBE];
/* Must have key and actions. */ /* Must have key and actions. */
error = -EINVAL; error = -EINVAL;
if (!a[OVS_FLOW_ATTR_KEY]) { if (!a[OVS_FLOW_ATTR_KEY]) {
OVS_NLERR("Flow key attribute not present in new flow.\n"); OVS_NLERR(log, "Flow key attr not present in new flow.");
goto error; goto error;
} }
if (!a[OVS_FLOW_ATTR_ACTIONS]) { if (!a[OVS_FLOW_ATTR_ACTIONS]) {
OVS_NLERR("Flow actions attribute not present in new flow.\n"); OVS_NLERR(log, "Flow actions attr not present in new flow.");
goto error; goto error;
} }
...@@ -878,8 +880,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -878,8 +880,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
/* Extract key. */ /* Extract key. */
ovs_match_init(&match, &new_flow->unmasked_key, &mask); ovs_match_init(&match, &new_flow->unmasked_key, &mask);
error = ovs_nla_get_match(&match, error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); a[OVS_FLOW_ATTR_MASK], log);
if (error) if (error)
goto err_kfree_flow; goto err_kfree_flow;
...@@ -887,9 +889,9 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -887,9 +889,9 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
/* Validate actions. */ /* Validate actions. */
error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key, error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
&acts); &acts, log);
if (error) { if (error) {
OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
goto err_kfree_flow; goto err_kfree_flow;
} }
...@@ -942,6 +944,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -942,6 +944,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
} }
/* The unmasked key has to be the same for flow updates. */ /* The unmasked key has to be the same for flow updates. */
if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) { if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
/* Look for any overlapping flow. */
flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
if (!flow) { if (!flow) {
error = -ENOENT; error = -ENOENT;
...@@ -984,16 +987,18 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -984,16 +987,18 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
/* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */ /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
const struct sw_flow_key *key, const struct sw_flow_key *key,
const struct sw_flow_mask *mask) const struct sw_flow_mask *mask,
bool log)
{ {
struct sw_flow_actions *acts; struct sw_flow_actions *acts;
struct sw_flow_key masked_key; struct sw_flow_key masked_key;
int error; int error;
ovs_flow_mask_key(&masked_key, key, mask); ovs_flow_mask_key(&masked_key, key, mask);
error = ovs_nla_copy_actions(a, &masked_key, &acts); error = ovs_nla_copy_actions(a, &masked_key, &acts, log);
if (error) { if (error) {
OVS_NLERR("Actions may not be safe on all matching packets.\n"); OVS_NLERR(log,
"Actions may not be safe on all matching packets");
return ERR_PTR(error); return ERR_PTR(error);
} }
...@@ -1012,23 +1017,25 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) ...@@ -1012,23 +1017,25 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
struct sw_flow_actions *old_acts = NULL, *acts = NULL; struct sw_flow_actions *old_acts = NULL, *acts = NULL;
struct sw_flow_match match; struct sw_flow_match match;
int error; int error;
bool log = !a[OVS_FLOW_ATTR_PROBE];
/* Extract key. */ /* Extract key. */
error = -EINVAL; error = -EINVAL;
if (!a[OVS_FLOW_ATTR_KEY]) { if (!a[OVS_FLOW_ATTR_KEY]) {
OVS_NLERR("Flow key attribute not present in set flow.\n"); OVS_NLERR(log, "Flow key attribute not present in set flow.");
goto error; goto error;
} }
ovs_match_init(&match, &key, &mask); ovs_match_init(&match, &key, &mask);
error = ovs_nla_get_match(&match, error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); a[OVS_FLOW_ATTR_MASK], log);
if (error) if (error)
goto error; goto error;
/* Validate actions. */ /* Validate actions. */
if (a[OVS_FLOW_ATTR_ACTIONS]) { if (a[OVS_FLOW_ATTR_ACTIONS]) {
acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask); acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask,
log);
if (IS_ERR(acts)) { if (IS_ERR(acts)) {
error = PTR_ERR(acts); error = PTR_ERR(acts);
goto error; goto error;
...@@ -1109,14 +1116,16 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) ...@@ -1109,14 +1116,16 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
struct datapath *dp; struct datapath *dp;
struct sw_flow_match match; struct sw_flow_match match;
int err; int err;
bool log = !a[OVS_FLOW_ATTR_PROBE];
if (!a[OVS_FLOW_ATTR_KEY]) { if (!a[OVS_FLOW_ATTR_KEY]) {
OVS_NLERR("Flow get message rejected, Key attribute missing.\n"); OVS_NLERR(log,
"Flow get message rejected, Key attribute missing.");
return -EINVAL; return -EINVAL;
} }
ovs_match_init(&match, &key, NULL); ovs_match_init(&match, &key, NULL);
err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, log);
if (err) if (err)
return err; return err;
...@@ -1157,10 +1166,12 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) ...@@ -1157,10 +1166,12 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
struct datapath *dp; struct datapath *dp;
struct sw_flow_match match; struct sw_flow_match match;
int err; int err;
bool log = !a[OVS_FLOW_ATTR_PROBE];
if (likely(a[OVS_FLOW_ATTR_KEY])) { if (likely(a[OVS_FLOW_ATTR_KEY])) {
ovs_match_init(&match, &key, NULL); ovs_match_init(&match, &key, NULL);
err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL,
log);
if (unlikely(err)) if (unlikely(err))
return err; return err;
} }
...@@ -1250,8 +1261,10 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1250,8 +1261,10 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED }, [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
[OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG },
}; };
static const struct genl_ops dp_flow_genl_ops[] = { static const struct genl_ops dp_flow_genl_ops[] = {
......
...@@ -199,9 +199,9 @@ void ovs_dp_notify_wq(struct work_struct *work); ...@@ -199,9 +199,9 @@ void ovs_dp_notify_wq(struct work_struct *work);
int action_fifos_init(void); int action_fifos_init(void);
void action_fifos_exit(void); void action_fifos_exit(void);
#define OVS_NLERR(fmt, ...) \ #define OVS_NLERR(logging_allowed, fmt, ...) \
do { \ do { \
if (net_ratelimit()) \ if (logging_allowed && net_ratelimit()) \
pr_info("netlink: " fmt, ##__VA_ARGS__); \ pr_info("netlink: " fmt "\n", ##__VA_ARGS__); \
} while (0) } while (0)
#endif /* datapath.h */ #endif /* datapath.h */
...@@ -712,12 +712,12 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, ...@@ -712,12 +712,12 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,
int ovs_flow_key_extract_userspace(const struct nlattr *attr, int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb, struct sk_buff *skb,
struct sw_flow_key *key) struct sw_flow_key *key, bool log)
{ {
int err; int err;
/* Extract metadata from netlink attributes. */ /* Extract metadata from netlink attributes. */
err = ovs_nla_get_flow_metadata(attr, key); err = ovs_nla_get_flow_metadata(attr, key, log);
if (err) if (err)
return err; return err;
......
...@@ -257,6 +257,6 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, ...@@ -257,6 +257,6 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,
/* Extract key from packet coming from userspace. */ /* Extract key from packet coming from userspace. */
int ovs_flow_key_extract_userspace(const struct nlattr *attr, int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb, struct sk_buff *skb,
struct sw_flow_key *key); struct sw_flow_key *key, bool log);
#endif /* flow.h */ #endif /* flow.h */
This diff is collapsed.
...@@ -45,17 +45,17 @@ void ovs_match_init(struct sw_flow_match *match, ...@@ -45,17 +45,17 @@ void ovs_match_init(struct sw_flow_match *match,
int ovs_nla_put_flow(const struct sw_flow_key *, int ovs_nla_put_flow(const struct sw_flow_key *,
const struct sw_flow_key *, struct sk_buff *); const struct sw_flow_key *, struct sk_buff *);
int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *); int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *,
bool log);
int ovs_nla_get_match(struct sw_flow_match *match, int ovs_nla_get_match(struct sw_flow_match *, const struct nlattr *key,
const struct nlattr *, const struct nlattr *mask, bool log);
const struct nlattr *);
int ovs_nla_put_egress_tunnel_key(struct sk_buff *, int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
const struct ovs_tunnel_info *); const struct ovs_tunnel_info *);
int ovs_nla_copy_actions(const struct nlattr *attr, int ovs_nla_copy_actions(const struct nlattr *attr,
const struct sw_flow_key *key, const struct sw_flow_key *key,
struct sw_flow_actions **sfa); struct sw_flow_actions **sfa, bool log);
int ovs_nla_put_actions(const struct nlattr *attr, int ovs_nla_put_actions(const struct nlattr *attr,
int len, struct sk_buff *skb); int len, struct sk_buff *skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment