Commit bef7f756 authored by andy zhou's avatar andy zhou Committed by David S. Miller

Openvswitch: Refactor sample and recirc actions implementation

Added clone_execute() that both the sample and the recirc
action implementation can use.
Signed-off-by: default avatarAndy Zhou <azhou@ovn.org>
Acked-by: default avatarPravin B Shelar <pshelar@ovn.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 798c1661
...@@ -44,10 +44,6 @@ ...@@ -44,10 +44,6 @@
#include "conntrack.h" #include "conntrack.h"
#include "vport.h" #include "vport.h"
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key,
const struct nlattr *attr, int len);
struct deferred_action { struct deferred_action {
struct sk_buff *skb; struct sk_buff *skb;
const struct nlattr *actions; const struct nlattr *actions;
...@@ -166,6 +162,12 @@ static bool is_flow_key_valid(const struct sw_flow_key *key) ...@@ -166,6 +162,12 @@ static bool is_flow_key_valid(const struct sw_flow_key *key)
return !(key->mac_proto & SW_FLOW_KEY_INVALID); return !(key->mac_proto & SW_FLOW_KEY_INVALID);
} }
static int clone_execute(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key,
u32 recirc_id,
const struct nlattr *actions, int len,
bool last, bool clone_flow_key);
static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr, static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr,
__be16 ethertype) __be16 ethertype)
{ {
...@@ -938,10 +940,9 @@ static int sample(struct datapath *dp, struct sk_buff *skb, ...@@ -938,10 +940,9 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
{ {
struct nlattr *actions; struct nlattr *actions;
struct nlattr *sample_arg; struct nlattr *sample_arg;
struct sw_flow_key *orig_key = key;
int rem = nla_len(attr); int rem = nla_len(attr);
int err = 0;
const struct sample_arg *arg; const struct sample_arg *arg;
bool clone_flow_key;
/* The first action is always 'OVS_SAMPLE_ATTR_ARG'. */ /* The first action is always 'OVS_SAMPLE_ATTR_ARG'. */
sample_arg = nla_data(attr); sample_arg = nla_data(attr);
...@@ -955,43 +956,9 @@ static int sample(struct datapath *dp, struct sk_buff *skb, ...@@ -955,43 +956,9 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
return 0; return 0;
} }
/* Unless the last action, sample works on the clone of SKB. */ clone_flow_key = !arg->exec;
skb = last ? skb : skb_clone(skb, GFP_ATOMIC); return clone_execute(dp, skb, key, 0, actions, rem, last,
if (!skb) { clone_flow_key);
/* Out of memory, skip this sample action.
*/
return 0;
}
/* In case the sample actions won't change 'key',
* it can be used directly to execute sample actions.
* Otherwise, allocate a new key from the
* next recursion level of 'flow_keys'. If
* successful, execute the sample actions without
* deferring.
*
* Defer the sample actions if the recursion
* limit has been reached.
*/
if (!arg->exec) {
__this_cpu_inc(exec_actions_level);
key = clone_key(key);
}
if (key) {
err = do_execute_actions(dp, skb, key, actions, rem);
} else if (!add_deferred_actions(skb, orig_key, actions, rem)) {
if (net_ratelimit())
pr_warn("%s: deferred action limit reached, drop sample action\n",
ovs_dp_name(dp));
kfree_skb(skb);
}
if (!arg->exec)
__this_cpu_dec(exec_actions_level);
return err;
} }
static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key,
...@@ -1102,10 +1069,9 @@ static int execute_masked_set_action(struct sk_buff *skb, ...@@ -1102,10 +1069,9 @@ static int execute_masked_set_action(struct sk_buff *skb,
static int execute_recirc(struct datapath *dp, struct sk_buff *skb, static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key, struct sw_flow_key *key,
const struct nlattr *a, int rem) const struct nlattr *a, bool last)
{ {
struct sw_flow_key *recirc_key; u32 recirc_id;
struct deferred_action *da;
if (!is_flow_key_valid(key)) { if (!is_flow_key_valid(key)) {
int err; int err;
...@@ -1116,40 +1082,8 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, ...@@ -1116,40 +1082,8 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
} }
BUG_ON(!is_flow_key_valid(key)); BUG_ON(!is_flow_key_valid(key));
if (!nla_is_last(a, rem)) { recirc_id = nla_get_u32(a);
/* Recirc action is the not the last action return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true);
* of the action list, need to clone the skb.
*/
skb = skb_clone(skb, GFP_ATOMIC);
/* Skip the recirc action when out of memory, but
* continue on with the rest of the action list.
*/
if (!skb)
return 0;
}
/* If within the limit of 'OVS_DEFERRED_ACTION_THRESHOLD',
* recirc immediately, otherwise, defer it for later execution.
*/
recirc_key = clone_key(key);
if (recirc_key) {
recirc_key->recirc_id = nla_get_u32(a);
ovs_dp_process_packet(skb, recirc_key);
} else {
da = add_deferred_actions(skb, key, NULL, 0);
if (da) {
recirc_key = &da->pkt_key;
recirc_key->recirc_id = nla_get_u32(a);
} else {
/* Log an error in case action fifo is full. */
kfree_skb(skb);
if (net_ratelimit())
pr_warn("%s: deferred action limit reached, drop recirc action\n",
ovs_dp_name(dp));
}
}
return 0;
} }
/* Execute a list of actions against 'skb'. */ /* Execute a list of actions against 'skb'. */
...@@ -1221,9 +1155,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -1221,9 +1155,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
err = pop_vlan(skb, key); err = pop_vlan(skb, key);
break; break;
case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_RECIRC: {
err = execute_recirc(dp, skb, key, a, rem); bool last = nla_is_last(a, rem);
if (nla_is_last(a, rem)) {
err = execute_recirc(dp, skb, key, a, last);
if (last) {
/* If this is the last action, the skb has /* If this is the last action, the skb has
* been consumed or freed. * been consumed or freed.
* Return immediately. * Return immediately.
...@@ -1231,6 +1167,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -1231,6 +1167,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
return err; return err;
} }
break; break;
}
case OVS_ACTION_ATTR_SET: case OVS_ACTION_ATTR_SET:
err = execute_set_action(skb, key, nla_data(a)); err = execute_set_action(skb, key, nla_data(a));
...@@ -1285,6 +1222,79 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -1285,6 +1222,79 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
return 0; return 0;
} }
/* Execute the actions on the clone of the packet. The effect of the
* execution does not affect the original 'skb' nor the original 'key'.
*
* The execution may be deferred in case the actions can not be executed
* immediately.
*/
static int clone_execute(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key, u32 recirc_id,
const struct nlattr *actions, int len,
bool last, bool clone_flow_key)
{
struct deferred_action *da;
struct sw_flow_key *clone;
skb = last ? skb : skb_clone(skb, GFP_ATOMIC);
if (!skb) {
/* Out of memory, skip this action.
*/
return 0;
}
/* When clone_flow_key is false, the 'key' will not be change
* by the actions, then the 'key' can be used directly.
* Otherwise, try to clone key from the next recursion level of
* 'flow_keys'. If clone is successful, execute the actions
* without deferring.
*/
clone = clone_flow_key ? clone_key(key) : key;
if (clone) {
int err = 0;
if (actions) { /* Sample action */
if (clone_flow_key)
__this_cpu_inc(exec_actions_level);
err = do_execute_actions(dp, skb, clone,
actions, len);
if (clone_flow_key)
__this_cpu_dec(exec_actions_level);
} else { /* Recirc action */
clone->recirc_id = recirc_id;
ovs_dp_process_packet(skb, clone);
}
return err;
}
/* Out of 'flow_keys' space. Defer actions */
da = add_deferred_actions(skb, key, actions, len);
if (da) {
if (!actions) { /* Recirc action */
key = &da->pkt_key;
key->recirc_id = recirc_id;
}
} else {
/* Out of per CPU action FIFO space. Drop the 'skb' and
* log an error.
*/
kfree_skb(skb);
if (net_ratelimit()) {
if (actions) { /* Sample action */
pr_warn("%s: deferred action limit reached, drop sample action\n",
ovs_dp_name(dp));
} else { /* Recirc action */
pr_warn("%s: deferred action limit reached, drop recirc action\n",
ovs_dp_name(dp));
}
}
}
return 0;
}
static void process_deferred_actions(struct datapath *dp) static void process_deferred_actions(struct datapath *dp)
{ {
struct action_fifo *fifo = this_cpu_ptr(action_fifos); struct action_fifo *fifo = this_cpu_ptr(action_fifos);
......
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