* [net-next ovs clone action 1/3] openvswitch: deferred fifo api change @ 2017-01-31 16:47 Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 2/3] openvswitch: Refactor recirc key allocation Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action Andy Zhou 0 siblings, 2 replies; 7+ messages in thread From: Andy Zhou @ 2017-01-31 16:47 UTC (permalink / raw) To: davem; +Cc: netdev, Andy Zhou add_deferred_actions() API currently requires actions to be passed in as a fully encoded netlink message. So far both 'sample' and 'recirc' actions happens to carry actions as fully encoded netlink messages. However, this requirement is more restrictive than necessary, future patch will need to pass in action lists that are not fully encoded by themselves. Signed-off-by: Andy Zhou <azhou@ovn.org> --- net/openvswitch/actions.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index efa9a88..6f025cd 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -51,6 +51,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct deferred_action { struct sk_buff *skb; const struct nlattr *actions; + int actions_len; /* Store pkt_key clone when creating deferred action. */ struct sw_flow_key pkt_key; @@ -119,8 +120,9 @@ static struct deferred_action *action_fifo_put(struct action_fifo *fifo) /* Return true if fifo is not full */ static struct deferred_action *add_deferred_actions(struct sk_buff *skb, - const struct sw_flow_key *key, - const struct nlattr *attr) + const struct sw_flow_key *key, + const struct nlattr *actions, + const int actions_len) { struct action_fifo *fifo; struct deferred_action *da; @@ -129,7 +131,8 @@ static struct deferred_action *add_deferred_actions(struct sk_buff *skb, da = action_fifo_put(fifo); if (da) { da->skb = skb; - da->actions = attr; + da->actions = actions; + da->actions_len = actions_len; da->pkt_key = *key; } @@ -967,7 +970,8 @@ static int sample(struct datapath *dp, struct sk_buff *skb, /* Skip the sample action when out of memory. */ return 0; - if (!add_deferred_actions(skb, key, a)) { + if (!add_deferred_actions(skb, key, nla_data(acts_list), + nla_len(acts_list))) { if (net_ratelimit()) pr_warn("%s: deferred actions limit reached, dropping sample action\n", ovs_dp_name(dp)); @@ -1122,7 +1126,7 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, return 0; } - da = add_deferred_actions(skb, key, NULL); + da = add_deferred_actions(skb, key, NULL, 0); if (da) { da->pkt_key.recirc_id = nla_get_u32(a); } else { @@ -1277,10 +1281,10 @@ static void process_deferred_actions(struct datapath *dp) struct sk_buff *skb = da->skb; struct sw_flow_key *key = &da->pkt_key; const struct nlattr *actions = da->actions; + int actions_len = da->actions_len; if (actions) - do_execute_actions(dp, skb, key, actions, - nla_len(actions)); + do_execute_actions(dp, skb, key, actions, actions_len); else ovs_dp_process_packet(skb, key); } while (!action_fifo_is_empty(fifo)); -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [net-next ovs clone action 2/3] openvswitch: Refactor recirc key allocation. 2017-01-31 16:47 [net-next ovs clone action 1/3] openvswitch: deferred fifo api change Andy Zhou @ 2017-01-31 16:47 ` Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action Andy Zhou 1 sibling, 0 replies; 7+ messages in thread From: Andy Zhou @ 2017-01-31 16:47 UTC (permalink / raw) To: davem; +Cc: netdev, Andy Zhou The logic of allocating and copy key for each 'exec_actions_level' was specific to execute_recirc(). However, future patches will reuse as well. Refactor the logic into its own function clone_key(). Signed-off-by: Andy Zhou <azhou@ovn.org> --- net/openvswitch/actions.c | 72 +++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 6f025cd..73bd4ad 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2014 Nicira, Inc. + * Copyright (c) 2007-2017 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -75,7 +75,7 @@ struct ovs_frag_data { #define DEFERRED_ACTION_FIFO_SIZE 10 #define OVS_RECURSION_LIMIT 5 -#define OVS_DEFERRED_ACTION_THRESHOLD (OVS_RECURSION_LIMIT - 2) +#define OVS_ACTION_RECURSION_THRESHOLD (OVS_RECURSION_LIMIT - 2) struct action_fifo { int head; int tail; @@ -83,14 +83,32 @@ struct action_fifo { struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE]; }; -struct recirc_keys { - struct sw_flow_key key[OVS_DEFERRED_ACTION_THRESHOLD]; +struct action_flow_keys { + struct sw_flow_key key[OVS_ACTION_RECURSION_THRESHOLD]; }; static struct action_fifo __percpu *action_fifos; -static struct recirc_keys __percpu *recirc_keys; +static struct action_flow_keys __percpu *flow_keys; static DEFINE_PER_CPU(int, exec_actions_level); +/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys' + * space. Since the storage is pre-allocated, the caller does not + * need to check for NULL return pointer. + */ +static struct sw_flow_key *clone_key(const struct sw_flow_key *key_) +{ + struct action_flow_keys *keys = this_cpu_ptr(flow_keys); + int level = this_cpu_read(exec_actions_level); + struct sw_flow_key *key = NULL; + + if (level <= OVS_ACTION_RECURSION_THRESHOLD) { + key = &keys->key[level - 1]; + *key = *key_; + } + + return key; +} + static void action_fifo_init(struct action_fifo *fifo) { fifo->head = 0; @@ -1089,8 +1107,8 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *a, int rem) { + struct sw_flow_key *recirc_key; struct deferred_action *da; - int level; if (!is_flow_key_valid(key)) { int err; @@ -1114,29 +1132,27 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, return 0; } - level = this_cpu_read(exec_actions_level); - if (level <= OVS_DEFERRED_ACTION_THRESHOLD) { - struct recirc_keys *rks = this_cpu_ptr(recirc_keys); - struct sw_flow_key *recirc_key = &rks->key[level - 1]; - - *recirc_key = *key; + /* If we are within the limit of 'OVS_ACTION_RECURSION_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); - - return 0; - } - - da = add_deferred_actions(skb, key, NULL, 0); - if (da) { - da->pkt_key.recirc_id = 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)); + 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; } @@ -1326,8 +1342,8 @@ int action_fifos_init(void) if (!action_fifos) return -ENOMEM; - recirc_keys = alloc_percpu(struct recirc_keys); - if (!recirc_keys) { + flow_keys = alloc_percpu(struct action_flow_keys); + if (!flow_keys) { free_percpu(action_fifos); return -ENOMEM; } @@ -1338,5 +1354,5 @@ int action_fifos_init(void) void action_fifos_exit(void) { free_percpu(action_fifos); - free_percpu(recirc_keys); + free_percpu(flow_keys); } -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action 2017-01-31 16:47 [net-next ovs clone action 1/3] openvswitch: deferred fifo api change Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 2/3] openvswitch: Refactor recirc key allocation Andy Zhou @ 2017-01-31 16:47 ` Andy Zhou 2017-02-02 2:30 ` Pravin Shelar 2018-06-28 15:20 ` [PATCH net-next] " Yifeng Sun 1 sibling, 2 replies; 7+ messages in thread From: Andy Zhou @ 2017-01-31 16:47 UTC (permalink / raw) To: davem; +Cc: netdev, Andy Zhou Add 'clone' kernel datapath support. In case the actions within clone do not modify the current flow, the actions are executed without making a copy of current key before execution. This analysis is done once per flow installation. On the other hand, in case the actions within clone may modify current flow key, a key has to be copied. In case the percpu 'flow_keys' is available for the next 'exec_actions_level', the clone actions will be executed without using the deferred fifo. Otherwise, deferred fifo is used this clone action. Signed-off-by: Andy Zhou <azhou@ovn.org> --- include/uapi/linux/openvswitch.h | 1 + net/openvswitch/actions.c | 66 ++++++++++++++++++++++ net/openvswitch/datapath.h | 3 + net/openvswitch/flow_netlink.c | 117 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 186 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 375d812..910969d 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -780,6 +780,7 @@ enum ovs_action_attr { OVS_ACTION_ATTR_TRUNC, /* u32 struct ovs_action_trunc. */ OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ OVS_ACTION_ATTR_POP_ETH, /* No argument. */ + OVS_ACTION_ATTR_CLONE, /* Nested OVS_ACTION_ATTR_*. */ __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 73bd4ad..b75388f 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1156,6 +1156,55 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, return 0; } +static int execute_clone(struct datapath *dp, struct sk_buff *skb, + struct sw_flow_key *key, const struct nlattr *a) +{ + struct nlattr *actions; + struct sw_flow_key *orig = key; + int rem; + int err = 0; + bool exec = false; + + actions = nla_data(a); + rem = nla_len(a); + if (nla_type(a) == OVS_CLONE_ATTR_EXEC) { + exec = true; + actions = nla_next(actions, &rem); + } + + /* In case the clone actions won't change 'key', + * we can use key for the clone execution. + * Otherwise, try to allocate a key from the + * next recursion level of 'flow_keys'. If + * successful, we can still execute the clone + * actions without deferring. + * + * Defer the clone action if the action recursion + * limit has been reached. + */ + if (!exec) { + __this_cpu_inc(exec_actions_level); + key = clone_key(key); + } + + if (key) { + err = do_execute_actions(dp, skb, key, actions, rem); + } else { + struct deferred_action *da; + + da = add_deferred_actions(skb, orig, actions, rem); + + if (!da && net_ratelimit()) + pr_warn("%s: deferred action limit reached, drop clone action\n", + ovs_dp_name(dp)); + } + + if (!exec) + __this_cpu_dec(exec_actions_level); + + return err; +} + /* Execute a list of actions against 'skb'. */ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, @@ -1271,6 +1320,23 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, case OVS_ACTION_ATTR_POP_ETH: err = pop_eth(skb, key); break; + + case OVS_ACTION_ATTR_CLONE: { + bool last = nla_is_last(a, rem); + struct sk_buff *clone_skb; + + clone_skb = last ? skb : skb_clone(skb, GFP_ATOMIC); + + if (!clone_skb) + /* Out of memory, skip this clone action. + */ + break; + + err = execute_clone(dp, clone_skb, key, a); + if (last) + return err; + break; + } } if (unlikely(err)) { diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 1c6e937..2ea9f30 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -220,4 +220,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, if (logging_allowed && net_ratelimit()) \ pr_info("netlink: " fmt "\n", ##__VA_ARGS__); \ } while (0) + +#define OVS_CLONE_ATTR_EXEC (OVS_ACTION_ATTR_MAX + 1) + #endif /* datapath.h */ diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index c87d359..2d314f6 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2014 Nicira, Inc. + * Copyright (c) 2007-2017 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -59,6 +59,40 @@ struct ovs_len_tbl { #define OVS_ATTR_NESTED -1 #define OVS_ATTR_VARIABLE -2 +static bool actions_may_change_flow(const struct nlattr *actions) +{ + struct nlattr *nla; + int rem; + + nla_for_each_nested(nla, actions, rem) { + u16 action = nla_type(nla); + + switch (action) { + case OVS_ACTION_ATTR_OUTPUT: + case OVS_ACTION_ATTR_RECIRC: + case OVS_ACTION_ATTR_USERSPACE: + case OVS_ACTION_ATTR_SAMPLE: + case OVS_ACTION_ATTR_TRUNC: + case OVS_ACTION_ATTR_CLONE: + break; + + case OVS_ACTION_ATTR_PUSH_MPLS: + case OVS_ACTION_ATTR_POP_MPLS: + case OVS_ACTION_ATTR_PUSH_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_SET: + case OVS_ACTION_ATTR_SET_MASKED: + case OVS_ACTION_ATTR_HASH: + case OVS_ACTION_ATTR_CT: + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: + default: + return true; + } + } + return false; +} + static void update_range(struct sw_flow_match *match, size_t offset, size_t size, bool is_mask) { @@ -2342,6 +2376,46 @@ static int validate_userspace(const struct nlattr *attr) return 0; } +static int copy_clone(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, int depth, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, bool log, bool last) +{ + int start, err; + bool exec; + + start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log); + if (start < 0) + return start; + + /* When both skb and flow may be changed, put the clone + * into a deferred fifo. On the other hand, if only skb + * may be modified, the actions can be executed in place. + * + * Do this analysis at the flow installation time. + * Set 'clone_action->exec' to true if the actions can be + * executed without being deferred. + * + * If the clone is the last action, it can always be excuted + * rather than deferred. + */ + exec = last || !actions_may_change_flow(attr); + + if (exec) { + err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, NULL, 0, + log); + if (err) + return err; + } + + err = __ovs_nla_copy_actions(net, attr, key, depth, sfa, + eth_type, vlan_tci, log); + + add_nested_action_end(*sfa, start); + + return err; +} + static int copy_action(const struct nlattr *from, struct sw_flow_actions **sfa, bool log) { @@ -2386,6 +2460,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc), [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth), [OVS_ACTION_ATTR_POP_ETH] = 0, + [OVS_ACTION_ATTR_CLONE] = (u32)-1, }; const struct ovs_action_push_vlan *vlan; int type = nla_type(a); @@ -2536,6 +2611,14 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, mac_proto = MAC_PROTO_ETHERNET; break; + case OVS_ACTION_ATTR_CLONE: + err = copy_clone(net, a, key, depth, sfa, eth_type, + vlan_tci, log, nla_is_last(a, rem)); + if (err) + return err; + skip_copy = true; + break; + default: OVS_NLERR(log, "Unknown Action type %d", type); return -EINVAL; @@ -2609,6 +2692,32 @@ static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) return err; } +static int clone_action_to_attr(const struct nlattr *clone, + struct sk_buff *skb) +{ + struct nlattr *start, *actions; + int rem, err = 0; + + start = nla_nest_start(skb, OVS_ACTION_ATTR_CLONE); + if (!start) + return -EMSGSIZE; + + actions = nla_data(clone); + rem = nla_len(clone); + /* Skip internal 'OVS_CLONE_ATTR_EXEC' flag, if present, + */ + if (nla_type(actions) == OVS_CLONE_ATTR_EXEC) + actions = nla_next(actions, &rem); + + err = ovs_nla_put_actions(actions, rem, skb); + if (err) + return err; + + nla_nest_end(skb, start); + + return err; +} + static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) { const struct nlattr *ovs_key = nla_data(a); @@ -2697,6 +2806,12 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb) return err; break; + case OVS_ACTION_ATTR_CLONE: + err = clone_action_to_attr(a, skb); + if (err) + return err; + break; + default: if (nla_put(skb, type, nla_len(a), nla_data(a))) return -EMSGSIZE; -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action 2017-01-31 16:47 ` [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action Andy Zhou @ 2017-02-02 2:30 ` Pravin Shelar 2017-02-02 3:31 ` Andy Zhou 2018-06-28 15:20 ` [PATCH net-next] " Yifeng Sun 1 sibling, 1 reply; 7+ messages in thread From: Pravin Shelar @ 2017-02-02 2:30 UTC (permalink / raw) To: Andy Zhou; +Cc: David S. Miller, Linux Kernel Network Developers On Tue, Jan 31, 2017 at 8:47 AM, Andy Zhou <azhou@ovn.org> wrote: > Add 'clone' kernel datapath support. In case the actions within clone > do not modify the current flow, the actions are executed without > making a copy of current key before execution. This analysis is > done once per flow installation. > > On the other hand, in case the actions within clone may modify > current flow key, a key has to be copied. In case the percpu > 'flow_keys' is available for the next 'exec_actions_level', the clone > actions will be executed without using the deferred fifo. Otherwise, > deferred fifo is used this clone action. > I think we can use sample action to clone packet and apply optimization to sample action. That will allow greater use of existing action without additional complexity. Thanks, Pravin. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action 2017-02-02 2:30 ` Pravin Shelar @ 2017-02-02 3:31 ` Andy Zhou 0 siblings, 0 replies; 7+ messages in thread From: Andy Zhou @ 2017-02-02 3:31 UTC (permalink / raw) To: Pravin Shelar; +Cc: David S. Miller, Linux Kernel Network Developers On Wed, Feb 1, 2017 at 6:30 PM, Pravin Shelar <pshelar@ovn.org> wrote: > On Tue, Jan 31, 2017 at 8:47 AM, Andy Zhou <azhou@ovn.org> wrote: >> Add 'clone' kernel datapath support. In case the actions within clone >> do not modify the current flow, the actions are executed without >> making a copy of current key before execution. This analysis is >> done once per flow installation. >> >> On the other hand, in case the actions within clone may modify >> current flow key, a key has to be copied. In case the percpu >> 'flow_keys' is available for the next 'exec_actions_level', the clone >> actions will be executed without using the deferred fifo. Otherwise, >> deferred fifo is used this clone action. >> > > I think we can use sample action to clone packet and apply > optimization to sample action. That will allow greater use of existing > action without additional complexity. > O.K. I will rework the patch series to apply the optimizations to the sample action. Thanks for the review and comment. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next] openvswitch: kernel datapath clone action 2017-01-31 16:47 ` [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action Andy Zhou 2017-02-02 2:30 ` Pravin Shelar @ 2018-06-28 15:20 ` Yifeng Sun 2018-06-29 22:08 ` Pravin Shelar 1 sibling, 1 reply; 7+ messages in thread From: Yifeng Sun @ 2018-06-28 15:20 UTC (permalink / raw) To: azhou, pshelar, netdev; +Cc: Yifeng Sun Add 'clone' action to kernel datapath by using existing functions. When actions within clone don't modify the current flow, the flow key is not cloned before executing clone actions. This is a follow up patch for this incomplete work: https://patchwork.ozlabs.org/patch/722096/ Signed-off-by: Yifeng Sun <pkusunyifeng@gmail.com> Signed-off-by: Andy Zhou <azhou@ovn.org> --- include/uapi/linux/openvswitch.h | 8 +++++ net/openvswitch/actions.c | 33 ++++++++++++++++++ net/openvswitch/flow_netlink.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 863aaba..5de8583 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -625,6 +625,11 @@ struct sample_arg { * 'OVS_SAMPLE_ATTR_PROBABILITY'. */ }; + +#define OVS_CLONE_ATTR_EXEC 0 /* Specify an u32 value. When nonzero, + * actions in clone will not change flow + * keys. False otherwise. + */ #endif /** @@ -840,6 +845,8 @@ struct ovs_action_push_eth { * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off the packet. * @OVS_ACTION_ATTR_METER: Run packet through a meter, which may drop the * packet, or modify the packet (e.g., change the DSCP field). + * @OVS_ACTION_ATTR_CLONE: make a copy of the packet and execute a list of + * actions without affecting the original packet and key. * * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * fields within a header are modifiable, e.g. the IPv4 protocol and fragment @@ -873,6 +880,7 @@ enum ovs_action_attr { OVS_ACTION_ATTR_PUSH_NSH, /* Nested OVS_NSH_KEY_ATTR_*. */ OVS_ACTION_ATTR_POP_NSH, /* No argument. */ OVS_ACTION_ATTR_METER, /* u32 meter ID. */ + OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */ __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 30a5df2..4444e31 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1057,6 +1057,28 @@ static int sample(struct datapath *dp, struct sk_buff *skb, clone_flow_key); } +/* When 'last' is true, clone() should always consume the 'skb'. + * Otherwise, clone() should keep 'skb' intact regardless what + * actions are executed within clone(). + */ +static int clone(struct datapath *dp, struct sk_buff *skb, + struct sw_flow_key *key, const struct nlattr *attr, + bool last) +{ + struct nlattr *actions; + struct nlattr *clone_arg; + int rem = nla_len(attr); + bool clone_flow_key; + + /* The first action is always 'OVS_CLONE_ATTR_ARG'. */ + clone_arg = nla_data(attr); + clone_flow_key = !nla_get_u32(clone_arg); + actions = nla_next(clone_arg, &rem); + + return clone_execute(dp, skb, key, 0, actions, rem, last, + clone_flow_key); +} + static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr) { @@ -1336,6 +1358,17 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, consume_skb(skb); return 0; } + break; + + case OVS_ACTION_ATTR_CLONE: { + bool last = nla_is_last(a, rem); + + err = clone(dp, skb, key, a, last); + if (last) + return err; + + break; + } } if (unlikely(err)) { diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 492ab0c..6938b56 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2460,6 +2460,40 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, return 0; } +static int validate_and_copy_clone(struct net *net, + const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, + bool log, bool last) +{ + int start, err; + u32 exec; + + if (nla_len(attr) && nla_len(attr) < NLA_HDRLEN) + return -EINVAL; + + start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log); + if (start < 0) + return start; + + exec = last || !actions_may_change_flow(attr); + + err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec, + sizeof(exec), log); + if (err) + return err; + + err = __ovs_nla_copy_actions(net, attr, key, sfa, + eth_type, vlan_tci, log); + if (err) + return err; + + add_nested_action_end(*sfa, start); + + return 0; +} + void ovs_match_init(struct sw_flow_match *match, struct sw_flow_key *key, bool reset_key, @@ -2844,6 +2878,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1, [OVS_ACTION_ATTR_POP_NSH] = 0, [OVS_ACTION_ATTR_METER] = sizeof(u32), + [OVS_ACTION_ATTR_CLONE] = (u32)-1, }; const struct ovs_action_push_vlan *vlan; int type = nla_type(a); @@ -3033,6 +3068,18 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, /* Non-existent meters are simply ignored. */ break; + case OVS_ACTION_ATTR_CLONE: { + bool last = nla_is_last(a, rem); + + err = validate_and_copy_clone(net, a, key, sfa, + eth_type, vlan_tci, + log, last); + if (err) + return err; + skip_copy = true; + break; + } + default: OVS_NLERR(log, "Unknown Action type %d", type); return -EINVAL; @@ -3111,6 +3158,26 @@ static int sample_action_to_attr(const struct nlattr *attr, return err; } +static int clone_action_to_attr(const struct nlattr *attr, + struct sk_buff *skb) +{ + struct nlattr *start; + int err = 0, rem = nla_len(attr); + + start = nla_nest_start(skb, OVS_ACTION_ATTR_CLONE); + if (!start) + return -EMSGSIZE; + + err = ovs_nla_put_actions(nla_data(attr), rem, skb); + + if (err) + nla_nest_cancel(skb, start); + else + nla_nest_end(skb, start); + + return err; +} + static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) { const struct nlattr *ovs_key = nla_data(a); @@ -3199,6 +3266,12 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb) return err; break; + case OVS_ACTION_ATTR_CLONE: + err = clone_action_to_attr(a, skb); + if (err) + return err; + break; + default: if (nla_put(skb, type, nla_len(a), nla_data(a))) return -EMSGSIZE; -- 2.7.4 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next] openvswitch: kernel datapath clone action 2018-06-28 15:20 ` [PATCH net-next] " Yifeng Sun @ 2018-06-29 22:08 ` Pravin Shelar 0 siblings, 0 replies; 7+ messages in thread From: Pravin Shelar @ 2018-06-29 22:08 UTC (permalink / raw) To: Yifeng Sun; +Cc: Andy Zhou, Linux Kernel Network Developers On Thu, Jun 28, 2018 at 8:20 AM, Yifeng Sun <pkusunyifeng@gmail.com> wrote: > Add 'clone' action to kernel datapath by using existing functions. > When actions within clone don't modify the current flow, the flow > key is not cloned before executing clone actions. > > This is a follow up patch for this incomplete work: > https://patchwork.ozlabs.org/patch/722096/ > > Signed-off-by: Yifeng Sun <pkusunyifeng@gmail.com> > Signed-off-by: Andy Zhou <azhou@ovn.org> > --- > include/uapi/linux/openvswitch.h | 8 +++++ > net/openvswitch/actions.c | 33 ++++++++++++++++++ > net/openvswitch/flow_netlink.c | 73 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 114 insertions(+) > > diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h > index 863aaba..5de8583 100644 > --- a/include/uapi/linux/openvswitch.h > +++ b/include/uapi/linux/openvswitch.h > @@ -625,6 +625,11 @@ struct sample_arg { > * 'OVS_SAMPLE_ATTR_PROBABILITY'. > */ > }; > + > +#define OVS_CLONE_ATTR_EXEC 0 /* Specify an u32 value. When nonzero, > + * actions in clone will not change flow > + * keys. False otherwise. > + */ > #endif This symbol is used only in datapath, so we can move it to kernel headers from uapi. > diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c > index 30a5df2..4444e31 100644 > --- a/net/openvswitch/actions.c > +++ b/net/openvswitch/actions.c > @@ -1057,6 +1057,28 @@ static int sample(struct datapath *dp, struct sk_buff *skb, > clone_flow_key); > } > > +/* When 'last' is true, clone() should always consume the 'skb'. > + * Otherwise, clone() should keep 'skb' intact regardless what > + * actions are executed within clone(). > + */ > +static int clone(struct datapath *dp, struct sk_buff *skb, > + struct sw_flow_key *key, const struct nlattr *attr, > + bool last) > +{ > + struct nlattr *actions; > + struct nlattr *clone_arg; > + int rem = nla_len(attr); > + bool clone_flow_key; > + > + /* The first action is always 'OVS_CLONE_ATTR_ARG'. */ > + clone_arg = nla_data(attr); > + clone_flow_key = !nla_get_u32(clone_arg); > + actions = nla_next(clone_arg, &rem); > + Since OVS_CLONE_ATTR_EXEC means do not clone the key, it can be named accordingly. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2018-06-29 22:53 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-01-31 16:47 [net-next ovs clone action 1/3] openvswitch: deferred fifo api change Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 2/3] openvswitch: Refactor recirc key allocation Andy Zhou 2017-01-31 16:47 ` [net-next ovs clone action 3/3] openvswitch: kernel datapath clone action Andy Zhou 2017-02-02 2:30 ` Pravin Shelar 2017-02-02 3:31 ` Andy Zhou 2018-06-28 15:20 ` [PATCH net-next] " Yifeng Sun 2018-06-29 22:08 ` Pravin Shelar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox