Thanks. Pushed to master with suggested changes.
On Fri, Sep 5, 2014 at 4:23 PM, Pravin Shelar <pshe...@nicira.com> wrote: > On Fri, Sep 5, 2014 at 2:52 PM, Andy Zhou <az...@nicira.com> wrote: >> Since kernel stack is limited in size, it is not wise to using >> recursive function with large stack frames. >> >> This patch provides an alternative implementation of recirc action >> without using recursion. >> >> A per CPU fixed sized, 'deferred action FIFO', is used to store either >> recirc or sample actions encountered during execution of an action >> list. Not executing recirc or sample action in place, but rather execute >> them laster as 'deferred actions' avoids recursion. >> >> Deferred actions are only executed after all other actions has been >> executed, including the ones triggered by loopback from the kernel >> network stack. >> >> The size of the private FIFO, currently set to 20, limits the number >> of total 'deferred actions' any one packet can accumulate. >> >> Signed-off-by: Andy Zhou <az...@nicira.com> >> > Thanks for fixing all issue. > Acked-by: Pravin B Shelar <pshe...@nicira.com> > > I have couple of minor comments below. > >> --- >> v8->v7: >> Always free skb from execute_recirc() >> Dynamically allocating per CPU action fifos >> >> v6->v7: >> Always clone the packet key >> >> v5->v6: >> Remove ovs_ prefix for internal symbols. >> Remove actions.h >> Rename ovs_exec_actions_count to exec_actions_limit >> Rename ovs_process_deferred_packets() to >> process_deferred_actions() >> >> v4->v5: >> Reset fifo after processing deferred actions >> move private data structures from actions.h to actions.c >> remove action_fifo init functions, since default percpu data >> will be zero. >> --- >> datapath/actions.c | 169 >> +++++++++++++++++++++++++++++++++++++++++++++++----- >> datapath/datapath.c | 5 ++ >> datapath/datapath.h | 3 + >> 3 files changed, 162 insertions(+), 15 deletions(-) >> >> diff --git a/datapath/actions.c b/datapath/actions.c >> index 0a22e55..95f1e51 100644 >> --- a/datapath/actions.c >> +++ b/datapath/actions.c >> @@ -40,12 +40,80 @@ >> #include "vlan.h" >> #include "vport.h" >> >> +struct deferred_action { >> + struct sk_buff *skb; >> + const struct nlattr *actions; >> + >> + /* Store pkt_key clone when creating deferred action. */ >> + struct sw_flow_key pkt_key; >> +}; >> + >> +#define DEFERRED_ACTION_FIFO_SIZE 10 >> +struct action_fifo { >> + int head; >> + int tail; >> + /* Deferred action fifo queue storage. */ >> + struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE]; >> +}; >> + >> +static struct action_fifo *action_fifos; >> +#define EXEC_ACTIONS_LEVEL_LIMIT 4 /* limit used to detect packet >> + looping by the network stack */ >> +static DEFINE_PER_CPU(int, exec_actions_level); >> + >> +static void action_fifo_init(struct action_fifo *fifo) >> +{ >> + fifo->head = 0; >> + fifo->tail = 0; >> +} >> + >> +static bool action_fifo_is_empty(struct action_fifo *fifo) >> +{ >> + return (fifo->head == fifo->tail); >> +} >> + >> +static struct deferred_action * >> +action_fifo_get(struct action_fifo *fifo) >> +{ >> + if (action_fifo_is_empty(fifo)) >> + return NULL; >> + >> + return &fifo->fifo[fifo->tail++]; >> +} >> + >> +static struct deferred_action * >> +action_fifo_put(struct action_fifo *fifo) >> +{ >> + if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1) >> + return NULL; >> + >> + return &fifo->fifo[fifo->head++]; >> +} >> + >> static void flow_key_clone(struct sk_buff *skb, struct sw_flow_key *new_key) >> { >> *new_key = *OVS_CB(skb)->pkt_key; >> OVS_CB(skb)->pkt_key = new_key; >> } >> >> +/* Return True iff fifo is not full */ > Typo. > >> +static bool add_deferred_actions(struct sk_buff *skb, >> + const struct nlattr *attr) >> +{ >> + struct action_fifo *fifo; >> + struct deferred_action *da; >> + >> + fifo = this_cpu_ptr(action_fifos); >> + da = action_fifo_put(fifo); >> + if (da) { >> + da->skb = skb; >> + da->actions = attr; >> + flow_key_clone(skb, &da->pkt_key); >> + } >> + >> + return (da != NULL); >> +} >> + >> static void flow_key_set_recirc_id(struct sk_buff *skb, u32 recirc_id) >> { >> OVS_CB(skb)->pkt_key->recirc_id = recirc_id; >> @@ -689,7 +757,6 @@ static bool last_action(const struct nlattr *a, int rem) >> static int sample(struct datapath *dp, struct sk_buff *skb, >> const struct nlattr *attr) >> { >> - struct sw_flow_key sample_key; >> const struct nlattr *acts_list = NULL; >> const struct nlattr *a; >> int rem; >> @@ -728,10 +795,15 @@ static int sample(struct datapath *dp, struct sk_buff >> *skb, >> /* Skip the sample action when out of memory. */ >> return 0; >> >> - flow_key_clone(skb, &sample_key); >> + if (!add_deferred_actions(skb, a)) { >> + if (net_ratelimit()) >> + pr_warn("%s: deferred actions limit reached, >> dropping sample action\n", >> + ovs_dp_name(dp)); >> >> - /* do_execute_actions() will consume the cloned skb. */ >> - return do_execute_actions(dp, skb, a, rem); >> + kfree_skb(skb); >> + } >> + >> + return 0; >> } >> >> static void execute_hash(struct sk_buff *skb, const struct nlattr *attr) >> @@ -750,7 +822,7 @@ static void execute_hash(struct sk_buff *skb, const >> struct nlattr *attr) >> } >> >> static int execute_set_action(struct sk_buff *skb, >> - const struct nlattr *nested_attr) >> + const struct nlattr *nested_attr) >> { >> int err = 0; >> >> @@ -801,12 +873,9 @@ static int execute_set_action(struct sk_buff *skb, >> return err; >> } >> >> - >> static int execute_recirc(struct datapath *dp, struct sk_buff *skb, >> const struct nlattr *a, int rem) >> { >> - struct sw_flow_key recirc_key; >> - >> if (!is_skb_flow_key_valid(skb)) { >> int err; >> >> @@ -819,25 +888,31 @@ static int execute_recirc(struct datapath *dp, struct >> sk_buff *skb, >> >> if (!last_action(a, rem)) { >> /* Recirc action is the not the last action >> - * of the action list. */ >> + * 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; >> + } >> >> - flow_key_clone(skb, &recirc_key); >> + if (add_deferred_actions(skb, NULL)) { >> + flow_key_set_recirc_id(skb, nla_get_u32(a)); >> + } else { >> + kfree_skb(skb); >> + >> + if (net_ratelimit()) >> + pr_warn("%s: deferred action limit reached, drop >> recirc action\n", >> + ovs_dp_name(dp)); >> } >> >> - flow_key_set_recirc_id(skb, nla_get_u32(a)); >> - ovs_dp_process_packet(skb); >> return 0; >> } >> >> /* Execute a list of actions against 'skb'. */ >> static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, >> - const struct nlattr *attr, int len) >> + const struct nlattr *attr, int len) >> { >> /* Every output action needs a separate clone of 'skb', but the >> common >> * case is just a single output action, so that doing a clone and >> @@ -924,8 +999,72 @@ static int do_execute_actions(struct datapath *dp, >> struct sk_buff *skb, >> return 0; >> } >> >> +static void process_deferred_actions(struct datapath *dp) >> +{ >> + struct action_fifo *fifo = this_cpu_ptr(action_fifos); >> + >> + /* Do not touch the FIFO in case there is no deferred actions. */ >> + if (action_fifo_is_empty(fifo)) >> + return; >> + >> + /* Finishing executing all deferred actions. */ >> + do { >> + struct deferred_action *da = action_fifo_get(fifo); >> + struct sk_buff *skb = da->skb; >> + const struct nlattr *actions = da->actions; >> + >> + if (actions) >> + do_execute_actions(dp, skb, actions, >> + nla_len(actions)); >> + else >> + ovs_dp_process_packet(skb); >> + } while (!action_fifo_is_empty(fifo)); >> + >> + /* Reset FIFO for the next packet. */ >> + action_fifo_init(fifo); >> +} >> + >> /* Execute a list of actions against 'skb'. */ >> -int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, struct >> sw_flow_actions *acts) >> +int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, >> + struct sw_flow_actions *acts) >> +{ >> + int level = this_cpu_read(exec_actions_level); >> + int err; >> + >> + if (unlikely(level >= EXEC_ACTIONS_LEVEL_LIMIT)) { >> + if (net_ratelimit()) >> + pr_warn("%s: packet loop detected, dropping.\n", >> + ovs_dp_name(dp)); >> + >> + kfree_skb(skb); >> + return -ELOOP; >> + } >> + >> + this_cpu_inc(exec_actions_level); >> + >> + err = do_execute_actions(dp, skb, acts->actions, acts->actions_len); >> + >> + if (!level) >> + process_deferred_actions(dp); >> + >> + this_cpu_dec(exec_actions_level); >> + >> + /* This return status currently does not reflect the errors >> + * encounted during deferred actions execution. Probably needs to >> + * be fixed in the future. */ >> + return err; >> +} >> + >> +int action_fifos_init(void) >> +{ >> + action_fifos = alloc_percpu(struct action_fifo); >> + if (!action_fifos) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> +void action_fifos_exit(void) >> { >> - return do_execute_actions(dp, skb, acts->actions, acts->actions_len); >> + free_percpu(action_fifos); >> } >> diff --git a/datapath/datapath.c b/datapath/datapath.c >> index a668222..33ff7bc 100644 >> --- a/datapath/datapath.c >> +++ b/datapath/datapath.c >> @@ -2131,6 +2131,10 @@ static int __init dp_init(void) >> pr_info("Open vSwitch switching datapath %s, built "__DATE__" >> "__TIME__"\n", >> VERSION); >> >> + err = action_fifos_init(); >> + if (err) >> + goto error; >> + >> err = ovs_flow_init(); >> if (err) >> goto error; > Needs to free percpu memory in case of error here. > >> @@ -2173,6 +2177,7 @@ static void dp_cleanup(void) >> rcu_barrier(); >> ovs_vport_exit(); >> ovs_flow_exit(); >> + action_fifos_exit(); >> } >> >> module_init(dp_init); >> diff --git a/datapath/datapath.h b/datapath/datapath.h >> index eba2fc4..c5d3c86 100644 >> --- a/datapath/datapath.h >> +++ b/datapath/datapath.h >> @@ -201,6 +201,9 @@ int ovs_execute_actions(struct datapath *dp, struct >> sk_buff *skb, >> struct sw_flow_actions *acts); >> void ovs_dp_notify_wq(struct work_struct *work); >> >> +int action_fifos_init(void); >> +void action_fifos_exit(void); >> + >> #define OVS_NLERR(fmt, ...) \ >> do { \ >> if (net_ratelimit()) \ >> -- >> 1.9.1 >> >> _______________________________________________ >> dev mailing list >> dev@openvswitch.org >> http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev