xref: /openbmc/linux/net/openvswitch/datapath.c (revision fd5e9fccbd504c5179ab57ff695c610bca8809d6)
1c9422999SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ccb1352eSJesse Gross /*
3ad552007SBen Pfaff  * Copyright (c) 2007-2014 Nicira, Inc.
4ccb1352eSJesse Gross  */
5ccb1352eSJesse Gross 
6ccb1352eSJesse Gross #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7ccb1352eSJesse Gross 
8ccb1352eSJesse Gross #include <linux/init.h>
9ccb1352eSJesse Gross #include <linux/module.h>
10ccb1352eSJesse Gross #include <linux/if_arp.h>
11ccb1352eSJesse Gross #include <linux/if_vlan.h>
12ccb1352eSJesse Gross #include <linux/in.h>
13ccb1352eSJesse Gross #include <linux/ip.h>
14ccb1352eSJesse Gross #include <linux/jhash.h>
15ccb1352eSJesse Gross #include <linux/delay.h>
16ccb1352eSJesse Gross #include <linux/time.h>
17ccb1352eSJesse Gross #include <linux/etherdevice.h>
18ccb1352eSJesse Gross #include <linux/genetlink.h>
19ccb1352eSJesse Gross #include <linux/kernel.h>
20ccb1352eSJesse Gross #include <linux/kthread.h>
21ccb1352eSJesse Gross #include <linux/mutex.h>
22ccb1352eSJesse Gross #include <linux/percpu.h>
23ccb1352eSJesse Gross #include <linux/rcupdate.h>
24ccb1352eSJesse Gross #include <linux/tcp.h>
25ccb1352eSJesse Gross #include <linux/udp.h>
26ccb1352eSJesse Gross #include <linux/ethtool.h>
27ccb1352eSJesse Gross #include <linux/wait.h>
28ccb1352eSJesse Gross #include <asm/div64.h>
29ccb1352eSJesse Gross #include <linux/highmem.h>
30ccb1352eSJesse Gross #include <linux/netfilter_bridge.h>
31ccb1352eSJesse Gross #include <linux/netfilter_ipv4.h>
32ccb1352eSJesse Gross #include <linux/inetdevice.h>
33ccb1352eSJesse Gross #include <linux/list.h>
34ccb1352eSJesse Gross #include <linux/openvswitch.h>
35ccb1352eSJesse Gross #include <linux/rculist.h>
36ccb1352eSJesse Gross #include <linux/dmi.h>
37ccb1352eSJesse Gross #include <net/genetlink.h>
38d457a0e3SEric Dumazet #include <net/gso.h>
3946df7b81SPravin B Shelar #include <net/net_namespace.h>
4046df7b81SPravin B Shelar #include <net/netns/generic.h>
4135d39fecSPaul Blakey #include <net/pkt_cls.h>
42ccb1352eSJesse Gross 
43ccb1352eSJesse Gross #include "datapath.h"
449d802da4SAdrian Moreno #include "drop.h"
45ccb1352eSJesse Gross #include "flow.h"
46e80857ccSAndy Zhou #include "flow_table.h"
47e6445719SPravin B Shelar #include "flow_netlink.h"
4896fbc13dSAndy Zhou #include "meter.h"
49c4ab7b56SAaron Conole #include "openvswitch_trace.h"
50ccb1352eSJesse Gross #include "vport-internal_dev.h"
51cff63a52SThomas Graf #include "vport-netdev.h"
52ccb1352eSJesse Gross 
53c7d03a00SAlexey Dobriyan unsigned int ovs_net_id __read_mostly;
548e4e1713SPravin B Shelar 
550c200ef9SPravin B Shelar static struct genl_family dp_packet_genl_family;
560c200ef9SPravin B Shelar static struct genl_family dp_flow_genl_family;
570c200ef9SPravin B Shelar static struct genl_family dp_datapath_genl_family;
580c200ef9SPravin B Shelar 
5974ed7ab9SJoe Stringer static const struct nla_policy flow_policy[];
6074ed7ab9SJoe Stringer 
6148e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_flow_multicast_group = {
6248e48a70Sstephen hemminger 	.name = OVS_FLOW_MCGROUP,
630c200ef9SPravin B Shelar };
640c200ef9SPravin B Shelar 
6548e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_datapath_multicast_group = {
6648e48a70Sstephen hemminger 	.name = OVS_DATAPATH_MCGROUP,
670c200ef9SPravin B Shelar };
680c200ef9SPravin B Shelar 
6948e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_vport_multicast_group = {
7048e48a70Sstephen hemminger 	.name = OVS_VPORT_MCGROUP,
710c200ef9SPravin B Shelar };
720c200ef9SPravin B Shelar 
73fb5d1e9eSJarno Rajahalme /* Check if need to build a reply message.
74fb5d1e9eSJarno Rajahalme  * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */
ovs_must_notify(struct genl_family * family,struct genl_info * info,unsigned int group)759b67aa4aSSamuel Gauthier static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
769b67aa4aSSamuel Gauthier 			    unsigned int group)
77fb5d1e9eSJarno Rajahalme {
78fb5d1e9eSJarno Rajahalme 	return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
79f8403a2eSJohannes Berg 	       genl_has_listeners(family, genl_info_net(info), group);
80fb5d1e9eSJarno Rajahalme }
81fb5d1e9eSJarno Rajahalme 
ovs_notify(struct genl_family * family,struct sk_buff * skb,struct genl_info * info)8268eb5503SJohannes Berg static void ovs_notify(struct genl_family *family,
832a94fe48SJohannes Berg 		       struct sk_buff *skb, struct genl_info *info)
84ed661185SThomas Graf {
8592c14d9bSJiri Benc 	genl_notify(family, skb, info, 0, GFP_KERNEL);
86ed661185SThomas Graf }
87ed661185SThomas Graf 
8846df7b81SPravin B Shelar /**
89ccb1352eSJesse Gross  * DOC: Locking:
90ccb1352eSJesse Gross  *
918e4e1713SPravin B Shelar  * All writes e.g. Writes to device state (add/remove datapath, port, set
928e4e1713SPravin B Shelar  * operations on vports, etc.), Writes to other state (flow table
938e4e1713SPravin B Shelar  * modifications, set miscellaneous datapath parameters, etc.) are protected
948e4e1713SPravin B Shelar  * by ovs_lock.
95ccb1352eSJesse Gross  *
96ccb1352eSJesse Gross  * Reads are protected by RCU.
97ccb1352eSJesse Gross  *
98ccb1352eSJesse Gross  * There are a few special cases (mostly stats) that have their own
99ccb1352eSJesse Gross  * synchronization but they nest under all of above and don't interact with
100ccb1352eSJesse Gross  * each other.
1018e4e1713SPravin B Shelar  *
1028e4e1713SPravin B Shelar  * The RTNL lock nests inside ovs_mutex.
103ccb1352eSJesse Gross  */
104ccb1352eSJesse Gross 
1058e4e1713SPravin B Shelar static DEFINE_MUTEX(ovs_mutex);
1068e4e1713SPravin B Shelar 
ovs_lock(void)1078e4e1713SPravin B Shelar void ovs_lock(void)
1088e4e1713SPravin B Shelar {
1098e4e1713SPravin B Shelar 	mutex_lock(&ovs_mutex);
1108e4e1713SPravin B Shelar }
1118e4e1713SPravin B Shelar 
ovs_unlock(void)1128e4e1713SPravin B Shelar void ovs_unlock(void)
1138e4e1713SPravin B Shelar {
1148e4e1713SPravin B Shelar 	mutex_unlock(&ovs_mutex);
1158e4e1713SPravin B Shelar }
1168e4e1713SPravin B Shelar 
1178e4e1713SPravin B Shelar #ifdef CONFIG_LOCKDEP
lockdep_ovsl_is_held(void)1188e4e1713SPravin B Shelar int lockdep_ovsl_is_held(void)
1198e4e1713SPravin B Shelar {
1208e4e1713SPravin B Shelar 	if (debug_locks)
1218e4e1713SPravin B Shelar 		return lockdep_is_held(&ovs_mutex);
1228e4e1713SPravin B Shelar 	else
1238e4e1713SPravin B Shelar 		return 1;
1248e4e1713SPravin B Shelar }
1258e4e1713SPravin B Shelar #endif
1268e4e1713SPravin B Shelar 
127ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *);
1288055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *,
129e8eedb85SPravin B Shelar 			     const struct sw_flow_key *,
130f2a4d086SWilliam Tu 			     const struct dp_upcall_info *,
131f2a4d086SWilliam Tu 			     uint32_t cutlen);
1328055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
133e8eedb85SPravin B Shelar 				  const struct sw_flow_key *,
134f2a4d086SWilliam Tu 				  const struct dp_upcall_info *,
135f2a4d086SWilliam Tu 				  uint32_t cutlen);
136ccb1352eSJesse Gross 
137eac87c41SEelco Chaudron static void ovs_dp_masks_rebalance(struct work_struct *work);
138eac87c41SEelco Chaudron 
139b83d23a2SMark Gray static int ovs_dp_set_upcall_portids(struct datapath *, const struct nlattr *);
140b83d23a2SMark Gray 
1418e4e1713SPravin B Shelar /* Must be called with rcu_read_lock or ovs_mutex. */
ovs_dp_name(const struct datapath * dp)142971427f3SAndy Zhou const char *ovs_dp_name(const struct datapath *dp)
143ccb1352eSJesse Gross {
1448e4e1713SPravin B Shelar 	struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
145c9db965cSThomas Graf 	return ovs_vport_name(vport);
146ccb1352eSJesse Gross }
147ccb1352eSJesse Gross 
get_dpifindex(const struct datapath * dp)14812eb18f7SThomas Graf static int get_dpifindex(const struct datapath *dp)
149ccb1352eSJesse Gross {
150ccb1352eSJesse Gross 	struct vport *local;
151ccb1352eSJesse Gross 	int ifindex;
152ccb1352eSJesse Gross 
153ccb1352eSJesse Gross 	rcu_read_lock();
154ccb1352eSJesse Gross 
15515eac2a7SPravin B Shelar 	local = ovs_vport_rcu(dp, OVSP_LOCAL);
156ccb1352eSJesse Gross 	if (local)
157be4ace6eSThomas Graf 		ifindex = local->dev->ifindex;
158ccb1352eSJesse Gross 	else
159ccb1352eSJesse Gross 		ifindex = 0;
160ccb1352eSJesse Gross 
161ccb1352eSJesse Gross 	rcu_read_unlock();
162ccb1352eSJesse Gross 
163ccb1352eSJesse Gross 	return ifindex;
164ccb1352eSJesse Gross }
165ccb1352eSJesse Gross 
destroy_dp_rcu(struct rcu_head * rcu)166ccb1352eSJesse Gross static void destroy_dp_rcu(struct rcu_head *rcu)
167ccb1352eSJesse Gross {
168ccb1352eSJesse Gross 	struct datapath *dp = container_of(rcu, struct datapath, rcu);
169ccb1352eSJesse Gross 
1709b996e54SPravin B Shelar 	ovs_flow_tbl_destroy(&dp->table);
171ccb1352eSJesse Gross 	free_percpu(dp->stats_percpu);
17215eac2a7SPravin B Shelar 	kfree(dp->ports);
17396fbc13dSAndy Zhou 	ovs_meters_exit(dp);
174076999e4SMark Gray 	kfree(rcu_dereference_raw(dp->upcall_portids));
175ccb1352eSJesse Gross 	kfree(dp);
176ccb1352eSJesse Gross }
177ccb1352eSJesse Gross 
vport_hash_bucket(const struct datapath * dp,u16 port_no)17815eac2a7SPravin B Shelar static struct hlist_head *vport_hash_bucket(const struct datapath *dp,
17915eac2a7SPravin B Shelar 					    u16 port_no)
18015eac2a7SPravin B Shelar {
18115eac2a7SPravin B Shelar 	return &dp->ports[port_no & (DP_VPORT_HASH_BUCKETS - 1)];
18215eac2a7SPravin B Shelar }
18315eac2a7SPravin B Shelar 
184bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */
ovs_lookup_vport(const struct datapath * dp,u16 port_no)18515eac2a7SPravin B Shelar struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
18615eac2a7SPravin B Shelar {
18715eac2a7SPravin B Shelar 	struct vport *vport;
18815eac2a7SPravin B Shelar 	struct hlist_head *head;
18915eac2a7SPravin B Shelar 
19015eac2a7SPravin B Shelar 	head = vport_hash_bucket(dp, port_no);
19153742e69SMadhuparna Bhowmik 	hlist_for_each_entry_rcu(vport, head, dp_hash_node,
19253742e69SMadhuparna Bhowmik 				 lockdep_ovsl_is_held()) {
19315eac2a7SPravin B Shelar 		if (vport->port_no == port_no)
19415eac2a7SPravin B Shelar 			return vport;
19515eac2a7SPravin B Shelar 	}
19615eac2a7SPravin B Shelar 	return NULL;
19715eac2a7SPravin B Shelar }
19815eac2a7SPravin B Shelar 
1998e4e1713SPravin B Shelar /* Called with ovs_mutex. */
new_vport(const struct vport_parms * parms)200ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *parms)
201ccb1352eSJesse Gross {
202ccb1352eSJesse Gross 	struct vport *vport;
203ccb1352eSJesse Gross 
204ccb1352eSJesse Gross 	vport = ovs_vport_add(parms);
205ccb1352eSJesse Gross 	if (!IS_ERR(vport)) {
206ccb1352eSJesse Gross 		struct datapath *dp = parms->dp;
20715eac2a7SPravin B Shelar 		struct hlist_head *head = vport_hash_bucket(dp, vport->port_no);
208ccb1352eSJesse Gross 
20915eac2a7SPravin B Shelar 		hlist_add_head_rcu(&vport->dp_hash_node, head);
210ccb1352eSJesse Gross 	}
211ccb1352eSJesse Gross 	return vport;
212ccb1352eSJesse Gross }
213ccb1352eSJesse Gross 
ovs_vport_update_upcall_stats(struct sk_buff * skb,const struct dp_upcall_info * upcall_info,bool upcall_result)2141933ea36Swangchuanlei static void ovs_vport_update_upcall_stats(struct sk_buff *skb,
2151933ea36Swangchuanlei 					  const struct dp_upcall_info *upcall_info,
2161933ea36Swangchuanlei 					  bool upcall_result)
2171933ea36Swangchuanlei {
2181933ea36Swangchuanlei 	struct vport *p = OVS_CB(skb)->input_vport;
2191933ea36Swangchuanlei 	struct vport_upcall_stats_percpu *stats;
2201933ea36Swangchuanlei 
2211933ea36Swangchuanlei 	if (upcall_info->cmd != OVS_PACKET_CMD_MISS &&
2221933ea36Swangchuanlei 	    upcall_info->cmd != OVS_PACKET_CMD_ACTION)
2231933ea36Swangchuanlei 		return;
2241933ea36Swangchuanlei 
2251933ea36Swangchuanlei 	stats = this_cpu_ptr(p->upcall_stats);
2261933ea36Swangchuanlei 	u64_stats_update_begin(&stats->syncp);
2271933ea36Swangchuanlei 	if (upcall_result)
2281933ea36Swangchuanlei 		u64_stats_inc(&stats->n_success);
2291933ea36Swangchuanlei 	else
2301933ea36Swangchuanlei 		u64_stats_inc(&stats->n_fail);
2311933ea36Swangchuanlei 	u64_stats_update_end(&stats->syncp);
2321933ea36Swangchuanlei }
2331933ea36Swangchuanlei 
ovs_dp_detach_port(struct vport * p)234ccb1352eSJesse Gross void ovs_dp_detach_port(struct vport *p)
235ccb1352eSJesse Gross {
2368e4e1713SPravin B Shelar 	ASSERT_OVSL();
237ccb1352eSJesse Gross 
238ccb1352eSJesse Gross 	/* First drop references to device. */
23915eac2a7SPravin B Shelar 	hlist_del_rcu(&p->dp_hash_node);
240ccb1352eSJesse Gross 
241ccb1352eSJesse Gross 	/* Then destroy it. */
242ccb1352eSJesse Gross 	ovs_vport_del(p);
243ccb1352eSJesse Gross }
244ccb1352eSJesse Gross 
245ccb1352eSJesse Gross /* Must be called with rcu_read_lock. */
ovs_dp_process_packet(struct sk_buff * skb,struct sw_flow_key * key)2468c8b1b83SPravin B Shelar void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
247ccb1352eSJesse Gross {
24883c8df26SPravin B Shelar 	const struct vport *p = OVS_CB(skb)->input_vport;
249ccb1352eSJesse Gross 	struct datapath *dp = p->dp;
250ccb1352eSJesse Gross 	struct sw_flow *flow;
251d98612b8SLorand Jakab 	struct sw_flow_actions *sf_acts;
252ccb1352eSJesse Gross 	struct dp_stats_percpu *stats;
253ccb1352eSJesse Gross 	u64 *stats_counter;
2541bd7116fSAndy Zhou 	u32 n_mask_hit;
2559d2f627bSEelco Chaudron 	u32 n_cache_hit;
256aa733660SYifeng Sun 	int error;
257ccb1352eSJesse Gross 
258404f2f10SShan Wei 	stats = this_cpu_ptr(dp->stats_percpu);
259ccb1352eSJesse Gross 
260ccb1352eSJesse Gross 	/* Look up flow. */
26104b7d136STonghao Zhang 	flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb),
2629d2f627bSEelco Chaudron 					 &n_mask_hit, &n_cache_hit);
263ccb1352eSJesse Gross 	if (unlikely(!flow)) {
264ccb1352eSJesse Gross 		struct dp_upcall_info upcall;
265ccb1352eSJesse Gross 
266ccea7445SNeil McKee 		memset(&upcall, 0, sizeof(upcall));
267ccb1352eSJesse Gross 		upcall.cmd = OVS_PACKET_CMD_MISS;
268b83d23a2SMark Gray 
269b83d23a2SMark Gray 		if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU)
270784dcfa5SMark Gray 			upcall.portid =
271784dcfa5SMark Gray 			    ovs_dp_get_upcall_portid(dp, smp_processor_id());
272b83d23a2SMark Gray 		else
2735cd667b0SAlex Wang 			upcall.portid = ovs_vport_find_upcall_portid(p, skb);
274b83d23a2SMark Gray 
2757f8a436eSJoe Stringer 		upcall.mru = OVS_CB(skb)->mru;
276f2a4d086SWilliam Tu 		error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
2771100248aSMike Pattrick 		switch (error) {
2781100248aSMike Pattrick 		case 0:
2791100248aSMike Pattrick 		case -EAGAIN:
2801100248aSMike Pattrick 		case -ERESTARTSYS:
2811100248aSMike Pattrick 		case -EINTR:
282ccb1352eSJesse Gross 			consume_skb(skb);
2831100248aSMike Pattrick 			break;
2841100248aSMike Pattrick 		default:
2851100248aSMike Pattrick 			kfree_skb(skb);
2861100248aSMike Pattrick 			break;
2871100248aSMike Pattrick 		}
288ccb1352eSJesse Gross 		stats_counter = &stats->n_missed;
289ccb1352eSJesse Gross 		goto out;
290ccb1352eSJesse Gross 	}
291ccb1352eSJesse Gross 
292d98612b8SLorand Jakab 	ovs_flow_stats_update(flow, key->tp.flags, skb);
293d98612b8SLorand Jakab 	sf_acts = rcu_dereference(flow->sf_acts);
294aa733660SYifeng Sun 	error = ovs_execute_actions(dp, skb, sf_acts, key);
295aa733660SYifeng Sun 	if (unlikely(error))
296aa733660SYifeng Sun 		net_dbg_ratelimited("ovs: action execution error on datapath %s: %d\n",
297aa733660SYifeng Sun 				    ovs_dp_name(dp), error);
298ccb1352eSJesse Gross 
299e298e505SPravin B Shelar 	stats_counter = &stats->n_hit;
300ccb1352eSJesse Gross 
301ccb1352eSJesse Gross out:
302ccb1352eSJesse Gross 	/* Update datapath statistics. */
303df9d9fdfSWANG Cong 	u64_stats_update_begin(&stats->syncp);
304ccb1352eSJesse Gross 	(*stats_counter)++;
3051bd7116fSAndy Zhou 	stats->n_mask_hit += n_mask_hit;
3069d2f627bSEelco Chaudron 	stats->n_cache_hit += n_cache_hit;
307df9d9fdfSWANG Cong 	u64_stats_update_end(&stats->syncp);
308ccb1352eSJesse Gross }
309ccb1352eSJesse Gross 
ovs_dp_upcall(struct datapath * dp,struct sk_buff * skb,const struct sw_flow_key * key,const struct dp_upcall_info * upcall_info,uint32_t cutlen)310ccb1352eSJesse Gross int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
311e8eedb85SPravin B Shelar 		  const struct sw_flow_key *key,
312f2a4d086SWilliam Tu 		  const struct dp_upcall_info *upcall_info,
313f2a4d086SWilliam Tu 		  uint32_t cutlen)
314ccb1352eSJesse Gross {
315ccb1352eSJesse Gross 	struct dp_stats_percpu *stats;
316ccb1352eSJesse Gross 	int err;
317ccb1352eSJesse Gross 
318c4ab7b56SAaron Conole 	if (trace_ovs_dp_upcall_enabled())
319c4ab7b56SAaron Conole 		trace_ovs_dp_upcall(dp, skb, key, upcall_info);
320c4ab7b56SAaron Conole 
32115e47304SEric W. Biederman 	if (upcall_info->portid == 0) {
322ccb1352eSJesse Gross 		err = -ENOTCONN;
323ccb1352eSJesse Gross 		goto err;
324ccb1352eSJesse Gross 	}
325ccb1352eSJesse Gross 
326ccb1352eSJesse Gross 	if (!skb_is_gso(skb))
327f2a4d086SWilliam Tu 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
328ccb1352eSJesse Gross 	else
329f2a4d086SWilliam Tu 		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);
3301933ea36Swangchuanlei 
3311933ea36Swangchuanlei 	ovs_vport_update_upcall_stats(skb, upcall_info, !err);
332ccb1352eSJesse Gross 	if (err)
333ccb1352eSJesse Gross 		goto err;
334ccb1352eSJesse Gross 
335ccb1352eSJesse Gross 	return 0;
336ccb1352eSJesse Gross 
337ccb1352eSJesse Gross err:
338404f2f10SShan Wei 	stats = this_cpu_ptr(dp->stats_percpu);
339ccb1352eSJesse Gross 
340df9d9fdfSWANG Cong 	u64_stats_update_begin(&stats->syncp);
341ccb1352eSJesse Gross 	stats->n_lost++;
342df9d9fdfSWANG Cong 	u64_stats_update_end(&stats->syncp);
343ccb1352eSJesse Gross 
344ccb1352eSJesse Gross 	return err;
345ccb1352eSJesse Gross }
346ccb1352eSJesse Gross 
queue_gso_packets(struct datapath * dp,struct sk_buff * skb,const struct sw_flow_key * key,const struct dp_upcall_info * upcall_info,uint32_t cutlen)3478055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
348e8eedb85SPravin B Shelar 			     const struct sw_flow_key *key,
349f2a4d086SWilliam Tu 			     const struct dp_upcall_info *upcall_info,
350f2a4d086SWilliam Tu 			     uint32_t cutlen)
351ccb1352eSJesse Gross {
3522734166eSGustavo A. R. Silva 	unsigned int gso_type = skb_shinfo(skb)->gso_type;
3530c19f846SWillem de Bruijn 	struct sw_flow_key later_key;
354ccb1352eSJesse Gross 	struct sk_buff *segs, *nskb;
355ccb1352eSJesse Gross 	int err;
356ccb1352eSJesse Gross 
357a08e7fd9SCambda Zhu 	BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_GSO_CB_OFFSET);
35809c5e605SThomas Graf 	segs = __skb_gso_segment(skb, NETIF_F_SG, false);
35992e5dfc3SPravin B Shelar 	if (IS_ERR(segs))
36092e5dfc3SPravin B Shelar 		return PTR_ERR(segs);
361330966e5SFlorian Westphal 	if (segs == NULL)
362330966e5SFlorian Westphal 		return -EINVAL;
363ccb1352eSJesse Gross 
3640c19f846SWillem de Bruijn 	if (gso_type & SKB_GSO_UDP) {
3650c19f846SWillem de Bruijn 		/* The initial flow key extracted by ovs_flow_key_extract()
3660c19f846SWillem de Bruijn 		 * in this case is for a first fragment, so we need to
3670c19f846SWillem de Bruijn 		 * properly mark later fragments.
3680c19f846SWillem de Bruijn 		 */
3690c19f846SWillem de Bruijn 		later_key = *key;
3700c19f846SWillem de Bruijn 		later_key.ip.frag = OVS_FRAG_TYPE_LATER;
3710c19f846SWillem de Bruijn 	}
3720c19f846SWillem de Bruijn 
373e8eedb85SPravin B Shelar 	/* Queue all of the segments. */
3742cec4448SJason A. Donenfeld 	skb_list_walk_safe(segs, skb, nskb) {
3750c19f846SWillem de Bruijn 		if (gso_type & SKB_GSO_UDP && skb != segs)
3760c19f846SWillem de Bruijn 			key = &later_key;
3770c19f846SWillem de Bruijn 
378f2a4d086SWilliam Tu 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
379e8eedb85SPravin B Shelar 		if (err)
380e8eedb85SPravin B Shelar 			break;
381e8eedb85SPravin B Shelar 
3822cec4448SJason A. Donenfeld 	}
383ccb1352eSJesse Gross 
384ccb1352eSJesse Gross 	/* Free all of the segments. */
3852cec4448SJason A. Donenfeld 	skb_list_walk_safe(segs, skb, nskb) {
386ccb1352eSJesse Gross 		if (err)
387ccb1352eSJesse Gross 			kfree_skb(skb);
388ccb1352eSJesse Gross 		else
389ccb1352eSJesse Gross 			consume_skb(skb);
3902cec4448SJason A. Donenfeld 	}
391ccb1352eSJesse Gross 	return err;
392ccb1352eSJesse Gross }
393ccb1352eSJesse Gross 
upcall_msg_size(const struct dp_upcall_info * upcall_info,unsigned int hdrlen,int actions_attrlen)3948f0aad6fSWenyu Zhang static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
395494bea39SLiping Zhang 			      unsigned int hdrlen, int actions_attrlen)
396c3ff8cfeSThomas Graf {
397c3ff8cfeSThomas Graf 	size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
398bda56f14SThomas Graf 		+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
399b95e5928SWilliam Tu 		+ nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */
400bd1903b7STonghao Zhang 		+ nla_total_size(sizeof(unsigned int)) /* OVS_PACKET_ATTR_LEN */
401bd1903b7STonghao Zhang 		+ nla_total_size(sizeof(u64)); /* OVS_PACKET_ATTR_HASH */
402c3ff8cfeSThomas Graf 
403c3ff8cfeSThomas Graf 	/* OVS_PACKET_ATTR_USERDATA */
4048f0aad6fSWenyu Zhang 	if (upcall_info->userdata)
4058f0aad6fSWenyu Zhang 		size += NLA_ALIGN(upcall_info->userdata->nla_len);
4068f0aad6fSWenyu Zhang 
4078f0aad6fSWenyu Zhang 	/* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
4088f0aad6fSWenyu Zhang 	if (upcall_info->egress_tun_info)
4098f0aad6fSWenyu Zhang 		size += nla_total_size(ovs_tun_key_attr_size());
410c3ff8cfeSThomas Graf 
411ccea7445SNeil McKee 	/* OVS_PACKET_ATTR_ACTIONS */
412ccea7445SNeil McKee 	if (upcall_info->actions_len)
413494bea39SLiping Zhang 		size += nla_total_size(actions_attrlen);
414ccea7445SNeil McKee 
4157f8a436eSJoe Stringer 	/* OVS_PACKET_ATTR_MRU */
4167f8a436eSJoe Stringer 	if (upcall_info->mru)
4177f8a436eSJoe Stringer 		size += nla_total_size(sizeof(upcall_info->mru));
4187f8a436eSJoe Stringer 
419c3ff8cfeSThomas Graf 	return size;
420c3ff8cfeSThomas Graf }
421c3ff8cfeSThomas Graf 
pad_packet(struct datapath * dp,struct sk_buff * skb)4227f8a436eSJoe Stringer static void pad_packet(struct datapath *dp, struct sk_buff *skb)
4237f8a436eSJoe Stringer {
4247f8a436eSJoe Stringer 	if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
4257f8a436eSJoe Stringer 		size_t plen = NLA_ALIGN(skb->len) - skb->len;
4267f8a436eSJoe Stringer 
4277f8a436eSJoe Stringer 		if (plen > 0)
428b080db58SJohannes Berg 			skb_put_zero(skb, plen);
4297f8a436eSJoe Stringer 	}
4307f8a436eSJoe Stringer }
4317f8a436eSJoe Stringer 
queue_userspace_packet(struct datapath * dp,struct sk_buff * skb,const struct sw_flow_key * key,const struct dp_upcall_info * upcall_info,uint32_t cutlen)4328055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
433e8eedb85SPravin B Shelar 				  const struct sw_flow_key *key,
434f2a4d086SWilliam Tu 				  const struct dp_upcall_info *upcall_info,
435f2a4d086SWilliam Tu 				  uint32_t cutlen)
436ccb1352eSJesse Gross {
437ccb1352eSJesse Gross 	struct ovs_header *upcall;
438ccb1352eSJesse Gross 	struct sk_buff *nskb = NULL;
4394ee45ea0SLi RongQing 	struct sk_buff *user_skb = NULL; /* to be queued to userspace */
440ccb1352eSJesse Gross 	struct nlattr *nla;
441795449d8SThomas Graf 	size_t len;
442bda56f14SThomas Graf 	unsigned int hlen;
4438055a89cSThomas Graf 	int err, dp_ifindex;
444bd1903b7STonghao Zhang 	u64 hash;
4458055a89cSThomas Graf 
4468055a89cSThomas Graf 	dp_ifindex = get_dpifindex(dp);
4478055a89cSThomas Graf 	if (!dp_ifindex)
4488055a89cSThomas Graf 		return -ENODEV;
449ccb1352eSJesse Gross 
450df8a39deSJiri Pirko 	if (skb_vlan_tag_present(skb)) {
451ccb1352eSJesse Gross 		nskb = skb_clone(skb, GFP_ATOMIC);
452ccb1352eSJesse Gross 		if (!nskb)
453ccb1352eSJesse Gross 			return -ENOMEM;
454ccb1352eSJesse Gross 
4555968250cSJiri Pirko 		nskb = __vlan_hwaccel_push_inside(nskb);
4568aa51d64SDan Carpenter 		if (!nskb)
457ccb1352eSJesse Gross 			return -ENOMEM;
458ccb1352eSJesse Gross 
459ccb1352eSJesse Gross 		skb = nskb;
460ccb1352eSJesse Gross 	}
461ccb1352eSJesse Gross 
462ccb1352eSJesse Gross 	if (nla_attr_size(skb->len) > USHRT_MAX) {
463ccb1352eSJesse Gross 		err = -EFBIG;
464ccb1352eSJesse Gross 		goto out;
465ccb1352eSJesse Gross 	}
466ccb1352eSJesse Gross 
467bda56f14SThomas Graf 	/* Complete checksum if needed */
468bda56f14SThomas Graf 	if (skb->ip_summed == CHECKSUM_PARTIAL &&
4697529390dSDavide Caratti 	    (err = skb_csum_hwoffload_help(skb, 0)))
470bda56f14SThomas Graf 		goto out;
471bda56f14SThomas Graf 
472bda56f14SThomas Graf 	/* Older versions of OVS user space enforce alignment of the last
473bda56f14SThomas Graf 	 * Netlink attribute to NLA_ALIGNTO which would require extensive
474bda56f14SThomas Graf 	 * padding logic. Only perform zerocopy if padding is not required.
475bda56f14SThomas Graf 	 */
476bda56f14SThomas Graf 	if (dp->user_features & OVS_DP_F_UNALIGNED)
477bda56f14SThomas Graf 		hlen = skb_zerocopy_headlen(skb);
478bda56f14SThomas Graf 	else
479bda56f14SThomas Graf 		hlen = skb->len;
480bda56f14SThomas Graf 
481494bea39SLiping Zhang 	len = upcall_msg_size(upcall_info, hlen - cutlen,
482494bea39SLiping Zhang 			      OVS_CB(skb)->acts_origlen);
483551ddc05SFlorian Westphal 	user_skb = genlmsg_new(len, GFP_ATOMIC);
484ccb1352eSJesse Gross 	if (!user_skb) {
485ccb1352eSJesse Gross 		err = -ENOMEM;
486ccb1352eSJesse Gross 		goto out;
487ccb1352eSJesse Gross 	}
488ccb1352eSJesse Gross 
489ccb1352eSJesse Gross 	upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
490ccb1352eSJesse Gross 			     0, upcall_info->cmd);
4916f19893bSKangjie Lu 	if (!upcall) {
4926f19893bSKangjie Lu 		err = -EINVAL;
4936f19893bSKangjie Lu 		goto out;
4946f19893bSKangjie Lu 	}
495ccb1352eSJesse Gross 	upcall->dp_ifindex = dp_ifindex;
496ccb1352eSJesse Gross 
4975b4237bbSJoe Stringer 	err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb);
498a734d1f4SEelco Chaudron 	if (err)
499a734d1f4SEelco Chaudron 		goto out;
500ccb1352eSJesse Gross 
501ccb1352eSJesse Gross 	if (upcall_info->userdata)
5024490108bSBen Pfaff 		__nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
5034490108bSBen Pfaff 			  nla_len(upcall_info->userdata),
5044490108bSBen Pfaff 			  nla_data(upcall_info->userdata));
505ccb1352eSJesse Gross 
5068f0aad6fSWenyu Zhang 	if (upcall_info->egress_tun_info) {
507ae0be8deSMichal Kubecek 		nla = nla_nest_start_noflag(user_skb,
508ae0be8deSMichal Kubecek 					    OVS_PACKET_ATTR_EGRESS_TUN_KEY);
5090fff9bd4SKangjie Lu 		if (!nla) {
5100fff9bd4SKangjie Lu 			err = -EMSGSIZE;
5110fff9bd4SKangjie Lu 			goto out;
5120fff9bd4SKangjie Lu 		}
513fc4099f1SPravin B Shelar 		err = ovs_nla_put_tunnel_info(user_skb,
514fc4099f1SPravin B Shelar 					      upcall_info->egress_tun_info);
515a734d1f4SEelco Chaudron 		if (err)
516a734d1f4SEelco Chaudron 			goto out;
517a734d1f4SEelco Chaudron 
5188f0aad6fSWenyu Zhang 		nla_nest_end(user_skb, nla);
5198f0aad6fSWenyu Zhang 	}
5208f0aad6fSWenyu Zhang 
521ccea7445SNeil McKee 	if (upcall_info->actions_len) {
522ae0be8deSMichal Kubecek 		nla = nla_nest_start_noflag(user_skb, OVS_PACKET_ATTR_ACTIONS);
5230fff9bd4SKangjie Lu 		if (!nla) {
5240fff9bd4SKangjie Lu 			err = -EMSGSIZE;
5250fff9bd4SKangjie Lu 			goto out;
5260fff9bd4SKangjie Lu 		}
527ccea7445SNeil McKee 		err = ovs_nla_put_actions(upcall_info->actions,
528ccea7445SNeil McKee 					  upcall_info->actions_len,
529ccea7445SNeil McKee 					  user_skb);
530ccea7445SNeil McKee 		if (!err)
531ccea7445SNeil McKee 			nla_nest_end(user_skb, nla);
532ccea7445SNeil McKee 		else
533ccea7445SNeil McKee 			nla_nest_cancel(user_skb, nla);
534ccea7445SNeil McKee 	}
535ccea7445SNeil McKee 
5367f8a436eSJoe Stringer 	/* Add OVS_PACKET_ATTR_MRU */
53761ca533cSTonghao Zhang 	if (upcall_info->mru &&
53861ca533cSTonghao Zhang 	    nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU, upcall_info->mru)) {
5397f8a436eSJoe Stringer 		err = -ENOBUFS;
5407f8a436eSJoe Stringer 		goto out;
5417f8a436eSJoe Stringer 	}
5427f8a436eSJoe Stringer 
543b95e5928SWilliam Tu 	/* Add OVS_PACKET_ATTR_LEN when packet is truncated */
54461ca533cSTonghao Zhang 	if (cutlen > 0 &&
54561ca533cSTonghao Zhang 	    nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
546b95e5928SWilliam Tu 		err = -ENOBUFS;
547b95e5928SWilliam Tu 		goto out;
548b95e5928SWilliam Tu 	}
549b95e5928SWilliam Tu 
550bd1903b7STonghao Zhang 	/* Add OVS_PACKET_ATTR_HASH */
551bd1903b7STonghao Zhang 	hash = skb_get_hash_raw(skb);
552bd1903b7STonghao Zhang 	if (skb->sw_hash)
553bd1903b7STonghao Zhang 		hash |= OVS_PACKET_HASH_SW_BIT;
554bd1903b7STonghao Zhang 
555bd1903b7STonghao Zhang 	if (skb->l4_hash)
556bd1903b7STonghao Zhang 		hash |= OVS_PACKET_HASH_L4_BIT;
557bd1903b7STonghao Zhang 
558bd1903b7STonghao Zhang 	if (nla_put(user_skb, OVS_PACKET_ATTR_HASH, sizeof (u64), &hash)) {
559bd1903b7STonghao Zhang 		err = -ENOBUFS;
560bd1903b7STonghao Zhang 		goto out;
561bd1903b7STonghao Zhang 	}
562bd1903b7STonghao Zhang 
563bda56f14SThomas Graf 	/* Only reserve room for attribute header, packet data is added
564bda56f14SThomas Graf 	 * in skb_zerocopy() */
565bda56f14SThomas Graf 	if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
566bda56f14SThomas Graf 		err = -ENOBUFS;
567bda56f14SThomas Graf 		goto out;
568bda56f14SThomas Graf 	}
569f2a4d086SWilliam Tu 	nla->nla_len = nla_attr_size(skb->len - cutlen);
570ccb1352eSJesse Gross 
571f2a4d086SWilliam Tu 	err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
57236d5fe6aSZoltan Kiss 	if (err)
57336d5fe6aSZoltan Kiss 		goto out;
574ccb1352eSJesse Gross 
575aea0bb4fSThomas Graf 	/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
5767f8a436eSJoe Stringer 	pad_packet(dp, user_skb);
577aea0bb4fSThomas Graf 
578bda56f14SThomas Graf 	((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
579bda56f14SThomas Graf 
5808055a89cSThomas Graf 	err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
5814ee45ea0SLi RongQing 	user_skb = NULL;
582ccb1352eSJesse Gross out:
58336d5fe6aSZoltan Kiss 	if (err)
58436d5fe6aSZoltan Kiss 		skb_tx_error(skb);
585c21ab2afSMike Pattrick 	consume_skb(user_skb);
586c21ab2afSMike Pattrick 	consume_skb(nskb);
587c21ab2afSMike Pattrick 
588ccb1352eSJesse Gross 	return err;
589ccb1352eSJesse Gross }
590ccb1352eSJesse Gross 
ovs_packet_cmd_execute(struct sk_buff * skb,struct genl_info * info)591ccb1352eSJesse Gross static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
592ccb1352eSJesse Gross {
593bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
5947f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
595ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
596ccb1352eSJesse Gross 	struct sw_flow_actions *acts;
597ccb1352eSJesse Gross 	struct sk_buff *packet;
598ccb1352eSJesse Gross 	struct sw_flow *flow;
599d98612b8SLorand Jakab 	struct sw_flow_actions *sf_acts;
600ccb1352eSJesse Gross 	struct datapath *dp;
60183c8df26SPravin B Shelar 	struct vport *input_vport;
6027f8a436eSJoe Stringer 	u16 mru = 0;
603bd1903b7STonghao Zhang 	u64 hash;
604ccb1352eSJesse Gross 	int len;
605ccb1352eSJesse Gross 	int err;
6061ba39804SThomas Graf 	bool log = !a[OVS_PACKET_ATTR_PROBE];
607ccb1352eSJesse Gross 
608ccb1352eSJesse Gross 	err = -EINVAL;
609ccb1352eSJesse Gross 	if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
610dded45fcSThomas Graf 	    !a[OVS_PACKET_ATTR_ACTIONS])
611ccb1352eSJesse Gross 		goto err;
612ccb1352eSJesse Gross 
613ccb1352eSJesse Gross 	len = nla_len(a[OVS_PACKET_ATTR_PACKET]);
614ccb1352eSJesse Gross 	packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL);
615ccb1352eSJesse Gross 	err = -ENOMEM;
616ccb1352eSJesse Gross 	if (!packet)
617ccb1352eSJesse Gross 		goto err;
618ccb1352eSJesse Gross 	skb_reserve(packet, NET_IP_ALIGN);
619ccb1352eSJesse Gross 
62032686a9dSThomas Graf 	nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
621ccb1352eSJesse Gross 
6227f8a436eSJoe Stringer 	/* Set packet's mru */
6237f8a436eSJoe Stringer 	if (a[OVS_PACKET_ATTR_MRU]) {
6247f8a436eSJoe Stringer 		mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
6257f8a436eSJoe Stringer 		packet->ignore_df = 1;
6267f8a436eSJoe Stringer 	}
6277f8a436eSJoe Stringer 	OVS_CB(packet)->mru = mru;
6287f8a436eSJoe Stringer 
629bd1903b7STonghao Zhang 	if (a[OVS_PACKET_ATTR_HASH]) {
630bd1903b7STonghao Zhang 		hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
631bd1903b7STonghao Zhang 
632bd1903b7STonghao Zhang 		__skb_set_hash(packet, hash & 0xFFFFFFFFULL,
633bd1903b7STonghao Zhang 			       !!(hash & OVS_PACKET_HASH_SW_BIT),
634bd1903b7STonghao Zhang 			       !!(hash & OVS_PACKET_HASH_L4_BIT));
635bd1903b7STonghao Zhang 	}
636bd1903b7STonghao Zhang 
637ccb1352eSJesse Gross 	/* Build an sw_flow for sending this packet. */
63823dabf88SJarno Rajahalme 	flow = ovs_flow_alloc();
639ccb1352eSJesse Gross 	err = PTR_ERR(flow);
640ccb1352eSJesse Gross 	if (IS_ERR(flow))
641ccb1352eSJesse Gross 		goto err_kfree_skb;
642ccb1352eSJesse Gross 
643c2ac6673SJoe Stringer 	err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY],
644c2ac6673SJoe Stringer 					     packet, &flow->key, log);
645ccb1352eSJesse Gross 	if (err)
646ccb1352eSJesse Gross 		goto err_flow_free;
647ccb1352eSJesse Gross 
6487f8a436eSJoe Stringer 	err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS],
64905da5898SJarno Rajahalme 				   &flow->key, &acts, log);
65074f84a57SPravin B Shelar 	if (err)
65174f84a57SPravin B Shelar 		goto err_flow_free;
652ccb1352eSJesse Gross 
653f5796684SJesse Gross 	rcu_assign_pointer(flow->sf_acts, acts);
654ccb1352eSJesse Gross 	packet->priority = flow->key.phy.priority;
65539c7caebSAnsis Atteka 	packet->mark = flow->key.phy.skb_mark;
656ccb1352eSJesse Gross 
657ccb1352eSJesse Gross 	rcu_read_lock();
6587f8a436eSJoe Stringer 	dp = get_dp_rcu(net, ovs_header->dp_ifindex);
659ccb1352eSJesse Gross 	err = -ENODEV;
660ccb1352eSJesse Gross 	if (!dp)
661ccb1352eSJesse Gross 		goto err_unlock;
662ccb1352eSJesse Gross 
66383c8df26SPravin B Shelar 	input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port);
66483c8df26SPravin B Shelar 	if (!input_vport)
66583c8df26SPravin B Shelar 		input_vport = ovs_vport_rcu(dp, OVSP_LOCAL);
66683c8df26SPravin B Shelar 
66783c8df26SPravin B Shelar 	if (!input_vport)
66883c8df26SPravin B Shelar 		goto err_unlock;
66983c8df26SPravin B Shelar 
6707f8a436eSJoe Stringer 	packet->dev = input_vport->dev;
67183c8df26SPravin B Shelar 	OVS_CB(packet)->input_vport = input_vport;
672d98612b8SLorand Jakab 	sf_acts = rcu_dereference(flow->sf_acts);
67383c8df26SPravin B Shelar 
674ccb1352eSJesse Gross 	local_bh_disable();
675d98612b8SLorand Jakab 	err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
676ccb1352eSJesse Gross 	local_bh_enable();
677ccb1352eSJesse Gross 	rcu_read_unlock();
678ccb1352eSJesse Gross 
67903f0d916SAndy Zhou 	ovs_flow_free(flow, false);
680ccb1352eSJesse Gross 	return err;
681ccb1352eSJesse Gross 
682ccb1352eSJesse Gross err_unlock:
683ccb1352eSJesse Gross 	rcu_read_unlock();
684ccb1352eSJesse Gross err_flow_free:
68503f0d916SAndy Zhou 	ovs_flow_free(flow, false);
686ccb1352eSJesse Gross err_kfree_skb:
687ccb1352eSJesse Gross 	kfree_skb(packet);
688ccb1352eSJesse Gross err:
689ccb1352eSJesse Gross 	return err;
690ccb1352eSJesse Gross }
691ccb1352eSJesse Gross 
692ccb1352eSJesse Gross static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
693dded45fcSThomas Graf 	[OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
694ccb1352eSJesse Gross 	[OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
695ccb1352eSJesse Gross 	[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
6961ba39804SThomas Graf 	[OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
6977f8a436eSJoe Stringer 	[OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
698b5ab1f1bSJakub Kicinski 	[OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
699ccb1352eSJesse Gross };
700ccb1352eSJesse Gross 
70166a9b928SJakub Kicinski static const struct genl_small_ops dp_packet_genl_ops[] = {
702ccb1352eSJesse Gross 	{ .cmd = OVS_PACKET_CMD_EXECUTE,
703ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7044a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
705ccb1352eSJesse Gross 	  .doit = ovs_packet_cmd_execute
706ccb1352eSJesse Gross 	}
707ccb1352eSJesse Gross };
708ccb1352eSJesse Gross 
70956989f6dSJohannes Berg static struct genl_family dp_packet_genl_family __ro_after_init = {
7100c200ef9SPravin B Shelar 	.hdrsize = sizeof(struct ovs_header),
7110c200ef9SPravin B Shelar 	.name = OVS_PACKET_FAMILY,
7120c200ef9SPravin B Shelar 	.version = OVS_PACKET_VERSION,
7130c200ef9SPravin B Shelar 	.maxattr = OVS_PACKET_ATTR_MAX,
7143b0f31f2SJohannes Berg 	.policy = packet_policy,
7150c200ef9SPravin B Shelar 	.netnsok = true,
7160c200ef9SPravin B Shelar 	.parallel_ops = true,
71766a9b928SJakub Kicinski 	.small_ops = dp_packet_genl_ops,
71866a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_packet_genl_ops),
7199c5d03d3SJakub Kicinski 	.resv_start_op = OVS_PACKET_CMD_EXECUTE + 1,
720489111e5SJohannes Berg 	.module = THIS_MODULE,
7210c200ef9SPravin B Shelar };
7220c200ef9SPravin B Shelar 
get_dp_stats(const struct datapath * dp,struct ovs_dp_stats * stats,struct ovs_dp_megaflow_stats * mega_stats)72312eb18f7SThomas Graf static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats,
7241bd7116fSAndy Zhou 			 struct ovs_dp_megaflow_stats *mega_stats)
725ccb1352eSJesse Gross {
726ccb1352eSJesse Gross 	int i;
727ccb1352eSJesse Gross 
7281bd7116fSAndy Zhou 	memset(mega_stats, 0, sizeof(*mega_stats));
7291bd7116fSAndy Zhou 
730b637e498SPravin B Shelar 	stats->n_flows = ovs_flow_tbl_count(&dp->table);
7311bd7116fSAndy Zhou 	mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table);
732ccb1352eSJesse Gross 
733ccb1352eSJesse Gross 	stats->n_hit = stats->n_missed = stats->n_lost = 0;
7341bd7116fSAndy Zhou 
735ccb1352eSJesse Gross 	for_each_possible_cpu(i) {
736ccb1352eSJesse Gross 		const struct dp_stats_percpu *percpu_stats;
737ccb1352eSJesse Gross 		struct dp_stats_percpu local_stats;
738ccb1352eSJesse Gross 		unsigned int start;
739ccb1352eSJesse Gross 
740ccb1352eSJesse Gross 		percpu_stats = per_cpu_ptr(dp->stats_percpu, i);
741ccb1352eSJesse Gross 
742ccb1352eSJesse Gross 		do {
743d120d1a6SThomas Gleixner 			start = u64_stats_fetch_begin(&percpu_stats->syncp);
744ccb1352eSJesse Gross 			local_stats = *percpu_stats;
745d120d1a6SThomas Gleixner 		} while (u64_stats_fetch_retry(&percpu_stats->syncp, start));
746ccb1352eSJesse Gross 
747ccb1352eSJesse Gross 		stats->n_hit += local_stats.n_hit;
748ccb1352eSJesse Gross 		stats->n_missed += local_stats.n_missed;
749ccb1352eSJesse Gross 		stats->n_lost += local_stats.n_lost;
7501bd7116fSAndy Zhou 		mega_stats->n_mask_hit += local_stats.n_mask_hit;
7519d2f627bSEelco Chaudron 		mega_stats->n_cache_hit += local_stats.n_cache_hit;
752ccb1352eSJesse Gross 	}
753ccb1352eSJesse Gross }
754ccb1352eSJesse Gross 
should_fill_key(const struct sw_flow_id * sfid,uint32_t ufid_flags)75574ed7ab9SJoe Stringer static bool should_fill_key(const struct sw_flow_id *sfid, uint32_t ufid_flags)
756c3ff8cfeSThomas Graf {
75774ed7ab9SJoe Stringer 	return ovs_identifier_is_ufid(sfid) &&
75874ed7ab9SJoe Stringer 	       !(ufid_flags & OVS_UFID_F_OMIT_KEY);
75974ed7ab9SJoe Stringer }
76074ed7ab9SJoe Stringer 
should_fill_mask(uint32_t ufid_flags)76174ed7ab9SJoe Stringer static bool should_fill_mask(uint32_t ufid_flags)
76274ed7ab9SJoe Stringer {
76374ed7ab9SJoe Stringer 	return !(ufid_flags & OVS_UFID_F_OMIT_MASK);
76474ed7ab9SJoe Stringer }
76574ed7ab9SJoe Stringer 
should_fill_actions(uint32_t ufid_flags)76674ed7ab9SJoe Stringer static bool should_fill_actions(uint32_t ufid_flags)
76774ed7ab9SJoe Stringer {
76874ed7ab9SJoe Stringer 	return !(ufid_flags & OVS_UFID_F_OMIT_ACTIONS);
76974ed7ab9SJoe Stringer }
77074ed7ab9SJoe Stringer 
ovs_flow_cmd_msg_size(const struct sw_flow_actions * acts,const struct sw_flow_id * sfid,uint32_t ufid_flags)77174ed7ab9SJoe Stringer static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
77274ed7ab9SJoe Stringer 				    const struct sw_flow_id *sfid,
77374ed7ab9SJoe Stringer 				    uint32_t ufid_flags)
77474ed7ab9SJoe Stringer {
77574ed7ab9SJoe Stringer 	size_t len = NLMSG_ALIGN(sizeof(struct ovs_header));
77674ed7ab9SJoe Stringer 
7774e81c0b3SPaolo Abeni 	/* OVS_FLOW_ATTR_UFID, or unmasked flow key as fallback
7784e81c0b3SPaolo Abeni 	 * see ovs_nla_put_identifier()
7794e81c0b3SPaolo Abeni 	 */
78074ed7ab9SJoe Stringer 	if (sfid && ovs_identifier_is_ufid(sfid))
78174ed7ab9SJoe Stringer 		len += nla_total_size(sfid->ufid_len);
7824e81c0b3SPaolo Abeni 	else
7834e81c0b3SPaolo Abeni 		len += nla_total_size(ovs_key_attr_size());
78474ed7ab9SJoe Stringer 
78574ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_KEY */
78674ed7ab9SJoe Stringer 	if (!sfid || should_fill_key(sfid, ufid_flags))
78774ed7ab9SJoe Stringer 		len += nla_total_size(ovs_key_attr_size());
78874ed7ab9SJoe Stringer 
78974ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_MASK */
79074ed7ab9SJoe Stringer 	if (should_fill_mask(ufid_flags))
79174ed7ab9SJoe Stringer 		len += nla_total_size(ovs_key_attr_size());
79274ed7ab9SJoe Stringer 
79374ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_ACTIONS */
79474ed7ab9SJoe Stringer 	if (should_fill_actions(ufid_flags))
7958e2fed1cSJoe Stringer 		len += nla_total_size(acts->orig_len);
79674ed7ab9SJoe Stringer 
79774ed7ab9SJoe Stringer 	return len
79866c7a5eeSNicolas Dichtel 		+ nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
799c3ff8cfeSThomas Graf 		+ nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
80066c7a5eeSNicolas Dichtel 		+ nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */
801c3ff8cfeSThomas Graf }
802c3ff8cfeSThomas Graf 
803bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */
ovs_flow_cmd_fill_stats(const struct sw_flow * flow,struct sk_buff * skb)804ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
805ca7105f2SJoe Stringer 				   struct sk_buff *skb)
806ca7105f2SJoe Stringer {
807ca7105f2SJoe Stringer 	struct ovs_flow_stats stats;
808ca7105f2SJoe Stringer 	__be16 tcp_flags;
809ca7105f2SJoe Stringer 	unsigned long used;
81003f0d916SAndy Zhou 
811e298e505SPravin B Shelar 	ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
8120e9796b4SJarno Rajahalme 
813028d6a67SDavid S. Miller 	if (used &&
8140238b720SNicolas Dichtel 	    nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used),
8150238b720SNicolas Dichtel 			      OVS_FLOW_ATTR_PAD))
816ca7105f2SJoe Stringer 		return -EMSGSIZE;
817ccb1352eSJesse Gross 
818028d6a67SDavid S. Miller 	if (stats.n_packets &&
81966c7a5eeSNicolas Dichtel 	    nla_put_64bit(skb, OVS_FLOW_ATTR_STATS,
82066c7a5eeSNicolas Dichtel 			  sizeof(struct ovs_flow_stats), &stats,
82166c7a5eeSNicolas Dichtel 			  OVS_FLOW_ATTR_PAD))
822ca7105f2SJoe Stringer 		return -EMSGSIZE;
823ccb1352eSJesse Gross 
824e298e505SPravin B Shelar 	if ((u8)ntohs(tcp_flags) &&
825e298e505SPravin B Shelar 	     nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
826ca7105f2SJoe Stringer 		return -EMSGSIZE;
827ca7105f2SJoe Stringer 
828ca7105f2SJoe Stringer 	return 0;
829ca7105f2SJoe Stringer }
830ca7105f2SJoe Stringer 
831ca7105f2SJoe Stringer /* Called with ovs_mutex or RCU read lock. */
ovs_flow_cmd_fill_actions(const struct sw_flow * flow,struct sk_buff * skb,int skb_orig_len)832ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow,
833ca7105f2SJoe Stringer 				     struct sk_buff *skb, int skb_orig_len)
834ca7105f2SJoe Stringer {
835ca7105f2SJoe Stringer 	struct nlattr *start;
836ca7105f2SJoe Stringer 	int err;
837ccb1352eSJesse Gross 
838ccb1352eSJesse Gross 	/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
839ccb1352eSJesse Gross 	 * this is the first flow to be dumped into 'skb'.  This is unusual for
840ccb1352eSJesse Gross 	 * Netlink but individual action lists can be longer than
841ccb1352eSJesse Gross 	 * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this.
842ccb1352eSJesse Gross 	 * The userspace caller can always fetch the actions separately if it
843ccb1352eSJesse Gross 	 * really wants them.  (Most userspace callers in fact don't care.)
844ccb1352eSJesse Gross 	 *
845ccb1352eSJesse Gross 	 * This can only fail for dump operations because the skb is always
846ccb1352eSJesse Gross 	 * properly sized for single flows.
847ccb1352eSJesse Gross 	 */
848ae0be8deSMichal Kubecek 	start = nla_nest_start_noflag(skb, OVS_FLOW_ATTR_ACTIONS);
84974f84a57SPravin B Shelar 	if (start) {
850d57170b1SPravin B Shelar 		const struct sw_flow_actions *sf_acts;
851d57170b1SPravin B Shelar 
852663efa36SJesse Gross 		sf_acts = rcu_dereference_ovsl(flow->sf_acts);
853e6445719SPravin B Shelar 		err = ovs_nla_put_actions(sf_acts->actions,
854e6445719SPravin B Shelar 					  sf_acts->actions_len, skb);
8550e9796b4SJarno Rajahalme 
85674f84a57SPravin B Shelar 		if (!err)
85774f84a57SPravin B Shelar 			nla_nest_end(skb, start);
85874f84a57SPravin B Shelar 		else {
85974f84a57SPravin B Shelar 			if (skb_orig_len)
860ca7105f2SJoe Stringer 				return err;
861ccb1352eSJesse Gross 
86274f84a57SPravin B Shelar 			nla_nest_cancel(skb, start);
86374f84a57SPravin B Shelar 		}
864ca7105f2SJoe Stringer 	} else if (skb_orig_len) {
865ca7105f2SJoe Stringer 		return -EMSGSIZE;
866ca7105f2SJoe Stringer 	}
867ca7105f2SJoe Stringer 
868ca7105f2SJoe Stringer 	return 0;
869ca7105f2SJoe Stringer }
870ca7105f2SJoe Stringer 
871ca7105f2SJoe Stringer /* Called with ovs_mutex or RCU read lock. */
ovs_flow_cmd_fill_info(const struct sw_flow * flow,int dp_ifindex,struct sk_buff * skb,u32 portid,u32 seq,u32 flags,u8 cmd,u32 ufid_flags)872ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
873ca7105f2SJoe Stringer 				  struct sk_buff *skb, u32 portid,
87474ed7ab9SJoe Stringer 				  u32 seq, u32 flags, u8 cmd, u32 ufid_flags)
875ca7105f2SJoe Stringer {
876ca7105f2SJoe Stringer 	const int skb_orig_len = skb->len;
877ca7105f2SJoe Stringer 	struct ovs_header *ovs_header;
878ca7105f2SJoe Stringer 	int err;
879ca7105f2SJoe Stringer 
880ca7105f2SJoe Stringer 	ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family,
881ca7105f2SJoe Stringer 				 flags, cmd);
882ca7105f2SJoe Stringer 	if (!ovs_header)
883ca7105f2SJoe Stringer 		return -EMSGSIZE;
884ca7105f2SJoe Stringer 
885ca7105f2SJoe Stringer 	ovs_header->dp_ifindex = dp_ifindex;
886ca7105f2SJoe Stringer 
88774ed7ab9SJoe Stringer 	err = ovs_nla_put_identifier(flow, skb);
8885b4237bbSJoe Stringer 	if (err)
8895b4237bbSJoe Stringer 		goto error;
8905b4237bbSJoe Stringer 
89174ed7ab9SJoe Stringer 	if (should_fill_key(&flow->id, ufid_flags)) {
89274ed7ab9SJoe Stringer 		err = ovs_nla_put_masked_key(flow, skb);
89374ed7ab9SJoe Stringer 		if (err)
89474ed7ab9SJoe Stringer 			goto error;
89574ed7ab9SJoe Stringer 	}
89674ed7ab9SJoe Stringer 
89774ed7ab9SJoe Stringer 	if (should_fill_mask(ufid_flags)) {
8985b4237bbSJoe Stringer 		err = ovs_nla_put_mask(flow, skb);
899ca7105f2SJoe Stringer 		if (err)
900ca7105f2SJoe Stringer 			goto error;
90174ed7ab9SJoe Stringer 	}
902ca7105f2SJoe Stringer 
903ca7105f2SJoe Stringer 	err = ovs_flow_cmd_fill_stats(flow, skb);
904ca7105f2SJoe Stringer 	if (err)
905ca7105f2SJoe Stringer 		goto error;
906ca7105f2SJoe Stringer 
90774ed7ab9SJoe Stringer 	if (should_fill_actions(ufid_flags)) {
908ca7105f2SJoe Stringer 		err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len);
909ca7105f2SJoe Stringer 		if (err)
910ca7105f2SJoe Stringer 			goto error;
91174ed7ab9SJoe Stringer 	}
91274f84a57SPravin B Shelar 
913053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
914053c095aSJohannes Berg 	return 0;
915ccb1352eSJesse Gross 
916ccb1352eSJesse Gross error:
917ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
918ccb1352eSJesse Gross 	return err;
919ccb1352eSJesse Gross }
920ccb1352eSJesse Gross 
9210e9796b4SJarno Rajahalme /* May not be called with RCU read lock. */
ovs_flow_cmd_alloc_info(const struct sw_flow_actions * acts,const struct sw_flow_id * sfid,struct genl_info * info,bool always,uint32_t ufid_flags)9220e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts,
92374ed7ab9SJoe Stringer 					       const struct sw_flow_id *sfid,
924fb5d1e9eSJarno Rajahalme 					       struct genl_info *info,
92574ed7ab9SJoe Stringer 					       bool always,
92674ed7ab9SJoe Stringer 					       uint32_t ufid_flags)
927ccb1352eSJesse Gross {
928fb5d1e9eSJarno Rajahalme 	struct sk_buff *skb;
92974ed7ab9SJoe Stringer 	size_t len;
930ccb1352eSJesse Gross 
9319b67aa4aSSamuel Gauthier 	if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0))
932fb5d1e9eSJarno Rajahalme 		return NULL;
933fb5d1e9eSJarno Rajahalme 
93474ed7ab9SJoe Stringer 	len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
935551ddc05SFlorian Westphal 	skb = genlmsg_new(len, GFP_KERNEL);
936fb5d1e9eSJarno Rajahalme 	if (!skb)
937fb5d1e9eSJarno Rajahalme 		return ERR_PTR(-ENOMEM);
938fb5d1e9eSJarno Rajahalme 
939fb5d1e9eSJarno Rajahalme 	return skb;
940ccb1352eSJesse Gross }
941ccb1352eSJesse Gross 
9420e9796b4SJarno Rajahalme /* Called with ovs_mutex. */
ovs_flow_cmd_build_info(const struct sw_flow * flow,int dp_ifindex,struct genl_info * info,u8 cmd,bool always,u32 ufid_flags)9430e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
9440e9796b4SJarno Rajahalme 					       int dp_ifindex,
9450e9796b4SJarno Rajahalme 					       struct genl_info *info, u8 cmd,
94674ed7ab9SJoe Stringer 					       bool always, u32 ufid_flags)
947ccb1352eSJesse Gross {
948ccb1352eSJesse Gross 	struct sk_buff *skb;
949ccb1352eSJesse Gross 	int retval;
950ccb1352eSJesse Gross 
95174ed7ab9SJoe Stringer 	skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts),
95274ed7ab9SJoe Stringer 				      &flow->id, info, always, ufid_flags);
953d0e992aaSHimangi Saraogi 	if (IS_ERR_OR_NULL(skb))
954fb5d1e9eSJarno Rajahalme 		return skb;
955ccb1352eSJesse Gross 
9560e9796b4SJarno Rajahalme 	retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
9570e9796b4SJarno Rajahalme 					info->snd_portid, info->snd_seq, 0,
95874ed7ab9SJoe Stringer 					cmd, ufid_flags);
9598ffeb03fSPaolo Abeni 	if (WARN_ON_ONCE(retval < 0)) {
9608ffeb03fSPaolo Abeni 		kfree_skb(skb);
9618ffeb03fSPaolo Abeni 		skb = ERR_PTR(retval);
9628ffeb03fSPaolo Abeni 	}
963ccb1352eSJesse Gross 	return skb;
964ccb1352eSJesse Gross }
965ccb1352eSJesse Gross 
ovs_flow_cmd_new(struct sk_buff * skb,struct genl_info * info)96637bdc87bSJarno Rajahalme static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
967ccb1352eSJesse Gross {
9687f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
969ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
970bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
97174ed7ab9SJoe Stringer 	struct sw_flow *flow = NULL, *new_flow;
97203f0d916SAndy Zhou 	struct sw_flow_mask mask;
973ccb1352eSJesse Gross 	struct sk_buff *reply;
974ccb1352eSJesse Gross 	struct datapath *dp;
97568bb1010SEelco Chaudron 	struct sw_flow_key *key;
97637bdc87bSJarno Rajahalme 	struct sw_flow_actions *acts;
97737bdc87bSJarno Rajahalme 	struct sw_flow_match match;
97874ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
97937bdc87bSJarno Rajahalme 	int error;
98005da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
98137bdc87bSJarno Rajahalme 
982893f139bSJarno Rajahalme 	/* Must have key and actions. */
98337bdc87bSJarno Rajahalme 	error = -EINVAL;
984426cda5cSJesse Gross 	if (!a[OVS_FLOW_ATTR_KEY]) {
98505da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow key attr not present in new flow.");
98637bdc87bSJarno Rajahalme 		goto error;
987426cda5cSJesse Gross 	}
988426cda5cSJesse Gross 	if (!a[OVS_FLOW_ATTR_ACTIONS]) {
98905da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow actions attr not present in new flow.");
99037bdc87bSJarno Rajahalme 		goto error;
991426cda5cSJesse Gross 	}
99237bdc87bSJarno Rajahalme 
993893f139bSJarno Rajahalme 	/* Most of the time we need to allocate a new flow, do it before
994893f139bSJarno Rajahalme 	 * locking.
995893f139bSJarno Rajahalme 	 */
996893f139bSJarno Rajahalme 	new_flow = ovs_flow_alloc();
997893f139bSJarno Rajahalme 	if (IS_ERR(new_flow)) {
998893f139bSJarno Rajahalme 		error = PTR_ERR(new_flow);
999893f139bSJarno Rajahalme 		goto error;
1000893f139bSJarno Rajahalme 	}
1001893f139bSJarno Rajahalme 
1002893f139bSJarno Rajahalme 	/* Extract key. */
100368bb1010SEelco Chaudron 	key = kzalloc(sizeof(*key), GFP_KERNEL);
100468bb1010SEelco Chaudron 	if (!key) {
100568bb1010SEelco Chaudron 		error = -ENOMEM;
10060c598aedSFedor Pchelkin 		goto err_kfree_flow;
100768bb1010SEelco Chaudron 	}
100868bb1010SEelco Chaudron 
100968bb1010SEelco Chaudron 	ovs_match_init(&match, key, false, &mask);
1010c2ac6673SJoe Stringer 	error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
101105da5898SJarno Rajahalme 				  a[OVS_FLOW_ATTR_MASK], log);
1012893f139bSJarno Rajahalme 	if (error)
10130c598aedSFedor Pchelkin 		goto err_kfree_key;
1014893f139bSJarno Rajahalme 
101568bb1010SEelco Chaudron 	ovs_flow_mask_key(&new_flow->key, key, true, &mask);
101668bb1010SEelco Chaudron 
101774ed7ab9SJoe Stringer 	/* Extract flow identifier. */
101874ed7ab9SJoe Stringer 	error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
101968bb1010SEelco Chaudron 				       key, log);
102074ed7ab9SJoe Stringer 	if (error)
10210c598aedSFedor Pchelkin 		goto err_kfree_key;
1022893f139bSJarno Rajahalme 
1023893f139bSJarno Rajahalme 	/* Validate actions. */
10247f8a436eSJoe Stringer 	error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
10257f8a436eSJoe Stringer 				     &new_flow->key, &acts, log);
102637bdc87bSJarno Rajahalme 	if (error) {
102705da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
10280c598aedSFedor Pchelkin 		goto err_kfree_key;
1029893f139bSJarno Rajahalme 	}
1030893f139bSJarno Rajahalme 
103174ed7ab9SJoe Stringer 	reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
103274ed7ab9SJoe Stringer 					ufid_flags);
1033893f139bSJarno Rajahalme 	if (IS_ERR(reply)) {
1034893f139bSJarno Rajahalme 		error = PTR_ERR(reply);
1035893f139bSJarno Rajahalme 		goto err_kfree_acts;
103637bdc87bSJarno Rajahalme 	}
103737bdc87bSJarno Rajahalme 
103837bdc87bSJarno Rajahalme 	ovs_lock();
10397f8a436eSJoe Stringer 	dp = get_dp(net, ovs_header->dp_ifindex);
1040893f139bSJarno Rajahalme 	if (unlikely(!dp)) {
104137bdc87bSJarno Rajahalme 		error = -ENODEV;
104237bdc87bSJarno Rajahalme 		goto err_unlock_ovs;
104337bdc87bSJarno Rajahalme 	}
104474ed7ab9SJoe Stringer 
1045893f139bSJarno Rajahalme 	/* Check if this is a duplicate flow */
104674ed7ab9SJoe Stringer 	if (ovs_identifier_is_ufid(&new_flow->id))
104774ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
104874ed7ab9SJoe Stringer 	if (!flow)
104968bb1010SEelco Chaudron 		flow = ovs_flow_tbl_lookup(&dp->table, key);
1050893f139bSJarno Rajahalme 	if (likely(!flow)) {
1051893f139bSJarno Rajahalme 		rcu_assign_pointer(new_flow->sf_acts, acts);
105237bdc87bSJarno Rajahalme 
105337bdc87bSJarno Rajahalme 		/* Put flow in bucket. */
1054893f139bSJarno Rajahalme 		error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
1055893f139bSJarno Rajahalme 		if (unlikely(error)) {
105637bdc87bSJarno Rajahalme 			acts = NULL;
1057893f139bSJarno Rajahalme 			goto err_unlock_ovs;
105837bdc87bSJarno Rajahalme 		}
1059893f139bSJarno Rajahalme 
1060893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1061893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(new_flow,
1062893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1063893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1064893f139bSJarno Rajahalme 						       info->snd_seq, 0,
106574ed7ab9SJoe Stringer 						       OVS_FLOW_CMD_NEW,
106674ed7ab9SJoe Stringer 						       ufid_flags);
1067893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1068893f139bSJarno Rajahalme 		}
1069893f139bSJarno Rajahalme 		ovs_unlock();
107037bdc87bSJarno Rajahalme 	} else {
107137bdc87bSJarno Rajahalme 		struct sw_flow_actions *old_acts;
107237bdc87bSJarno Rajahalme 
107337bdc87bSJarno Rajahalme 		/* Bail out if we're not allowed to modify an existing flow.
107437bdc87bSJarno Rajahalme 		 * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
107537bdc87bSJarno Rajahalme 		 * because Generic Netlink treats the latter as a dump
107637bdc87bSJarno Rajahalme 		 * request.  We also accept NLM_F_EXCL in case that bug ever
107737bdc87bSJarno Rajahalme 		 * gets fixed.
107837bdc87bSJarno Rajahalme 		 */
1079893f139bSJarno Rajahalme 		if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
1080893f139bSJarno Rajahalme 							 | NLM_F_EXCL))) {
108137bdc87bSJarno Rajahalme 			error = -EEXIST;
108237bdc87bSJarno Rajahalme 			goto err_unlock_ovs;
1083893f139bSJarno Rajahalme 		}
108474ed7ab9SJoe Stringer 		/* The flow identifier has to be the same for flow updates.
108574ed7ab9SJoe Stringer 		 * Look for any overlapping flow.
108674ed7ab9SJoe Stringer 		 */
108774ed7ab9SJoe Stringer 		if (unlikely(!ovs_flow_cmp(flow, &match))) {
108874ed7ab9SJoe Stringer 			if (ovs_identifier_is_key(&flow->id))
108974ed7ab9SJoe Stringer 				flow = ovs_flow_tbl_lookup_exact(&dp->table,
109074ed7ab9SJoe Stringer 								 &match);
109174ed7ab9SJoe Stringer 			else /* UFID matches but key is different */
109274ed7ab9SJoe Stringer 				flow = NULL;
10934a46b24eSAlex Wang 			if (!flow) {
10944a46b24eSAlex Wang 				error = -ENOENT;
109537bdc87bSJarno Rajahalme 				goto err_unlock_ovs;
1096893f139bSJarno Rajahalme 			}
10974a46b24eSAlex Wang 		}
109837bdc87bSJarno Rajahalme 		/* Update actions. */
109937bdc87bSJarno Rajahalme 		old_acts = ovsl_dereference(flow->sf_acts);
110037bdc87bSJarno Rajahalme 		rcu_assign_pointer(flow->sf_acts, acts);
110137bdc87bSJarno Rajahalme 
1102893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1103893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(flow,
1104893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1105893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1106893f139bSJarno Rajahalme 						       info->snd_seq, 0,
110774ed7ab9SJoe Stringer 						       OVS_FLOW_CMD_NEW,
110874ed7ab9SJoe Stringer 						       ufid_flags);
1109893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1110893f139bSJarno Rajahalme 		}
111137bdc87bSJarno Rajahalme 		ovs_unlock();
111237bdc87bSJarno Rajahalme 
111334ae932aSThomas Graf 		ovs_nla_free_flow_actions_rcu(old_acts);
1114893f139bSJarno Rajahalme 		ovs_flow_free(new_flow, false);
111537bdc87bSJarno Rajahalme 	}
1116893f139bSJarno Rajahalme 
1117893f139bSJarno Rajahalme 	if (reply)
1118893f139bSJarno Rajahalme 		ovs_notify(&dp_flow_genl_family, reply, info);
111968bb1010SEelco Chaudron 
112068bb1010SEelco Chaudron 	kfree(key);
112137bdc87bSJarno Rajahalme 	return 0;
112237bdc87bSJarno Rajahalme 
112337bdc87bSJarno Rajahalme err_unlock_ovs:
112437bdc87bSJarno Rajahalme 	ovs_unlock();
1125893f139bSJarno Rajahalme 	kfree_skb(reply);
1126893f139bSJarno Rajahalme err_kfree_acts:
112734ae932aSThomas Graf 	ovs_nla_free_flow_actions(acts);
112868bb1010SEelco Chaudron err_kfree_key:
112968bb1010SEelco Chaudron 	kfree(key);
11300c598aedSFedor Pchelkin err_kfree_flow:
11310c598aedSFedor Pchelkin 	ovs_flow_free(new_flow, false);
113237bdc87bSJarno Rajahalme error:
113337bdc87bSJarno Rajahalme 	return error;
113437bdc87bSJarno Rajahalme }
113537bdc87bSJarno Rajahalme 
11362fdb957dSPravin B Shelar /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
1137cf3266adSTonghao Zhang static noinline_for_stack
get_flow_actions(struct net * net,const struct nlattr * a,const struct sw_flow_key * key,const struct sw_flow_mask * mask,bool log)1138cf3266adSTonghao Zhang struct sw_flow_actions *get_flow_actions(struct net *net,
11397f8a436eSJoe Stringer 					 const struct nlattr *a,
11406b205b2cSJesse Gross 					 const struct sw_flow_key *key,
114105da5898SJarno Rajahalme 					 const struct sw_flow_mask *mask,
114205da5898SJarno Rajahalme 					 bool log)
11436b205b2cSJesse Gross {
11446b205b2cSJesse Gross 	struct sw_flow_actions *acts;
11456b205b2cSJesse Gross 	struct sw_flow_key masked_key;
11466b205b2cSJesse Gross 	int error;
11476b205b2cSJesse Gross 
1148ae5f2fb1SJesse Gross 	ovs_flow_mask_key(&masked_key, key, true, mask);
11497f8a436eSJoe Stringer 	error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
11506b205b2cSJesse Gross 	if (error) {
115105da5898SJarno Rajahalme 		OVS_NLERR(log,
115205da5898SJarno Rajahalme 			  "Actions may not be safe on all matching packets");
11536b205b2cSJesse Gross 		return ERR_PTR(error);
11546b205b2cSJesse Gross 	}
11556b205b2cSJesse Gross 
11566b205b2cSJesse Gross 	return acts;
11576b205b2cSJesse Gross }
11586b205b2cSJesse Gross 
11599cc9a5cbSTonghao Zhang /* Factor out match-init and action-copy to avoid
11609cc9a5cbSTonghao Zhang  * "Wframe-larger-than=1024" warning. Because mask is only
11619cc9a5cbSTonghao Zhang  * used to get actions, we new a function to save some
11629cc9a5cbSTonghao Zhang  * stack space.
11639cc9a5cbSTonghao Zhang  *
11649cc9a5cbSTonghao Zhang  * If there are not key and action attrs, we return 0
11659cc9a5cbSTonghao Zhang  * directly. In the case, the caller will also not use the
11669cc9a5cbSTonghao Zhang  * match as before. If there is action attr, we try to get
11679cc9a5cbSTonghao Zhang  * actions and save them to *acts. Before returning from
11689cc9a5cbSTonghao Zhang  * the function, we reset the match->mask pointer. Because
11699cc9a5cbSTonghao Zhang  * we should not to return match object with dangling reference
11709cc9a5cbSTonghao Zhang  * to mask.
11719cc9a5cbSTonghao Zhang  * */
117226063790SArnd Bergmann static noinline_for_stack int
ovs_nla_init_match_and_action(struct net * net,struct sw_flow_match * match,struct sw_flow_key * key,struct nlattr ** a,struct sw_flow_actions ** acts,bool log)117326063790SArnd Bergmann ovs_nla_init_match_and_action(struct net *net,
11749cc9a5cbSTonghao Zhang 			      struct sw_flow_match *match,
11759cc9a5cbSTonghao Zhang 			      struct sw_flow_key *key,
11769cc9a5cbSTonghao Zhang 			      struct nlattr **a,
11779cc9a5cbSTonghao Zhang 			      struct sw_flow_actions **acts,
11789cc9a5cbSTonghao Zhang 			      bool log)
11799cc9a5cbSTonghao Zhang {
11809cc9a5cbSTonghao Zhang 	struct sw_flow_mask mask;
11819cc9a5cbSTonghao Zhang 	int error = 0;
11829cc9a5cbSTonghao Zhang 
11839cc9a5cbSTonghao Zhang 	if (a[OVS_FLOW_ATTR_KEY]) {
11849cc9a5cbSTonghao Zhang 		ovs_match_init(match, key, true, &mask);
11859cc9a5cbSTonghao Zhang 		error = ovs_nla_get_match(net, match, a[OVS_FLOW_ATTR_KEY],
11869cc9a5cbSTonghao Zhang 					  a[OVS_FLOW_ATTR_MASK], log);
11879cc9a5cbSTonghao Zhang 		if (error)
11889cc9a5cbSTonghao Zhang 			goto error;
11899cc9a5cbSTonghao Zhang 	}
11909cc9a5cbSTonghao Zhang 
11919cc9a5cbSTonghao Zhang 	if (a[OVS_FLOW_ATTR_ACTIONS]) {
11929cc9a5cbSTonghao Zhang 		if (!a[OVS_FLOW_ATTR_KEY]) {
11939cc9a5cbSTonghao Zhang 			OVS_NLERR(log,
11949cc9a5cbSTonghao Zhang 				  "Flow key attribute not present in set flow.");
11955829e62aSChristophe JAILLET 			error = -EINVAL;
11965829e62aSChristophe JAILLET 			goto error;
11979cc9a5cbSTonghao Zhang 		}
11989cc9a5cbSTonghao Zhang 
11999cc9a5cbSTonghao Zhang 		*acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key,
12009cc9a5cbSTonghao Zhang 					 &mask, log);
12019cc9a5cbSTonghao Zhang 		if (IS_ERR(*acts)) {
12029cc9a5cbSTonghao Zhang 			error = PTR_ERR(*acts);
12039cc9a5cbSTonghao Zhang 			goto error;
12049cc9a5cbSTonghao Zhang 		}
12059cc9a5cbSTonghao Zhang 	}
12069cc9a5cbSTonghao Zhang 
12079cc9a5cbSTonghao Zhang 	/* On success, error is 0. */
12089cc9a5cbSTonghao Zhang error:
12099cc9a5cbSTonghao Zhang 	match->mask = NULL;
12109cc9a5cbSTonghao Zhang 	return error;
12119cc9a5cbSTonghao Zhang }
12129cc9a5cbSTonghao Zhang 
ovs_flow_cmd_set(struct sk_buff * skb,struct genl_info * info)121337bdc87bSJarno Rajahalme static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
121437bdc87bSJarno Rajahalme {
12157f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
121637bdc87bSJarno Rajahalme 	struct nlattr **a = info->attrs;
1217bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
12186b205b2cSJesse Gross 	struct sw_flow_key key;
121937bdc87bSJarno Rajahalme 	struct sw_flow *flow;
122037bdc87bSJarno Rajahalme 	struct sk_buff *reply = NULL;
122137bdc87bSJarno Rajahalme 	struct datapath *dp;
1222893f139bSJarno Rajahalme 	struct sw_flow_actions *old_acts = NULL, *acts = NULL;
122303f0d916SAndy Zhou 	struct sw_flow_match match;
122474ed7ab9SJoe Stringer 	struct sw_flow_id sfid;
122574ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
12266f15cdbfSSamuel Gauthier 	int error = 0;
122705da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
122874ed7ab9SJoe Stringer 	bool ufid_present;
1229ccb1352eSJesse Gross 
123074ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
12319cc9a5cbSTonghao Zhang 	if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) {
12326f15cdbfSSamuel Gauthier 		OVS_NLERR(log,
12336f15cdbfSSamuel Gauthier 			  "Flow set message rejected, Key attribute missing.");
12349cc9a5cbSTonghao Zhang 		return -EINVAL;
12356f15cdbfSSamuel Gauthier 	}
12369cc9a5cbSTonghao Zhang 
12379cc9a5cbSTonghao Zhang 	error = ovs_nla_init_match_and_action(net, &match, &key, a,
12389cc9a5cbSTonghao Zhang 					      &acts, log);
1239ccb1352eSJesse Gross 	if (error)
1240ccb1352eSJesse Gross 		goto error;
1241ccb1352eSJesse Gross 
12429cc9a5cbSTonghao Zhang 	if (acts) {
1243893f139bSJarno Rajahalme 		/* Can allocate before locking if have acts. */
124474ed7ab9SJoe Stringer 		reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false,
124574ed7ab9SJoe Stringer 						ufid_flags);
1246893f139bSJarno Rajahalme 		if (IS_ERR(reply)) {
1247893f139bSJarno Rajahalme 			error = PTR_ERR(reply);
1248893f139bSJarno Rajahalme 			goto err_kfree_acts;
124903f0d916SAndy Zhou 		}
1250ccb1352eSJesse Gross 	}
1251ccb1352eSJesse Gross 
12528e4e1713SPravin B Shelar 	ovs_lock();
12537f8a436eSJoe Stringer 	dp = get_dp(net, ovs_header->dp_ifindex);
1254893f139bSJarno Rajahalme 	if (unlikely(!dp)) {
1255ccb1352eSJesse Gross 		error = -ENODEV;
12568e4e1713SPravin B Shelar 		goto err_unlock_ovs;
1257893f139bSJarno Rajahalme 	}
125837bdc87bSJarno Rajahalme 	/* Check that the flow exists. */
125974ed7ab9SJoe Stringer 	if (ufid_present)
126074ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &sfid);
126174ed7ab9SJoe Stringer 	else
12624a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
1263893f139bSJarno Rajahalme 	if (unlikely(!flow)) {
1264ccb1352eSJesse Gross 		error = -ENOENT;
12658e4e1713SPravin B Shelar 		goto err_unlock_ovs;
1266893f139bSJarno Rajahalme 	}
12674a46b24eSAlex Wang 
1268be52c9e9SJarno Rajahalme 	/* Update actions, if present. */
1269893f139bSJarno Rajahalme 	if (likely(acts)) {
12708e4e1713SPravin B Shelar 		old_acts = ovsl_dereference(flow->sf_acts);
127174f84a57SPravin B Shelar 		rcu_assign_pointer(flow->sf_acts, acts);
12720e9796b4SJarno Rajahalme 
1273893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1274893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(flow,
1275893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1276893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1277893f139bSJarno Rajahalme 						       info->snd_seq, 0,
1278804fe108SYifeng Sun 						       OVS_FLOW_CMD_SET,
127974ed7ab9SJoe Stringer 						       ufid_flags);
1280893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1281893f139bSJarno Rajahalme 		}
1282893f139bSJarno Rajahalme 	} else {
1283893f139bSJarno Rajahalme 		/* Could not alloc without acts before locking. */
12840e9796b4SJarno Rajahalme 		reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
1285804fe108SYifeng Sun 						info, OVS_FLOW_CMD_SET, false,
128674ed7ab9SJoe Stringer 						ufid_flags);
128774ed7ab9SJoe Stringer 
1288b5ffe634SViresh Kumar 		if (IS_ERR(reply)) {
1289893f139bSJarno Rajahalme 			error = PTR_ERR(reply);
1290893f139bSJarno Rajahalme 			goto err_unlock_ovs;
1291893f139bSJarno Rajahalme 		}
1292893f139bSJarno Rajahalme 	}
1293893f139bSJarno Rajahalme 
1294ccb1352eSJesse Gross 	/* Clear stats. */
1295e298e505SPravin B Shelar 	if (a[OVS_FLOW_ATTR_CLEAR])
1296e298e505SPravin B Shelar 		ovs_flow_stats_clear(flow);
12978e4e1713SPravin B Shelar 	ovs_unlock();
1298ccb1352eSJesse Gross 
1299893f139bSJarno Rajahalme 	if (reply)
13002a94fe48SJohannes Berg 		ovs_notify(&dp_flow_genl_family, reply, info);
1301893f139bSJarno Rajahalme 	if (old_acts)
130234ae932aSThomas Graf 		ovs_nla_free_flow_actions_rcu(old_acts);
1303fb5d1e9eSJarno Rajahalme 
1304ccb1352eSJesse Gross 	return 0;
1305ccb1352eSJesse Gross 
13068e4e1713SPravin B Shelar err_unlock_ovs:
13078e4e1713SPravin B Shelar 	ovs_unlock();
1308893f139bSJarno Rajahalme 	kfree_skb(reply);
1309893f139bSJarno Rajahalme err_kfree_acts:
131034ae932aSThomas Graf 	ovs_nla_free_flow_actions(acts);
1311ccb1352eSJesse Gross error:
1312ccb1352eSJesse Gross 	return error;
1313ccb1352eSJesse Gross }
1314ccb1352eSJesse Gross 
ovs_flow_cmd_get(struct sk_buff * skb,struct genl_info * info)1315ccb1352eSJesse Gross static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
1316ccb1352eSJesse Gross {
1317ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1318bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
1319c2ac6673SJoe Stringer 	struct net *net = sock_net(skb->sk);
1320ccb1352eSJesse Gross 	struct sw_flow_key key;
1321ccb1352eSJesse Gross 	struct sk_buff *reply;
1322ccb1352eSJesse Gross 	struct sw_flow *flow;
1323ccb1352eSJesse Gross 	struct datapath *dp;
132403f0d916SAndy Zhou 	struct sw_flow_match match;
132574ed7ab9SJoe Stringer 	struct sw_flow_id ufid;
132674ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
132774ed7ab9SJoe Stringer 	int err = 0;
132805da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
132974ed7ab9SJoe Stringer 	bool ufid_present;
1330ccb1352eSJesse Gross 
133174ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
133274ed7ab9SJoe Stringer 	if (a[OVS_FLOW_ATTR_KEY]) {
13332279994dSpravin shelar 		ovs_match_init(&match, &key, true, NULL);
1334c2ac6673SJoe Stringer 		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
133574ed7ab9SJoe Stringer 					log);
133674ed7ab9SJoe Stringer 	} else if (!ufid_present) {
133705da5898SJarno Rajahalme 		OVS_NLERR(log,
133805da5898SJarno Rajahalme 			  "Flow get message rejected, Key attribute missing.");
133974ed7ab9SJoe Stringer 		err = -EINVAL;
134003f0d916SAndy Zhou 	}
1341ccb1352eSJesse Gross 	if (err)
1342ccb1352eSJesse Gross 		return err;
1343ccb1352eSJesse Gross 
13448e4e1713SPravin B Shelar 	ovs_lock();
134546df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
13468e4e1713SPravin B Shelar 	if (!dp) {
13478e4e1713SPravin B Shelar 		err = -ENODEV;
13488e4e1713SPravin B Shelar 		goto unlock;
13498e4e1713SPravin B Shelar 	}
1350ccb1352eSJesse Gross 
135174ed7ab9SJoe Stringer 	if (ufid_present)
135274ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
135374ed7ab9SJoe Stringer 	else
13544a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
13554a46b24eSAlex Wang 	if (!flow) {
13568e4e1713SPravin B Shelar 		err = -ENOENT;
13578e4e1713SPravin B Shelar 		goto unlock;
13588e4e1713SPravin B Shelar 	}
1359ccb1352eSJesse Gross 
13600e9796b4SJarno Rajahalme 	reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
1361804fe108SYifeng Sun 					OVS_FLOW_CMD_GET, true, ufid_flags);
13628e4e1713SPravin B Shelar 	if (IS_ERR(reply)) {
13638e4e1713SPravin B Shelar 		err = PTR_ERR(reply);
13648e4e1713SPravin B Shelar 		goto unlock;
13658e4e1713SPravin B Shelar 	}
1366ccb1352eSJesse Gross 
13678e4e1713SPravin B Shelar 	ovs_unlock();
1368ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
13698e4e1713SPravin B Shelar unlock:
13708e4e1713SPravin B Shelar 	ovs_unlock();
13718e4e1713SPravin B Shelar 	return err;
1372ccb1352eSJesse Gross }
1373ccb1352eSJesse Gross 
ovs_flow_cmd_del(struct sk_buff * skb,struct genl_info * info)1374ccb1352eSJesse Gross static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
1375ccb1352eSJesse Gross {
1376ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1377bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
1378c2ac6673SJoe Stringer 	struct net *net = sock_net(skb->sk);
1379ccb1352eSJesse Gross 	struct sw_flow_key key;
1380ccb1352eSJesse Gross 	struct sk_buff *reply;
138174ed7ab9SJoe Stringer 	struct sw_flow *flow = NULL;
1382ccb1352eSJesse Gross 	struct datapath *dp;
138303f0d916SAndy Zhou 	struct sw_flow_match match;
138474ed7ab9SJoe Stringer 	struct sw_flow_id ufid;
138574ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
1386ccb1352eSJesse Gross 	int err;
138705da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
138874ed7ab9SJoe Stringer 	bool ufid_present;
1389ccb1352eSJesse Gross 
139074ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
139174ed7ab9SJoe Stringer 	if (a[OVS_FLOW_ATTR_KEY]) {
13922279994dSpravin shelar 		ovs_match_init(&match, &key, true, NULL);
1393c2ac6673SJoe Stringer 		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
1394c2ac6673SJoe Stringer 					NULL, log);
1395aed06778SJarno Rajahalme 		if (unlikely(err))
1396aed06778SJarno Rajahalme 			return err;
1397aed06778SJarno Rajahalme 	}
1398aed06778SJarno Rajahalme 
13998e4e1713SPravin B Shelar 	ovs_lock();
140046df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1401aed06778SJarno Rajahalme 	if (unlikely(!dp)) {
14028e4e1713SPravin B Shelar 		err = -ENODEV;
14038e4e1713SPravin B Shelar 		goto unlock;
14048e4e1713SPravin B Shelar 	}
140546df7b81SPravin B Shelar 
140674ed7ab9SJoe Stringer 	if (unlikely(!a[OVS_FLOW_ATTR_KEY] && !ufid_present)) {
1407b637e498SPravin B Shelar 		err = ovs_flow_tbl_flush(&dp->table);
14088e4e1713SPravin B Shelar 		goto unlock;
14098e4e1713SPravin B Shelar 	}
141003f0d916SAndy Zhou 
141174ed7ab9SJoe Stringer 	if (ufid_present)
141274ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
141374ed7ab9SJoe Stringer 	else
14144a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
14154a46b24eSAlex Wang 	if (unlikely(!flow)) {
14168e4e1713SPravin B Shelar 		err = -ENOENT;
14178e4e1713SPravin B Shelar 		goto unlock;
14188e4e1713SPravin B Shelar 	}
1419ccb1352eSJesse Gross 
1420b637e498SPravin B Shelar 	ovs_flow_tbl_remove(&dp->table, flow);
1421aed06778SJarno Rajahalme 	ovs_unlock();
1422ccb1352eSJesse Gross 
1423aed06778SJarno Rajahalme 	reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts,
142474ed7ab9SJoe Stringer 					&flow->id, info, false, ufid_flags);
1425aed06778SJarno Rajahalme 	if (likely(reply)) {
1426b90f5aa4SEnrico Weigelt 		if (!IS_ERR(reply)) {
1427aed06778SJarno Rajahalme 			rcu_read_lock();	/*To keep RCU checker happy. */
14280e9796b4SJarno Rajahalme 			err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
14290e9796b4SJarno Rajahalme 						     reply, info->snd_portid,
1430fb5d1e9eSJarno Rajahalme 						     info->snd_seq, 0,
143174ed7ab9SJoe Stringer 						     OVS_FLOW_CMD_DEL,
143274ed7ab9SJoe Stringer 						     ufid_flags);
1433aed06778SJarno Rajahalme 			rcu_read_unlock();
14348a574f86SPaolo Abeni 			if (WARN_ON_ONCE(err < 0)) {
14358a574f86SPaolo Abeni 				kfree_skb(reply);
14368a574f86SPaolo Abeni 				goto out_free;
14378a574f86SPaolo Abeni 			}
1438ccb1352eSJesse Gross 
14392a94fe48SJohannes Berg 			ovs_notify(&dp_flow_genl_family, reply, info);
1440aed06778SJarno Rajahalme 		} else {
1441cf3266adSTonghao Zhang 			netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
1442cf3266adSTonghao Zhang 					PTR_ERR(reply));
1443aed06778SJarno Rajahalme 		}
1444aed06778SJarno Rajahalme 	}
1445aed06778SJarno Rajahalme 
14468a574f86SPaolo Abeni out_free:
1447aed06778SJarno Rajahalme 	ovs_flow_free(flow, true);
1448ccb1352eSJesse Gross 	return 0;
14498e4e1713SPravin B Shelar unlock:
14508e4e1713SPravin B Shelar 	ovs_unlock();
14518e4e1713SPravin B Shelar 	return err;
1452ccb1352eSJesse Gross }
1453ccb1352eSJesse Gross 
ovs_flow_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)1454ccb1352eSJesse Gross static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
1455ccb1352eSJesse Gross {
145674ed7ab9SJoe Stringer 	struct nlattr *a[__OVS_FLOW_ATTR_MAX];
1457ccb1352eSJesse Gross 	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
1458b637e498SPravin B Shelar 	struct table_instance *ti;
1459ccb1352eSJesse Gross 	struct datapath *dp;
146074ed7ab9SJoe Stringer 	u32 ufid_flags;
146174ed7ab9SJoe Stringer 	int err;
146274ed7ab9SJoe Stringer 
14638cb08174SJohannes Berg 	err = genlmsg_parse_deprecated(cb->nlh, &dp_flow_genl_family, a,
1464fceb6435SJohannes Berg 				       OVS_FLOW_ATTR_MAX, flow_policy, NULL);
146574ed7ab9SJoe Stringer 	if (err)
146674ed7ab9SJoe Stringer 		return err;
146774ed7ab9SJoe Stringer 	ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
1468ccb1352eSJesse Gross 
1469d57170b1SPravin B Shelar 	rcu_read_lock();
1470cc3a5ae6SAndy Zhou 	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
14718e4e1713SPravin B Shelar 	if (!dp) {
1472d57170b1SPravin B Shelar 		rcu_read_unlock();
1473ccb1352eSJesse Gross 		return -ENODEV;
14748e4e1713SPravin B Shelar 	}
1475ccb1352eSJesse Gross 
1476b637e498SPravin B Shelar 	ti = rcu_dereference(dp->table.ti);
1477ccb1352eSJesse Gross 	for (;;) {
1478ccb1352eSJesse Gross 		struct sw_flow *flow;
1479ccb1352eSJesse Gross 		u32 bucket, obj;
1480ccb1352eSJesse Gross 
1481ccb1352eSJesse Gross 		bucket = cb->args[0];
1482ccb1352eSJesse Gross 		obj = cb->args[1];
1483b637e498SPravin B Shelar 		flow = ovs_flow_tbl_dump_next(ti, &bucket, &obj);
1484ccb1352eSJesse Gross 		if (!flow)
1485ccb1352eSJesse Gross 			break;
1486ccb1352eSJesse Gross 
14870e9796b4SJarno Rajahalme 		if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
148815e47304SEric W. Biederman 					   NETLINK_CB(cb->skb).portid,
1489ccb1352eSJesse Gross 					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
1490804fe108SYifeng Sun 					   OVS_FLOW_CMD_GET, ufid_flags) < 0)
1491ccb1352eSJesse Gross 			break;
1492ccb1352eSJesse Gross 
1493ccb1352eSJesse Gross 		cb->args[0] = bucket;
1494ccb1352eSJesse Gross 		cb->args[1] = obj;
1495ccb1352eSJesse Gross 	}
1496d57170b1SPravin B Shelar 	rcu_read_unlock();
1497ccb1352eSJesse Gross 	return skb->len;
1498ccb1352eSJesse Gross }
1499ccb1352eSJesse Gross 
15000c200ef9SPravin B Shelar static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
15010c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
150205da5898SJarno Rajahalme 	[OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED },
15030c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
15040c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
150505da5898SJarno Rajahalme 	[OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG },
150674ed7ab9SJoe Stringer 	[OVS_FLOW_ATTR_UFID] = { .type = NLA_UNSPEC, .len = 1 },
150774ed7ab9SJoe Stringer 	[OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
15080c200ef9SPravin B Shelar };
15090c200ef9SPravin B Shelar 
151066a9b928SJakub Kicinski static const struct genl_small_ops dp_flow_genl_ops[] = {
1511ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_NEW,
1512ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15134a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
151437bdc87bSJarno Rajahalme 	  .doit = ovs_flow_cmd_new
1515ccb1352eSJesse Gross 	},
1516ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_DEL,
1517ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15184a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
1519ccb1352eSJesse Gross 	  .doit = ovs_flow_cmd_del
1520ccb1352eSJesse Gross 	},
1521ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_GET,
1522ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1523ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
1524ccb1352eSJesse Gross 	  .doit = ovs_flow_cmd_get,
1525ccb1352eSJesse Gross 	  .dumpit = ovs_flow_cmd_dump
1526ccb1352eSJesse Gross 	},
1527ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_SET,
1528ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15294a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
153037bdc87bSJarno Rajahalme 	  .doit = ovs_flow_cmd_set,
1531ccb1352eSJesse Gross 	},
1532ccb1352eSJesse Gross };
1533ccb1352eSJesse Gross 
153456989f6dSJohannes Berg static struct genl_family dp_flow_genl_family __ro_after_init = {
1535ccb1352eSJesse Gross 	.hdrsize = sizeof(struct ovs_header),
15360c200ef9SPravin B Shelar 	.name = OVS_FLOW_FAMILY,
15370c200ef9SPravin B Shelar 	.version = OVS_FLOW_VERSION,
15380c200ef9SPravin B Shelar 	.maxattr = OVS_FLOW_ATTR_MAX,
15393b0f31f2SJohannes Berg 	.policy = flow_policy,
15403a4e0d6aSPravin B Shelar 	.netnsok = true,
15413a4e0d6aSPravin B Shelar 	.parallel_ops = true,
154266a9b928SJakub Kicinski 	.small_ops = dp_flow_genl_ops,
154366a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_flow_genl_ops),
15449c5d03d3SJakub Kicinski 	.resv_start_op = OVS_FLOW_CMD_SET + 1,
15450c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_flow_multicast_group,
15460c200ef9SPravin B Shelar 	.n_mcgrps = 1,
1547489111e5SJohannes Berg 	.module = THIS_MODULE,
1548ccb1352eSJesse Gross };
1549ccb1352eSJesse Gross 
ovs_dp_cmd_msg_size(void)1550c3ff8cfeSThomas Graf static size_t ovs_dp_cmd_msg_size(void)
1551c3ff8cfeSThomas Graf {
1552c3ff8cfeSThomas Graf 	size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
1553c3ff8cfeSThomas Graf 
1554c3ff8cfeSThomas Graf 	msgsize += nla_total_size(IFNAMSIZ);
155566c7a5eeSNicolas Dichtel 	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
155666c7a5eeSNicolas Dichtel 	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
155745fb9c35SDaniele Di Proietto 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
15589bf24f59SEelco Chaudron 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE */
1559347541e2SAndrey Zhadchenko 	msgsize += nla_total_size(sizeof(u32) * nr_cpu_ids); /* OVS_DP_ATTR_PER_CPU_PIDS */
1560c3ff8cfeSThomas Graf 
1561c3ff8cfeSThomas Graf 	return msgsize;
1562c3ff8cfeSThomas Graf }
1563c3ff8cfeSThomas Graf 
15648ec609d8SPravin B Shelar /* Called with ovs_mutex. */
ovs_dp_cmd_fill_info(struct datapath * dp,struct sk_buff * skb,u32 portid,u32 seq,u32 flags,u8 cmd)1565ccb1352eSJesse Gross static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
156615e47304SEric W. Biederman 				u32 portid, u32 seq, u32 flags, u8 cmd)
1567ccb1352eSJesse Gross {
1568ccb1352eSJesse Gross 	struct ovs_header *ovs_header;
1569ccb1352eSJesse Gross 	struct ovs_dp_stats dp_stats;
15701bd7116fSAndy Zhou 	struct ovs_dp_megaflow_stats dp_megaflow_stats;
1571347541e2SAndrey Zhadchenko 	struct dp_nlsk_pids *pids = ovsl_dereference(dp->upcall_portids);
1572347541e2SAndrey Zhadchenko 	int err, pids_len;
1573ccb1352eSJesse Gross 
157415e47304SEric W. Biederman 	ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family,
1575ccb1352eSJesse Gross 				 flags, cmd);
1576ccb1352eSJesse Gross 	if (!ovs_header)
1577ccb1352eSJesse Gross 		goto error;
1578ccb1352eSJesse Gross 
1579ccb1352eSJesse Gross 	ovs_header->dp_ifindex = get_dpifindex(dp);
1580ccb1352eSJesse Gross 
1581ccb1352eSJesse Gross 	err = nla_put_string(skb, OVS_DP_ATTR_NAME, ovs_dp_name(dp));
1582ccb1352eSJesse Gross 	if (err)
1583ccb1352eSJesse Gross 		goto nla_put_failure;
1584ccb1352eSJesse Gross 
15851bd7116fSAndy Zhou 	get_dp_stats(dp, &dp_stats, &dp_megaflow_stats);
158666c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
158766c7a5eeSNicolas Dichtel 			  &dp_stats, OVS_DP_ATTR_PAD))
15881bd7116fSAndy Zhou 		goto nla_put_failure;
15891bd7116fSAndy Zhou 
159066c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
15911bd7116fSAndy Zhou 			  sizeof(struct ovs_dp_megaflow_stats),
159266c7a5eeSNicolas Dichtel 			  &dp_megaflow_stats, OVS_DP_ATTR_PAD))
1593028d6a67SDavid S. Miller 		goto nla_put_failure;
1594ccb1352eSJesse Gross 
159543d4be9cSThomas Graf 	if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
159643d4be9cSThomas Graf 		goto nla_put_failure;
159743d4be9cSThomas Graf 
15989bf24f59SEelco Chaudron 	if (nla_put_u32(skb, OVS_DP_ATTR_MASKS_CACHE_SIZE,
15999bf24f59SEelco Chaudron 			ovs_flow_tbl_masks_cache_size(&dp->table)))
16009bf24f59SEelco Chaudron 		goto nla_put_failure;
16019bf24f59SEelco Chaudron 
1602347541e2SAndrey Zhadchenko 	if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU && pids) {
1603347541e2SAndrey Zhadchenko 		pids_len = min(pids->n_pids, nr_cpu_ids) * sizeof(u32);
1604347541e2SAndrey Zhadchenko 		if (nla_put(skb, OVS_DP_ATTR_PER_CPU_PIDS, pids_len, &pids->pids))
1605347541e2SAndrey Zhadchenko 			goto nla_put_failure;
1606347541e2SAndrey Zhadchenko 	}
1607347541e2SAndrey Zhadchenko 
1608053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
1609053c095aSJohannes Berg 	return 0;
1610ccb1352eSJesse Gross 
1611ccb1352eSJesse Gross nla_put_failure:
1612ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
1613ccb1352eSJesse Gross error:
1614ccb1352eSJesse Gross 	return -EMSGSIZE;
1615ccb1352eSJesse Gross }
1616ccb1352eSJesse Gross 
ovs_dp_cmd_alloc_info(void)1617263ea090SFlorian Westphal static struct sk_buff *ovs_dp_cmd_alloc_info(void)
1618ccb1352eSJesse Gross {
1619551ddc05SFlorian Westphal 	return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
1620ccb1352eSJesse Gross }
1621ccb1352eSJesse Gross 
1622bb6f9a70SJarno Rajahalme /* Called with rcu_read_lock or ovs_mutex. */
lookup_datapath(struct net * net,const struct ovs_header * ovs_header,struct nlattr * a[OVS_DP_ATTR_MAX+1])162346df7b81SPravin B Shelar static struct datapath *lookup_datapath(struct net *net,
162412eb18f7SThomas Graf 					const struct ovs_header *ovs_header,
1625ccb1352eSJesse Gross 					struct nlattr *a[OVS_DP_ATTR_MAX + 1])
1626ccb1352eSJesse Gross {
1627ccb1352eSJesse Gross 	struct datapath *dp;
1628ccb1352eSJesse Gross 
1629ccb1352eSJesse Gross 	if (!a[OVS_DP_ATTR_NAME])
163046df7b81SPravin B Shelar 		dp = get_dp(net, ovs_header->dp_ifindex);
1631ccb1352eSJesse Gross 	else {
1632ccb1352eSJesse Gross 		struct vport *vport;
1633ccb1352eSJesse Gross 
163446df7b81SPravin B Shelar 		vport = ovs_vport_locate(net, nla_data(a[OVS_DP_ATTR_NAME]));
1635ccb1352eSJesse Gross 		dp = vport && vport->port_no == OVSP_LOCAL ? vport->dp : NULL;
1636ccb1352eSJesse Gross 	}
1637ccb1352eSJesse Gross 	return dp ? dp : ERR_PTR(-ENODEV);
1638ccb1352eSJesse Gross }
1639ccb1352eSJesse Gross 
ovs_dp_reset_user_features(struct sk_buff * skb,struct genl_info * info)1640cf3266adSTonghao Zhang static void ovs_dp_reset_user_features(struct sk_buff *skb,
1641cf3266adSTonghao Zhang 				       struct genl_info *info)
164244da5ae5SThomas Graf {
164344da5ae5SThomas Graf 	struct datapath *dp;
164444da5ae5SThomas Graf 
1645bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1646cf3266adSTonghao Zhang 			     info->attrs);
16473c7eacfcSJiri Pirko 	if (IS_ERR(dp))
164844da5ae5SThomas Graf 		return;
164944da5ae5SThomas Graf 
1650fd954cc1SAaron Conole 	pr_warn("%s: Dropping previously announced user features\n",
1651fd954cc1SAaron Conole 		ovs_dp_name(dp));
165244da5ae5SThomas Graf 	dp->user_features = 0;
165344da5ae5SThomas Graf }
165444da5ae5SThomas Graf 
ovs_dp_set_upcall_portids(struct datapath * dp,const struct nlattr * ids)1655b83d23a2SMark Gray static int ovs_dp_set_upcall_portids(struct datapath *dp,
1656b83d23a2SMark Gray 			      const struct nlattr *ids)
1657b83d23a2SMark Gray {
1658b83d23a2SMark Gray 	struct dp_nlsk_pids *old, *dp_nlsk_pids;
1659b83d23a2SMark Gray 
1660b83d23a2SMark Gray 	if (!nla_len(ids) || nla_len(ids) % sizeof(u32))
1661b83d23a2SMark Gray 		return -EINVAL;
1662b83d23a2SMark Gray 
1663b83d23a2SMark Gray 	old = ovsl_dereference(dp->upcall_portids);
1664b83d23a2SMark Gray 
1665b83d23a2SMark Gray 	dp_nlsk_pids = kmalloc(sizeof(*dp_nlsk_pids) + nla_len(ids),
1666b83d23a2SMark Gray 			       GFP_KERNEL);
1667b83d23a2SMark Gray 	if (!dp_nlsk_pids)
1668b83d23a2SMark Gray 		return -ENOMEM;
1669b83d23a2SMark Gray 
1670b83d23a2SMark Gray 	dp_nlsk_pids->n_pids = nla_len(ids) / sizeof(u32);
1671b83d23a2SMark Gray 	nla_memcpy(dp_nlsk_pids->pids, ids, nla_len(ids));
1672b83d23a2SMark Gray 
1673b83d23a2SMark Gray 	rcu_assign_pointer(dp->upcall_portids, dp_nlsk_pids);
1674b83d23a2SMark Gray 
1675b83d23a2SMark Gray 	kfree_rcu(old, rcu);
1676b83d23a2SMark Gray 
1677b83d23a2SMark Gray 	return 0;
1678b83d23a2SMark Gray }
1679b83d23a2SMark Gray 
ovs_dp_get_upcall_portid(const struct datapath * dp,uint32_t cpu_id)1680b83d23a2SMark Gray u32 ovs_dp_get_upcall_portid(const struct datapath *dp, uint32_t cpu_id)
1681b83d23a2SMark Gray {
1682b83d23a2SMark Gray 	struct dp_nlsk_pids *dp_nlsk_pids;
1683b83d23a2SMark Gray 
1684b83d23a2SMark Gray 	dp_nlsk_pids = rcu_dereference(dp->upcall_portids);
1685b83d23a2SMark Gray 
1686b83d23a2SMark Gray 	if (dp_nlsk_pids) {
1687b83d23a2SMark Gray 		if (cpu_id < dp_nlsk_pids->n_pids) {
1688b83d23a2SMark Gray 			return dp_nlsk_pids->pids[cpu_id];
1689784dcfa5SMark Gray 		} else if (dp_nlsk_pids->n_pids > 0 &&
1690784dcfa5SMark Gray 			   cpu_id >= dp_nlsk_pids->n_pids) {
1691784dcfa5SMark Gray 			/* If the number of netlink PIDs is mismatched with
1692784dcfa5SMark Gray 			 * the number of CPUs as seen by the kernel, log this
1693784dcfa5SMark Gray 			 * and send the upcall to an arbitrary socket (0) in
1694784dcfa5SMark Gray 			 * order to not drop packets
1695b83d23a2SMark Gray 			 */
1696b83d23a2SMark Gray 			pr_info_ratelimited("cpu_id mismatch with handler threads");
1697784dcfa5SMark Gray 			return dp_nlsk_pids->pids[cpu_id %
1698784dcfa5SMark Gray 						  dp_nlsk_pids->n_pids];
1699b83d23a2SMark Gray 		} else {
1700b83d23a2SMark Gray 			return 0;
1701b83d23a2SMark Gray 		}
1702b83d23a2SMark Gray 	} else {
1703b83d23a2SMark Gray 		return 0;
1704b83d23a2SMark Gray 	}
1705b83d23a2SMark Gray }
1706b83d23a2SMark Gray 
ovs_dp_change(struct datapath * dp,struct nlattr * a[])170795a7233cSPaul Blakey static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
170843d4be9cSThomas Graf {
170935d39fecSPaul Blakey 	u32 user_features = 0, old_features = dp->user_features;
1710b83d23a2SMark Gray 	int err;
171195a7233cSPaul Blakey 
171295a7233cSPaul Blakey 	if (a[OVS_DP_ATTR_USER_FEATURES]) {
171395a7233cSPaul Blakey 		user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
171495a7233cSPaul Blakey 
171595a7233cSPaul Blakey 		if (user_features & ~(OVS_DP_F_VPORT_PIDS |
171695a7233cSPaul Blakey 				      OVS_DP_F_UNALIGNED |
1717b83d23a2SMark Gray 				      OVS_DP_F_TC_RECIRC_SHARING |
1718b83d23a2SMark Gray 				      OVS_DP_F_DISPATCH_UPCALL_PER_CPU))
171995a7233cSPaul Blakey 			return -EOPNOTSUPP;
172095a7233cSPaul Blakey 
172195a7233cSPaul Blakey #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
172295a7233cSPaul Blakey 		if (user_features & OVS_DP_F_TC_RECIRC_SHARING)
172395a7233cSPaul Blakey 			return -EOPNOTSUPP;
172495a7233cSPaul Blakey #endif
172595a7233cSPaul Blakey 	}
172695a7233cSPaul Blakey 
17279bf24f59SEelco Chaudron 	if (a[OVS_DP_ATTR_MASKS_CACHE_SIZE]) {
17289bf24f59SEelco Chaudron 		int err;
17299bf24f59SEelco Chaudron 		u32 cache_size;
17309bf24f59SEelco Chaudron 
17319bf24f59SEelco Chaudron 		cache_size = nla_get_u32(a[OVS_DP_ATTR_MASKS_CACHE_SIZE]);
17329bf24f59SEelco Chaudron 		err = ovs_flow_tbl_masks_cache_resize(&dp->table, cache_size);
17339bf24f59SEelco Chaudron 		if (err)
17349bf24f59SEelco Chaudron 			return err;
17359bf24f59SEelco Chaudron 	}
17369bf24f59SEelco Chaudron 
173795a7233cSPaul Blakey 	dp->user_features = user_features;
173895a7233cSPaul Blakey 
1739b83d23a2SMark Gray 	if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU &&
1740b83d23a2SMark Gray 	    a[OVS_DP_ATTR_PER_CPU_PIDS]) {
1741b83d23a2SMark Gray 		/* Upcall Netlink Port IDs have been updated */
1742b83d23a2SMark Gray 		err = ovs_dp_set_upcall_portids(dp,
1743b83d23a2SMark Gray 						a[OVS_DP_ATTR_PER_CPU_PIDS]);
1744b83d23a2SMark Gray 		if (err)
1745b83d23a2SMark Gray 			return err;
1746b83d23a2SMark Gray 	}
1747b83d23a2SMark Gray 
174835d39fecSPaul Blakey 	if ((dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
174935d39fecSPaul Blakey 	    !(old_features & OVS_DP_F_TC_RECIRC_SHARING))
175035d39fecSPaul Blakey 		tc_skb_ext_tc_enable();
175135d39fecSPaul Blakey 	else if (!(dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
175235d39fecSPaul Blakey 		 (old_features & OVS_DP_F_TC_RECIRC_SHARING))
175335d39fecSPaul Blakey 		tc_skb_ext_tc_disable();
175495a7233cSPaul Blakey 
175595a7233cSPaul Blakey 	return 0;
175643d4be9cSThomas Graf }
175743d4be9cSThomas Graf 
ovs_dp_stats_init(struct datapath * dp)1758eec62eadSTonghao Zhang static int ovs_dp_stats_init(struct datapath *dp)
1759eec62eadSTonghao Zhang {
1760eec62eadSTonghao Zhang 	dp->stats_percpu = netdev_alloc_pcpu_stats(struct dp_stats_percpu);
1761eec62eadSTonghao Zhang 	if (!dp->stats_percpu)
1762eec62eadSTonghao Zhang 		return -ENOMEM;
1763eec62eadSTonghao Zhang 
1764eec62eadSTonghao Zhang 	return 0;
1765eec62eadSTonghao Zhang }
1766eec62eadSTonghao Zhang 
ovs_dp_vport_init(struct datapath * dp)1767eec62eadSTonghao Zhang static int ovs_dp_vport_init(struct datapath *dp)
1768eec62eadSTonghao Zhang {
1769eec62eadSTonghao Zhang 	int i;
1770eec62eadSTonghao Zhang 
1771eec62eadSTonghao Zhang 	dp->ports = kmalloc_array(DP_VPORT_HASH_BUCKETS,
1772eec62eadSTonghao Zhang 				  sizeof(struct hlist_head),
1773eec62eadSTonghao Zhang 				  GFP_KERNEL);
1774eec62eadSTonghao Zhang 	if (!dp->ports)
1775eec62eadSTonghao Zhang 		return -ENOMEM;
1776eec62eadSTonghao Zhang 
1777eec62eadSTonghao Zhang 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
1778eec62eadSTonghao Zhang 		INIT_HLIST_HEAD(&dp->ports[i]);
1779eec62eadSTonghao Zhang 
1780eec62eadSTonghao Zhang 	return 0;
1781eec62eadSTonghao Zhang }
1782eec62eadSTonghao Zhang 
ovs_dp_cmd_new(struct sk_buff * skb,struct genl_info * info)1783ccb1352eSJesse Gross static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1784ccb1352eSJesse Gross {
1785ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1786ccb1352eSJesse Gross 	struct vport_parms parms;
1787ccb1352eSJesse Gross 	struct sk_buff *reply;
1788ccb1352eSJesse Gross 	struct datapath *dp;
1789ccb1352eSJesse Gross 	struct vport *vport;
179046df7b81SPravin B Shelar 	struct ovs_net *ovs_net;
1791eec62eadSTonghao Zhang 	int err;
1792ccb1352eSJesse Gross 
1793ccb1352eSJesse Gross 	err = -EINVAL;
1794ccb1352eSJesse Gross 	if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
1795ccb1352eSJesse Gross 		goto err;
1796ccb1352eSJesse Gross 
1797263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
17986093ae9aSJarno Rajahalme 	if (!reply)
17996093ae9aSJarno Rajahalme 		return -ENOMEM;
1800ccb1352eSJesse Gross 
1801ccb1352eSJesse Gross 	err = -ENOMEM;
1802ccb1352eSJesse Gross 	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
1803ccb1352eSJesse Gross 	if (dp == NULL)
1804eec62eadSTonghao Zhang 		goto err_destroy_reply;
180546df7b81SPravin B Shelar 
1806efd7ef1cSEric W. Biederman 	ovs_dp_set_net(dp, sock_net(skb->sk));
1807ccb1352eSJesse Gross 
1808ccb1352eSJesse Gross 	/* Allocate table. */
1809b637e498SPravin B Shelar 	err = ovs_flow_tbl_init(&dp->table);
1810b637e498SPravin B Shelar 	if (err)
1811eec62eadSTonghao Zhang 		goto err_destroy_dp;
1812ccb1352eSJesse Gross 
1813eec62eadSTonghao Zhang 	err = ovs_dp_stats_init(dp);
1814eec62eadSTonghao Zhang 	if (err)
1815ccb1352eSJesse Gross 		goto err_destroy_table;
1816ccb1352eSJesse Gross 
1817eec62eadSTonghao Zhang 	err = ovs_dp_vport_init(dp);
1818eec62eadSTonghao Zhang 	if (err)
1819eec62eadSTonghao Zhang 		goto err_destroy_stats;
182015eac2a7SPravin B Shelar 
182196fbc13dSAndy Zhou 	err = ovs_meters_init(dp);
182296fbc13dSAndy Zhou 	if (err)
1823eec62eadSTonghao Zhang 		goto err_destroy_ports;
182496fbc13dSAndy Zhou 
1825ccb1352eSJesse Gross 	/* Set up our datapath device. */
1826ccb1352eSJesse Gross 	parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
1827ccb1352eSJesse Gross 	parms.type = OVS_VPORT_TYPE_INTERNAL;
1828ccb1352eSJesse Gross 	parms.options = NULL;
1829ccb1352eSJesse Gross 	parms.dp = dp;
1830ccb1352eSJesse Gross 	parms.port_no = OVSP_LOCAL;
18315cd667b0SAlex Wang 	parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
183254c4ef34SAndrey Zhadchenko 	parms.desired_ifindex = a[OVS_DP_ATTR_IFINDEX]
1833a552bfa1SJakub Kicinski 		? nla_get_s32(a[OVS_DP_ATTR_IFINDEX]) : 0;
1834ccb1352eSJesse Gross 
18356093ae9aSJarno Rajahalme 	/* So far only local changes have been made, now need the lock. */
18366093ae9aSJarno Rajahalme 	ovs_lock();
18376093ae9aSJarno Rajahalme 
1838fea07a48SEelco Chaudron 	err = ovs_dp_change(dp, a);
1839fea07a48SEelco Chaudron 	if (err)
1840fea07a48SEelco Chaudron 		goto err_unlock_and_destroy_meters;
1841fea07a48SEelco Chaudron 
1842ccb1352eSJesse Gross 	vport = new_vport(&parms);
1843ccb1352eSJesse Gross 	if (IS_ERR(vport)) {
1844ccb1352eSJesse Gross 		err = PTR_ERR(vport);
1845ccb1352eSJesse Gross 		if (err == -EBUSY)
1846ccb1352eSJesse Gross 			err = -EEXIST;
1847ccb1352eSJesse Gross 
184844da5ae5SThomas Graf 		if (err == -EEXIST) {
184944da5ae5SThomas Graf 			/* An outdated user space instance that does not understand
185044da5ae5SThomas Graf 			 * the concept of user_features has attempted to create a new
185144da5ae5SThomas Graf 			 * datapath and is likely to reuse it. Drop all user features.
185244da5ae5SThomas Graf 			 */
185344da5ae5SThomas Graf 			if (info->genlhdr->version < OVS_DP_VER_FEATURES)
185444da5ae5SThomas Graf 				ovs_dp_reset_user_features(skb, info);
185544da5ae5SThomas Graf 		}
185644da5ae5SThomas Graf 
1857a87406f4SAndrey Zhadchenko 		goto err_destroy_portids;
1858ccb1352eSJesse Gross 	}
1859ccb1352eSJesse Gross 
18606093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18616093ae9aSJarno Rajahalme 				   info->snd_seq, 0, OVS_DP_CMD_NEW);
18626093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
1863ccb1352eSJesse Gross 
186446df7b81SPravin B Shelar 	ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
186559a35d60SPravin B Shelar 	list_add_tail_rcu(&dp->list_node, &ovs_net->dps);
18668e4e1713SPravin B Shelar 
18678e4e1713SPravin B Shelar 	ovs_unlock();
1868ccb1352eSJesse Gross 
18692a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1870ccb1352eSJesse Gross 	return 0;
1871ccb1352eSJesse Gross 
1872a87406f4SAndrey Zhadchenko err_destroy_portids:
1873a87406f4SAndrey Zhadchenko 	kfree(rcu_dereference_raw(dp->upcall_portids));
1874fea07a48SEelco Chaudron err_unlock_and_destroy_meters:
1875fea07a48SEelco Chaudron 	ovs_unlock();
187696fbc13dSAndy Zhou 	ovs_meters_exit(dp);
1877eec62eadSTonghao Zhang err_destroy_ports:
187815eac2a7SPravin B Shelar 	kfree(dp->ports);
1879eec62eadSTonghao Zhang err_destroy_stats:
1880ccb1352eSJesse Gross 	free_percpu(dp->stats_percpu);
1881ccb1352eSJesse Gross err_destroy_table:
18829b996e54SPravin B Shelar 	ovs_flow_tbl_destroy(&dp->table);
1883eec62eadSTonghao Zhang err_destroy_dp:
1884ccb1352eSJesse Gross 	kfree(dp);
1885eec62eadSTonghao Zhang err_destroy_reply:
18866093ae9aSJarno Rajahalme 	kfree_skb(reply);
1887ccb1352eSJesse Gross err:
1888ccb1352eSJesse Gross 	return err;
1889ccb1352eSJesse Gross }
1890ccb1352eSJesse Gross 
18918e4e1713SPravin B Shelar /* Called with ovs_mutex. */
__dp_destroy(struct datapath * dp)189246df7b81SPravin B Shelar static void __dp_destroy(struct datapath *dp)
1893ccb1352eSJesse Gross {
18941f3a090bSTonghao Zhang 	struct flow_table *table = &dp->table;
189515eac2a7SPravin B Shelar 	int i;
1896ccb1352eSJesse Gross 
189735d39fecSPaul Blakey 	if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
189835d39fecSPaul Blakey 		tc_skb_ext_tc_disable();
189935d39fecSPaul Blakey 
190015eac2a7SPravin B Shelar 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
190115eac2a7SPravin B Shelar 		struct vport *vport;
1902b67bfe0dSSasha Levin 		struct hlist_node *n;
190315eac2a7SPravin B Shelar 
1904b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node)
1905ccb1352eSJesse Gross 			if (vport->port_no != OVSP_LOCAL)
1906ccb1352eSJesse Gross 				ovs_dp_detach_port(vport);
190715eac2a7SPravin B Shelar 	}
1908ccb1352eSJesse Gross 
190959a35d60SPravin B Shelar 	list_del_rcu(&dp->list_node);
1910ccb1352eSJesse Gross 
19118e4e1713SPravin B Shelar 	/* OVSP_LOCAL is datapath internal port. We need to make sure that
1912e80857ccSAndy Zhou 	 * all ports in datapath are destroyed first before freeing datapath.
1913ccb1352eSJesse Gross 	 */
19148e4e1713SPravin B Shelar 	ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
1915ccb1352eSJesse Gross 
19161f3a090bSTonghao Zhang 	/* Flush sw_flow in the tables. RCU cb only releases resource
19171f3a090bSTonghao Zhang 	 * such as dp, ports and tables. That may avoid some issues
19181f3a090bSTonghao Zhang 	 * such as RCU usage warning.
19191f3a090bSTonghao Zhang 	 */
19201f3a090bSTonghao Zhang 	table_instance_flow_flush(table, ovsl_dereference(table->ti),
19211f3a090bSTonghao Zhang 				  ovsl_dereference(table->ufid_ti));
19221f3a090bSTonghao Zhang 
19231f3a090bSTonghao Zhang 	/* RCU destroy the ports, meters and flow tables. */
1924ccb1352eSJesse Gross 	call_rcu(&dp->rcu, destroy_dp_rcu);
192546df7b81SPravin B Shelar }
192646df7b81SPravin B Shelar 
ovs_dp_cmd_del(struct sk_buff * skb,struct genl_info * info)192746df7b81SPravin B Shelar static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
192846df7b81SPravin B Shelar {
192946df7b81SPravin B Shelar 	struct sk_buff *reply;
193046df7b81SPravin B Shelar 	struct datapath *dp;
193146df7b81SPravin B Shelar 	int err;
193246df7b81SPravin B Shelar 
1933263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
19346093ae9aSJarno Rajahalme 	if (!reply)
19356093ae9aSJarno Rajahalme 		return -ENOMEM;
19366093ae9aSJarno Rajahalme 
19378e4e1713SPravin B Shelar 	ovs_lock();
1938bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1939bffcc688SJakub Kicinski 			     info->attrs);
194046df7b81SPravin B Shelar 	err = PTR_ERR(dp);
194146df7b81SPravin B Shelar 	if (IS_ERR(dp))
19426093ae9aSJarno Rajahalme 		goto err_unlock_free;
194346df7b81SPravin B Shelar 
19446093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
19456093ae9aSJarno Rajahalme 				   info->snd_seq, 0, OVS_DP_CMD_DEL);
19466093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
194746df7b81SPravin B Shelar 
194846df7b81SPravin B Shelar 	__dp_destroy(dp);
19498e4e1713SPravin B Shelar 	ovs_unlock();
1950ccb1352eSJesse Gross 
19512a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1952ccb1352eSJesse Gross 
1953ccb1352eSJesse Gross 	return 0;
19546093ae9aSJarno Rajahalme 
19556093ae9aSJarno Rajahalme err_unlock_free:
19568e4e1713SPravin B Shelar 	ovs_unlock();
19576093ae9aSJarno Rajahalme 	kfree_skb(reply);
19588e4e1713SPravin B Shelar 	return err;
1959ccb1352eSJesse Gross }
1960ccb1352eSJesse Gross 
ovs_dp_cmd_set(struct sk_buff * skb,struct genl_info * info)1961ccb1352eSJesse Gross static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
1962ccb1352eSJesse Gross {
1963ccb1352eSJesse Gross 	struct sk_buff *reply;
1964ccb1352eSJesse Gross 	struct datapath *dp;
1965ccb1352eSJesse Gross 	int err;
1966ccb1352eSJesse Gross 
1967263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
19686093ae9aSJarno Rajahalme 	if (!reply)
19696093ae9aSJarno Rajahalme 		return -ENOMEM;
19706093ae9aSJarno Rajahalme 
19718e4e1713SPravin B Shelar 	ovs_lock();
1972bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1973bffcc688SJakub Kicinski 			     info->attrs);
19748e4e1713SPravin B Shelar 	err = PTR_ERR(dp);
1975ccb1352eSJesse Gross 	if (IS_ERR(dp))
19766093ae9aSJarno Rajahalme 		goto err_unlock_free;
1977ccb1352eSJesse Gross 
197895a7233cSPaul Blakey 	err = ovs_dp_change(dp, info->attrs);
197995a7233cSPaul Blakey 	if (err)
198095a7233cSPaul Blakey 		goto err_unlock_free;
198143d4be9cSThomas Graf 
19826093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1983804fe108SYifeng Sun 				   info->snd_seq, 0, OVS_DP_CMD_SET);
19846093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
1985ccb1352eSJesse Gross 
19868e4e1713SPravin B Shelar 	ovs_unlock();
19872a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1988ccb1352eSJesse Gross 
1989ccb1352eSJesse Gross 	return 0;
19906093ae9aSJarno Rajahalme 
19916093ae9aSJarno Rajahalme err_unlock_free:
19928e4e1713SPravin B Shelar 	ovs_unlock();
19936093ae9aSJarno Rajahalme 	kfree_skb(reply);
19948e4e1713SPravin B Shelar 	return err;
1995ccb1352eSJesse Gross }
1996ccb1352eSJesse Gross 
ovs_dp_cmd_get(struct sk_buff * skb,struct genl_info * info)1997ccb1352eSJesse Gross static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
1998ccb1352eSJesse Gross {
1999ccb1352eSJesse Gross 	struct sk_buff *reply;
2000ccb1352eSJesse Gross 	struct datapath *dp;
20018e4e1713SPravin B Shelar 	int err;
2002ccb1352eSJesse Gross 
2003263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
20046093ae9aSJarno Rajahalme 	if (!reply)
20056093ae9aSJarno Rajahalme 		return -ENOMEM;
20066093ae9aSJarno Rajahalme 
20078ec609d8SPravin B Shelar 	ovs_lock();
2008bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
2009bffcc688SJakub Kicinski 			     info->attrs);
20108e4e1713SPravin B Shelar 	if (IS_ERR(dp)) {
20118e4e1713SPravin B Shelar 		err = PTR_ERR(dp);
20126093ae9aSJarno Rajahalme 		goto err_unlock_free;
20138e4e1713SPravin B Shelar 	}
20146093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
2015804fe108SYifeng Sun 				   info->snd_seq, 0, OVS_DP_CMD_GET);
20166093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
20178ec609d8SPravin B Shelar 	ovs_unlock();
2018ccb1352eSJesse Gross 
2019ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
20208e4e1713SPravin B Shelar 
20216093ae9aSJarno Rajahalme err_unlock_free:
20228ec609d8SPravin B Shelar 	ovs_unlock();
20236093ae9aSJarno Rajahalme 	kfree_skb(reply);
20248e4e1713SPravin B Shelar 	return err;
2025ccb1352eSJesse Gross }
2026ccb1352eSJesse Gross 
ovs_dp_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)2027ccb1352eSJesse Gross static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
2028ccb1352eSJesse Gross {
202946df7b81SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id);
2030ccb1352eSJesse Gross 	struct datapath *dp;
2031ccb1352eSJesse Gross 	int skip = cb->args[0];
2032ccb1352eSJesse Gross 	int i = 0;
2033ccb1352eSJesse Gross 
20348ec609d8SPravin B Shelar 	ovs_lock();
20358ec609d8SPravin B Shelar 	list_for_each_entry(dp, &ovs_net->dps, list_node) {
203677676fdbSBen Pfaff 		if (i >= skip &&
203715e47304SEric W. Biederman 		    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
2038ccb1352eSJesse Gross 					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
2039804fe108SYifeng Sun 					 OVS_DP_CMD_GET) < 0)
2040ccb1352eSJesse Gross 			break;
2041ccb1352eSJesse Gross 		i++;
2042ccb1352eSJesse Gross 	}
20438ec609d8SPravin B Shelar 	ovs_unlock();
2044ccb1352eSJesse Gross 
2045ccb1352eSJesse Gross 	cb->args[0] = i;
2046ccb1352eSJesse Gross 
2047ccb1352eSJesse Gross 	return skb->len;
2048ccb1352eSJesse Gross }
2049ccb1352eSJesse Gross 
20500c200ef9SPravin B Shelar static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
20510c200ef9SPravin B Shelar 	[OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
20520c200ef9SPravin B Shelar 	[OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
20530c200ef9SPravin B Shelar 	[OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
20549bf24f59SEelco Chaudron 	[OVS_DP_ATTR_MASKS_CACHE_SIZE] =  NLA_POLICY_RANGE(NLA_U32, 0,
20559bf24f59SEelco Chaudron 		PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
2056a552bfa1SJakub Kicinski 	[OVS_DP_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
20570c200ef9SPravin B Shelar };
20580c200ef9SPravin B Shelar 
205966a9b928SJakub Kicinski static const struct genl_small_ops dp_datapath_genl_ops[] = {
2060ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_NEW,
2061ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20624a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2063ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_new
2064ccb1352eSJesse Gross 	},
2065ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_DEL,
2066ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20674a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2068ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_del
2069ccb1352eSJesse Gross 	},
2070ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_GET,
2071ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2072ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
2073ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_get,
2074ccb1352eSJesse Gross 	  .dumpit = ovs_dp_cmd_dump
2075ccb1352eSJesse Gross 	},
2076ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_SET,
2077ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20784a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2079ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_set,
2080ccb1352eSJesse Gross 	},
2081ccb1352eSJesse Gross };
2082ccb1352eSJesse Gross 
208356989f6dSJohannes Berg static struct genl_family dp_datapath_genl_family __ro_after_init = {
2084ccb1352eSJesse Gross 	.hdrsize = sizeof(struct ovs_header),
20850c200ef9SPravin B Shelar 	.name = OVS_DATAPATH_FAMILY,
20860c200ef9SPravin B Shelar 	.version = OVS_DATAPATH_VERSION,
20870c200ef9SPravin B Shelar 	.maxattr = OVS_DP_ATTR_MAX,
20883b0f31f2SJohannes Berg 	.policy = datapath_policy,
20893a4e0d6aSPravin B Shelar 	.netnsok = true,
20903a4e0d6aSPravin B Shelar 	.parallel_ops = true,
209166a9b928SJakub Kicinski 	.small_ops = dp_datapath_genl_ops,
209266a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_datapath_genl_ops),
20939c5d03d3SJakub Kicinski 	.resv_start_op = OVS_DP_CMD_SET + 1,
20940c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_datapath_multicast_group,
20950c200ef9SPravin B Shelar 	.n_mcgrps = 1,
2096489111e5SJohannes Berg 	.module = THIS_MODULE,
2097ccb1352eSJesse Gross };
2098ccb1352eSJesse Gross 
20998e4e1713SPravin B Shelar /* Called with ovs_mutex or RCU read lock. */
ovs_vport_cmd_fill_info(struct vport * vport,struct sk_buff * skb,struct net * net,u32 portid,u32 seq,u32 flags,u8 cmd,gfp_t gfp)2100ccb1352eSJesse Gross static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
21019354d452SJiri Benc 				   struct net *net, u32 portid, u32 seq,
2102d4e4fdf9SGuillaume Nault 				   u32 flags, u8 cmd, gfp_t gfp)
2103ccb1352eSJesse Gross {
2104ccb1352eSJesse Gross 	struct ovs_header *ovs_header;
2105ccb1352eSJesse Gross 	struct ovs_vport_stats vport_stats;
2106*8ec57509SEric Dumazet 	struct net *net_vport;
2107ccb1352eSJesse Gross 	int err;
2108ccb1352eSJesse Gross 
210915e47304SEric W. Biederman 	ovs_header = genlmsg_put(skb, portid, seq, &dp_vport_genl_family,
2110ccb1352eSJesse Gross 				 flags, cmd);
2111ccb1352eSJesse Gross 	if (!ovs_header)
2112ccb1352eSJesse Gross 		return -EMSGSIZE;
2113ccb1352eSJesse Gross 
2114ccb1352eSJesse Gross 	ovs_header->dp_ifindex = get_dpifindex(vport->dp);
2115ccb1352eSJesse Gross 
2116028d6a67SDavid S. Miller 	if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
2117028d6a67SDavid S. Miller 	    nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
21185cd667b0SAlex Wang 	    nla_put_string(skb, OVS_VPORT_ATTR_NAME,
21199354d452SJiri Benc 			   ovs_vport_name(vport)) ||
21209354d452SJiri Benc 	    nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex))
2121028d6a67SDavid S. Miller 		goto nla_put_failure;
2122ccb1352eSJesse Gross 
2123*8ec57509SEric Dumazet 	rcu_read_lock();
2124*8ec57509SEric Dumazet 	net_vport = dev_net_rcu(vport->dev);
2125*8ec57509SEric Dumazet 	if (!net_eq(net, net_vport)) {
2126*8ec57509SEric Dumazet 		int id = peernet2id_alloc(net, net_vport, GFP_ATOMIC);
21279354d452SJiri Benc 
21289354d452SJiri Benc 		if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
2129*8ec57509SEric Dumazet 			goto nla_put_failure_unlock;
21309354d452SJiri Benc 	}
2131*8ec57509SEric Dumazet 	rcu_read_unlock();
21329354d452SJiri Benc 
2133ccb1352eSJesse Gross 	ovs_vport_get_stats(vport, &vport_stats);
213466c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
213566c7a5eeSNicolas Dichtel 			  sizeof(struct ovs_vport_stats), &vport_stats,
213666c7a5eeSNicolas Dichtel 			  OVS_VPORT_ATTR_PAD))
2137028d6a67SDavid S. Miller 		goto nla_put_failure;
2138ccb1352eSJesse Gross 
21391933ea36Swangchuanlei 	if (ovs_vport_get_upcall_stats(vport, skb))
21401933ea36Swangchuanlei 		goto nla_put_failure;
21411933ea36Swangchuanlei 
21425cd667b0SAlex Wang 	if (ovs_vport_get_upcall_portids(vport, skb))
21435cd667b0SAlex Wang 		goto nla_put_failure;
21445cd667b0SAlex Wang 
2145ccb1352eSJesse Gross 	err = ovs_vport_get_options(vport, skb);
2146ccb1352eSJesse Gross 	if (err == -EMSGSIZE)
2147ccb1352eSJesse Gross 		goto error;
2148ccb1352eSJesse Gross 
2149053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
2150053c095aSJohannes Berg 	return 0;
2151ccb1352eSJesse Gross 
2152*8ec57509SEric Dumazet nla_put_failure_unlock:
2153*8ec57509SEric Dumazet 	rcu_read_unlock();
2154ccb1352eSJesse Gross nla_put_failure:
2155ccb1352eSJesse Gross 	err = -EMSGSIZE;
2156ccb1352eSJesse Gross error:
2157ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
2158ccb1352eSJesse Gross 	return err;
2159ccb1352eSJesse Gross }
2160ccb1352eSJesse Gross 
ovs_vport_cmd_alloc_info(void)21616093ae9aSJarno Rajahalme static struct sk_buff *ovs_vport_cmd_alloc_info(void)
21626093ae9aSJarno Rajahalme {
21636093ae9aSJarno Rajahalme 	return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
21646093ae9aSJarno Rajahalme }
21656093ae9aSJarno Rajahalme 
21666093ae9aSJarno Rajahalme /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
ovs_vport_cmd_build_info(struct vport * vport,struct net * net,u32 portid,u32 seq,u8 cmd)21679354d452SJiri Benc struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
21689354d452SJiri Benc 					 u32 portid, u32 seq, u8 cmd)
2169ccb1352eSJesse Gross {
2170ccb1352eSJesse Gross 	struct sk_buff *skb;
2171ccb1352eSJesse Gross 	int retval;
2172ccb1352eSJesse Gross 
2173d4e4fdf9SGuillaume Nault 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2174ccb1352eSJesse Gross 	if (!skb)
2175ccb1352eSJesse Gross 		return ERR_PTR(-ENOMEM);
2176ccb1352eSJesse Gross 
2177d4e4fdf9SGuillaume Nault 	retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd,
2178d4e4fdf9SGuillaume Nault 					 GFP_KERNEL);
2179a9341512SJesse Gross 	BUG_ON(retval < 0);
2180a9341512SJesse Gross 
2181ccb1352eSJesse Gross 	return skb;
2182ccb1352eSJesse Gross }
2183ccb1352eSJesse Gross 
21848e4e1713SPravin B Shelar /* Called with ovs_mutex or RCU read lock. */
lookup_vport(struct net * net,const struct ovs_header * ovs_header,struct nlattr * a[OVS_VPORT_ATTR_MAX+1])218546df7b81SPravin B Shelar static struct vport *lookup_vport(struct net *net,
218612eb18f7SThomas Graf 				  const struct ovs_header *ovs_header,
2187ccb1352eSJesse Gross 				  struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
2188ccb1352eSJesse Gross {
2189ccb1352eSJesse Gross 	struct datapath *dp;
2190ccb1352eSJesse Gross 	struct vport *vport;
2191ccb1352eSJesse Gross 
21929354d452SJiri Benc 	if (a[OVS_VPORT_ATTR_IFINDEX])
21939354d452SJiri Benc 		return ERR_PTR(-EOPNOTSUPP);
2194ccb1352eSJesse Gross 	if (a[OVS_VPORT_ATTR_NAME]) {
219546df7b81SPravin B Shelar 		vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME]));
2196ccb1352eSJesse Gross 		if (!vport)
2197ccb1352eSJesse Gross 			return ERR_PTR(-ENODEV);
2198651a68eaSBen Pfaff 		if (ovs_header->dp_ifindex &&
2199651a68eaSBen Pfaff 		    ovs_header->dp_ifindex != get_dpifindex(vport->dp))
2200651a68eaSBen Pfaff 			return ERR_PTR(-ENODEV);
2201ccb1352eSJesse Gross 		return vport;
2202ccb1352eSJesse Gross 	} else if (a[OVS_VPORT_ATTR_PORT_NO]) {
2203ccb1352eSJesse Gross 		u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
2204ccb1352eSJesse Gross 
2205ccb1352eSJesse Gross 		if (port_no >= DP_MAX_PORTS)
2206ccb1352eSJesse Gross 			return ERR_PTR(-EFBIG);
2207ccb1352eSJesse Gross 
220846df7b81SPravin B Shelar 		dp = get_dp(net, ovs_header->dp_ifindex);
2209ccb1352eSJesse Gross 		if (!dp)
2210ccb1352eSJesse Gross 			return ERR_PTR(-ENODEV);
2211ccb1352eSJesse Gross 
22128e4e1713SPravin B Shelar 		vport = ovs_vport_ovsl_rcu(dp, port_no);
2213ccb1352eSJesse Gross 		if (!vport)
221414408dbaSJarno Rajahalme 			return ERR_PTR(-ENODEV);
2215ccb1352eSJesse Gross 		return vport;
2216ccb1352eSJesse Gross 	} else
2217ccb1352eSJesse Gross 		return ERR_PTR(-EINVAL);
22189354d452SJiri Benc 
2219ccb1352eSJesse Gross }
2220ccb1352eSJesse Gross 
ovs_get_max_headroom(struct datapath * dp)22216b660c41STaehee Yoo static unsigned int ovs_get_max_headroom(struct datapath *dp)
22223a927bc7SPaolo Abeni {
22236b660c41STaehee Yoo 	unsigned int dev_headroom, max_headroom = 0;
22243a927bc7SPaolo Abeni 	struct net_device *dev;
22253a927bc7SPaolo Abeni 	struct vport *vport;
22263a927bc7SPaolo Abeni 	int i;
22273a927bc7SPaolo Abeni 
22283a927bc7SPaolo Abeni 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
222953742e69SMadhuparna Bhowmik 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
223053742e69SMadhuparna Bhowmik 					 lockdep_ovsl_is_held()) {
22313a927bc7SPaolo Abeni 			dev = vport->dev;
22323a927bc7SPaolo Abeni 			dev_headroom = netdev_get_fwd_headroom(dev);
22333a927bc7SPaolo Abeni 			if (dev_headroom > max_headroom)
22343a927bc7SPaolo Abeni 				max_headroom = dev_headroom;
22353a927bc7SPaolo Abeni 		}
22363a927bc7SPaolo Abeni 	}
22373a927bc7SPaolo Abeni 
22386b660c41STaehee Yoo 	return max_headroom;
22396b660c41STaehee Yoo }
22406b660c41STaehee Yoo 
22416b660c41STaehee Yoo /* Called with ovs_mutex */
ovs_update_headroom(struct datapath * dp,unsigned int new_headroom)22426b660c41STaehee Yoo static void ovs_update_headroom(struct datapath *dp, unsigned int new_headroom)
22436b660c41STaehee Yoo {
22446b660c41STaehee Yoo 	struct vport *vport;
22456b660c41STaehee Yoo 	int i;
22466b660c41STaehee Yoo 
22476b660c41STaehee Yoo 	dp->max_headroom = new_headroom;
2248cf3266adSTonghao Zhang 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
224953742e69SMadhuparna Bhowmik 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
225053742e69SMadhuparna Bhowmik 					 lockdep_ovsl_is_held())
22516b660c41STaehee Yoo 			netdev_set_rx_headroom(vport->dev, new_headroom);
22523a927bc7SPaolo Abeni 	}
2253cf3266adSTonghao Zhang }
22543a927bc7SPaolo Abeni 
ovs_vport_cmd_new(struct sk_buff * skb,struct genl_info * info)2255ccb1352eSJesse Gross static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
2256ccb1352eSJesse Gross {
2257ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2258bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
2259ccb1352eSJesse Gross 	struct vport_parms parms;
2260ccb1352eSJesse Gross 	struct sk_buff *reply;
2261ccb1352eSJesse Gross 	struct vport *vport;
2262ccb1352eSJesse Gross 	struct datapath *dp;
22636b660c41STaehee Yoo 	unsigned int new_headroom;
2264ccb1352eSJesse Gross 	u32 port_no;
2265ccb1352eSJesse Gross 	int err;
2266ccb1352eSJesse Gross 
2267ccb1352eSJesse Gross 	if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
2268ccb1352eSJesse Gross 	    !a[OVS_VPORT_ATTR_UPCALL_PID])
22696093ae9aSJarno Rajahalme 		return -EINVAL;
227054c4ef34SAndrey Zhadchenko 
227154c4ef34SAndrey Zhadchenko 	parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]);
227254c4ef34SAndrey Zhadchenko 
227354c4ef34SAndrey Zhadchenko 	if (a[OVS_VPORT_ATTR_IFINDEX] && parms.type != OVS_VPORT_TYPE_INTERNAL)
22749354d452SJiri Benc 		return -EOPNOTSUPP;
22756093ae9aSJarno Rajahalme 
22766093ae9aSJarno Rajahalme 	port_no = a[OVS_VPORT_ATTR_PORT_NO]
22776093ae9aSJarno Rajahalme 		? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
22786093ae9aSJarno Rajahalme 	if (port_no >= DP_MAX_PORTS)
22796093ae9aSJarno Rajahalme 		return -EFBIG;
22806093ae9aSJarno Rajahalme 
22816093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
22826093ae9aSJarno Rajahalme 	if (!reply)
22836093ae9aSJarno Rajahalme 		return -ENOMEM;
2284ccb1352eSJesse Gross 
22858e4e1713SPravin B Shelar 	ovs_lock();
228662b9c8d0SThomas Graf restart:
228746df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
2288ccb1352eSJesse Gross 	err = -ENODEV;
2289ccb1352eSJesse Gross 	if (!dp)
22906093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2291ccb1352eSJesse Gross 
22926093ae9aSJarno Rajahalme 	if (port_no) {
22938e4e1713SPravin B Shelar 		vport = ovs_vport_ovsl(dp, port_no);
2294ccb1352eSJesse Gross 		err = -EBUSY;
2295ccb1352eSJesse Gross 		if (vport)
22966093ae9aSJarno Rajahalme 			goto exit_unlock_free;
2297ccb1352eSJesse Gross 	} else {
2298ccb1352eSJesse Gross 		for (port_no = 1; ; port_no++) {
2299ccb1352eSJesse Gross 			if (port_no >= DP_MAX_PORTS) {
2300ccb1352eSJesse Gross 				err = -EFBIG;
23016093ae9aSJarno Rajahalme 				goto exit_unlock_free;
2302ccb1352eSJesse Gross 			}
23038e4e1713SPravin B Shelar 			vport = ovs_vport_ovsl(dp, port_no);
2304ccb1352eSJesse Gross 			if (!vport)
2305ccb1352eSJesse Gross 				break;
2306ccb1352eSJesse Gross 		}
2307ccb1352eSJesse Gross 	}
2308ccb1352eSJesse Gross 
2309ccb1352eSJesse Gross 	parms.name = nla_data(a[OVS_VPORT_ATTR_NAME]);
2310ccb1352eSJesse Gross 	parms.options = a[OVS_VPORT_ATTR_OPTIONS];
2311ccb1352eSJesse Gross 	parms.dp = dp;
2312ccb1352eSJesse Gross 	parms.port_no = port_no;
23135cd667b0SAlex Wang 	parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
231454c4ef34SAndrey Zhadchenko 	parms.desired_ifindex = a[OVS_VPORT_ATTR_IFINDEX]
2315a552bfa1SJakub Kicinski 		? nla_get_s32(a[OVS_VPORT_ATTR_IFINDEX]) : 0;
2316ccb1352eSJesse Gross 
2317ccb1352eSJesse Gross 	vport = new_vport(&parms);
2318ccb1352eSJesse Gross 	err = PTR_ERR(vport);
231962b9c8d0SThomas Graf 	if (IS_ERR(vport)) {
232062b9c8d0SThomas Graf 		if (err == -EAGAIN)
232162b9c8d0SThomas Graf 			goto restart;
23226093ae9aSJarno Rajahalme 		goto exit_unlock_free;
232362b9c8d0SThomas Graf 	}
2324ccb1352eSJesse Gross 
23259354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23269354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2327d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_NEW, GFP_KERNEL);
23283a927bc7SPaolo Abeni 
23296b660c41STaehee Yoo 	new_headroom = netdev_get_fwd_headroom(vport->dev);
23306b660c41STaehee Yoo 
23316b660c41STaehee Yoo 	if (new_headroom > dp->max_headroom)
23326b660c41STaehee Yoo 		ovs_update_headroom(dp, new_headroom);
23333a927bc7SPaolo Abeni 	else
23343a927bc7SPaolo Abeni 		netdev_set_rx_headroom(vport->dev, dp->max_headroom);
23353a927bc7SPaolo Abeni 
23366093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
23376093ae9aSJarno Rajahalme 	ovs_unlock();
2338ed661185SThomas Graf 
23392a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
23406093ae9aSJarno Rajahalme 	return 0;
2341ccb1352eSJesse Gross 
23426093ae9aSJarno Rajahalme exit_unlock_free:
23438e4e1713SPravin B Shelar 	ovs_unlock();
23446093ae9aSJarno Rajahalme 	kfree_skb(reply);
2345ccb1352eSJesse Gross 	return err;
2346ccb1352eSJesse Gross }
2347ccb1352eSJesse Gross 
ovs_vport_cmd_set(struct sk_buff * skb,struct genl_info * info)2348ccb1352eSJesse Gross static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
2349ccb1352eSJesse Gross {
2350ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2351ccb1352eSJesse Gross 	struct sk_buff *reply;
2352ccb1352eSJesse Gross 	struct vport *vport;
2353ccb1352eSJesse Gross 	int err;
2354ccb1352eSJesse Gross 
23556093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
23566093ae9aSJarno Rajahalme 	if (!reply)
23576093ae9aSJarno Rajahalme 		return -ENOMEM;
23586093ae9aSJarno Rajahalme 
23598e4e1713SPravin B Shelar 	ovs_lock();
2360bffcc688SJakub Kicinski 	vport = lookup_vport(sock_net(skb->sk), genl_info_userhdr(info), a);
2361ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2362ccb1352eSJesse Gross 	if (IS_ERR(vport))
23636093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2364ccb1352eSJesse Gross 
2365ccb1352eSJesse Gross 	if (a[OVS_VPORT_ATTR_TYPE] &&
2366f44f3408SJesse Gross 	    nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) {
2367ccb1352eSJesse Gross 		err = -EINVAL;
23686093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2369a9341512SJesse Gross 	}
2370a9341512SJesse Gross 
2371f44f3408SJesse Gross 	if (a[OVS_VPORT_ATTR_OPTIONS]) {
2372ccb1352eSJesse Gross 		err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
237303fbf8b3SAnsis Atteka 		if (err)
23746093ae9aSJarno Rajahalme 			goto exit_unlock_free;
2375f44f3408SJesse Gross 	}
2376a9341512SJesse Gross 
23775cd667b0SAlex Wang 
23785cd667b0SAlex Wang 	if (a[OVS_VPORT_ATTR_UPCALL_PID]) {
23795cd667b0SAlex Wang 		struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID];
23805cd667b0SAlex Wang 
23815cd667b0SAlex Wang 		err = ovs_vport_set_upcall_portids(vport, ids);
23825cd667b0SAlex Wang 		if (err)
23835cd667b0SAlex Wang 			goto exit_unlock_free;
23845cd667b0SAlex Wang 	}
2385ccb1352eSJesse Gross 
23869354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23879354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2388d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_SET, GFP_KERNEL);
2389a9341512SJesse Gross 	BUG_ON(err < 0);
2390ccb1352eSJesse Gross 
23918e4e1713SPravin B Shelar 	ovs_unlock();
23922a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
23938e4e1713SPravin B Shelar 	return 0;
2394ccb1352eSJesse Gross 
23956093ae9aSJarno Rajahalme exit_unlock_free:
23968e4e1713SPravin B Shelar 	ovs_unlock();
23976093ae9aSJarno Rajahalme 	kfree_skb(reply);
2398ccb1352eSJesse Gross 	return err;
2399ccb1352eSJesse Gross }
2400ccb1352eSJesse Gross 
ovs_vport_cmd_del(struct sk_buff * skb,struct genl_info * info)2401ccb1352eSJesse Gross static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
2402ccb1352eSJesse Gross {
24036b660c41STaehee Yoo 	bool update_headroom = false;
2404ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2405ccb1352eSJesse Gross 	struct sk_buff *reply;
24063a927bc7SPaolo Abeni 	struct datapath *dp;
2407ccb1352eSJesse Gross 	struct vport *vport;
24086b660c41STaehee Yoo 	unsigned int new_headroom;
2409ccb1352eSJesse Gross 	int err;
2410ccb1352eSJesse Gross 
24116093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
24126093ae9aSJarno Rajahalme 	if (!reply)
24136093ae9aSJarno Rajahalme 		return -ENOMEM;
24146093ae9aSJarno Rajahalme 
24158e4e1713SPravin B Shelar 	ovs_lock();
2416bffcc688SJakub Kicinski 	vport = lookup_vport(sock_net(skb->sk), genl_info_userhdr(info), a);
2417ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2418ccb1352eSJesse Gross 	if (IS_ERR(vport))
24196093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2420ccb1352eSJesse Gross 
2421ccb1352eSJesse Gross 	if (vport->port_no == OVSP_LOCAL) {
2422ccb1352eSJesse Gross 		err = -EINVAL;
24236093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2424ccb1352eSJesse Gross 	}
2425ccb1352eSJesse Gross 
24269354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
24279354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2428d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_DEL, GFP_KERNEL);
24296093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
24303a927bc7SPaolo Abeni 
24313a927bc7SPaolo Abeni 	/* the vport deletion may trigger dp headroom update */
24323a927bc7SPaolo Abeni 	dp = vport->dp;
24333a927bc7SPaolo Abeni 	if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
24346b660c41STaehee Yoo 		update_headroom = true;
24356b660c41STaehee Yoo 
24363a927bc7SPaolo Abeni 	netdev_reset_rx_headroom(vport->dev);
2437ccb1352eSJesse Gross 	ovs_dp_detach_port(vport);
24383a927bc7SPaolo Abeni 
24396b660c41STaehee Yoo 	if (update_headroom) {
24406b660c41STaehee Yoo 		new_headroom = ovs_get_max_headroom(dp);
24416b660c41STaehee Yoo 
24426b660c41STaehee Yoo 		if (new_headroom < dp->max_headroom)
24436b660c41STaehee Yoo 			ovs_update_headroom(dp, new_headroom);
24446b660c41STaehee Yoo 	}
24456093ae9aSJarno Rajahalme 	ovs_unlock();
2446ccb1352eSJesse Gross 
24472a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
24486093ae9aSJarno Rajahalme 	return 0;
2449ccb1352eSJesse Gross 
24506093ae9aSJarno Rajahalme exit_unlock_free:
24518e4e1713SPravin B Shelar 	ovs_unlock();
24526093ae9aSJarno Rajahalme 	kfree_skb(reply);
2453ccb1352eSJesse Gross 	return err;
2454ccb1352eSJesse Gross }
2455ccb1352eSJesse Gross 
ovs_vport_cmd_get(struct sk_buff * skb,struct genl_info * info)2456ccb1352eSJesse Gross static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
2457ccb1352eSJesse Gross {
2458ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2459bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
2460ccb1352eSJesse Gross 	struct sk_buff *reply;
2461ccb1352eSJesse Gross 	struct vport *vport;
2462ccb1352eSJesse Gross 	int err;
2463ccb1352eSJesse Gross 
24646093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
24656093ae9aSJarno Rajahalme 	if (!reply)
24666093ae9aSJarno Rajahalme 		return -ENOMEM;
24676093ae9aSJarno Rajahalme 
2468ccb1352eSJesse Gross 	rcu_read_lock();
246946df7b81SPravin B Shelar 	vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
2470ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2471ccb1352eSJesse Gross 	if (IS_ERR(vport))
24726093ae9aSJarno Rajahalme 		goto exit_unlock_free;
24739354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
24749354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2475d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_GET, GFP_ATOMIC);
24766093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
2477ccb1352eSJesse Gross 	rcu_read_unlock();
2478ccb1352eSJesse Gross 
2479ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
2480ccb1352eSJesse Gross 
24816093ae9aSJarno Rajahalme exit_unlock_free:
2482ccb1352eSJesse Gross 	rcu_read_unlock();
24836093ae9aSJarno Rajahalme 	kfree_skb(reply);
2484ccb1352eSJesse Gross 	return err;
2485ccb1352eSJesse Gross }
2486ccb1352eSJesse Gross 
ovs_vport_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)2487ccb1352eSJesse Gross static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
2488ccb1352eSJesse Gross {
2489ccb1352eSJesse Gross 	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
2490ccb1352eSJesse Gross 	struct datapath *dp;
249115eac2a7SPravin B Shelar 	int bucket = cb->args[0], skip = cb->args[1];
249215eac2a7SPravin B Shelar 	int i, j = 0;
2493ccb1352eSJesse Gross 
2494ccb1352eSJesse Gross 	rcu_read_lock();
2495cc3a5ae6SAndy Zhou 	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
249642ee19e2SJarno Rajahalme 	if (!dp) {
249742ee19e2SJarno Rajahalme 		rcu_read_unlock();
249842ee19e2SJarno Rajahalme 		return -ENODEV;
249942ee19e2SJarno Rajahalme 	}
250015eac2a7SPravin B Shelar 	for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
2501ccb1352eSJesse Gross 		struct vport *vport;
2502ccb1352eSJesse Gross 
250315eac2a7SPravin B Shelar 		j = 0;
2504b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
250515eac2a7SPravin B Shelar 			if (j >= skip &&
250615eac2a7SPravin B Shelar 			    ovs_vport_cmd_fill_info(vport, skb,
25079354d452SJiri Benc 						    sock_net(skb->sk),
250815e47304SEric W. Biederman 						    NETLINK_CB(cb->skb).portid,
250915eac2a7SPravin B Shelar 						    cb->nlh->nlmsg_seq,
251015eac2a7SPravin B Shelar 						    NLM_F_MULTI,
2511d4e4fdf9SGuillaume Nault 						    OVS_VPORT_CMD_GET,
2512d4e4fdf9SGuillaume Nault 						    GFP_ATOMIC) < 0)
251315eac2a7SPravin B Shelar 				goto out;
251415eac2a7SPravin B Shelar 
251515eac2a7SPravin B Shelar 			j++;
2516ccb1352eSJesse Gross 		}
251715eac2a7SPravin B Shelar 		skip = 0;
251815eac2a7SPravin B Shelar 	}
251915eac2a7SPravin B Shelar out:
2520ccb1352eSJesse Gross 	rcu_read_unlock();
2521ccb1352eSJesse Gross 
252215eac2a7SPravin B Shelar 	cb->args[0] = i;
252315eac2a7SPravin B Shelar 	cb->args[1] = j;
2524ccb1352eSJesse Gross 
252515eac2a7SPravin B Shelar 	return skb->len;
2526ccb1352eSJesse Gross }
2527ccb1352eSJesse Gross 
ovs_dp_masks_rebalance(struct work_struct * work)2528eac87c41SEelco Chaudron static void ovs_dp_masks_rebalance(struct work_struct *work)
2529eac87c41SEelco Chaudron {
2530a65878d6SEelco Chaudron 	struct ovs_net *ovs_net = container_of(work, struct ovs_net,
2531eac87c41SEelco Chaudron 					       masks_rebalance.work);
2532a65878d6SEelco Chaudron 	struct datapath *dp;
2533eac87c41SEelco Chaudron 
2534eac87c41SEelco Chaudron 	ovs_lock();
2535a65878d6SEelco Chaudron 
2536a65878d6SEelco Chaudron 	list_for_each_entry(dp, &ovs_net->dps, list_node)
2537eac87c41SEelco Chaudron 		ovs_flow_masks_rebalance(&dp->table);
2538a65878d6SEelco Chaudron 
2539eac87c41SEelco Chaudron 	ovs_unlock();
2540eac87c41SEelco Chaudron 
2541a65878d6SEelco Chaudron 	schedule_delayed_work(&ovs_net->masks_rebalance,
2542eac87c41SEelco Chaudron 			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
2543eac87c41SEelco Chaudron }
2544eac87c41SEelco Chaudron 
25450c200ef9SPravin B Shelar static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
25460c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
25470c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
25480c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
25490c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
2550ea8564c8SLi RongQing 	[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC },
25510c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
2552a552bfa1SJakub Kicinski 	[OVS_VPORT_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
25539354d452SJiri Benc 	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
25541933ea36Swangchuanlei 	[OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED },
25550c200ef9SPravin B Shelar };
25560c200ef9SPravin B Shelar 
255766a9b928SJakub Kicinski static const struct genl_small_ops dp_vport_genl_ops[] = {
2558ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_NEW,
2559ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25604a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2561ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_new
2562ccb1352eSJesse Gross 	},
2563ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_DEL,
2564ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25654a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2566ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_del
2567ccb1352eSJesse Gross 	},
2568ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_GET,
2569ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2570ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
2571ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_get,
2572ccb1352eSJesse Gross 	  .dumpit = ovs_vport_cmd_dump
2573ccb1352eSJesse Gross 	},
2574ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_SET,
2575ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25764a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2577ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_set,
2578ccb1352eSJesse Gross 	},
2579ccb1352eSJesse Gross };
2580ccb1352eSJesse Gross 
258156989f6dSJohannes Berg struct genl_family dp_vport_genl_family __ro_after_init = {
25820c200ef9SPravin B Shelar 	.hdrsize = sizeof(struct ovs_header),
25830c200ef9SPravin B Shelar 	.name = OVS_VPORT_FAMILY,
25840c200ef9SPravin B Shelar 	.version = OVS_VPORT_VERSION,
25850c200ef9SPravin B Shelar 	.maxattr = OVS_VPORT_ATTR_MAX,
25863b0f31f2SJohannes Berg 	.policy = vport_policy,
25870c200ef9SPravin B Shelar 	.netnsok = true,
25880c200ef9SPravin B Shelar 	.parallel_ops = true,
258966a9b928SJakub Kicinski 	.small_ops = dp_vport_genl_ops,
259066a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_vport_genl_ops),
2591e4ba4554SJakub Kicinski 	.resv_start_op = OVS_VPORT_CMD_SET + 1,
25920c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_vport_multicast_group,
25930c200ef9SPravin B Shelar 	.n_mcgrps = 1,
2594489111e5SJohannes Berg 	.module = THIS_MODULE,
2595ccb1352eSJesse Gross };
2596ccb1352eSJesse Gross 
25970c200ef9SPravin B Shelar static struct genl_family * const dp_genl_families[] = {
25980c200ef9SPravin B Shelar 	&dp_datapath_genl_family,
25990c200ef9SPravin B Shelar 	&dp_vport_genl_family,
26000c200ef9SPravin B Shelar 	&dp_flow_genl_family,
26010c200ef9SPravin B Shelar 	&dp_packet_genl_family,
260296fbc13dSAndy Zhou 	&dp_meter_genl_family,
260311efd5cbSYi-Hung Wei #if	IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
260411efd5cbSYi-Hung Wei 	&dp_ct_limit_genl_family,
260511efd5cbSYi-Hung Wei #endif
2606ccb1352eSJesse Gross };
2607ccb1352eSJesse Gross 
dp_unregister_genl(int n_families)2608ccb1352eSJesse Gross static void dp_unregister_genl(int n_families)
2609ccb1352eSJesse Gross {
2610ccb1352eSJesse Gross 	int i;
2611ccb1352eSJesse Gross 
2612ccb1352eSJesse Gross 	for (i = 0; i < n_families; i++)
26130c200ef9SPravin B Shelar 		genl_unregister_family(dp_genl_families[i]);
2614ccb1352eSJesse Gross }
2615ccb1352eSJesse Gross 
dp_register_genl(void)261656989f6dSJohannes Berg static int __init dp_register_genl(void)
2617ccb1352eSJesse Gross {
2618ccb1352eSJesse Gross 	int err;
2619ccb1352eSJesse Gross 	int i;
2620ccb1352eSJesse Gross 
2621ccb1352eSJesse Gross 	for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
2622ccb1352eSJesse Gross 
26230c200ef9SPravin B Shelar 		err = genl_register_family(dp_genl_families[i]);
2624ccb1352eSJesse Gross 		if (err)
2625ccb1352eSJesse Gross 			goto error;
2626ccb1352eSJesse Gross 	}
2627ccb1352eSJesse Gross 
2628ccb1352eSJesse Gross 	return 0;
2629ccb1352eSJesse Gross 
2630ccb1352eSJesse Gross error:
26310c200ef9SPravin B Shelar 	dp_unregister_genl(i);
2632ccb1352eSJesse Gross 	return err;
2633ccb1352eSJesse Gross }
2634ccb1352eSJesse Gross 
ovs_init_net(struct net * net)263546df7b81SPravin B Shelar static int __net_init ovs_init_net(struct net *net)
263646df7b81SPravin B Shelar {
263746df7b81SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
2638e0afe914SEelco Chaudron 	int err;
263946df7b81SPravin B Shelar 
264046df7b81SPravin B Shelar 	INIT_LIST_HEAD(&ovs_net->dps);
26418e4e1713SPravin B Shelar 	INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
2642a65878d6SEelco Chaudron 	INIT_DELAYED_WORK(&ovs_net->masks_rebalance, ovs_dp_masks_rebalance);
2643e0afe914SEelco Chaudron 
2644e0afe914SEelco Chaudron 	err = ovs_ct_init(net);
2645e0afe914SEelco Chaudron 	if (err)
2646e0afe914SEelco Chaudron 		return err;
2647e0afe914SEelco Chaudron 
2648a65878d6SEelco Chaudron 	schedule_delayed_work(&ovs_net->masks_rebalance,
2649a65878d6SEelco Chaudron 			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
2650e0afe914SEelco Chaudron 	return 0;
265146df7b81SPravin B Shelar }
265246df7b81SPravin B Shelar 
list_vports_from_net(struct net * net,struct net * dnet,struct list_head * head)26537b4577a9SPravin B Shelar static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
26547b4577a9SPravin B Shelar 					    struct list_head *head)
26557b4577a9SPravin B Shelar {
26567b4577a9SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
26577b4577a9SPravin B Shelar 	struct datapath *dp;
26587b4577a9SPravin B Shelar 
26597b4577a9SPravin B Shelar 	list_for_each_entry(dp, &ovs_net->dps, list_node) {
26607b4577a9SPravin B Shelar 		int i;
26617b4577a9SPravin B Shelar 
26627b4577a9SPravin B Shelar 		for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
26637b4577a9SPravin B Shelar 			struct vport *vport;
26647b4577a9SPravin B Shelar 
26657b4577a9SPravin B Shelar 			hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
26667b4577a9SPravin B Shelar 				if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
26677b4577a9SPravin B Shelar 					continue;
26687b4577a9SPravin B Shelar 
2669be4ace6eSThomas Graf 				if (dev_net(vport->dev) == dnet)
26707b4577a9SPravin B Shelar 					list_add(&vport->detach_list, head);
26717b4577a9SPravin B Shelar 			}
26727b4577a9SPravin B Shelar 		}
26737b4577a9SPravin B Shelar 	}
26747b4577a9SPravin B Shelar }
26757b4577a9SPravin B Shelar 
ovs_exit_net(struct net * dnet)26767b4577a9SPravin B Shelar static void __net_exit ovs_exit_net(struct net *dnet)
267746df7b81SPravin B Shelar {
267846df7b81SPravin B Shelar 	struct datapath *dp, *dp_next;
26797b4577a9SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
26807b4577a9SPravin B Shelar 	struct vport *vport, *vport_next;
26817b4577a9SPravin B Shelar 	struct net *net;
26827b4577a9SPravin B Shelar 	LIST_HEAD(head);
268346df7b81SPravin B Shelar 
26848e4e1713SPravin B Shelar 	ovs_lock();
268527de77ceSTonghao Zhang 
268627de77ceSTonghao Zhang 	ovs_ct_exit(dnet);
268727de77ceSTonghao Zhang 
268846df7b81SPravin B Shelar 	list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
268946df7b81SPravin B Shelar 		__dp_destroy(dp);
26907b4577a9SPravin B Shelar 
2691f0b07bb1SKirill Tkhai 	down_read(&net_rwsem);
26927b4577a9SPravin B Shelar 	for_each_net(net)
26937b4577a9SPravin B Shelar 		list_vports_from_net(net, dnet, &head);
2694f0b07bb1SKirill Tkhai 	up_read(&net_rwsem);
26957b4577a9SPravin B Shelar 
26967b4577a9SPravin B Shelar 	/* Detach all vports from given namespace. */
26977b4577a9SPravin B Shelar 	list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
26987b4577a9SPravin B Shelar 		list_del(&vport->detach_list);
26997b4577a9SPravin B Shelar 		ovs_dp_detach_port(vport);
27007b4577a9SPravin B Shelar 	}
27017b4577a9SPravin B Shelar 
27028e4e1713SPravin B Shelar 	ovs_unlock();
27038e4e1713SPravin B Shelar 
2704a65878d6SEelco Chaudron 	cancel_delayed_work_sync(&ovs_net->masks_rebalance);
27058e4e1713SPravin B Shelar 	cancel_work_sync(&ovs_net->dp_notify_work);
270646df7b81SPravin B Shelar }
270746df7b81SPravin B Shelar 
270846df7b81SPravin B Shelar static struct pernet_operations ovs_net_ops = {
270946df7b81SPravin B Shelar 	.init = ovs_init_net,
271046df7b81SPravin B Shelar 	.exit = ovs_exit_net,
271146df7b81SPravin B Shelar 	.id   = &ovs_net_id,
271246df7b81SPravin B Shelar 	.size = sizeof(struct ovs_net),
271346df7b81SPravin B Shelar };
271446df7b81SPravin B Shelar 
27159d802da4SAdrian Moreno static const char * const ovs_drop_reasons[] = {
27166be50c89SMenglong Dong #define S(x) [(x) & ~SKB_DROP_REASON_SUBSYS_MASK] = (#x),
27179d802da4SAdrian Moreno 	OVS_DROP_REASONS(S)
27189d802da4SAdrian Moreno #undef S
27199d802da4SAdrian Moreno };
27209d802da4SAdrian Moreno 
27219d802da4SAdrian Moreno static struct drop_reason_list drop_reason_list_ovs = {
27229d802da4SAdrian Moreno 	.reasons = ovs_drop_reasons,
27239d802da4SAdrian Moreno 	.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
27249d802da4SAdrian Moreno };
27259d802da4SAdrian Moreno 
dp_init(void)2726ccb1352eSJesse Gross static int __init dp_init(void)
2727ccb1352eSJesse Gross {
2728ccb1352eSJesse Gross 	int err;
2729ccb1352eSJesse Gross 
2730cf3266adSTonghao Zhang 	BUILD_BUG_ON(sizeof(struct ovs_skb_cb) >
2731cf3266adSTonghao Zhang 		     sizeof_field(struct sk_buff, cb));
2732ccb1352eSJesse Gross 
2733ccb1352eSJesse Gross 	pr_info("Open vSwitch switching datapath\n");
2734ccb1352eSJesse Gross 
2735971427f3SAndy Zhou 	err = action_fifos_init();
2736ccb1352eSJesse Gross 	if (err)
2737ccb1352eSJesse Gross 		goto error;
2738ccb1352eSJesse Gross 
2739971427f3SAndy Zhou 	err = ovs_internal_dev_rtnl_link_register();
2740971427f3SAndy Zhou 	if (err)
2741971427f3SAndy Zhou 		goto error_action_fifos_exit;
2742971427f3SAndy Zhou 
27435b9e7e16SJiri Pirko 	err = ovs_flow_init();
27445b9e7e16SJiri Pirko 	if (err)
27455b9e7e16SJiri Pirko 		goto error_unreg_rtnl_link;
27465b9e7e16SJiri Pirko 
2747ccb1352eSJesse Gross 	err = ovs_vport_init();
2748ccb1352eSJesse Gross 	if (err)
2749ccb1352eSJesse Gross 		goto error_flow_exit;
2750ccb1352eSJesse Gross 
275146df7b81SPravin B Shelar 	err = register_pernet_device(&ovs_net_ops);
2752ccb1352eSJesse Gross 	if (err)
2753ccb1352eSJesse Gross 		goto error_vport_exit;
2754ccb1352eSJesse Gross 
275546df7b81SPravin B Shelar 	err = register_netdevice_notifier(&ovs_dp_device_notifier);
275646df7b81SPravin B Shelar 	if (err)
275746df7b81SPravin B Shelar 		goto error_netns_exit;
275846df7b81SPravin B Shelar 
275962b9c8d0SThomas Graf 	err = ovs_netdev_init();
276062b9c8d0SThomas Graf 	if (err)
276162b9c8d0SThomas Graf 		goto error_unreg_notifier;
276262b9c8d0SThomas Graf 
2763ccb1352eSJesse Gross 	err = dp_register_genl();
2764ccb1352eSJesse Gross 	if (err < 0)
276562b9c8d0SThomas Graf 		goto error_unreg_netdev;
2766ccb1352eSJesse Gross 
27679d802da4SAdrian Moreno 	drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH,
27689d802da4SAdrian Moreno 				     &drop_reason_list_ovs);
27699d802da4SAdrian Moreno 
2770ccb1352eSJesse Gross 	return 0;
2771ccb1352eSJesse Gross 
277262b9c8d0SThomas Graf error_unreg_netdev:
277362b9c8d0SThomas Graf 	ovs_netdev_exit();
2774ccb1352eSJesse Gross error_unreg_notifier:
2775ccb1352eSJesse Gross 	unregister_netdevice_notifier(&ovs_dp_device_notifier);
277646df7b81SPravin B Shelar error_netns_exit:
277746df7b81SPravin B Shelar 	unregister_pernet_device(&ovs_net_ops);
2778ccb1352eSJesse Gross error_vport_exit:
2779ccb1352eSJesse Gross 	ovs_vport_exit();
2780ccb1352eSJesse Gross error_flow_exit:
2781ccb1352eSJesse Gross 	ovs_flow_exit();
27825b9e7e16SJiri Pirko error_unreg_rtnl_link:
27835b9e7e16SJiri Pirko 	ovs_internal_dev_rtnl_link_unregister();
2784971427f3SAndy Zhou error_action_fifos_exit:
2785971427f3SAndy Zhou 	action_fifos_exit();
2786ccb1352eSJesse Gross error:
2787ccb1352eSJesse Gross 	return err;
2788ccb1352eSJesse Gross }
2789ccb1352eSJesse Gross 
dp_cleanup(void)2790ccb1352eSJesse Gross static void dp_cleanup(void)
2791ccb1352eSJesse Gross {
2792ccb1352eSJesse Gross 	dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
279362b9c8d0SThomas Graf 	ovs_netdev_exit();
2794ccb1352eSJesse Gross 	unregister_netdevice_notifier(&ovs_dp_device_notifier);
279546df7b81SPravin B Shelar 	unregister_pernet_device(&ovs_net_ops);
27969d802da4SAdrian Moreno 	drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH);
279746df7b81SPravin B Shelar 	rcu_barrier();
2798ccb1352eSJesse Gross 	ovs_vport_exit();
2799ccb1352eSJesse Gross 	ovs_flow_exit();
28005b9e7e16SJiri Pirko 	ovs_internal_dev_rtnl_link_unregister();
2801971427f3SAndy Zhou 	action_fifos_exit();
2802ccb1352eSJesse Gross }
2803ccb1352eSJesse Gross 
2804ccb1352eSJesse Gross module_init(dp_init);
2805ccb1352eSJesse Gross module_exit(dp_cleanup);
2806ccb1352eSJesse Gross 
2807ccb1352eSJesse Gross MODULE_DESCRIPTION("Open vSwitch switching datapath");
2808ccb1352eSJesse Gross MODULE_LICENSE("GPL");
2809ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_DATAPATH_FAMILY);
2810ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY);
2811ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY);
2812ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY);
281396fbc13dSAndy Zhou MODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY);
281411efd5cbSYi-Hung Wei MODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY);
2815