xref: /linux-6.15/net/openvswitch/datapath.c (revision 90b2f49a)
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/kernel.h>
19ccb1352eSJesse Gross #include <linux/kthread.h>
20ccb1352eSJesse Gross #include <linux/mutex.h>
21ccb1352eSJesse Gross #include <linux/percpu.h>
22ccb1352eSJesse Gross #include <linux/rcupdate.h>
23ccb1352eSJesse Gross #include <linux/tcp.h>
24ccb1352eSJesse Gross #include <linux/udp.h>
25ccb1352eSJesse Gross #include <linux/ethtool.h>
26ccb1352eSJesse Gross #include <linux/wait.h>
27ccb1352eSJesse Gross #include <asm/div64.h>
28ccb1352eSJesse Gross #include <linux/highmem.h>
29ccb1352eSJesse Gross #include <linux/netfilter_bridge.h>
30ccb1352eSJesse Gross #include <linux/netfilter_ipv4.h>
31ccb1352eSJesse Gross #include <linux/inetdevice.h>
32ccb1352eSJesse Gross #include <linux/list.h>
33ccb1352eSJesse Gross #include <linux/openvswitch.h>
34ccb1352eSJesse Gross #include <linux/rculist.h>
35ccb1352eSJesse Gross #include <linux/dmi.h>
36ccb1352eSJesse Gross #include <net/genetlink.h>
37d457a0e3SEric Dumazet #include <net/gso.h>
3846df7b81SPravin B Shelar #include <net/net_namespace.h>
3946df7b81SPravin B Shelar #include <net/netns/generic.h>
4035d39fecSPaul Blakey #include <net/pkt_cls.h>
41ccb1352eSJesse Gross 
42ccb1352eSJesse Gross #include "datapath.h"
439d802da4SAdrian Moreno #include "drop.h"
44ccb1352eSJesse Gross #include "flow.h"
45e80857ccSAndy Zhou #include "flow_table.h"
46e6445719SPravin B Shelar #include "flow_netlink.h"
4796fbc13dSAndy Zhou #include "meter.h"
48c4ab7b56SAaron Conole #include "openvswitch_trace.h"
49ccb1352eSJesse Gross #include "vport-internal_dev.h"
50cff63a52SThomas Graf #include "vport-netdev.h"
51ccb1352eSJesse Gross 
52c7d03a00SAlexey Dobriyan unsigned int ovs_net_id __read_mostly;
538e4e1713SPravin B Shelar 
540c200ef9SPravin B Shelar static struct genl_family dp_packet_genl_family;
550c200ef9SPravin B Shelar static struct genl_family dp_flow_genl_family;
560c200ef9SPravin B Shelar static struct genl_family dp_datapath_genl_family;
570c200ef9SPravin B Shelar 
5874ed7ab9SJoe Stringer static const struct nla_policy flow_policy[];
5974ed7ab9SJoe Stringer 
6048e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_flow_multicast_group = {
6148e48a70Sstephen hemminger 	.name = OVS_FLOW_MCGROUP,
620c200ef9SPravin B Shelar };
630c200ef9SPravin B Shelar 
6448e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_datapath_multicast_group = {
6548e48a70Sstephen hemminger 	.name = OVS_DATAPATH_MCGROUP,
660c200ef9SPravin B Shelar };
670c200ef9SPravin B Shelar 
6848e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_vport_multicast_group = {
6948e48a70Sstephen hemminger 	.name = OVS_VPORT_MCGROUP,
700c200ef9SPravin B Shelar };
710c200ef9SPravin B Shelar 
72fb5d1e9eSJarno Rajahalme /* Check if need to build a reply message.
73fb5d1e9eSJarno 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)749b67aa4aSSamuel Gauthier static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
759b67aa4aSSamuel Gauthier 			    unsigned int group)
76fb5d1e9eSJarno Rajahalme {
77fb5d1e9eSJarno Rajahalme 	return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
78f8403a2eSJohannes Berg 	       genl_has_listeners(family, genl_info_net(info), group);
79fb5d1e9eSJarno Rajahalme }
80fb5d1e9eSJarno Rajahalme 
ovs_notify(struct genl_family * family,struct sk_buff * skb,struct genl_info * info)8168eb5503SJohannes Berg static void ovs_notify(struct genl_family *family,
822a94fe48SJohannes Berg 		       struct sk_buff *skb, struct genl_info *info)
83ed661185SThomas Graf {
8492c14d9bSJiri Benc 	genl_notify(family, skb, info, 0, GFP_KERNEL);
85ed661185SThomas Graf }
86ed661185SThomas Graf 
8746df7b81SPravin B Shelar /**
88ccb1352eSJesse Gross  * DOC: Locking:
89ccb1352eSJesse Gross  *
908e4e1713SPravin B Shelar  * All writes e.g. Writes to device state (add/remove datapath, port, set
918e4e1713SPravin B Shelar  * operations on vports, etc.), Writes to other state (flow table
928e4e1713SPravin B Shelar  * modifications, set miscellaneous datapath parameters, etc.) are protected
938e4e1713SPravin B Shelar  * by ovs_lock.
94ccb1352eSJesse Gross  *
95ccb1352eSJesse Gross  * Reads are protected by RCU.
96ccb1352eSJesse Gross  *
97ccb1352eSJesse Gross  * There are a few special cases (mostly stats) that have their own
98ccb1352eSJesse Gross  * synchronization but they nest under all of above and don't interact with
99ccb1352eSJesse Gross  * each other.
1008e4e1713SPravin B Shelar  *
1018e4e1713SPravin B Shelar  * The RTNL lock nests inside ovs_mutex.
102ccb1352eSJesse Gross  */
103ccb1352eSJesse Gross 
1048e4e1713SPravin B Shelar static DEFINE_MUTEX(ovs_mutex);
1058e4e1713SPravin B Shelar 
ovs_lock(void)1068e4e1713SPravin B Shelar void ovs_lock(void)
1078e4e1713SPravin B Shelar {
1088e4e1713SPravin B Shelar 	mutex_lock(&ovs_mutex);
1098e4e1713SPravin B Shelar }
1108e4e1713SPravin B Shelar 
ovs_unlock(void)1118e4e1713SPravin B Shelar void ovs_unlock(void)
1128e4e1713SPravin B Shelar {
1138e4e1713SPravin B Shelar 	mutex_unlock(&ovs_mutex);
1148e4e1713SPravin B Shelar }
1158e4e1713SPravin B Shelar 
1168e4e1713SPravin B Shelar #ifdef CONFIG_LOCKDEP
lockdep_ovsl_is_held(void)1178e4e1713SPravin B Shelar int lockdep_ovsl_is_held(void)
1188e4e1713SPravin B Shelar {
1198e4e1713SPravin B Shelar 	if (debug_locks)
1208e4e1713SPravin B Shelar 		return lockdep_is_held(&ovs_mutex);
1218e4e1713SPravin B Shelar 	else
1228e4e1713SPravin B Shelar 		return 1;
1238e4e1713SPravin B Shelar }
1248e4e1713SPravin B Shelar #endif
1258e4e1713SPravin B Shelar 
126ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *);
1278055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *,
128e8eedb85SPravin B Shelar 			     const struct sw_flow_key *,
129f2a4d086SWilliam Tu 			     const struct dp_upcall_info *,
130f2a4d086SWilliam Tu 			     uint32_t cutlen);
1318055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
132e8eedb85SPravin B Shelar 				  const struct sw_flow_key *,
133f2a4d086SWilliam Tu 				  const struct dp_upcall_info *,
134f2a4d086SWilliam Tu 				  uint32_t cutlen);
135ccb1352eSJesse Gross 
136eac87c41SEelco Chaudron static void ovs_dp_masks_rebalance(struct work_struct *work);
137eac87c41SEelco Chaudron 
138b83d23a2SMark Gray static int ovs_dp_set_upcall_portids(struct datapath *, const struct nlattr *);
139b83d23a2SMark Gray 
1408e4e1713SPravin B Shelar /* Must be called with rcu_read_lock or ovs_mutex. */
ovs_dp_name(const struct datapath * dp)141971427f3SAndy Zhou const char *ovs_dp_name(const struct datapath *dp)
142ccb1352eSJesse Gross {
1438e4e1713SPravin B Shelar 	struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
144c9db965cSThomas Graf 	return ovs_vport_name(vport);
145ccb1352eSJesse Gross }
146ccb1352eSJesse Gross 
get_dpifindex(const struct datapath * dp)14712eb18f7SThomas Graf static int get_dpifindex(const struct datapath *dp)
148ccb1352eSJesse Gross {
149ccb1352eSJesse Gross 	struct vport *local;
150ccb1352eSJesse Gross 	int ifindex;
151ccb1352eSJesse Gross 
152ccb1352eSJesse Gross 	rcu_read_lock();
153ccb1352eSJesse Gross 
15415eac2a7SPravin B Shelar 	local = ovs_vport_rcu(dp, OVSP_LOCAL);
155ccb1352eSJesse Gross 	if (local)
156be4ace6eSThomas Graf 		ifindex = local->dev->ifindex;
157ccb1352eSJesse Gross 	else
158ccb1352eSJesse Gross 		ifindex = 0;
159ccb1352eSJesse Gross 
160ccb1352eSJesse Gross 	rcu_read_unlock();
161ccb1352eSJesse Gross 
162ccb1352eSJesse Gross 	return ifindex;
163ccb1352eSJesse Gross }
164ccb1352eSJesse Gross 
destroy_dp_rcu(struct rcu_head * rcu)165ccb1352eSJesse Gross static void destroy_dp_rcu(struct rcu_head *rcu)
166ccb1352eSJesse Gross {
167ccb1352eSJesse Gross 	struct datapath *dp = container_of(rcu, struct datapath, rcu);
168ccb1352eSJesse Gross 
1699b996e54SPravin B Shelar 	ovs_flow_tbl_destroy(&dp->table);
170ccb1352eSJesse Gross 	free_percpu(dp->stats_percpu);
17115eac2a7SPravin B Shelar 	kfree(dp->ports);
17296fbc13dSAndy Zhou 	ovs_meters_exit(dp);
173076999e4SMark Gray 	kfree(rcu_dereference_raw(dp->upcall_portids));
174ccb1352eSJesse Gross 	kfree(dp);
175ccb1352eSJesse Gross }
176ccb1352eSJesse Gross 
vport_hash_bucket(const struct datapath * dp,u16 port_no)17715eac2a7SPravin B Shelar static struct hlist_head *vport_hash_bucket(const struct datapath *dp,
17815eac2a7SPravin B Shelar 					    u16 port_no)
17915eac2a7SPravin B Shelar {
18015eac2a7SPravin B Shelar 	return &dp->ports[port_no & (DP_VPORT_HASH_BUCKETS - 1)];
18115eac2a7SPravin B Shelar }
18215eac2a7SPravin B Shelar 
183bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */
ovs_lookup_vport(const struct datapath * dp,u16 port_no)18415eac2a7SPravin B Shelar struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
18515eac2a7SPravin B Shelar {
18615eac2a7SPravin B Shelar 	struct vport *vport;
18715eac2a7SPravin B Shelar 	struct hlist_head *head;
18815eac2a7SPravin B Shelar 
18915eac2a7SPravin B Shelar 	head = vport_hash_bucket(dp, port_no);
19053742e69SMadhuparna Bhowmik 	hlist_for_each_entry_rcu(vport, head, dp_hash_node,
19153742e69SMadhuparna Bhowmik 				 lockdep_ovsl_is_held()) {
19215eac2a7SPravin B Shelar 		if (vport->port_no == port_no)
19315eac2a7SPravin B Shelar 			return vport;
19415eac2a7SPravin B Shelar 	}
19515eac2a7SPravin B Shelar 	return NULL;
19615eac2a7SPravin B Shelar }
19715eac2a7SPravin B Shelar 
1988e4e1713SPravin B Shelar /* Called with ovs_mutex. */
new_vport(const struct vport_parms * parms)199ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *parms)
200ccb1352eSJesse Gross {
201ccb1352eSJesse Gross 	struct vport *vport;
202ccb1352eSJesse Gross 
203ccb1352eSJesse Gross 	vport = ovs_vport_add(parms);
204ccb1352eSJesse Gross 	if (!IS_ERR(vport)) {
205ccb1352eSJesse Gross 		struct datapath *dp = parms->dp;
20615eac2a7SPravin B Shelar 		struct hlist_head *head = vport_hash_bucket(dp, vport->port_no);
207ccb1352eSJesse Gross 
20815eac2a7SPravin B Shelar 		hlist_add_head_rcu(&vport->dp_hash_node, head);
209ccb1352eSJesse Gross 	}
210ccb1352eSJesse Gross 	return vport;
211ccb1352eSJesse Gross }
212ccb1352eSJesse Gross 
ovs_vport_update_upcall_stats(struct sk_buff * skb,const struct dp_upcall_info * upcall_info,bool upcall_result)2131933ea36Swangchuanlei static void ovs_vport_update_upcall_stats(struct sk_buff *skb,
2141933ea36Swangchuanlei 					  const struct dp_upcall_info *upcall_info,
2151933ea36Swangchuanlei 					  bool upcall_result)
2161933ea36Swangchuanlei {
2171933ea36Swangchuanlei 	struct vport *p = OVS_CB(skb)->input_vport;
2181933ea36Swangchuanlei 	struct vport_upcall_stats_percpu *stats;
2191933ea36Swangchuanlei 
2201933ea36Swangchuanlei 	if (upcall_info->cmd != OVS_PACKET_CMD_MISS &&
2211933ea36Swangchuanlei 	    upcall_info->cmd != OVS_PACKET_CMD_ACTION)
2221933ea36Swangchuanlei 		return;
2231933ea36Swangchuanlei 
2241933ea36Swangchuanlei 	stats = this_cpu_ptr(p->upcall_stats);
2251933ea36Swangchuanlei 	u64_stats_update_begin(&stats->syncp);
2261933ea36Swangchuanlei 	if (upcall_result)
2271933ea36Swangchuanlei 		u64_stats_inc(&stats->n_success);
2281933ea36Swangchuanlei 	else
2291933ea36Swangchuanlei 		u64_stats_inc(&stats->n_fail);
2301933ea36Swangchuanlei 	u64_stats_update_end(&stats->syncp);
2311933ea36Swangchuanlei }
2321933ea36Swangchuanlei 
ovs_dp_detach_port(struct vport * p)233ccb1352eSJesse Gross void ovs_dp_detach_port(struct vport *p)
234ccb1352eSJesse Gross {
2358e4e1713SPravin B Shelar 	ASSERT_OVSL();
236ccb1352eSJesse Gross 
237ccb1352eSJesse Gross 	/* First drop references to device. */
23815eac2a7SPravin B Shelar 	hlist_del_rcu(&p->dp_hash_node);
239ccb1352eSJesse Gross 
240ccb1352eSJesse Gross 	/* Then destroy it. */
241ccb1352eSJesse Gross 	ovs_vport_del(p);
242ccb1352eSJesse Gross }
243ccb1352eSJesse Gross 
244ccb1352eSJesse Gross /* Must be called with rcu_read_lock. */
ovs_dp_process_packet(struct sk_buff * skb,struct sw_flow_key * key)2458c8b1b83SPravin B Shelar void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
246ccb1352eSJesse Gross {
24783c8df26SPravin B Shelar 	const struct vport *p = OVS_CB(skb)->input_vport;
248ccb1352eSJesse Gross 	struct datapath *dp = p->dp;
249ccb1352eSJesse Gross 	struct sw_flow *flow;
250d98612b8SLorand Jakab 	struct sw_flow_actions *sf_acts;
251ccb1352eSJesse Gross 	struct dp_stats_percpu *stats;
252ccb1352eSJesse Gross 	u64 *stats_counter;
2531bd7116fSAndy Zhou 	u32 n_mask_hit;
2549d2f627bSEelco Chaudron 	u32 n_cache_hit;
255aa733660SYifeng Sun 	int error;
256ccb1352eSJesse Gross 
257404f2f10SShan Wei 	stats = this_cpu_ptr(dp->stats_percpu);
258ccb1352eSJesse Gross 
259ccb1352eSJesse Gross 	/* Look up flow. */
26004b7d136STonghao Zhang 	flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb),
2619d2f627bSEelco Chaudron 					 &n_mask_hit, &n_cache_hit);
262ccb1352eSJesse Gross 	if (unlikely(!flow)) {
263ccb1352eSJesse Gross 		struct dp_upcall_info upcall;
264ccb1352eSJesse Gross 
265ccea7445SNeil McKee 		memset(&upcall, 0, sizeof(upcall));
266ccb1352eSJesse Gross 		upcall.cmd = OVS_PACKET_CMD_MISS;
267b83d23a2SMark Gray 
268b83d23a2SMark Gray 		if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU)
269784dcfa5SMark Gray 			upcall.portid =
270784dcfa5SMark Gray 			    ovs_dp_get_upcall_portid(dp, smp_processor_id());
271b83d23a2SMark Gray 		else
2725cd667b0SAlex Wang 			upcall.portid = ovs_vport_find_upcall_portid(p, skb);
273b83d23a2SMark Gray 
2747f8a436eSJoe Stringer 		upcall.mru = OVS_CB(skb)->mru;
275f2a4d086SWilliam Tu 		error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
2761100248aSMike Pattrick 		switch (error) {
2771100248aSMike Pattrick 		case 0:
2781100248aSMike Pattrick 		case -EAGAIN:
2791100248aSMike Pattrick 		case -ERESTARTSYS:
2801100248aSMike Pattrick 		case -EINTR:
281ccb1352eSJesse Gross 			consume_skb(skb);
2821100248aSMike Pattrick 			break;
2831100248aSMike Pattrick 		default:
2841100248aSMike Pattrick 			kfree_skb(skb);
2851100248aSMike Pattrick 			break;
2861100248aSMike Pattrick 		}
287ccb1352eSJesse Gross 		stats_counter = &stats->n_missed;
288ccb1352eSJesse Gross 		goto out;
289ccb1352eSJesse Gross 	}
290ccb1352eSJesse Gross 
291d98612b8SLorand Jakab 	ovs_flow_stats_update(flow, key->tp.flags, skb);
292d98612b8SLorand Jakab 	sf_acts = rcu_dereference(flow->sf_acts);
293aa733660SYifeng Sun 	error = ovs_execute_actions(dp, skb, sf_acts, key);
294aa733660SYifeng Sun 	if (unlikely(error))
295aa733660SYifeng Sun 		net_dbg_ratelimited("ovs: action execution error on datapath %s: %d\n",
296aa733660SYifeng Sun 				    ovs_dp_name(dp), error);
297ccb1352eSJesse Gross 
298e298e505SPravin B Shelar 	stats_counter = &stats->n_hit;
299ccb1352eSJesse Gross 
300ccb1352eSJesse Gross out:
301ccb1352eSJesse Gross 	/* Update datapath statistics. */
302df9d9fdfSWANG Cong 	u64_stats_update_begin(&stats->syncp);
303ccb1352eSJesse Gross 	(*stats_counter)++;
3041bd7116fSAndy Zhou 	stats->n_mask_hit += n_mask_hit;
3059d2f627bSEelco Chaudron 	stats->n_cache_hit += n_cache_hit;
306df9d9fdfSWANG Cong 	u64_stats_update_end(&stats->syncp);
307ccb1352eSJesse Gross }
308ccb1352eSJesse 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)309ccb1352eSJesse Gross int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
310e8eedb85SPravin B Shelar 		  const struct sw_flow_key *key,
311f2a4d086SWilliam Tu 		  const struct dp_upcall_info *upcall_info,
312f2a4d086SWilliam Tu 		  uint32_t cutlen)
313ccb1352eSJesse Gross {
314ccb1352eSJesse Gross 	struct dp_stats_percpu *stats;
315ccb1352eSJesse Gross 	int err;
316ccb1352eSJesse Gross 
317c4ab7b56SAaron Conole 	if (trace_ovs_dp_upcall_enabled())
318c4ab7b56SAaron Conole 		trace_ovs_dp_upcall(dp, skb, key, upcall_info);
319c4ab7b56SAaron Conole 
32015e47304SEric W. Biederman 	if (upcall_info->portid == 0) {
321ccb1352eSJesse Gross 		err = -ENOTCONN;
322ccb1352eSJesse Gross 		goto err;
323ccb1352eSJesse Gross 	}
324ccb1352eSJesse Gross 
325ccb1352eSJesse Gross 	if (!skb_is_gso(skb))
326f2a4d086SWilliam Tu 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
327ccb1352eSJesse Gross 	else
328f2a4d086SWilliam Tu 		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);
3291933ea36Swangchuanlei 
3301933ea36Swangchuanlei 	ovs_vport_update_upcall_stats(skb, upcall_info, !err);
331ccb1352eSJesse Gross 	if (err)
332ccb1352eSJesse Gross 		goto err;
333ccb1352eSJesse Gross 
334ccb1352eSJesse Gross 	return 0;
335ccb1352eSJesse Gross 
336ccb1352eSJesse Gross err:
337404f2f10SShan Wei 	stats = this_cpu_ptr(dp->stats_percpu);
338ccb1352eSJesse Gross 
339df9d9fdfSWANG Cong 	u64_stats_update_begin(&stats->syncp);
340ccb1352eSJesse Gross 	stats->n_lost++;
341df9d9fdfSWANG Cong 	u64_stats_update_end(&stats->syncp);
342ccb1352eSJesse Gross 
343ccb1352eSJesse Gross 	return err;
344ccb1352eSJesse Gross }
345ccb1352eSJesse 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)3468055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
347e8eedb85SPravin B Shelar 			     const struct sw_flow_key *key,
348f2a4d086SWilliam Tu 			     const struct dp_upcall_info *upcall_info,
349f2a4d086SWilliam Tu 			     uint32_t cutlen)
350ccb1352eSJesse Gross {
3512734166eSGustavo A. R. Silva 	unsigned int gso_type = skb_shinfo(skb)->gso_type;
3520c19f846SWillem de Bruijn 	struct sw_flow_key later_key;
353ccb1352eSJesse Gross 	struct sk_buff *segs, *nskb;
354ccb1352eSJesse Gross 	int err;
355ccb1352eSJesse Gross 
356a08e7fd9SCambda Zhu 	BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_GSO_CB_OFFSET);
35709c5e605SThomas Graf 	segs = __skb_gso_segment(skb, NETIF_F_SG, false);
35892e5dfc3SPravin B Shelar 	if (IS_ERR(segs))
35992e5dfc3SPravin B Shelar 		return PTR_ERR(segs);
360330966e5SFlorian Westphal 	if (segs == NULL)
361330966e5SFlorian Westphal 		return -EINVAL;
362ccb1352eSJesse Gross 
3630c19f846SWillem de Bruijn 	if (gso_type & SKB_GSO_UDP) {
3640c19f846SWillem de Bruijn 		/* The initial flow key extracted by ovs_flow_key_extract()
3650c19f846SWillem de Bruijn 		 * in this case is for a first fragment, so we need to
3660c19f846SWillem de Bruijn 		 * properly mark later fragments.
3670c19f846SWillem de Bruijn 		 */
3680c19f846SWillem de Bruijn 		later_key = *key;
3690c19f846SWillem de Bruijn 		later_key.ip.frag = OVS_FRAG_TYPE_LATER;
3700c19f846SWillem de Bruijn 	}
3710c19f846SWillem de Bruijn 
372e8eedb85SPravin B Shelar 	/* Queue all of the segments. */
3732cec4448SJason A. Donenfeld 	skb_list_walk_safe(segs, skb, nskb) {
3740c19f846SWillem de Bruijn 		if (gso_type & SKB_GSO_UDP && skb != segs)
3750c19f846SWillem de Bruijn 			key = &later_key;
3760c19f846SWillem de Bruijn 
377f2a4d086SWilliam Tu 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
378e8eedb85SPravin B Shelar 		if (err)
379e8eedb85SPravin B Shelar 			break;
380e8eedb85SPravin B Shelar 
3812cec4448SJason A. Donenfeld 	}
382ccb1352eSJesse Gross 
383ccb1352eSJesse Gross 	/* Free all of the segments. */
3842cec4448SJason A. Donenfeld 	skb_list_walk_safe(segs, skb, nskb) {
385ccb1352eSJesse Gross 		if (err)
386ccb1352eSJesse Gross 			kfree_skb(skb);
387ccb1352eSJesse Gross 		else
388ccb1352eSJesse Gross 			consume_skb(skb);
3892cec4448SJason A. Donenfeld 	}
390ccb1352eSJesse Gross 	return err;
391ccb1352eSJesse Gross }
392ccb1352eSJesse Gross 
upcall_msg_size(const struct dp_upcall_info * upcall_info,unsigned int hdrlen,int actions_attrlen)3938f0aad6fSWenyu Zhang static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
394494bea39SLiping Zhang 			      unsigned int hdrlen, int actions_attrlen)
395c3ff8cfeSThomas Graf {
396c3ff8cfeSThomas Graf 	size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
397bda56f14SThomas Graf 		+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
398b95e5928SWilliam Tu 		+ nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */
399bd1903b7STonghao Zhang 		+ nla_total_size(sizeof(unsigned int)) /* OVS_PACKET_ATTR_LEN */
400bd1903b7STonghao Zhang 		+ nla_total_size(sizeof(u64)); /* OVS_PACKET_ATTR_HASH */
401c3ff8cfeSThomas Graf 
402c3ff8cfeSThomas Graf 	/* OVS_PACKET_ATTR_USERDATA */
4038f0aad6fSWenyu Zhang 	if (upcall_info->userdata)
4048f0aad6fSWenyu Zhang 		size += NLA_ALIGN(upcall_info->userdata->nla_len);
4058f0aad6fSWenyu Zhang 
4068f0aad6fSWenyu Zhang 	/* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
4078f0aad6fSWenyu Zhang 	if (upcall_info->egress_tun_info)
4088f0aad6fSWenyu Zhang 		size += nla_total_size(ovs_tun_key_attr_size());
409c3ff8cfeSThomas Graf 
410ccea7445SNeil McKee 	/* OVS_PACKET_ATTR_ACTIONS */
411ccea7445SNeil McKee 	if (upcall_info->actions_len)
412494bea39SLiping Zhang 		size += nla_total_size(actions_attrlen);
413ccea7445SNeil McKee 
4147f8a436eSJoe Stringer 	/* OVS_PACKET_ATTR_MRU */
4157f8a436eSJoe Stringer 	if (upcall_info->mru)
4167f8a436eSJoe Stringer 		size += nla_total_size(sizeof(upcall_info->mru));
4177f8a436eSJoe Stringer 
418c3ff8cfeSThomas Graf 	return size;
419c3ff8cfeSThomas Graf }
420c3ff8cfeSThomas Graf 
pad_packet(struct datapath * dp,struct sk_buff * skb)4217f8a436eSJoe Stringer static void pad_packet(struct datapath *dp, struct sk_buff *skb)
4227f8a436eSJoe Stringer {
4237f8a436eSJoe Stringer 	if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
4247f8a436eSJoe Stringer 		size_t plen = NLA_ALIGN(skb->len) - skb->len;
4257f8a436eSJoe Stringer 
4267f8a436eSJoe Stringer 		if (plen > 0)
427b080db58SJohannes Berg 			skb_put_zero(skb, plen);
4287f8a436eSJoe Stringer 	}
4297f8a436eSJoe Stringer }
4307f8a436eSJoe 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)4318055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
432e8eedb85SPravin B Shelar 				  const struct sw_flow_key *key,
433f2a4d086SWilliam Tu 				  const struct dp_upcall_info *upcall_info,
434f2a4d086SWilliam Tu 				  uint32_t cutlen)
435ccb1352eSJesse Gross {
436ccb1352eSJesse Gross 	struct ovs_header *upcall;
437ccb1352eSJesse Gross 	struct sk_buff *nskb = NULL;
4384ee45ea0SLi RongQing 	struct sk_buff *user_skb = NULL; /* to be queued to userspace */
439ccb1352eSJesse Gross 	struct nlattr *nla;
440795449d8SThomas Graf 	size_t len;
441bda56f14SThomas Graf 	unsigned int hlen;
4428055a89cSThomas Graf 	int err, dp_ifindex;
443bd1903b7STonghao Zhang 	u64 hash;
4448055a89cSThomas Graf 
4458055a89cSThomas Graf 	dp_ifindex = get_dpifindex(dp);
4468055a89cSThomas Graf 	if (!dp_ifindex)
4478055a89cSThomas Graf 		return -ENODEV;
448ccb1352eSJesse Gross 
449df8a39deSJiri Pirko 	if (skb_vlan_tag_present(skb)) {
450ccb1352eSJesse Gross 		nskb = skb_clone(skb, GFP_ATOMIC);
451ccb1352eSJesse Gross 		if (!nskb)
452ccb1352eSJesse Gross 			return -ENOMEM;
453ccb1352eSJesse Gross 
4545968250cSJiri Pirko 		nskb = __vlan_hwaccel_push_inside(nskb);
4558aa51d64SDan Carpenter 		if (!nskb)
456ccb1352eSJesse Gross 			return -ENOMEM;
457ccb1352eSJesse Gross 
458ccb1352eSJesse Gross 		skb = nskb;
459ccb1352eSJesse Gross 	}
460ccb1352eSJesse Gross 
461ccb1352eSJesse Gross 	if (nla_attr_size(skb->len) > USHRT_MAX) {
462ccb1352eSJesse Gross 		err = -EFBIG;
463ccb1352eSJesse Gross 		goto out;
464ccb1352eSJesse Gross 	}
465ccb1352eSJesse Gross 
466bda56f14SThomas Graf 	/* Complete checksum if needed */
467bda56f14SThomas Graf 	if (skb->ip_summed == CHECKSUM_PARTIAL &&
4687529390dSDavide Caratti 	    (err = skb_csum_hwoffload_help(skb, 0)))
469bda56f14SThomas Graf 		goto out;
470bda56f14SThomas Graf 
471bda56f14SThomas Graf 	/* Older versions of OVS user space enforce alignment of the last
472bda56f14SThomas Graf 	 * Netlink attribute to NLA_ALIGNTO which would require extensive
473bda56f14SThomas Graf 	 * padding logic. Only perform zerocopy if padding is not required.
474bda56f14SThomas Graf 	 */
475bda56f14SThomas Graf 	if (dp->user_features & OVS_DP_F_UNALIGNED)
476bda56f14SThomas Graf 		hlen = skb_zerocopy_headlen(skb);
477bda56f14SThomas Graf 	else
478bda56f14SThomas Graf 		hlen = skb->len;
479bda56f14SThomas Graf 
480494bea39SLiping Zhang 	len = upcall_msg_size(upcall_info, hlen - cutlen,
481494bea39SLiping Zhang 			      OVS_CB(skb)->acts_origlen);
482551ddc05SFlorian Westphal 	user_skb = genlmsg_new(len, GFP_ATOMIC);
483ccb1352eSJesse Gross 	if (!user_skb) {
484ccb1352eSJesse Gross 		err = -ENOMEM;
485ccb1352eSJesse Gross 		goto out;
486ccb1352eSJesse Gross 	}
487ccb1352eSJesse Gross 
488ccb1352eSJesse Gross 	upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
489ccb1352eSJesse Gross 			     0, upcall_info->cmd);
4906f19893bSKangjie Lu 	if (!upcall) {
4916f19893bSKangjie Lu 		err = -EINVAL;
4926f19893bSKangjie Lu 		goto out;
4936f19893bSKangjie Lu 	}
494ccb1352eSJesse Gross 	upcall->dp_ifindex = dp_ifindex;
495ccb1352eSJesse Gross 
4965b4237bbSJoe Stringer 	err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb);
497a734d1f4SEelco Chaudron 	if (err)
498a734d1f4SEelco Chaudron 		goto out;
499ccb1352eSJesse Gross 
500ccb1352eSJesse Gross 	if (upcall_info->userdata)
5014490108bSBen Pfaff 		__nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
5024490108bSBen Pfaff 			  nla_len(upcall_info->userdata),
5034490108bSBen Pfaff 			  nla_data(upcall_info->userdata));
504ccb1352eSJesse Gross 
5058f0aad6fSWenyu Zhang 	if (upcall_info->egress_tun_info) {
506ae0be8deSMichal Kubecek 		nla = nla_nest_start_noflag(user_skb,
507ae0be8deSMichal Kubecek 					    OVS_PACKET_ATTR_EGRESS_TUN_KEY);
5080fff9bd4SKangjie Lu 		if (!nla) {
5090fff9bd4SKangjie Lu 			err = -EMSGSIZE;
5100fff9bd4SKangjie Lu 			goto out;
5110fff9bd4SKangjie Lu 		}
512fc4099f1SPravin B Shelar 		err = ovs_nla_put_tunnel_info(user_skb,
513fc4099f1SPravin B Shelar 					      upcall_info->egress_tun_info);
514a734d1f4SEelco Chaudron 		if (err)
515a734d1f4SEelco Chaudron 			goto out;
516a734d1f4SEelco Chaudron 
5178f0aad6fSWenyu Zhang 		nla_nest_end(user_skb, nla);
5188f0aad6fSWenyu Zhang 	}
5198f0aad6fSWenyu Zhang 
520ccea7445SNeil McKee 	if (upcall_info->actions_len) {
521ae0be8deSMichal Kubecek 		nla = nla_nest_start_noflag(user_skb, OVS_PACKET_ATTR_ACTIONS);
5220fff9bd4SKangjie Lu 		if (!nla) {
5230fff9bd4SKangjie Lu 			err = -EMSGSIZE;
5240fff9bd4SKangjie Lu 			goto out;
5250fff9bd4SKangjie Lu 		}
526ccea7445SNeil McKee 		err = ovs_nla_put_actions(upcall_info->actions,
527ccea7445SNeil McKee 					  upcall_info->actions_len,
528ccea7445SNeil McKee 					  user_skb);
529ccea7445SNeil McKee 		if (!err)
530ccea7445SNeil McKee 			nla_nest_end(user_skb, nla);
531ccea7445SNeil McKee 		else
532ccea7445SNeil McKee 			nla_nest_cancel(user_skb, nla);
533ccea7445SNeil McKee 	}
534ccea7445SNeil McKee 
5357f8a436eSJoe Stringer 	/* Add OVS_PACKET_ATTR_MRU */
53661ca533cSTonghao Zhang 	if (upcall_info->mru &&
53761ca533cSTonghao Zhang 	    nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU, upcall_info->mru)) {
5387f8a436eSJoe Stringer 		err = -ENOBUFS;
5397f8a436eSJoe Stringer 		goto out;
5407f8a436eSJoe Stringer 	}
5417f8a436eSJoe Stringer 
542b95e5928SWilliam Tu 	/* Add OVS_PACKET_ATTR_LEN when packet is truncated */
54361ca533cSTonghao Zhang 	if (cutlen > 0 &&
54461ca533cSTonghao Zhang 	    nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
545b95e5928SWilliam Tu 		err = -ENOBUFS;
546b95e5928SWilliam Tu 		goto out;
547b95e5928SWilliam Tu 	}
548b95e5928SWilliam Tu 
549bd1903b7STonghao Zhang 	/* Add OVS_PACKET_ATTR_HASH */
550bd1903b7STonghao Zhang 	hash = skb_get_hash_raw(skb);
551bd1903b7STonghao Zhang 	if (skb->sw_hash)
552bd1903b7STonghao Zhang 		hash |= OVS_PACKET_HASH_SW_BIT;
553bd1903b7STonghao Zhang 
554bd1903b7STonghao Zhang 	if (skb->l4_hash)
555bd1903b7STonghao Zhang 		hash |= OVS_PACKET_HASH_L4_BIT;
556bd1903b7STonghao Zhang 
557bd1903b7STonghao Zhang 	if (nla_put(user_skb, OVS_PACKET_ATTR_HASH, sizeof (u64), &hash)) {
558bd1903b7STonghao Zhang 		err = -ENOBUFS;
559bd1903b7STonghao Zhang 		goto out;
560bd1903b7STonghao Zhang 	}
561bd1903b7STonghao Zhang 
562bda56f14SThomas Graf 	/* Only reserve room for attribute header, packet data is added
563bda56f14SThomas Graf 	 * in skb_zerocopy() */
564bda56f14SThomas Graf 	if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
565bda56f14SThomas Graf 		err = -ENOBUFS;
566bda56f14SThomas Graf 		goto out;
567bda56f14SThomas Graf 	}
568f2a4d086SWilliam Tu 	nla->nla_len = nla_attr_size(skb->len - cutlen);
569ccb1352eSJesse Gross 
570f2a4d086SWilliam Tu 	err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
57136d5fe6aSZoltan Kiss 	if (err)
57236d5fe6aSZoltan Kiss 		goto out;
573ccb1352eSJesse Gross 
574aea0bb4fSThomas Graf 	/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
5757f8a436eSJoe Stringer 	pad_packet(dp, user_skb);
576aea0bb4fSThomas Graf 
577bda56f14SThomas Graf 	((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
578bda56f14SThomas Graf 
5798055a89cSThomas Graf 	err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
5804ee45ea0SLi RongQing 	user_skb = NULL;
581ccb1352eSJesse Gross out:
58236d5fe6aSZoltan Kiss 	if (err)
58336d5fe6aSZoltan Kiss 		skb_tx_error(skb);
584c21ab2afSMike Pattrick 	consume_skb(user_skb);
585c21ab2afSMike Pattrick 	consume_skb(nskb);
586c21ab2afSMike Pattrick 
587ccb1352eSJesse Gross 	return err;
588ccb1352eSJesse Gross }
589ccb1352eSJesse Gross 
ovs_packet_cmd_execute(struct sk_buff * skb,struct genl_info * info)590ccb1352eSJesse Gross static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
591ccb1352eSJesse Gross {
592bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
5937f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
594ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
595ccb1352eSJesse Gross 	struct sw_flow_actions *acts;
596ccb1352eSJesse Gross 	struct sk_buff *packet;
597ccb1352eSJesse Gross 	struct sw_flow *flow;
598d98612b8SLorand Jakab 	struct sw_flow_actions *sf_acts;
599ccb1352eSJesse Gross 	struct datapath *dp;
60083c8df26SPravin B Shelar 	struct vport *input_vport;
6017f8a436eSJoe Stringer 	u16 mru = 0;
602bd1903b7STonghao Zhang 	u64 hash;
603ccb1352eSJesse Gross 	int len;
604ccb1352eSJesse Gross 	int err;
6051ba39804SThomas Graf 	bool log = !a[OVS_PACKET_ATTR_PROBE];
606ccb1352eSJesse Gross 
607ccb1352eSJesse Gross 	err = -EINVAL;
608ccb1352eSJesse Gross 	if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
609dded45fcSThomas Graf 	    !a[OVS_PACKET_ATTR_ACTIONS])
610ccb1352eSJesse Gross 		goto err;
611ccb1352eSJesse Gross 
612ccb1352eSJesse Gross 	len = nla_len(a[OVS_PACKET_ATTR_PACKET]);
613ccb1352eSJesse Gross 	packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL);
614ccb1352eSJesse Gross 	err = -ENOMEM;
615ccb1352eSJesse Gross 	if (!packet)
616ccb1352eSJesse Gross 		goto err;
617ccb1352eSJesse Gross 	skb_reserve(packet, NET_IP_ALIGN);
618ccb1352eSJesse Gross 
61932686a9dSThomas Graf 	nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
620ccb1352eSJesse Gross 
6217f8a436eSJoe Stringer 	/* Set packet's mru */
6227f8a436eSJoe Stringer 	if (a[OVS_PACKET_ATTR_MRU]) {
6237f8a436eSJoe Stringer 		mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
6247f8a436eSJoe Stringer 		packet->ignore_df = 1;
6257f8a436eSJoe Stringer 	}
6267f8a436eSJoe Stringer 	OVS_CB(packet)->mru = mru;
6277f8a436eSJoe Stringer 
628bd1903b7STonghao Zhang 	if (a[OVS_PACKET_ATTR_HASH]) {
629bd1903b7STonghao Zhang 		hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
630bd1903b7STonghao Zhang 
631bd1903b7STonghao Zhang 		__skb_set_hash(packet, hash & 0xFFFFFFFFULL,
632bd1903b7STonghao Zhang 			       !!(hash & OVS_PACKET_HASH_SW_BIT),
633bd1903b7STonghao Zhang 			       !!(hash & OVS_PACKET_HASH_L4_BIT));
634bd1903b7STonghao Zhang 	}
635bd1903b7STonghao Zhang 
636ccb1352eSJesse Gross 	/* Build an sw_flow for sending this packet. */
63723dabf88SJarno Rajahalme 	flow = ovs_flow_alloc();
638ccb1352eSJesse Gross 	err = PTR_ERR(flow);
639ccb1352eSJesse Gross 	if (IS_ERR(flow))
640ccb1352eSJesse Gross 		goto err_kfree_skb;
641ccb1352eSJesse Gross 
642c2ac6673SJoe Stringer 	err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY],
643c2ac6673SJoe Stringer 					     packet, &flow->key, log);
644ccb1352eSJesse Gross 	if (err)
645ccb1352eSJesse Gross 		goto err_flow_free;
646ccb1352eSJesse Gross 
6477f8a436eSJoe Stringer 	err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS],
64805da5898SJarno Rajahalme 				   &flow->key, &acts, log);
64974f84a57SPravin B Shelar 	if (err)
65074f84a57SPravin B Shelar 		goto err_flow_free;
651ccb1352eSJesse Gross 
652f5796684SJesse Gross 	rcu_assign_pointer(flow->sf_acts, acts);
653ccb1352eSJesse Gross 	packet->priority = flow->key.phy.priority;
65439c7caebSAnsis Atteka 	packet->mark = flow->key.phy.skb_mark;
655ccb1352eSJesse Gross 
656ccb1352eSJesse Gross 	rcu_read_lock();
6577f8a436eSJoe Stringer 	dp = get_dp_rcu(net, ovs_header->dp_ifindex);
658ccb1352eSJesse Gross 	err = -ENODEV;
659ccb1352eSJesse Gross 	if (!dp)
660ccb1352eSJesse Gross 		goto err_unlock;
661ccb1352eSJesse Gross 
66283c8df26SPravin B Shelar 	input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port);
66383c8df26SPravin B Shelar 	if (!input_vport)
66483c8df26SPravin B Shelar 		input_vport = ovs_vport_rcu(dp, OVSP_LOCAL);
66583c8df26SPravin B Shelar 
66683c8df26SPravin B Shelar 	if (!input_vport)
66783c8df26SPravin B Shelar 		goto err_unlock;
66883c8df26SPravin B Shelar 
6697f8a436eSJoe Stringer 	packet->dev = input_vport->dev;
67083c8df26SPravin B Shelar 	OVS_CB(packet)->input_vport = input_vport;
671d98612b8SLorand Jakab 	sf_acts = rcu_dereference(flow->sf_acts);
67283c8df26SPravin B Shelar 
673ccb1352eSJesse Gross 	local_bh_disable();
674d98612b8SLorand Jakab 	err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
675ccb1352eSJesse Gross 	local_bh_enable();
676ccb1352eSJesse Gross 	rcu_read_unlock();
677ccb1352eSJesse Gross 
67803f0d916SAndy Zhou 	ovs_flow_free(flow, false);
679ccb1352eSJesse Gross 	return err;
680ccb1352eSJesse Gross 
681ccb1352eSJesse Gross err_unlock:
682ccb1352eSJesse Gross 	rcu_read_unlock();
683ccb1352eSJesse Gross err_flow_free:
68403f0d916SAndy Zhou 	ovs_flow_free(flow, false);
685ccb1352eSJesse Gross err_kfree_skb:
686ccb1352eSJesse Gross 	kfree_skb(packet);
687ccb1352eSJesse Gross err:
688ccb1352eSJesse Gross 	return err;
689ccb1352eSJesse Gross }
690ccb1352eSJesse Gross 
691ccb1352eSJesse Gross static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
692dded45fcSThomas Graf 	[OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
693ccb1352eSJesse Gross 	[OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
694ccb1352eSJesse Gross 	[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
6951ba39804SThomas Graf 	[OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
6967f8a436eSJoe Stringer 	[OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
697b5ab1f1bSJakub Kicinski 	[OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
698ccb1352eSJesse Gross };
699ccb1352eSJesse Gross 
70066a9b928SJakub Kicinski static const struct genl_small_ops dp_packet_genl_ops[] = {
701ccb1352eSJesse Gross 	{ .cmd = OVS_PACKET_CMD_EXECUTE,
702ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7034a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
704ccb1352eSJesse Gross 	  .doit = ovs_packet_cmd_execute
705ccb1352eSJesse Gross 	}
706ccb1352eSJesse Gross };
707ccb1352eSJesse Gross 
70856989f6dSJohannes Berg static struct genl_family dp_packet_genl_family __ro_after_init = {
7090c200ef9SPravin B Shelar 	.hdrsize = sizeof(struct ovs_header),
7100c200ef9SPravin B Shelar 	.name = OVS_PACKET_FAMILY,
7110c200ef9SPravin B Shelar 	.version = OVS_PACKET_VERSION,
7120c200ef9SPravin B Shelar 	.maxattr = OVS_PACKET_ATTR_MAX,
7133b0f31f2SJohannes Berg 	.policy = packet_policy,
7140c200ef9SPravin B Shelar 	.netnsok = true,
7150c200ef9SPravin B Shelar 	.parallel_ops = true,
71666a9b928SJakub Kicinski 	.small_ops = dp_packet_genl_ops,
71766a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_packet_genl_ops),
7189c5d03d3SJakub Kicinski 	.resv_start_op = OVS_PACKET_CMD_EXECUTE + 1,
719489111e5SJohannes Berg 	.module = THIS_MODULE,
7200c200ef9SPravin B Shelar };
7210c200ef9SPravin B Shelar 
get_dp_stats(const struct datapath * dp,struct ovs_dp_stats * stats,struct ovs_dp_megaflow_stats * mega_stats)72212eb18f7SThomas Graf static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats,
7231bd7116fSAndy Zhou 			 struct ovs_dp_megaflow_stats *mega_stats)
724ccb1352eSJesse Gross {
725ccb1352eSJesse Gross 	int i;
726ccb1352eSJesse Gross 
7271bd7116fSAndy Zhou 	memset(mega_stats, 0, sizeof(*mega_stats));
7281bd7116fSAndy Zhou 
729b637e498SPravin B Shelar 	stats->n_flows = ovs_flow_tbl_count(&dp->table);
7301bd7116fSAndy Zhou 	mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table);
731ccb1352eSJesse Gross 
732ccb1352eSJesse Gross 	stats->n_hit = stats->n_missed = stats->n_lost = 0;
7331bd7116fSAndy Zhou 
734ccb1352eSJesse Gross 	for_each_possible_cpu(i) {
735ccb1352eSJesse Gross 		const struct dp_stats_percpu *percpu_stats;
736ccb1352eSJesse Gross 		struct dp_stats_percpu local_stats;
737ccb1352eSJesse Gross 		unsigned int start;
738ccb1352eSJesse Gross 
739ccb1352eSJesse Gross 		percpu_stats = per_cpu_ptr(dp->stats_percpu, i);
740ccb1352eSJesse Gross 
741ccb1352eSJesse Gross 		do {
742d120d1a6SThomas Gleixner 			start = u64_stats_fetch_begin(&percpu_stats->syncp);
743ccb1352eSJesse Gross 			local_stats = *percpu_stats;
744d120d1a6SThomas Gleixner 		} while (u64_stats_fetch_retry(&percpu_stats->syncp, start));
745ccb1352eSJesse Gross 
746ccb1352eSJesse Gross 		stats->n_hit += local_stats.n_hit;
747ccb1352eSJesse Gross 		stats->n_missed += local_stats.n_missed;
748ccb1352eSJesse Gross 		stats->n_lost += local_stats.n_lost;
7491bd7116fSAndy Zhou 		mega_stats->n_mask_hit += local_stats.n_mask_hit;
7509d2f627bSEelco Chaudron 		mega_stats->n_cache_hit += local_stats.n_cache_hit;
751ccb1352eSJesse Gross 	}
752ccb1352eSJesse Gross }
753ccb1352eSJesse Gross 
should_fill_key(const struct sw_flow_id * sfid,uint32_t ufid_flags)75474ed7ab9SJoe Stringer static bool should_fill_key(const struct sw_flow_id *sfid, uint32_t ufid_flags)
755c3ff8cfeSThomas Graf {
75674ed7ab9SJoe Stringer 	return ovs_identifier_is_ufid(sfid) &&
75774ed7ab9SJoe Stringer 	       !(ufid_flags & OVS_UFID_F_OMIT_KEY);
75874ed7ab9SJoe Stringer }
75974ed7ab9SJoe Stringer 
should_fill_mask(uint32_t ufid_flags)76074ed7ab9SJoe Stringer static bool should_fill_mask(uint32_t ufid_flags)
76174ed7ab9SJoe Stringer {
76274ed7ab9SJoe Stringer 	return !(ufid_flags & OVS_UFID_F_OMIT_MASK);
76374ed7ab9SJoe Stringer }
76474ed7ab9SJoe Stringer 
should_fill_actions(uint32_t ufid_flags)76574ed7ab9SJoe Stringer static bool should_fill_actions(uint32_t ufid_flags)
76674ed7ab9SJoe Stringer {
76774ed7ab9SJoe Stringer 	return !(ufid_flags & OVS_UFID_F_OMIT_ACTIONS);
76874ed7ab9SJoe Stringer }
76974ed7ab9SJoe Stringer 
ovs_flow_cmd_msg_size(const struct sw_flow_actions * acts,const struct sw_flow_id * sfid,uint32_t ufid_flags)77074ed7ab9SJoe Stringer static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
77174ed7ab9SJoe Stringer 				    const struct sw_flow_id *sfid,
77274ed7ab9SJoe Stringer 				    uint32_t ufid_flags)
77374ed7ab9SJoe Stringer {
77474ed7ab9SJoe Stringer 	size_t len = NLMSG_ALIGN(sizeof(struct ovs_header));
77574ed7ab9SJoe Stringer 
7764e81c0b3SPaolo Abeni 	/* OVS_FLOW_ATTR_UFID, or unmasked flow key as fallback
7774e81c0b3SPaolo Abeni 	 * see ovs_nla_put_identifier()
7784e81c0b3SPaolo Abeni 	 */
77974ed7ab9SJoe Stringer 	if (sfid && ovs_identifier_is_ufid(sfid))
78074ed7ab9SJoe Stringer 		len += nla_total_size(sfid->ufid_len);
7814e81c0b3SPaolo Abeni 	else
7824e81c0b3SPaolo Abeni 		len += nla_total_size(ovs_key_attr_size());
78374ed7ab9SJoe Stringer 
78474ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_KEY */
78574ed7ab9SJoe Stringer 	if (!sfid || should_fill_key(sfid, ufid_flags))
78674ed7ab9SJoe Stringer 		len += nla_total_size(ovs_key_attr_size());
78774ed7ab9SJoe Stringer 
78874ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_MASK */
78974ed7ab9SJoe Stringer 	if (should_fill_mask(ufid_flags))
79074ed7ab9SJoe Stringer 		len += nla_total_size(ovs_key_attr_size());
79174ed7ab9SJoe Stringer 
79274ed7ab9SJoe Stringer 	/* OVS_FLOW_ATTR_ACTIONS */
79374ed7ab9SJoe Stringer 	if (should_fill_actions(ufid_flags))
7948e2fed1cSJoe Stringer 		len += nla_total_size(acts->orig_len);
79574ed7ab9SJoe Stringer 
79674ed7ab9SJoe Stringer 	return len
79766c7a5eeSNicolas Dichtel 		+ nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
798c3ff8cfeSThomas Graf 		+ nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
79966c7a5eeSNicolas Dichtel 		+ nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */
800c3ff8cfeSThomas Graf }
801c3ff8cfeSThomas Graf 
802bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */
ovs_flow_cmd_fill_stats(const struct sw_flow * flow,struct sk_buff * skb)803ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
804ca7105f2SJoe Stringer 				   struct sk_buff *skb)
805ca7105f2SJoe Stringer {
806ca7105f2SJoe Stringer 	struct ovs_flow_stats stats;
807ca7105f2SJoe Stringer 	__be16 tcp_flags;
808ca7105f2SJoe Stringer 	unsigned long used;
80903f0d916SAndy Zhou 
810e298e505SPravin B Shelar 	ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
8110e9796b4SJarno Rajahalme 
812028d6a67SDavid S. Miller 	if (used &&
8130238b720SNicolas Dichtel 	    nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used),
8140238b720SNicolas Dichtel 			      OVS_FLOW_ATTR_PAD))
815ca7105f2SJoe Stringer 		return -EMSGSIZE;
816ccb1352eSJesse Gross 
817028d6a67SDavid S. Miller 	if (stats.n_packets &&
81866c7a5eeSNicolas Dichtel 	    nla_put_64bit(skb, OVS_FLOW_ATTR_STATS,
81966c7a5eeSNicolas Dichtel 			  sizeof(struct ovs_flow_stats), &stats,
82066c7a5eeSNicolas Dichtel 			  OVS_FLOW_ATTR_PAD))
821ca7105f2SJoe Stringer 		return -EMSGSIZE;
822ccb1352eSJesse Gross 
823e298e505SPravin B Shelar 	if ((u8)ntohs(tcp_flags) &&
824e298e505SPravin B Shelar 	     nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
825ca7105f2SJoe Stringer 		return -EMSGSIZE;
826ca7105f2SJoe Stringer 
827ca7105f2SJoe Stringer 	return 0;
828ca7105f2SJoe Stringer }
829ca7105f2SJoe Stringer 
830ca7105f2SJoe 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)831ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow,
832ca7105f2SJoe Stringer 				     struct sk_buff *skb, int skb_orig_len)
833ca7105f2SJoe Stringer {
834ca7105f2SJoe Stringer 	struct nlattr *start;
835ca7105f2SJoe Stringer 	int err;
836ccb1352eSJesse Gross 
837ccb1352eSJesse Gross 	/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
838ccb1352eSJesse Gross 	 * this is the first flow to be dumped into 'skb'.  This is unusual for
839ccb1352eSJesse Gross 	 * Netlink but individual action lists can be longer than
840ccb1352eSJesse Gross 	 * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this.
841ccb1352eSJesse Gross 	 * The userspace caller can always fetch the actions separately if it
842ccb1352eSJesse Gross 	 * really wants them.  (Most userspace callers in fact don't care.)
843ccb1352eSJesse Gross 	 *
844ccb1352eSJesse Gross 	 * This can only fail for dump operations because the skb is always
845ccb1352eSJesse Gross 	 * properly sized for single flows.
846ccb1352eSJesse Gross 	 */
847ae0be8deSMichal Kubecek 	start = nla_nest_start_noflag(skb, OVS_FLOW_ATTR_ACTIONS);
84874f84a57SPravin B Shelar 	if (start) {
849d57170b1SPravin B Shelar 		const struct sw_flow_actions *sf_acts;
850d57170b1SPravin B Shelar 
851663efa36SJesse Gross 		sf_acts = rcu_dereference_ovsl(flow->sf_acts);
852e6445719SPravin B Shelar 		err = ovs_nla_put_actions(sf_acts->actions,
853e6445719SPravin B Shelar 					  sf_acts->actions_len, skb);
8540e9796b4SJarno Rajahalme 
85574f84a57SPravin B Shelar 		if (!err)
85674f84a57SPravin B Shelar 			nla_nest_end(skb, start);
85774f84a57SPravin B Shelar 		else {
85874f84a57SPravin B Shelar 			if (skb_orig_len)
859ca7105f2SJoe Stringer 				return err;
860ccb1352eSJesse Gross 
86174f84a57SPravin B Shelar 			nla_nest_cancel(skb, start);
86274f84a57SPravin B Shelar 		}
863ca7105f2SJoe Stringer 	} else if (skb_orig_len) {
864ca7105f2SJoe Stringer 		return -EMSGSIZE;
865ca7105f2SJoe Stringer 	}
866ca7105f2SJoe Stringer 
867ca7105f2SJoe Stringer 	return 0;
868ca7105f2SJoe Stringer }
869ca7105f2SJoe Stringer 
870ca7105f2SJoe 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)871ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
872ca7105f2SJoe Stringer 				  struct sk_buff *skb, u32 portid,
87374ed7ab9SJoe Stringer 				  u32 seq, u32 flags, u8 cmd, u32 ufid_flags)
874ca7105f2SJoe Stringer {
875ca7105f2SJoe Stringer 	const int skb_orig_len = skb->len;
876ca7105f2SJoe Stringer 	struct ovs_header *ovs_header;
877ca7105f2SJoe Stringer 	int err;
878ca7105f2SJoe Stringer 
879ca7105f2SJoe Stringer 	ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family,
880ca7105f2SJoe Stringer 				 flags, cmd);
881ca7105f2SJoe Stringer 	if (!ovs_header)
882ca7105f2SJoe Stringer 		return -EMSGSIZE;
883ca7105f2SJoe Stringer 
884ca7105f2SJoe Stringer 	ovs_header->dp_ifindex = dp_ifindex;
885ca7105f2SJoe Stringer 
88674ed7ab9SJoe Stringer 	err = ovs_nla_put_identifier(flow, skb);
8875b4237bbSJoe Stringer 	if (err)
8885b4237bbSJoe Stringer 		goto error;
8895b4237bbSJoe Stringer 
89074ed7ab9SJoe Stringer 	if (should_fill_key(&flow->id, ufid_flags)) {
89174ed7ab9SJoe Stringer 		err = ovs_nla_put_masked_key(flow, skb);
89274ed7ab9SJoe Stringer 		if (err)
89374ed7ab9SJoe Stringer 			goto error;
89474ed7ab9SJoe Stringer 	}
89574ed7ab9SJoe Stringer 
89674ed7ab9SJoe Stringer 	if (should_fill_mask(ufid_flags)) {
8975b4237bbSJoe Stringer 		err = ovs_nla_put_mask(flow, skb);
898ca7105f2SJoe Stringer 		if (err)
899ca7105f2SJoe Stringer 			goto error;
90074ed7ab9SJoe Stringer 	}
901ca7105f2SJoe Stringer 
902ca7105f2SJoe Stringer 	err = ovs_flow_cmd_fill_stats(flow, skb);
903ca7105f2SJoe Stringer 	if (err)
904ca7105f2SJoe Stringer 		goto error;
905ca7105f2SJoe Stringer 
90674ed7ab9SJoe Stringer 	if (should_fill_actions(ufid_flags)) {
907ca7105f2SJoe Stringer 		err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len);
908ca7105f2SJoe Stringer 		if (err)
909ca7105f2SJoe Stringer 			goto error;
91074ed7ab9SJoe Stringer 	}
91174f84a57SPravin B Shelar 
912053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
913053c095aSJohannes Berg 	return 0;
914ccb1352eSJesse Gross 
915ccb1352eSJesse Gross error:
916ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
917ccb1352eSJesse Gross 	return err;
918ccb1352eSJesse Gross }
919ccb1352eSJesse Gross 
9200e9796b4SJarno 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)9210e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts,
92274ed7ab9SJoe Stringer 					       const struct sw_flow_id *sfid,
923fb5d1e9eSJarno Rajahalme 					       struct genl_info *info,
92474ed7ab9SJoe Stringer 					       bool always,
92574ed7ab9SJoe Stringer 					       uint32_t ufid_flags)
926ccb1352eSJesse Gross {
927fb5d1e9eSJarno Rajahalme 	struct sk_buff *skb;
92874ed7ab9SJoe Stringer 	size_t len;
929ccb1352eSJesse Gross 
9309b67aa4aSSamuel Gauthier 	if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0))
931fb5d1e9eSJarno Rajahalme 		return NULL;
932fb5d1e9eSJarno Rajahalme 
93374ed7ab9SJoe Stringer 	len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
934551ddc05SFlorian Westphal 	skb = genlmsg_new(len, GFP_KERNEL);
935fb5d1e9eSJarno Rajahalme 	if (!skb)
936fb5d1e9eSJarno Rajahalme 		return ERR_PTR(-ENOMEM);
937fb5d1e9eSJarno Rajahalme 
938fb5d1e9eSJarno Rajahalme 	return skb;
939ccb1352eSJesse Gross }
940ccb1352eSJesse Gross 
9410e9796b4SJarno 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)9420e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
9430e9796b4SJarno Rajahalme 					       int dp_ifindex,
9440e9796b4SJarno Rajahalme 					       struct genl_info *info, u8 cmd,
94574ed7ab9SJoe Stringer 					       bool always, u32 ufid_flags)
946ccb1352eSJesse Gross {
947ccb1352eSJesse Gross 	struct sk_buff *skb;
948ccb1352eSJesse Gross 	int retval;
949ccb1352eSJesse Gross 
95074ed7ab9SJoe Stringer 	skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts),
95174ed7ab9SJoe Stringer 				      &flow->id, info, always, ufid_flags);
952d0e992aaSHimangi Saraogi 	if (IS_ERR_OR_NULL(skb))
953fb5d1e9eSJarno Rajahalme 		return skb;
954ccb1352eSJesse Gross 
9550e9796b4SJarno Rajahalme 	retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
9560e9796b4SJarno Rajahalme 					info->snd_portid, info->snd_seq, 0,
95774ed7ab9SJoe Stringer 					cmd, ufid_flags);
9588ffeb03fSPaolo Abeni 	if (WARN_ON_ONCE(retval < 0)) {
9598ffeb03fSPaolo Abeni 		kfree_skb(skb);
9608ffeb03fSPaolo Abeni 		skb = ERR_PTR(retval);
9618ffeb03fSPaolo Abeni 	}
962ccb1352eSJesse Gross 	return skb;
963ccb1352eSJesse Gross }
964ccb1352eSJesse Gross 
ovs_flow_cmd_new(struct sk_buff * skb,struct genl_info * info)96537bdc87bSJarno Rajahalme static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
966ccb1352eSJesse Gross {
9677f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
968ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
969bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
97074ed7ab9SJoe Stringer 	struct sw_flow *flow = NULL, *new_flow;
97103f0d916SAndy Zhou 	struct sw_flow_mask mask;
972ccb1352eSJesse Gross 	struct sk_buff *reply;
973ccb1352eSJesse Gross 	struct datapath *dp;
97468bb1010SEelco Chaudron 	struct sw_flow_key *key;
97537bdc87bSJarno Rajahalme 	struct sw_flow_actions *acts;
97637bdc87bSJarno Rajahalme 	struct sw_flow_match match;
97774ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
97837bdc87bSJarno Rajahalme 	int error;
97905da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
98037bdc87bSJarno Rajahalme 
981893f139bSJarno Rajahalme 	/* Must have key and actions. */
98237bdc87bSJarno Rajahalme 	error = -EINVAL;
983426cda5cSJesse Gross 	if (!a[OVS_FLOW_ATTR_KEY]) {
98405da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow key attr not present in new flow.");
98537bdc87bSJarno Rajahalme 		goto error;
986426cda5cSJesse Gross 	}
987426cda5cSJesse Gross 	if (!a[OVS_FLOW_ATTR_ACTIONS]) {
98805da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow actions attr not present in new flow.");
98937bdc87bSJarno Rajahalme 		goto error;
990426cda5cSJesse Gross 	}
99137bdc87bSJarno Rajahalme 
992893f139bSJarno Rajahalme 	/* Most of the time we need to allocate a new flow, do it before
993893f139bSJarno Rajahalme 	 * locking.
994893f139bSJarno Rajahalme 	 */
995893f139bSJarno Rajahalme 	new_flow = ovs_flow_alloc();
996893f139bSJarno Rajahalme 	if (IS_ERR(new_flow)) {
997893f139bSJarno Rajahalme 		error = PTR_ERR(new_flow);
998893f139bSJarno Rajahalme 		goto error;
999893f139bSJarno Rajahalme 	}
1000893f139bSJarno Rajahalme 
1001893f139bSJarno Rajahalme 	/* Extract key. */
100268bb1010SEelco Chaudron 	key = kzalloc(sizeof(*key), GFP_KERNEL);
100368bb1010SEelco Chaudron 	if (!key) {
100468bb1010SEelco Chaudron 		error = -ENOMEM;
10050c598aedSFedor Pchelkin 		goto err_kfree_flow;
100668bb1010SEelco Chaudron 	}
100768bb1010SEelco Chaudron 
100868bb1010SEelco Chaudron 	ovs_match_init(&match, key, false, &mask);
1009c2ac6673SJoe Stringer 	error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
101005da5898SJarno Rajahalme 				  a[OVS_FLOW_ATTR_MASK], log);
1011893f139bSJarno Rajahalme 	if (error)
10120c598aedSFedor Pchelkin 		goto err_kfree_key;
1013893f139bSJarno Rajahalme 
101468bb1010SEelco Chaudron 	ovs_flow_mask_key(&new_flow->key, key, true, &mask);
101568bb1010SEelco Chaudron 
101674ed7ab9SJoe Stringer 	/* Extract flow identifier. */
101774ed7ab9SJoe Stringer 	error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
101868bb1010SEelco Chaudron 				       key, log);
101974ed7ab9SJoe Stringer 	if (error)
10200c598aedSFedor Pchelkin 		goto err_kfree_key;
1021893f139bSJarno Rajahalme 
1022893f139bSJarno Rajahalme 	/* Validate actions. */
10237f8a436eSJoe Stringer 	error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
10247f8a436eSJoe Stringer 				     &new_flow->key, &acts, log);
102537bdc87bSJarno Rajahalme 	if (error) {
102605da5898SJarno Rajahalme 		OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
10270c598aedSFedor Pchelkin 		goto err_kfree_key;
1028893f139bSJarno Rajahalme 	}
1029893f139bSJarno Rajahalme 
103074ed7ab9SJoe Stringer 	reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
103174ed7ab9SJoe Stringer 					ufid_flags);
1032893f139bSJarno Rajahalme 	if (IS_ERR(reply)) {
1033893f139bSJarno Rajahalme 		error = PTR_ERR(reply);
1034893f139bSJarno Rajahalme 		goto err_kfree_acts;
103537bdc87bSJarno Rajahalme 	}
103637bdc87bSJarno Rajahalme 
103737bdc87bSJarno Rajahalme 	ovs_lock();
10387f8a436eSJoe Stringer 	dp = get_dp(net, ovs_header->dp_ifindex);
1039893f139bSJarno Rajahalme 	if (unlikely(!dp)) {
104037bdc87bSJarno Rajahalme 		error = -ENODEV;
104137bdc87bSJarno Rajahalme 		goto err_unlock_ovs;
104237bdc87bSJarno Rajahalme 	}
104374ed7ab9SJoe Stringer 
1044893f139bSJarno Rajahalme 	/* Check if this is a duplicate flow */
104574ed7ab9SJoe Stringer 	if (ovs_identifier_is_ufid(&new_flow->id))
104674ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
104774ed7ab9SJoe Stringer 	if (!flow)
104868bb1010SEelco Chaudron 		flow = ovs_flow_tbl_lookup(&dp->table, key);
1049893f139bSJarno Rajahalme 	if (likely(!flow)) {
1050893f139bSJarno Rajahalme 		rcu_assign_pointer(new_flow->sf_acts, acts);
105137bdc87bSJarno Rajahalme 
105237bdc87bSJarno Rajahalme 		/* Put flow in bucket. */
1053893f139bSJarno Rajahalme 		error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
1054893f139bSJarno Rajahalme 		if (unlikely(error)) {
105537bdc87bSJarno Rajahalme 			acts = NULL;
1056893f139bSJarno Rajahalme 			goto err_unlock_ovs;
105737bdc87bSJarno Rajahalme 		}
1058893f139bSJarno Rajahalme 
1059893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1060893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(new_flow,
1061893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1062893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1063893f139bSJarno Rajahalme 						       info->snd_seq, 0,
106474ed7ab9SJoe Stringer 						       OVS_FLOW_CMD_NEW,
106574ed7ab9SJoe Stringer 						       ufid_flags);
1066893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1067893f139bSJarno Rajahalme 		}
1068893f139bSJarno Rajahalme 		ovs_unlock();
106937bdc87bSJarno Rajahalme 	} else {
107037bdc87bSJarno Rajahalme 		struct sw_flow_actions *old_acts;
107137bdc87bSJarno Rajahalme 
107237bdc87bSJarno Rajahalme 		/* Bail out if we're not allowed to modify an existing flow.
107337bdc87bSJarno Rajahalme 		 * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
107437bdc87bSJarno Rajahalme 		 * because Generic Netlink treats the latter as a dump
107537bdc87bSJarno Rajahalme 		 * request.  We also accept NLM_F_EXCL in case that bug ever
107637bdc87bSJarno Rajahalme 		 * gets fixed.
107737bdc87bSJarno Rajahalme 		 */
1078893f139bSJarno Rajahalme 		if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
1079893f139bSJarno Rajahalme 							 | NLM_F_EXCL))) {
108037bdc87bSJarno Rajahalme 			error = -EEXIST;
108137bdc87bSJarno Rajahalme 			goto err_unlock_ovs;
1082893f139bSJarno Rajahalme 		}
108374ed7ab9SJoe Stringer 		/* The flow identifier has to be the same for flow updates.
108474ed7ab9SJoe Stringer 		 * Look for any overlapping flow.
108574ed7ab9SJoe Stringer 		 */
108674ed7ab9SJoe Stringer 		if (unlikely(!ovs_flow_cmp(flow, &match))) {
108774ed7ab9SJoe Stringer 			if (ovs_identifier_is_key(&flow->id))
108874ed7ab9SJoe Stringer 				flow = ovs_flow_tbl_lookup_exact(&dp->table,
108974ed7ab9SJoe Stringer 								 &match);
109074ed7ab9SJoe Stringer 			else /* UFID matches but key is different */
109174ed7ab9SJoe Stringer 				flow = NULL;
10924a46b24eSAlex Wang 			if (!flow) {
10934a46b24eSAlex Wang 				error = -ENOENT;
109437bdc87bSJarno Rajahalme 				goto err_unlock_ovs;
1095893f139bSJarno Rajahalme 			}
10964a46b24eSAlex Wang 		}
109737bdc87bSJarno Rajahalme 		/* Update actions. */
109837bdc87bSJarno Rajahalme 		old_acts = ovsl_dereference(flow->sf_acts);
109937bdc87bSJarno Rajahalme 		rcu_assign_pointer(flow->sf_acts, acts);
110037bdc87bSJarno Rajahalme 
1101893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1102893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(flow,
1103893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1104893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1105893f139bSJarno Rajahalme 						       info->snd_seq, 0,
110674ed7ab9SJoe Stringer 						       OVS_FLOW_CMD_NEW,
110774ed7ab9SJoe Stringer 						       ufid_flags);
1108893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1109893f139bSJarno Rajahalme 		}
111037bdc87bSJarno Rajahalme 		ovs_unlock();
111137bdc87bSJarno Rajahalme 
111234ae932aSThomas Graf 		ovs_nla_free_flow_actions_rcu(old_acts);
1113893f139bSJarno Rajahalme 		ovs_flow_free(new_flow, false);
111437bdc87bSJarno Rajahalme 	}
1115893f139bSJarno Rajahalme 
1116893f139bSJarno Rajahalme 	if (reply)
1117893f139bSJarno Rajahalme 		ovs_notify(&dp_flow_genl_family, reply, info);
111868bb1010SEelco Chaudron 
111968bb1010SEelco Chaudron 	kfree(key);
112037bdc87bSJarno Rajahalme 	return 0;
112137bdc87bSJarno Rajahalme 
112237bdc87bSJarno Rajahalme err_unlock_ovs:
112337bdc87bSJarno Rajahalme 	ovs_unlock();
1124893f139bSJarno Rajahalme 	kfree_skb(reply);
1125893f139bSJarno Rajahalme err_kfree_acts:
112634ae932aSThomas Graf 	ovs_nla_free_flow_actions(acts);
112768bb1010SEelco Chaudron err_kfree_key:
112868bb1010SEelco Chaudron 	kfree(key);
11290c598aedSFedor Pchelkin err_kfree_flow:
11300c598aedSFedor Pchelkin 	ovs_flow_free(new_flow, false);
113137bdc87bSJarno Rajahalme error:
113237bdc87bSJarno Rajahalme 	return error;
113337bdc87bSJarno Rajahalme }
113437bdc87bSJarno Rajahalme 
11352fdb957dSPravin B Shelar /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
1136cf3266adSTonghao 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)1137cf3266adSTonghao Zhang struct sw_flow_actions *get_flow_actions(struct net *net,
11387f8a436eSJoe Stringer 					 const struct nlattr *a,
11396b205b2cSJesse Gross 					 const struct sw_flow_key *key,
114005da5898SJarno Rajahalme 					 const struct sw_flow_mask *mask,
114105da5898SJarno Rajahalme 					 bool log)
11426b205b2cSJesse Gross {
11436b205b2cSJesse Gross 	struct sw_flow_actions *acts;
11446b205b2cSJesse Gross 	struct sw_flow_key masked_key;
11456b205b2cSJesse Gross 	int error;
11466b205b2cSJesse Gross 
1147ae5f2fb1SJesse Gross 	ovs_flow_mask_key(&masked_key, key, true, mask);
11487f8a436eSJoe Stringer 	error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
11496b205b2cSJesse Gross 	if (error) {
115005da5898SJarno Rajahalme 		OVS_NLERR(log,
115105da5898SJarno Rajahalme 			  "Actions may not be safe on all matching packets");
11526b205b2cSJesse Gross 		return ERR_PTR(error);
11536b205b2cSJesse Gross 	}
11546b205b2cSJesse Gross 
11556b205b2cSJesse Gross 	return acts;
11566b205b2cSJesse Gross }
11576b205b2cSJesse Gross 
11589cc9a5cbSTonghao Zhang /* Factor out match-init and action-copy to avoid
11599cc9a5cbSTonghao Zhang  * "Wframe-larger-than=1024" warning. Because mask is only
11609cc9a5cbSTonghao Zhang  * used to get actions, we new a function to save some
11619cc9a5cbSTonghao Zhang  * stack space.
11629cc9a5cbSTonghao Zhang  *
11639cc9a5cbSTonghao Zhang  * If there are not key and action attrs, we return 0
11649cc9a5cbSTonghao Zhang  * directly. In the case, the caller will also not use the
11659cc9a5cbSTonghao Zhang  * match as before. If there is action attr, we try to get
11669cc9a5cbSTonghao Zhang  * actions and save them to *acts. Before returning from
11679cc9a5cbSTonghao Zhang  * the function, we reset the match->mask pointer. Because
11689cc9a5cbSTonghao Zhang  * we should not to return match object with dangling reference
11699cc9a5cbSTonghao Zhang  * to mask.
11709cc9a5cbSTonghao Zhang  * */
117126063790SArnd 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)117226063790SArnd Bergmann ovs_nla_init_match_and_action(struct net *net,
11739cc9a5cbSTonghao Zhang 			      struct sw_flow_match *match,
11749cc9a5cbSTonghao Zhang 			      struct sw_flow_key *key,
11759cc9a5cbSTonghao Zhang 			      struct nlattr **a,
11769cc9a5cbSTonghao Zhang 			      struct sw_flow_actions **acts,
11779cc9a5cbSTonghao Zhang 			      bool log)
11789cc9a5cbSTonghao Zhang {
11799cc9a5cbSTonghao Zhang 	struct sw_flow_mask mask;
11809cc9a5cbSTonghao Zhang 	int error = 0;
11819cc9a5cbSTonghao Zhang 
11829cc9a5cbSTonghao Zhang 	if (a[OVS_FLOW_ATTR_KEY]) {
11839cc9a5cbSTonghao Zhang 		ovs_match_init(match, key, true, &mask);
11849cc9a5cbSTonghao Zhang 		error = ovs_nla_get_match(net, match, a[OVS_FLOW_ATTR_KEY],
11859cc9a5cbSTonghao Zhang 					  a[OVS_FLOW_ATTR_MASK], log);
11869cc9a5cbSTonghao Zhang 		if (error)
11879cc9a5cbSTonghao Zhang 			goto error;
11889cc9a5cbSTonghao Zhang 	}
11899cc9a5cbSTonghao Zhang 
11909cc9a5cbSTonghao Zhang 	if (a[OVS_FLOW_ATTR_ACTIONS]) {
11919cc9a5cbSTonghao Zhang 		if (!a[OVS_FLOW_ATTR_KEY]) {
11929cc9a5cbSTonghao Zhang 			OVS_NLERR(log,
11939cc9a5cbSTonghao Zhang 				  "Flow key attribute not present in set flow.");
11945829e62aSChristophe JAILLET 			error = -EINVAL;
11955829e62aSChristophe JAILLET 			goto error;
11969cc9a5cbSTonghao Zhang 		}
11979cc9a5cbSTonghao Zhang 
11989cc9a5cbSTonghao Zhang 		*acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key,
11999cc9a5cbSTonghao Zhang 					 &mask, log);
12009cc9a5cbSTonghao Zhang 		if (IS_ERR(*acts)) {
12019cc9a5cbSTonghao Zhang 			error = PTR_ERR(*acts);
12029cc9a5cbSTonghao Zhang 			goto error;
12039cc9a5cbSTonghao Zhang 		}
12049cc9a5cbSTonghao Zhang 	}
12059cc9a5cbSTonghao Zhang 
12069cc9a5cbSTonghao Zhang 	/* On success, error is 0. */
12079cc9a5cbSTonghao Zhang error:
12089cc9a5cbSTonghao Zhang 	match->mask = NULL;
12099cc9a5cbSTonghao Zhang 	return error;
12109cc9a5cbSTonghao Zhang }
12119cc9a5cbSTonghao Zhang 
ovs_flow_cmd_set(struct sk_buff * skb,struct genl_info * info)121237bdc87bSJarno Rajahalme static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
121337bdc87bSJarno Rajahalme {
12147f8a436eSJoe Stringer 	struct net *net = sock_net(skb->sk);
121537bdc87bSJarno Rajahalme 	struct nlattr **a = info->attrs;
1216bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
12176b205b2cSJesse Gross 	struct sw_flow_key key;
121837bdc87bSJarno Rajahalme 	struct sw_flow *flow;
121937bdc87bSJarno Rajahalme 	struct sk_buff *reply = NULL;
122037bdc87bSJarno Rajahalme 	struct datapath *dp;
1221893f139bSJarno Rajahalme 	struct sw_flow_actions *old_acts = NULL, *acts = NULL;
122203f0d916SAndy Zhou 	struct sw_flow_match match;
122374ed7ab9SJoe Stringer 	struct sw_flow_id sfid;
122474ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
12256f15cdbfSSamuel Gauthier 	int error = 0;
122605da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
122774ed7ab9SJoe Stringer 	bool ufid_present;
1228ccb1352eSJesse Gross 
122974ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
12309cc9a5cbSTonghao Zhang 	if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) {
12316f15cdbfSSamuel Gauthier 		OVS_NLERR(log,
12326f15cdbfSSamuel Gauthier 			  "Flow set message rejected, Key attribute missing.");
12339cc9a5cbSTonghao Zhang 		return -EINVAL;
12346f15cdbfSSamuel Gauthier 	}
12359cc9a5cbSTonghao Zhang 
12369cc9a5cbSTonghao Zhang 	error = ovs_nla_init_match_and_action(net, &match, &key, a,
12379cc9a5cbSTonghao Zhang 					      &acts, log);
1238ccb1352eSJesse Gross 	if (error)
1239ccb1352eSJesse Gross 		goto error;
1240ccb1352eSJesse Gross 
12419cc9a5cbSTonghao Zhang 	if (acts) {
1242893f139bSJarno Rajahalme 		/* Can allocate before locking if have acts. */
124374ed7ab9SJoe Stringer 		reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false,
124474ed7ab9SJoe Stringer 						ufid_flags);
1245893f139bSJarno Rajahalme 		if (IS_ERR(reply)) {
1246893f139bSJarno Rajahalme 			error = PTR_ERR(reply);
1247893f139bSJarno Rajahalme 			goto err_kfree_acts;
124803f0d916SAndy Zhou 		}
1249ccb1352eSJesse Gross 	}
1250ccb1352eSJesse Gross 
12518e4e1713SPravin B Shelar 	ovs_lock();
12527f8a436eSJoe Stringer 	dp = get_dp(net, ovs_header->dp_ifindex);
1253893f139bSJarno Rajahalme 	if (unlikely(!dp)) {
1254ccb1352eSJesse Gross 		error = -ENODEV;
12558e4e1713SPravin B Shelar 		goto err_unlock_ovs;
1256893f139bSJarno Rajahalme 	}
125737bdc87bSJarno Rajahalme 	/* Check that the flow exists. */
125874ed7ab9SJoe Stringer 	if (ufid_present)
125974ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &sfid);
126074ed7ab9SJoe Stringer 	else
12614a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
1262893f139bSJarno Rajahalme 	if (unlikely(!flow)) {
1263ccb1352eSJesse Gross 		error = -ENOENT;
12648e4e1713SPravin B Shelar 		goto err_unlock_ovs;
1265893f139bSJarno Rajahalme 	}
12664a46b24eSAlex Wang 
1267be52c9e9SJarno Rajahalme 	/* Update actions, if present. */
1268893f139bSJarno Rajahalme 	if (likely(acts)) {
12698e4e1713SPravin B Shelar 		old_acts = ovsl_dereference(flow->sf_acts);
127074f84a57SPravin B Shelar 		rcu_assign_pointer(flow->sf_acts, acts);
12710e9796b4SJarno Rajahalme 
1272893f139bSJarno Rajahalme 		if (unlikely(reply)) {
1273893f139bSJarno Rajahalme 			error = ovs_flow_cmd_fill_info(flow,
1274893f139bSJarno Rajahalme 						       ovs_header->dp_ifindex,
1275893f139bSJarno Rajahalme 						       reply, info->snd_portid,
1276893f139bSJarno Rajahalme 						       info->snd_seq, 0,
1277804fe108SYifeng Sun 						       OVS_FLOW_CMD_SET,
127874ed7ab9SJoe Stringer 						       ufid_flags);
1279893f139bSJarno Rajahalme 			BUG_ON(error < 0);
1280893f139bSJarno Rajahalme 		}
1281893f139bSJarno Rajahalme 	} else {
1282893f139bSJarno Rajahalme 		/* Could not alloc without acts before locking. */
12830e9796b4SJarno Rajahalme 		reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
1284804fe108SYifeng Sun 						info, OVS_FLOW_CMD_SET, false,
128574ed7ab9SJoe Stringer 						ufid_flags);
128674ed7ab9SJoe Stringer 
1287b5ffe634SViresh Kumar 		if (IS_ERR(reply)) {
1288893f139bSJarno Rajahalme 			error = PTR_ERR(reply);
1289893f139bSJarno Rajahalme 			goto err_unlock_ovs;
1290893f139bSJarno Rajahalme 		}
1291893f139bSJarno Rajahalme 	}
1292893f139bSJarno Rajahalme 
1293ccb1352eSJesse Gross 	/* Clear stats. */
1294e298e505SPravin B Shelar 	if (a[OVS_FLOW_ATTR_CLEAR])
1295e298e505SPravin B Shelar 		ovs_flow_stats_clear(flow);
12968e4e1713SPravin B Shelar 	ovs_unlock();
1297ccb1352eSJesse Gross 
1298893f139bSJarno Rajahalme 	if (reply)
12992a94fe48SJohannes Berg 		ovs_notify(&dp_flow_genl_family, reply, info);
1300893f139bSJarno Rajahalme 	if (old_acts)
130134ae932aSThomas Graf 		ovs_nla_free_flow_actions_rcu(old_acts);
1302fb5d1e9eSJarno Rajahalme 
1303ccb1352eSJesse Gross 	return 0;
1304ccb1352eSJesse Gross 
13058e4e1713SPravin B Shelar err_unlock_ovs:
13068e4e1713SPravin B Shelar 	ovs_unlock();
1307893f139bSJarno Rajahalme 	kfree_skb(reply);
1308893f139bSJarno Rajahalme err_kfree_acts:
130934ae932aSThomas Graf 	ovs_nla_free_flow_actions(acts);
1310ccb1352eSJesse Gross error:
1311ccb1352eSJesse Gross 	return error;
1312ccb1352eSJesse Gross }
1313ccb1352eSJesse Gross 
ovs_flow_cmd_get(struct sk_buff * skb,struct genl_info * info)1314ccb1352eSJesse Gross static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
1315ccb1352eSJesse Gross {
1316ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1317bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
1318c2ac6673SJoe Stringer 	struct net *net = sock_net(skb->sk);
1319ccb1352eSJesse Gross 	struct sw_flow_key key;
1320ccb1352eSJesse Gross 	struct sk_buff *reply;
1321ccb1352eSJesse Gross 	struct sw_flow *flow;
1322ccb1352eSJesse Gross 	struct datapath *dp;
132303f0d916SAndy Zhou 	struct sw_flow_match match;
132474ed7ab9SJoe Stringer 	struct sw_flow_id ufid;
132574ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
132674ed7ab9SJoe Stringer 	int err = 0;
132705da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
132874ed7ab9SJoe Stringer 	bool ufid_present;
1329ccb1352eSJesse Gross 
133074ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
133174ed7ab9SJoe Stringer 	if (a[OVS_FLOW_ATTR_KEY]) {
13322279994dSpravin shelar 		ovs_match_init(&match, &key, true, NULL);
1333c2ac6673SJoe Stringer 		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
133474ed7ab9SJoe Stringer 					log);
133574ed7ab9SJoe Stringer 	} else if (!ufid_present) {
133605da5898SJarno Rajahalme 		OVS_NLERR(log,
133705da5898SJarno Rajahalme 			  "Flow get message rejected, Key attribute missing.");
133874ed7ab9SJoe Stringer 		err = -EINVAL;
133903f0d916SAndy Zhou 	}
1340ccb1352eSJesse Gross 	if (err)
1341ccb1352eSJesse Gross 		return err;
1342ccb1352eSJesse Gross 
13438e4e1713SPravin B Shelar 	ovs_lock();
134446df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
13458e4e1713SPravin B Shelar 	if (!dp) {
13468e4e1713SPravin B Shelar 		err = -ENODEV;
13478e4e1713SPravin B Shelar 		goto unlock;
13488e4e1713SPravin B Shelar 	}
1349ccb1352eSJesse Gross 
135074ed7ab9SJoe Stringer 	if (ufid_present)
135174ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
135274ed7ab9SJoe Stringer 	else
13534a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
13544a46b24eSAlex Wang 	if (!flow) {
13558e4e1713SPravin B Shelar 		err = -ENOENT;
13568e4e1713SPravin B Shelar 		goto unlock;
13578e4e1713SPravin B Shelar 	}
1358ccb1352eSJesse Gross 
13590e9796b4SJarno Rajahalme 	reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
1360804fe108SYifeng Sun 					OVS_FLOW_CMD_GET, true, ufid_flags);
13618e4e1713SPravin B Shelar 	if (IS_ERR(reply)) {
13628e4e1713SPravin B Shelar 		err = PTR_ERR(reply);
13638e4e1713SPravin B Shelar 		goto unlock;
13648e4e1713SPravin B Shelar 	}
1365ccb1352eSJesse Gross 
13668e4e1713SPravin B Shelar 	ovs_unlock();
1367ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
13688e4e1713SPravin B Shelar unlock:
13698e4e1713SPravin B Shelar 	ovs_unlock();
13708e4e1713SPravin B Shelar 	return err;
1371ccb1352eSJesse Gross }
1372ccb1352eSJesse Gross 
ovs_flow_cmd_del(struct sk_buff * skb,struct genl_info * info)1373ccb1352eSJesse Gross static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
1374ccb1352eSJesse Gross {
1375ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1376bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
1377c2ac6673SJoe Stringer 	struct net *net = sock_net(skb->sk);
1378ccb1352eSJesse Gross 	struct sw_flow_key key;
1379ccb1352eSJesse Gross 	struct sk_buff *reply;
138074ed7ab9SJoe Stringer 	struct sw_flow *flow = NULL;
1381ccb1352eSJesse Gross 	struct datapath *dp;
138203f0d916SAndy Zhou 	struct sw_flow_match match;
138374ed7ab9SJoe Stringer 	struct sw_flow_id ufid;
138474ed7ab9SJoe Stringer 	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
1385ccb1352eSJesse Gross 	int err;
138605da5898SJarno Rajahalme 	bool log = !a[OVS_FLOW_ATTR_PROBE];
138774ed7ab9SJoe Stringer 	bool ufid_present;
1388ccb1352eSJesse Gross 
138974ed7ab9SJoe Stringer 	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
139074ed7ab9SJoe Stringer 	if (a[OVS_FLOW_ATTR_KEY]) {
13912279994dSpravin shelar 		ovs_match_init(&match, &key, true, NULL);
1392c2ac6673SJoe Stringer 		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
1393c2ac6673SJoe Stringer 					NULL, log);
1394aed06778SJarno Rajahalme 		if (unlikely(err))
1395aed06778SJarno Rajahalme 			return err;
1396aed06778SJarno Rajahalme 	}
1397aed06778SJarno Rajahalme 
13988e4e1713SPravin B Shelar 	ovs_lock();
139946df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1400aed06778SJarno Rajahalme 	if (unlikely(!dp)) {
14018e4e1713SPravin B Shelar 		err = -ENODEV;
14028e4e1713SPravin B Shelar 		goto unlock;
14038e4e1713SPravin B Shelar 	}
140446df7b81SPravin B Shelar 
140574ed7ab9SJoe Stringer 	if (unlikely(!a[OVS_FLOW_ATTR_KEY] && !ufid_present)) {
1406b637e498SPravin B Shelar 		err = ovs_flow_tbl_flush(&dp->table);
14078e4e1713SPravin B Shelar 		goto unlock;
14088e4e1713SPravin B Shelar 	}
140903f0d916SAndy Zhou 
141074ed7ab9SJoe Stringer 	if (ufid_present)
141174ed7ab9SJoe Stringer 		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
141274ed7ab9SJoe Stringer 	else
14134a46b24eSAlex Wang 		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
14144a46b24eSAlex Wang 	if (unlikely(!flow)) {
14158e4e1713SPravin B Shelar 		err = -ENOENT;
14168e4e1713SPravin B Shelar 		goto unlock;
14178e4e1713SPravin B Shelar 	}
1418ccb1352eSJesse Gross 
1419b637e498SPravin B Shelar 	ovs_flow_tbl_remove(&dp->table, flow);
1420aed06778SJarno Rajahalme 	ovs_unlock();
1421ccb1352eSJesse Gross 
1422aed06778SJarno Rajahalme 	reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts,
142374ed7ab9SJoe Stringer 					&flow->id, info, false, ufid_flags);
1424aed06778SJarno Rajahalme 	if (likely(reply)) {
1425b90f5aa4SEnrico Weigelt 		if (!IS_ERR(reply)) {
1426aed06778SJarno Rajahalme 			rcu_read_lock();	/*To keep RCU checker happy. */
14270e9796b4SJarno Rajahalme 			err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
14280e9796b4SJarno Rajahalme 						     reply, info->snd_portid,
1429fb5d1e9eSJarno Rajahalme 						     info->snd_seq, 0,
143074ed7ab9SJoe Stringer 						     OVS_FLOW_CMD_DEL,
143174ed7ab9SJoe Stringer 						     ufid_flags);
1432aed06778SJarno Rajahalme 			rcu_read_unlock();
14338a574f86SPaolo Abeni 			if (WARN_ON_ONCE(err < 0)) {
14348a574f86SPaolo Abeni 				kfree_skb(reply);
14358a574f86SPaolo Abeni 				goto out_free;
14368a574f86SPaolo Abeni 			}
1437ccb1352eSJesse Gross 
14382a94fe48SJohannes Berg 			ovs_notify(&dp_flow_genl_family, reply, info);
1439aed06778SJarno Rajahalme 		} else {
1440cf3266adSTonghao Zhang 			netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
1441cf3266adSTonghao Zhang 					PTR_ERR(reply));
1442aed06778SJarno Rajahalme 		}
1443aed06778SJarno Rajahalme 	}
1444aed06778SJarno Rajahalme 
14458a574f86SPaolo Abeni out_free:
1446aed06778SJarno Rajahalme 	ovs_flow_free(flow, true);
1447ccb1352eSJesse Gross 	return 0;
14488e4e1713SPravin B Shelar unlock:
14498e4e1713SPravin B Shelar 	ovs_unlock();
14508e4e1713SPravin B Shelar 	return err;
1451ccb1352eSJesse Gross }
1452ccb1352eSJesse Gross 
ovs_flow_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)1453ccb1352eSJesse Gross static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
1454ccb1352eSJesse Gross {
145574ed7ab9SJoe Stringer 	struct nlattr *a[__OVS_FLOW_ATTR_MAX];
1456ccb1352eSJesse Gross 	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
1457b637e498SPravin B Shelar 	struct table_instance *ti;
1458ccb1352eSJesse Gross 	struct datapath *dp;
145974ed7ab9SJoe Stringer 	u32 ufid_flags;
146074ed7ab9SJoe Stringer 	int err;
146174ed7ab9SJoe Stringer 
14628cb08174SJohannes Berg 	err = genlmsg_parse_deprecated(cb->nlh, &dp_flow_genl_family, a,
1463fceb6435SJohannes Berg 				       OVS_FLOW_ATTR_MAX, flow_policy, NULL);
146474ed7ab9SJoe Stringer 	if (err)
146574ed7ab9SJoe Stringer 		return err;
146674ed7ab9SJoe Stringer 	ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
1467ccb1352eSJesse Gross 
1468d57170b1SPravin B Shelar 	rcu_read_lock();
1469cc3a5ae6SAndy Zhou 	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
14708e4e1713SPravin B Shelar 	if (!dp) {
1471d57170b1SPravin B Shelar 		rcu_read_unlock();
1472ccb1352eSJesse Gross 		return -ENODEV;
14738e4e1713SPravin B Shelar 	}
1474ccb1352eSJesse Gross 
1475b637e498SPravin B Shelar 	ti = rcu_dereference(dp->table.ti);
1476ccb1352eSJesse Gross 	for (;;) {
1477ccb1352eSJesse Gross 		struct sw_flow *flow;
1478ccb1352eSJesse Gross 		u32 bucket, obj;
1479ccb1352eSJesse Gross 
1480ccb1352eSJesse Gross 		bucket = cb->args[0];
1481ccb1352eSJesse Gross 		obj = cb->args[1];
1482b637e498SPravin B Shelar 		flow = ovs_flow_tbl_dump_next(ti, &bucket, &obj);
1483ccb1352eSJesse Gross 		if (!flow)
1484ccb1352eSJesse Gross 			break;
1485ccb1352eSJesse Gross 
14860e9796b4SJarno Rajahalme 		if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
148715e47304SEric W. Biederman 					   NETLINK_CB(cb->skb).portid,
1488ccb1352eSJesse Gross 					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
1489804fe108SYifeng Sun 					   OVS_FLOW_CMD_GET, ufid_flags) < 0)
1490ccb1352eSJesse Gross 			break;
1491ccb1352eSJesse Gross 
1492ccb1352eSJesse Gross 		cb->args[0] = bucket;
1493ccb1352eSJesse Gross 		cb->args[1] = obj;
1494ccb1352eSJesse Gross 	}
1495d57170b1SPravin B Shelar 	rcu_read_unlock();
1496ccb1352eSJesse Gross 	return skb->len;
1497ccb1352eSJesse Gross }
1498ccb1352eSJesse Gross 
14990c200ef9SPravin B Shelar static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
15000c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
150105da5898SJarno Rajahalme 	[OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED },
15020c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
15030c200ef9SPravin B Shelar 	[OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
150405da5898SJarno Rajahalme 	[OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG },
150574ed7ab9SJoe Stringer 	[OVS_FLOW_ATTR_UFID] = { .type = NLA_UNSPEC, .len = 1 },
150674ed7ab9SJoe Stringer 	[OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
15070c200ef9SPravin B Shelar };
15080c200ef9SPravin B Shelar 
150966a9b928SJakub Kicinski static const struct genl_small_ops dp_flow_genl_ops[] = {
1510ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_NEW,
1511ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15124a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
151337bdc87bSJarno Rajahalme 	  .doit = ovs_flow_cmd_new
1514ccb1352eSJesse Gross 	},
1515ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_DEL,
1516ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15174a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
1518ccb1352eSJesse Gross 	  .doit = ovs_flow_cmd_del
1519ccb1352eSJesse Gross 	},
1520ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_GET,
1521ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1522ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
1523ccb1352eSJesse Gross 	  .doit = ovs_flow_cmd_get,
1524ccb1352eSJesse Gross 	  .dumpit = ovs_flow_cmd_dump
1525ccb1352eSJesse Gross 	},
1526ccb1352eSJesse Gross 	{ .cmd = OVS_FLOW_CMD_SET,
1527ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
15284a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
152937bdc87bSJarno Rajahalme 	  .doit = ovs_flow_cmd_set,
1530ccb1352eSJesse Gross 	},
1531ccb1352eSJesse Gross };
1532ccb1352eSJesse Gross 
153356989f6dSJohannes Berg static struct genl_family dp_flow_genl_family __ro_after_init = {
1534ccb1352eSJesse Gross 	.hdrsize = sizeof(struct ovs_header),
15350c200ef9SPravin B Shelar 	.name = OVS_FLOW_FAMILY,
15360c200ef9SPravin B Shelar 	.version = OVS_FLOW_VERSION,
15370c200ef9SPravin B Shelar 	.maxattr = OVS_FLOW_ATTR_MAX,
15383b0f31f2SJohannes Berg 	.policy = flow_policy,
15393a4e0d6aSPravin B Shelar 	.netnsok = true,
15403a4e0d6aSPravin B Shelar 	.parallel_ops = true,
154166a9b928SJakub Kicinski 	.small_ops = dp_flow_genl_ops,
154266a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_flow_genl_ops),
15439c5d03d3SJakub Kicinski 	.resv_start_op = OVS_FLOW_CMD_SET + 1,
15440c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_flow_multicast_group,
15450c200ef9SPravin B Shelar 	.n_mcgrps = 1,
1546489111e5SJohannes Berg 	.module = THIS_MODULE,
1547ccb1352eSJesse Gross };
1548ccb1352eSJesse Gross 
ovs_dp_cmd_msg_size(void)1549c3ff8cfeSThomas Graf static size_t ovs_dp_cmd_msg_size(void)
1550c3ff8cfeSThomas Graf {
1551c3ff8cfeSThomas Graf 	size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
1552c3ff8cfeSThomas Graf 
1553c3ff8cfeSThomas Graf 	msgsize += nla_total_size(IFNAMSIZ);
155466c7a5eeSNicolas Dichtel 	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
155566c7a5eeSNicolas Dichtel 	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
155645fb9c35SDaniele Di Proietto 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
15579bf24f59SEelco Chaudron 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE */
1558347541e2SAndrey Zhadchenko 	msgsize += nla_total_size(sizeof(u32) * nr_cpu_ids); /* OVS_DP_ATTR_PER_CPU_PIDS */
1559c3ff8cfeSThomas Graf 
1560c3ff8cfeSThomas Graf 	return msgsize;
1561c3ff8cfeSThomas Graf }
1562c3ff8cfeSThomas Graf 
15638ec609d8SPravin 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)1564ccb1352eSJesse Gross static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
156515e47304SEric W. Biederman 				u32 portid, u32 seq, u32 flags, u8 cmd)
1566ccb1352eSJesse Gross {
1567ccb1352eSJesse Gross 	struct ovs_header *ovs_header;
1568ccb1352eSJesse Gross 	struct ovs_dp_stats dp_stats;
15691bd7116fSAndy Zhou 	struct ovs_dp_megaflow_stats dp_megaflow_stats;
1570347541e2SAndrey Zhadchenko 	struct dp_nlsk_pids *pids = ovsl_dereference(dp->upcall_portids);
1571347541e2SAndrey Zhadchenko 	int err, pids_len;
1572ccb1352eSJesse Gross 
157315e47304SEric W. Biederman 	ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family,
1574ccb1352eSJesse Gross 				 flags, cmd);
1575ccb1352eSJesse Gross 	if (!ovs_header)
1576ccb1352eSJesse Gross 		goto error;
1577ccb1352eSJesse Gross 
1578ccb1352eSJesse Gross 	ovs_header->dp_ifindex = get_dpifindex(dp);
1579ccb1352eSJesse Gross 
1580ccb1352eSJesse Gross 	err = nla_put_string(skb, OVS_DP_ATTR_NAME, ovs_dp_name(dp));
1581ccb1352eSJesse Gross 	if (err)
1582ccb1352eSJesse Gross 		goto nla_put_failure;
1583ccb1352eSJesse Gross 
15841bd7116fSAndy Zhou 	get_dp_stats(dp, &dp_stats, &dp_megaflow_stats);
158566c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
158666c7a5eeSNicolas Dichtel 			  &dp_stats, OVS_DP_ATTR_PAD))
15871bd7116fSAndy Zhou 		goto nla_put_failure;
15881bd7116fSAndy Zhou 
158966c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
15901bd7116fSAndy Zhou 			  sizeof(struct ovs_dp_megaflow_stats),
159166c7a5eeSNicolas Dichtel 			  &dp_megaflow_stats, OVS_DP_ATTR_PAD))
1592028d6a67SDavid S. Miller 		goto nla_put_failure;
1593ccb1352eSJesse Gross 
159443d4be9cSThomas Graf 	if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
159543d4be9cSThomas Graf 		goto nla_put_failure;
159643d4be9cSThomas Graf 
15979bf24f59SEelco Chaudron 	if (nla_put_u32(skb, OVS_DP_ATTR_MASKS_CACHE_SIZE,
15989bf24f59SEelco Chaudron 			ovs_flow_tbl_masks_cache_size(&dp->table)))
15999bf24f59SEelco Chaudron 		goto nla_put_failure;
16009bf24f59SEelco Chaudron 
1601347541e2SAndrey Zhadchenko 	if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU && pids) {
1602347541e2SAndrey Zhadchenko 		pids_len = min(pids->n_pids, nr_cpu_ids) * sizeof(u32);
1603347541e2SAndrey Zhadchenko 		if (nla_put(skb, OVS_DP_ATTR_PER_CPU_PIDS, pids_len, &pids->pids))
1604347541e2SAndrey Zhadchenko 			goto nla_put_failure;
1605347541e2SAndrey Zhadchenko 	}
1606347541e2SAndrey Zhadchenko 
1607053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
1608053c095aSJohannes Berg 	return 0;
1609ccb1352eSJesse Gross 
1610ccb1352eSJesse Gross nla_put_failure:
1611ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
1612ccb1352eSJesse Gross error:
1613ccb1352eSJesse Gross 	return -EMSGSIZE;
1614ccb1352eSJesse Gross }
1615ccb1352eSJesse Gross 
ovs_dp_cmd_alloc_info(void)1616263ea090SFlorian Westphal static struct sk_buff *ovs_dp_cmd_alloc_info(void)
1617ccb1352eSJesse Gross {
1618551ddc05SFlorian Westphal 	return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
1619ccb1352eSJesse Gross }
1620ccb1352eSJesse Gross 
1621bb6f9a70SJarno 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])162246df7b81SPravin B Shelar static struct datapath *lookup_datapath(struct net *net,
162312eb18f7SThomas Graf 					const struct ovs_header *ovs_header,
1624ccb1352eSJesse Gross 					struct nlattr *a[OVS_DP_ATTR_MAX + 1])
1625ccb1352eSJesse Gross {
1626ccb1352eSJesse Gross 	struct datapath *dp;
1627ccb1352eSJesse Gross 
1628ccb1352eSJesse Gross 	if (!a[OVS_DP_ATTR_NAME])
162946df7b81SPravin B Shelar 		dp = get_dp(net, ovs_header->dp_ifindex);
1630ccb1352eSJesse Gross 	else {
1631ccb1352eSJesse Gross 		struct vport *vport;
1632ccb1352eSJesse Gross 
163346df7b81SPravin B Shelar 		vport = ovs_vport_locate(net, nla_data(a[OVS_DP_ATTR_NAME]));
1634ccb1352eSJesse Gross 		dp = vport && vport->port_no == OVSP_LOCAL ? vport->dp : NULL;
1635ccb1352eSJesse Gross 	}
1636ccb1352eSJesse Gross 	return dp ? dp : ERR_PTR(-ENODEV);
1637ccb1352eSJesse Gross }
1638ccb1352eSJesse Gross 
ovs_dp_reset_user_features(struct sk_buff * skb,struct genl_info * info)1639cf3266adSTonghao Zhang static void ovs_dp_reset_user_features(struct sk_buff *skb,
1640cf3266adSTonghao Zhang 				       struct genl_info *info)
164144da5ae5SThomas Graf {
164244da5ae5SThomas Graf 	struct datapath *dp;
164344da5ae5SThomas Graf 
1644bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1645cf3266adSTonghao Zhang 			     info->attrs);
16463c7eacfcSJiri Pirko 	if (IS_ERR(dp))
164744da5ae5SThomas Graf 		return;
164844da5ae5SThomas Graf 
1649fd954cc1SAaron Conole 	pr_warn("%s: Dropping previously announced user features\n",
1650fd954cc1SAaron Conole 		ovs_dp_name(dp));
165144da5ae5SThomas Graf 	dp->user_features = 0;
165244da5ae5SThomas Graf }
165344da5ae5SThomas Graf 
ovs_dp_set_upcall_portids(struct datapath * dp,const struct nlattr * ids)1654b83d23a2SMark Gray static int ovs_dp_set_upcall_portids(struct datapath *dp,
1655b83d23a2SMark Gray 			      const struct nlattr *ids)
1656b83d23a2SMark Gray {
1657b83d23a2SMark Gray 	struct dp_nlsk_pids *old, *dp_nlsk_pids;
1658b83d23a2SMark Gray 
1659b83d23a2SMark Gray 	if (!nla_len(ids) || nla_len(ids) % sizeof(u32))
1660b83d23a2SMark Gray 		return -EINVAL;
1661b83d23a2SMark Gray 
1662b83d23a2SMark Gray 	old = ovsl_dereference(dp->upcall_portids);
1663b83d23a2SMark Gray 
1664b83d23a2SMark Gray 	dp_nlsk_pids = kmalloc(sizeof(*dp_nlsk_pids) + nla_len(ids),
1665b83d23a2SMark Gray 			       GFP_KERNEL);
1666b83d23a2SMark Gray 	if (!dp_nlsk_pids)
1667b83d23a2SMark Gray 		return -ENOMEM;
1668b83d23a2SMark Gray 
1669b83d23a2SMark Gray 	dp_nlsk_pids->n_pids = nla_len(ids) / sizeof(u32);
1670b83d23a2SMark Gray 	nla_memcpy(dp_nlsk_pids->pids, ids, nla_len(ids));
1671b83d23a2SMark Gray 
1672b83d23a2SMark Gray 	rcu_assign_pointer(dp->upcall_portids, dp_nlsk_pids);
1673b83d23a2SMark Gray 
1674b83d23a2SMark Gray 	kfree_rcu(old, rcu);
1675b83d23a2SMark Gray 
1676b83d23a2SMark Gray 	return 0;
1677b83d23a2SMark Gray }
1678b83d23a2SMark Gray 
ovs_dp_get_upcall_portid(const struct datapath * dp,uint32_t cpu_id)1679b83d23a2SMark Gray u32 ovs_dp_get_upcall_portid(const struct datapath *dp, uint32_t cpu_id)
1680b83d23a2SMark Gray {
1681b83d23a2SMark Gray 	struct dp_nlsk_pids *dp_nlsk_pids;
1682b83d23a2SMark Gray 
1683b83d23a2SMark Gray 	dp_nlsk_pids = rcu_dereference(dp->upcall_portids);
1684b83d23a2SMark Gray 
1685b83d23a2SMark Gray 	if (dp_nlsk_pids) {
1686b83d23a2SMark Gray 		if (cpu_id < dp_nlsk_pids->n_pids) {
1687b83d23a2SMark Gray 			return dp_nlsk_pids->pids[cpu_id];
1688784dcfa5SMark Gray 		} else if (dp_nlsk_pids->n_pids > 0 &&
1689784dcfa5SMark Gray 			   cpu_id >= dp_nlsk_pids->n_pids) {
1690784dcfa5SMark Gray 			/* If the number of netlink PIDs is mismatched with
1691784dcfa5SMark Gray 			 * the number of CPUs as seen by the kernel, log this
1692784dcfa5SMark Gray 			 * and send the upcall to an arbitrary socket (0) in
1693784dcfa5SMark Gray 			 * order to not drop packets
1694b83d23a2SMark Gray 			 */
1695b83d23a2SMark Gray 			pr_info_ratelimited("cpu_id mismatch with handler threads");
1696784dcfa5SMark Gray 			return dp_nlsk_pids->pids[cpu_id %
1697784dcfa5SMark Gray 						  dp_nlsk_pids->n_pids];
1698b83d23a2SMark Gray 		} else {
1699b83d23a2SMark Gray 			return 0;
1700b83d23a2SMark Gray 		}
1701b83d23a2SMark Gray 	} else {
1702b83d23a2SMark Gray 		return 0;
1703b83d23a2SMark Gray 	}
1704b83d23a2SMark Gray }
1705b83d23a2SMark Gray 
ovs_dp_change(struct datapath * dp,struct nlattr * a[])170695a7233cSPaul Blakey static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
170743d4be9cSThomas Graf {
170835d39fecSPaul Blakey 	u32 user_features = 0, old_features = dp->user_features;
1709b83d23a2SMark Gray 	int err;
171095a7233cSPaul Blakey 
171195a7233cSPaul Blakey 	if (a[OVS_DP_ATTR_USER_FEATURES]) {
171295a7233cSPaul Blakey 		user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
171395a7233cSPaul Blakey 
171495a7233cSPaul Blakey 		if (user_features & ~(OVS_DP_F_VPORT_PIDS |
171595a7233cSPaul Blakey 				      OVS_DP_F_UNALIGNED |
1716b83d23a2SMark Gray 				      OVS_DP_F_TC_RECIRC_SHARING |
1717b83d23a2SMark Gray 				      OVS_DP_F_DISPATCH_UPCALL_PER_CPU))
171895a7233cSPaul Blakey 			return -EOPNOTSUPP;
171995a7233cSPaul Blakey 
172095a7233cSPaul Blakey #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
172195a7233cSPaul Blakey 		if (user_features & OVS_DP_F_TC_RECIRC_SHARING)
172295a7233cSPaul Blakey 			return -EOPNOTSUPP;
172395a7233cSPaul Blakey #endif
172495a7233cSPaul Blakey 	}
172595a7233cSPaul Blakey 
17269bf24f59SEelco Chaudron 	if (a[OVS_DP_ATTR_MASKS_CACHE_SIZE]) {
17279bf24f59SEelco Chaudron 		int err;
17289bf24f59SEelco Chaudron 		u32 cache_size;
17299bf24f59SEelco Chaudron 
17309bf24f59SEelco Chaudron 		cache_size = nla_get_u32(a[OVS_DP_ATTR_MASKS_CACHE_SIZE]);
17319bf24f59SEelco Chaudron 		err = ovs_flow_tbl_masks_cache_resize(&dp->table, cache_size);
17329bf24f59SEelco Chaudron 		if (err)
17339bf24f59SEelco Chaudron 			return err;
17349bf24f59SEelco Chaudron 	}
17359bf24f59SEelco Chaudron 
173695a7233cSPaul Blakey 	dp->user_features = user_features;
173795a7233cSPaul Blakey 
1738b83d23a2SMark Gray 	if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU &&
1739b83d23a2SMark Gray 	    a[OVS_DP_ATTR_PER_CPU_PIDS]) {
1740b83d23a2SMark Gray 		/* Upcall Netlink Port IDs have been updated */
1741b83d23a2SMark Gray 		err = ovs_dp_set_upcall_portids(dp,
1742b83d23a2SMark Gray 						a[OVS_DP_ATTR_PER_CPU_PIDS]);
1743b83d23a2SMark Gray 		if (err)
1744b83d23a2SMark Gray 			return err;
1745b83d23a2SMark Gray 	}
1746b83d23a2SMark Gray 
174735d39fecSPaul Blakey 	if ((dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
174835d39fecSPaul Blakey 	    !(old_features & OVS_DP_F_TC_RECIRC_SHARING))
174935d39fecSPaul Blakey 		tc_skb_ext_tc_enable();
175035d39fecSPaul Blakey 	else if (!(dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
175135d39fecSPaul Blakey 		 (old_features & OVS_DP_F_TC_RECIRC_SHARING))
175235d39fecSPaul Blakey 		tc_skb_ext_tc_disable();
175395a7233cSPaul Blakey 
175495a7233cSPaul Blakey 	return 0;
175543d4be9cSThomas Graf }
175643d4be9cSThomas Graf 
ovs_dp_stats_init(struct datapath * dp)1757eec62eadSTonghao Zhang static int ovs_dp_stats_init(struct datapath *dp)
1758eec62eadSTonghao Zhang {
1759eec62eadSTonghao Zhang 	dp->stats_percpu = netdev_alloc_pcpu_stats(struct dp_stats_percpu);
1760eec62eadSTonghao Zhang 	if (!dp->stats_percpu)
1761eec62eadSTonghao Zhang 		return -ENOMEM;
1762eec62eadSTonghao Zhang 
1763eec62eadSTonghao Zhang 	return 0;
1764eec62eadSTonghao Zhang }
1765eec62eadSTonghao Zhang 
ovs_dp_vport_init(struct datapath * dp)1766eec62eadSTonghao Zhang static int ovs_dp_vport_init(struct datapath *dp)
1767eec62eadSTonghao Zhang {
1768eec62eadSTonghao Zhang 	int i;
1769eec62eadSTonghao Zhang 
1770eec62eadSTonghao Zhang 	dp->ports = kmalloc_array(DP_VPORT_HASH_BUCKETS,
1771eec62eadSTonghao Zhang 				  sizeof(struct hlist_head),
1772eec62eadSTonghao Zhang 				  GFP_KERNEL);
1773eec62eadSTonghao Zhang 	if (!dp->ports)
1774eec62eadSTonghao Zhang 		return -ENOMEM;
1775eec62eadSTonghao Zhang 
1776eec62eadSTonghao Zhang 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
1777eec62eadSTonghao Zhang 		INIT_HLIST_HEAD(&dp->ports[i]);
1778eec62eadSTonghao Zhang 
1779eec62eadSTonghao Zhang 	return 0;
1780eec62eadSTonghao Zhang }
1781eec62eadSTonghao Zhang 
ovs_dp_cmd_new(struct sk_buff * skb,struct genl_info * info)1782ccb1352eSJesse Gross static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1783ccb1352eSJesse Gross {
1784ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
1785ccb1352eSJesse Gross 	struct vport_parms parms;
1786ccb1352eSJesse Gross 	struct sk_buff *reply;
1787ccb1352eSJesse Gross 	struct datapath *dp;
1788ccb1352eSJesse Gross 	struct vport *vport;
178946df7b81SPravin B Shelar 	struct ovs_net *ovs_net;
1790eec62eadSTonghao Zhang 	int err;
1791ccb1352eSJesse Gross 
1792ccb1352eSJesse Gross 	err = -EINVAL;
1793ccb1352eSJesse Gross 	if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
1794ccb1352eSJesse Gross 		goto err;
1795ccb1352eSJesse Gross 
1796263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
17976093ae9aSJarno Rajahalme 	if (!reply)
17986093ae9aSJarno Rajahalme 		return -ENOMEM;
1799ccb1352eSJesse Gross 
1800ccb1352eSJesse Gross 	err = -ENOMEM;
1801ccb1352eSJesse Gross 	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
1802ccb1352eSJesse Gross 	if (dp == NULL)
1803eec62eadSTonghao Zhang 		goto err_destroy_reply;
180446df7b81SPravin B Shelar 
1805efd7ef1cSEric W. Biederman 	ovs_dp_set_net(dp, sock_net(skb->sk));
1806ccb1352eSJesse Gross 
1807ccb1352eSJesse Gross 	/* Allocate table. */
1808b637e498SPravin B Shelar 	err = ovs_flow_tbl_init(&dp->table);
1809b637e498SPravin B Shelar 	if (err)
1810eec62eadSTonghao Zhang 		goto err_destroy_dp;
1811ccb1352eSJesse Gross 
1812eec62eadSTonghao Zhang 	err = ovs_dp_stats_init(dp);
1813eec62eadSTonghao Zhang 	if (err)
1814ccb1352eSJesse Gross 		goto err_destroy_table;
1815ccb1352eSJesse Gross 
1816eec62eadSTonghao Zhang 	err = ovs_dp_vport_init(dp);
1817eec62eadSTonghao Zhang 	if (err)
1818eec62eadSTonghao Zhang 		goto err_destroy_stats;
181915eac2a7SPravin B Shelar 
182096fbc13dSAndy Zhou 	err = ovs_meters_init(dp);
182196fbc13dSAndy Zhou 	if (err)
1822eec62eadSTonghao Zhang 		goto err_destroy_ports;
182396fbc13dSAndy Zhou 
1824ccb1352eSJesse Gross 	/* Set up our datapath device. */
1825ccb1352eSJesse Gross 	parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
1826ccb1352eSJesse Gross 	parms.type = OVS_VPORT_TYPE_INTERNAL;
1827ccb1352eSJesse Gross 	parms.options = NULL;
1828ccb1352eSJesse Gross 	parms.dp = dp;
1829ccb1352eSJesse Gross 	parms.port_no = OVSP_LOCAL;
18305cd667b0SAlex Wang 	parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
1831a885a6b2SJohannes Berg 	parms.desired_ifindex = nla_get_s32_default(a[OVS_DP_ATTR_IFINDEX], 0);
1832ccb1352eSJesse Gross 
18336093ae9aSJarno Rajahalme 	/* So far only local changes have been made, now need the lock. */
18346093ae9aSJarno Rajahalme 	ovs_lock();
18356093ae9aSJarno Rajahalme 
1836fea07a48SEelco Chaudron 	err = ovs_dp_change(dp, a);
1837fea07a48SEelco Chaudron 	if (err)
1838fea07a48SEelco Chaudron 		goto err_unlock_and_destroy_meters;
1839fea07a48SEelco Chaudron 
1840ccb1352eSJesse Gross 	vport = new_vport(&parms);
1841ccb1352eSJesse Gross 	if (IS_ERR(vport)) {
1842ccb1352eSJesse Gross 		err = PTR_ERR(vport);
1843ccb1352eSJesse Gross 		if (err == -EBUSY)
1844ccb1352eSJesse Gross 			err = -EEXIST;
1845ccb1352eSJesse Gross 
184644da5ae5SThomas Graf 		if (err == -EEXIST) {
184744da5ae5SThomas Graf 			/* An outdated user space instance that does not understand
184844da5ae5SThomas Graf 			 * the concept of user_features has attempted to create a new
184944da5ae5SThomas Graf 			 * datapath and is likely to reuse it. Drop all user features.
185044da5ae5SThomas Graf 			 */
185144da5ae5SThomas Graf 			if (info->genlhdr->version < OVS_DP_VER_FEATURES)
185244da5ae5SThomas Graf 				ovs_dp_reset_user_features(skb, info);
185344da5ae5SThomas Graf 		}
185444da5ae5SThomas Graf 
1855a87406f4SAndrey Zhadchenko 		goto err_destroy_portids;
1856ccb1352eSJesse Gross 	}
1857ccb1352eSJesse Gross 
18586093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18596093ae9aSJarno Rajahalme 				   info->snd_seq, 0, OVS_DP_CMD_NEW);
18606093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
1861ccb1352eSJesse Gross 
186246df7b81SPravin B Shelar 	ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
186359a35d60SPravin B Shelar 	list_add_tail_rcu(&dp->list_node, &ovs_net->dps);
18648e4e1713SPravin B Shelar 
18658e4e1713SPravin B Shelar 	ovs_unlock();
1866ccb1352eSJesse Gross 
18672a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1868ccb1352eSJesse Gross 	return 0;
1869ccb1352eSJesse Gross 
1870a87406f4SAndrey Zhadchenko err_destroy_portids:
1871a87406f4SAndrey Zhadchenko 	kfree(rcu_dereference_raw(dp->upcall_portids));
1872fea07a48SEelco Chaudron err_unlock_and_destroy_meters:
1873fea07a48SEelco Chaudron 	ovs_unlock();
187496fbc13dSAndy Zhou 	ovs_meters_exit(dp);
1875eec62eadSTonghao Zhang err_destroy_ports:
187615eac2a7SPravin B Shelar 	kfree(dp->ports);
1877eec62eadSTonghao Zhang err_destroy_stats:
1878ccb1352eSJesse Gross 	free_percpu(dp->stats_percpu);
1879ccb1352eSJesse Gross err_destroy_table:
18809b996e54SPravin B Shelar 	ovs_flow_tbl_destroy(&dp->table);
1881eec62eadSTonghao Zhang err_destroy_dp:
1882ccb1352eSJesse Gross 	kfree(dp);
1883eec62eadSTonghao Zhang err_destroy_reply:
18846093ae9aSJarno Rajahalme 	kfree_skb(reply);
1885ccb1352eSJesse Gross err:
1886ccb1352eSJesse Gross 	return err;
1887ccb1352eSJesse Gross }
1888ccb1352eSJesse Gross 
18898e4e1713SPravin B Shelar /* Called with ovs_mutex. */
__dp_destroy(struct datapath * dp)189046df7b81SPravin B Shelar static void __dp_destroy(struct datapath *dp)
1891ccb1352eSJesse Gross {
18921f3a090bSTonghao Zhang 	struct flow_table *table = &dp->table;
189315eac2a7SPravin B Shelar 	int i;
1894ccb1352eSJesse Gross 
189535d39fecSPaul Blakey 	if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
189635d39fecSPaul Blakey 		tc_skb_ext_tc_disable();
189735d39fecSPaul Blakey 
189815eac2a7SPravin B Shelar 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
189915eac2a7SPravin B Shelar 		struct vport *vport;
1900b67bfe0dSSasha Levin 		struct hlist_node *n;
190115eac2a7SPravin B Shelar 
1902b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node)
1903ccb1352eSJesse Gross 			if (vport->port_no != OVSP_LOCAL)
1904ccb1352eSJesse Gross 				ovs_dp_detach_port(vport);
190515eac2a7SPravin B Shelar 	}
1906ccb1352eSJesse Gross 
190759a35d60SPravin B Shelar 	list_del_rcu(&dp->list_node);
1908ccb1352eSJesse Gross 
19098e4e1713SPravin B Shelar 	/* OVSP_LOCAL is datapath internal port. We need to make sure that
1910e80857ccSAndy Zhou 	 * all ports in datapath are destroyed first before freeing datapath.
1911ccb1352eSJesse Gross 	 */
19128e4e1713SPravin B Shelar 	ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
1913ccb1352eSJesse Gross 
19141f3a090bSTonghao Zhang 	/* Flush sw_flow in the tables. RCU cb only releases resource
19151f3a090bSTonghao Zhang 	 * such as dp, ports and tables. That may avoid some issues
19161f3a090bSTonghao Zhang 	 * such as RCU usage warning.
19171f3a090bSTonghao Zhang 	 */
19181f3a090bSTonghao Zhang 	table_instance_flow_flush(table, ovsl_dereference(table->ti),
19191f3a090bSTonghao Zhang 				  ovsl_dereference(table->ufid_ti));
19201f3a090bSTonghao Zhang 
19211f3a090bSTonghao Zhang 	/* RCU destroy the ports, meters and flow tables. */
1922ccb1352eSJesse Gross 	call_rcu(&dp->rcu, destroy_dp_rcu);
192346df7b81SPravin B Shelar }
192446df7b81SPravin B Shelar 
ovs_dp_cmd_del(struct sk_buff * skb,struct genl_info * info)192546df7b81SPravin B Shelar static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
192646df7b81SPravin B Shelar {
192746df7b81SPravin B Shelar 	struct sk_buff *reply;
192846df7b81SPravin B Shelar 	struct datapath *dp;
192946df7b81SPravin B Shelar 	int err;
193046df7b81SPravin B Shelar 
1931263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
19326093ae9aSJarno Rajahalme 	if (!reply)
19336093ae9aSJarno Rajahalme 		return -ENOMEM;
19346093ae9aSJarno Rajahalme 
19358e4e1713SPravin B Shelar 	ovs_lock();
1936bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1937bffcc688SJakub Kicinski 			     info->attrs);
193846df7b81SPravin B Shelar 	err = PTR_ERR(dp);
193946df7b81SPravin B Shelar 	if (IS_ERR(dp))
19406093ae9aSJarno Rajahalme 		goto err_unlock_free;
194146df7b81SPravin B Shelar 
19426093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
19436093ae9aSJarno Rajahalme 				   info->snd_seq, 0, OVS_DP_CMD_DEL);
19446093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
194546df7b81SPravin B Shelar 
194646df7b81SPravin B Shelar 	__dp_destroy(dp);
19478e4e1713SPravin B Shelar 	ovs_unlock();
1948ccb1352eSJesse Gross 
19492a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1950ccb1352eSJesse Gross 
1951ccb1352eSJesse Gross 	return 0;
19526093ae9aSJarno Rajahalme 
19536093ae9aSJarno Rajahalme err_unlock_free:
19548e4e1713SPravin B Shelar 	ovs_unlock();
19556093ae9aSJarno Rajahalme 	kfree_skb(reply);
19568e4e1713SPravin B Shelar 	return err;
1957ccb1352eSJesse Gross }
1958ccb1352eSJesse Gross 
ovs_dp_cmd_set(struct sk_buff * skb,struct genl_info * info)1959ccb1352eSJesse Gross static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
1960ccb1352eSJesse Gross {
1961ccb1352eSJesse Gross 	struct sk_buff *reply;
1962ccb1352eSJesse Gross 	struct datapath *dp;
1963ccb1352eSJesse Gross 	int err;
1964ccb1352eSJesse Gross 
1965263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
19666093ae9aSJarno Rajahalme 	if (!reply)
19676093ae9aSJarno Rajahalme 		return -ENOMEM;
19686093ae9aSJarno Rajahalme 
19698e4e1713SPravin B Shelar 	ovs_lock();
1970bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
1971bffcc688SJakub Kicinski 			     info->attrs);
19728e4e1713SPravin B Shelar 	err = PTR_ERR(dp);
1973ccb1352eSJesse Gross 	if (IS_ERR(dp))
19746093ae9aSJarno Rajahalme 		goto err_unlock_free;
1975ccb1352eSJesse Gross 
197695a7233cSPaul Blakey 	err = ovs_dp_change(dp, info->attrs);
197795a7233cSPaul Blakey 	if (err)
197895a7233cSPaul Blakey 		goto err_unlock_free;
197943d4be9cSThomas Graf 
19806093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1981804fe108SYifeng Sun 				   info->snd_seq, 0, OVS_DP_CMD_SET);
19826093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
1983ccb1352eSJesse Gross 
19848e4e1713SPravin B Shelar 	ovs_unlock();
19852a94fe48SJohannes Berg 	ovs_notify(&dp_datapath_genl_family, reply, info);
1986ccb1352eSJesse Gross 
1987ccb1352eSJesse Gross 	return 0;
19886093ae9aSJarno Rajahalme 
19896093ae9aSJarno Rajahalme err_unlock_free:
19908e4e1713SPravin B Shelar 	ovs_unlock();
19916093ae9aSJarno Rajahalme 	kfree_skb(reply);
19928e4e1713SPravin B Shelar 	return err;
1993ccb1352eSJesse Gross }
1994ccb1352eSJesse Gross 
ovs_dp_cmd_get(struct sk_buff * skb,struct genl_info * info)1995ccb1352eSJesse Gross static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
1996ccb1352eSJesse Gross {
1997ccb1352eSJesse Gross 	struct sk_buff *reply;
1998ccb1352eSJesse Gross 	struct datapath *dp;
19998e4e1713SPravin B Shelar 	int err;
2000ccb1352eSJesse Gross 
2001263ea090SFlorian Westphal 	reply = ovs_dp_cmd_alloc_info();
20026093ae9aSJarno Rajahalme 	if (!reply)
20036093ae9aSJarno Rajahalme 		return -ENOMEM;
20046093ae9aSJarno Rajahalme 
20058ec609d8SPravin B Shelar 	ovs_lock();
2006bffcc688SJakub Kicinski 	dp = lookup_datapath(sock_net(skb->sk), genl_info_userhdr(info),
2007bffcc688SJakub Kicinski 			     info->attrs);
20088e4e1713SPravin B Shelar 	if (IS_ERR(dp)) {
20098e4e1713SPravin B Shelar 		err = PTR_ERR(dp);
20106093ae9aSJarno Rajahalme 		goto err_unlock_free;
20118e4e1713SPravin B Shelar 	}
20126093ae9aSJarno Rajahalme 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
2013804fe108SYifeng Sun 				   info->snd_seq, 0, OVS_DP_CMD_GET);
20146093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
20158ec609d8SPravin B Shelar 	ovs_unlock();
2016ccb1352eSJesse Gross 
2017ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
20188e4e1713SPravin B Shelar 
20196093ae9aSJarno Rajahalme err_unlock_free:
20208ec609d8SPravin B Shelar 	ovs_unlock();
20216093ae9aSJarno Rajahalme 	kfree_skb(reply);
20228e4e1713SPravin B Shelar 	return err;
2023ccb1352eSJesse Gross }
2024ccb1352eSJesse Gross 
ovs_dp_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)2025ccb1352eSJesse Gross static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
2026ccb1352eSJesse Gross {
202746df7b81SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id);
2028ccb1352eSJesse Gross 	struct datapath *dp;
2029ccb1352eSJesse Gross 	int skip = cb->args[0];
2030ccb1352eSJesse Gross 	int i = 0;
2031ccb1352eSJesse Gross 
20328ec609d8SPravin B Shelar 	ovs_lock();
20338ec609d8SPravin B Shelar 	list_for_each_entry(dp, &ovs_net->dps, list_node) {
203477676fdbSBen Pfaff 		if (i >= skip &&
203515e47304SEric W. Biederman 		    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
2036ccb1352eSJesse Gross 					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
2037804fe108SYifeng Sun 					 OVS_DP_CMD_GET) < 0)
2038ccb1352eSJesse Gross 			break;
2039ccb1352eSJesse Gross 		i++;
2040ccb1352eSJesse Gross 	}
20418ec609d8SPravin B Shelar 	ovs_unlock();
2042ccb1352eSJesse Gross 
2043ccb1352eSJesse Gross 	cb->args[0] = i;
2044ccb1352eSJesse Gross 
2045ccb1352eSJesse Gross 	return skb->len;
2046ccb1352eSJesse Gross }
2047ccb1352eSJesse Gross 
20480c200ef9SPravin B Shelar static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
20490c200ef9SPravin B Shelar 	[OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
20500c200ef9SPravin B Shelar 	[OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
20510c200ef9SPravin B Shelar 	[OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
20529bf24f59SEelco Chaudron 	[OVS_DP_ATTR_MASKS_CACHE_SIZE] =  NLA_POLICY_RANGE(NLA_U32, 0,
20539bf24f59SEelco Chaudron 		PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
2054a552bfa1SJakub Kicinski 	[OVS_DP_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
20550c200ef9SPravin B Shelar };
20560c200ef9SPravin B Shelar 
205766a9b928SJakub Kicinski static const struct genl_small_ops dp_datapath_genl_ops[] = {
2058ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_NEW,
2059ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20604a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2061ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_new
2062ccb1352eSJesse Gross 	},
2063ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_DEL,
2064ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20654a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2066ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_del
2067ccb1352eSJesse Gross 	},
2068ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_GET,
2069ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2070ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
2071ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_get,
2072ccb1352eSJesse Gross 	  .dumpit = ovs_dp_cmd_dump
2073ccb1352eSJesse Gross 	},
2074ccb1352eSJesse Gross 	{ .cmd = OVS_DP_CMD_SET,
2075ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20764a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2077ccb1352eSJesse Gross 	  .doit = ovs_dp_cmd_set,
2078ccb1352eSJesse Gross 	},
2079ccb1352eSJesse Gross };
2080ccb1352eSJesse Gross 
208156989f6dSJohannes Berg static struct genl_family dp_datapath_genl_family __ro_after_init = {
2082ccb1352eSJesse Gross 	.hdrsize = sizeof(struct ovs_header),
20830c200ef9SPravin B Shelar 	.name = OVS_DATAPATH_FAMILY,
20840c200ef9SPravin B Shelar 	.version = OVS_DATAPATH_VERSION,
20850c200ef9SPravin B Shelar 	.maxattr = OVS_DP_ATTR_MAX,
20863b0f31f2SJohannes Berg 	.policy = datapath_policy,
20873a4e0d6aSPravin B Shelar 	.netnsok = true,
20883a4e0d6aSPravin B Shelar 	.parallel_ops = true,
208966a9b928SJakub Kicinski 	.small_ops = dp_datapath_genl_ops,
209066a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_datapath_genl_ops),
20919c5d03d3SJakub Kicinski 	.resv_start_op = OVS_DP_CMD_SET + 1,
20920c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_datapath_multicast_group,
20930c200ef9SPravin B Shelar 	.n_mcgrps = 1,
2094489111e5SJohannes Berg 	.module = THIS_MODULE,
2095ccb1352eSJesse Gross };
2096ccb1352eSJesse Gross 
20978e4e1713SPravin 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)2098ccb1352eSJesse Gross static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
20999354d452SJiri Benc 				   struct net *net, u32 portid, u32 seq,
2100d4e4fdf9SGuillaume Nault 				   u32 flags, u8 cmd, gfp_t gfp)
2101ccb1352eSJesse Gross {
2102ccb1352eSJesse Gross 	struct ovs_header *ovs_header;
2103ccb1352eSJesse Gross 	struct ovs_vport_stats vport_stats;
2104*90b2f49aSEric Dumazet 	struct net *net_vport;
2105ccb1352eSJesse Gross 	int err;
2106ccb1352eSJesse Gross 
210715e47304SEric W. Biederman 	ovs_header = genlmsg_put(skb, portid, seq, &dp_vport_genl_family,
2108ccb1352eSJesse Gross 				 flags, cmd);
2109ccb1352eSJesse Gross 	if (!ovs_header)
2110ccb1352eSJesse Gross 		return -EMSGSIZE;
2111ccb1352eSJesse Gross 
2112ccb1352eSJesse Gross 	ovs_header->dp_ifindex = get_dpifindex(vport->dp);
2113ccb1352eSJesse Gross 
2114028d6a67SDavid S. Miller 	if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
2115028d6a67SDavid S. Miller 	    nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
21165cd667b0SAlex Wang 	    nla_put_string(skb, OVS_VPORT_ATTR_NAME,
21179354d452SJiri Benc 			   ovs_vport_name(vport)) ||
21189354d452SJiri Benc 	    nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex))
2119028d6a67SDavid S. Miller 		goto nla_put_failure;
2120ccb1352eSJesse Gross 
2121*90b2f49aSEric Dumazet 	rcu_read_lock();
2122*90b2f49aSEric Dumazet 	net_vport = dev_net_rcu(vport->dev);
2123*90b2f49aSEric Dumazet 	if (!net_eq(net, net_vport)) {
2124*90b2f49aSEric Dumazet 		int id = peernet2id_alloc(net, net_vport, GFP_ATOMIC);
21259354d452SJiri Benc 
21269354d452SJiri Benc 		if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
2127*90b2f49aSEric Dumazet 			goto nla_put_failure_unlock;
21289354d452SJiri Benc 	}
2129*90b2f49aSEric Dumazet 	rcu_read_unlock();
21309354d452SJiri Benc 
2131ccb1352eSJesse Gross 	ovs_vport_get_stats(vport, &vport_stats);
213266c7a5eeSNicolas Dichtel 	if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
213366c7a5eeSNicolas Dichtel 			  sizeof(struct ovs_vport_stats), &vport_stats,
213466c7a5eeSNicolas Dichtel 			  OVS_VPORT_ATTR_PAD))
2135028d6a67SDavid S. Miller 		goto nla_put_failure;
2136ccb1352eSJesse Gross 
21371933ea36Swangchuanlei 	if (ovs_vport_get_upcall_stats(vport, skb))
21381933ea36Swangchuanlei 		goto nla_put_failure;
21391933ea36Swangchuanlei 
21405cd667b0SAlex Wang 	if (ovs_vport_get_upcall_portids(vport, skb))
21415cd667b0SAlex Wang 		goto nla_put_failure;
21425cd667b0SAlex Wang 
2143ccb1352eSJesse Gross 	err = ovs_vport_get_options(vport, skb);
2144ccb1352eSJesse Gross 	if (err == -EMSGSIZE)
2145ccb1352eSJesse Gross 		goto error;
2146ccb1352eSJesse Gross 
2147053c095aSJohannes Berg 	genlmsg_end(skb, ovs_header);
2148053c095aSJohannes Berg 	return 0;
2149ccb1352eSJesse Gross 
2150*90b2f49aSEric Dumazet nla_put_failure_unlock:
2151*90b2f49aSEric Dumazet 	rcu_read_unlock();
2152ccb1352eSJesse Gross nla_put_failure:
2153ccb1352eSJesse Gross 	err = -EMSGSIZE;
2154ccb1352eSJesse Gross error:
2155ccb1352eSJesse Gross 	genlmsg_cancel(skb, ovs_header);
2156ccb1352eSJesse Gross 	return err;
2157ccb1352eSJesse Gross }
2158ccb1352eSJesse Gross 
ovs_vport_cmd_alloc_info(void)21596093ae9aSJarno Rajahalme static struct sk_buff *ovs_vport_cmd_alloc_info(void)
21606093ae9aSJarno Rajahalme {
21616093ae9aSJarno Rajahalme 	return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
21626093ae9aSJarno Rajahalme }
21636093ae9aSJarno Rajahalme 
21646093ae9aSJarno 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)21659354d452SJiri Benc struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
21669354d452SJiri Benc 					 u32 portid, u32 seq, u8 cmd)
2167ccb1352eSJesse Gross {
2168ccb1352eSJesse Gross 	struct sk_buff *skb;
2169ccb1352eSJesse Gross 	int retval;
2170ccb1352eSJesse Gross 
2171d4e4fdf9SGuillaume Nault 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2172ccb1352eSJesse Gross 	if (!skb)
2173ccb1352eSJesse Gross 		return ERR_PTR(-ENOMEM);
2174ccb1352eSJesse Gross 
2175d4e4fdf9SGuillaume Nault 	retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd,
2176d4e4fdf9SGuillaume Nault 					 GFP_KERNEL);
2177a9341512SJesse Gross 	BUG_ON(retval < 0);
2178a9341512SJesse Gross 
2179ccb1352eSJesse Gross 	return skb;
2180ccb1352eSJesse Gross }
2181ccb1352eSJesse Gross 
21828e4e1713SPravin 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])218346df7b81SPravin B Shelar static struct vport *lookup_vport(struct net *net,
218412eb18f7SThomas Graf 				  const struct ovs_header *ovs_header,
2185ccb1352eSJesse Gross 				  struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
2186ccb1352eSJesse Gross {
2187ccb1352eSJesse Gross 	struct datapath *dp;
2188ccb1352eSJesse Gross 	struct vport *vport;
2189ccb1352eSJesse Gross 
21909354d452SJiri Benc 	if (a[OVS_VPORT_ATTR_IFINDEX])
21919354d452SJiri Benc 		return ERR_PTR(-EOPNOTSUPP);
2192ccb1352eSJesse Gross 	if (a[OVS_VPORT_ATTR_NAME]) {
219346df7b81SPravin B Shelar 		vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME]));
2194ccb1352eSJesse Gross 		if (!vport)
2195ccb1352eSJesse Gross 			return ERR_PTR(-ENODEV);
2196651a68eaSBen Pfaff 		if (ovs_header->dp_ifindex &&
2197651a68eaSBen Pfaff 		    ovs_header->dp_ifindex != get_dpifindex(vport->dp))
2198651a68eaSBen Pfaff 			return ERR_PTR(-ENODEV);
2199ccb1352eSJesse Gross 		return vport;
2200ccb1352eSJesse Gross 	} else if (a[OVS_VPORT_ATTR_PORT_NO]) {
2201ccb1352eSJesse Gross 		u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
2202ccb1352eSJesse Gross 
2203ccb1352eSJesse Gross 		if (port_no >= DP_MAX_PORTS)
2204ccb1352eSJesse Gross 			return ERR_PTR(-EFBIG);
2205ccb1352eSJesse Gross 
220646df7b81SPravin B Shelar 		dp = get_dp(net, ovs_header->dp_ifindex);
2207ccb1352eSJesse Gross 		if (!dp)
2208ccb1352eSJesse Gross 			return ERR_PTR(-ENODEV);
2209ccb1352eSJesse Gross 
22108e4e1713SPravin B Shelar 		vport = ovs_vport_ovsl_rcu(dp, port_no);
2211ccb1352eSJesse Gross 		if (!vport)
221214408dbaSJarno Rajahalme 			return ERR_PTR(-ENODEV);
2213ccb1352eSJesse Gross 		return vport;
2214ccb1352eSJesse Gross 	} else
2215ccb1352eSJesse Gross 		return ERR_PTR(-EINVAL);
22169354d452SJiri Benc 
2217ccb1352eSJesse Gross }
2218ccb1352eSJesse Gross 
ovs_get_max_headroom(struct datapath * dp)22196b660c41STaehee Yoo static unsigned int ovs_get_max_headroom(struct datapath *dp)
22203a927bc7SPaolo Abeni {
22216b660c41STaehee Yoo 	unsigned int dev_headroom, max_headroom = 0;
22223a927bc7SPaolo Abeni 	struct net_device *dev;
22233a927bc7SPaolo Abeni 	struct vport *vport;
22243a927bc7SPaolo Abeni 	int i;
22253a927bc7SPaolo Abeni 
22263a927bc7SPaolo Abeni 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
222753742e69SMadhuparna Bhowmik 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
222853742e69SMadhuparna Bhowmik 					 lockdep_ovsl_is_held()) {
22293a927bc7SPaolo Abeni 			dev = vport->dev;
22303a927bc7SPaolo Abeni 			dev_headroom = netdev_get_fwd_headroom(dev);
22313a927bc7SPaolo Abeni 			if (dev_headroom > max_headroom)
22323a927bc7SPaolo Abeni 				max_headroom = dev_headroom;
22333a927bc7SPaolo Abeni 		}
22343a927bc7SPaolo Abeni 	}
22353a927bc7SPaolo Abeni 
22366b660c41STaehee Yoo 	return max_headroom;
22376b660c41STaehee Yoo }
22386b660c41STaehee Yoo 
22396b660c41STaehee Yoo /* Called with ovs_mutex */
ovs_update_headroom(struct datapath * dp,unsigned int new_headroom)22406b660c41STaehee Yoo static void ovs_update_headroom(struct datapath *dp, unsigned int new_headroom)
22416b660c41STaehee Yoo {
22426b660c41STaehee Yoo 	struct vport *vport;
22436b660c41STaehee Yoo 	int i;
22446b660c41STaehee Yoo 
22456b660c41STaehee Yoo 	dp->max_headroom = new_headroom;
2246cf3266adSTonghao Zhang 	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
224753742e69SMadhuparna Bhowmik 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
224853742e69SMadhuparna Bhowmik 					 lockdep_ovsl_is_held())
22496b660c41STaehee Yoo 			netdev_set_rx_headroom(vport->dev, new_headroom);
22503a927bc7SPaolo Abeni 	}
2251cf3266adSTonghao Zhang }
22523a927bc7SPaolo Abeni 
ovs_vport_cmd_new(struct sk_buff * skb,struct genl_info * info)2253ccb1352eSJesse Gross static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
2254ccb1352eSJesse Gross {
2255ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2256bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
2257ccb1352eSJesse Gross 	struct vport_parms parms;
2258ccb1352eSJesse Gross 	struct sk_buff *reply;
2259ccb1352eSJesse Gross 	struct vport *vport;
2260ccb1352eSJesse Gross 	struct datapath *dp;
22616b660c41STaehee Yoo 	unsigned int new_headroom;
2262ccb1352eSJesse Gross 	u32 port_no;
2263ccb1352eSJesse Gross 	int err;
2264ccb1352eSJesse Gross 
2265ccb1352eSJesse Gross 	if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
2266ccb1352eSJesse Gross 	    !a[OVS_VPORT_ATTR_UPCALL_PID])
22676093ae9aSJarno Rajahalme 		return -EINVAL;
226854c4ef34SAndrey Zhadchenko 
226954c4ef34SAndrey Zhadchenko 	parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]);
227054c4ef34SAndrey Zhadchenko 
227154c4ef34SAndrey Zhadchenko 	if (a[OVS_VPORT_ATTR_IFINDEX] && parms.type != OVS_VPORT_TYPE_INTERNAL)
22729354d452SJiri Benc 		return -EOPNOTSUPP;
22736093ae9aSJarno Rajahalme 
2274a885a6b2SJohannes Berg 	port_no = nla_get_u32_default(a[OVS_VPORT_ATTR_PORT_NO], 0);
22756093ae9aSJarno Rajahalme 	if (port_no >= DP_MAX_PORTS)
22766093ae9aSJarno Rajahalme 		return -EFBIG;
22776093ae9aSJarno Rajahalme 
22786093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
22796093ae9aSJarno Rajahalme 	if (!reply)
22806093ae9aSJarno Rajahalme 		return -ENOMEM;
2281ccb1352eSJesse Gross 
22828e4e1713SPravin B Shelar 	ovs_lock();
228362b9c8d0SThomas Graf restart:
228446df7b81SPravin B Shelar 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
2285ccb1352eSJesse Gross 	err = -ENODEV;
2286ccb1352eSJesse Gross 	if (!dp)
22876093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2288ccb1352eSJesse Gross 
22896093ae9aSJarno Rajahalme 	if (port_no) {
22908e4e1713SPravin B Shelar 		vport = ovs_vport_ovsl(dp, port_no);
2291ccb1352eSJesse Gross 		err = -EBUSY;
2292ccb1352eSJesse Gross 		if (vport)
22936093ae9aSJarno Rajahalme 			goto exit_unlock_free;
2294ccb1352eSJesse Gross 	} else {
2295ccb1352eSJesse Gross 		for (port_no = 1; ; port_no++) {
2296ccb1352eSJesse Gross 			if (port_no >= DP_MAX_PORTS) {
2297ccb1352eSJesse Gross 				err = -EFBIG;
22986093ae9aSJarno Rajahalme 				goto exit_unlock_free;
2299ccb1352eSJesse Gross 			}
23008e4e1713SPravin B Shelar 			vport = ovs_vport_ovsl(dp, port_no);
2301ccb1352eSJesse Gross 			if (!vport)
2302ccb1352eSJesse Gross 				break;
2303ccb1352eSJesse Gross 		}
2304ccb1352eSJesse Gross 	}
2305ccb1352eSJesse Gross 
2306ccb1352eSJesse Gross 	parms.name = nla_data(a[OVS_VPORT_ATTR_NAME]);
2307ccb1352eSJesse Gross 	parms.options = a[OVS_VPORT_ATTR_OPTIONS];
2308ccb1352eSJesse Gross 	parms.dp = dp;
2309ccb1352eSJesse Gross 	parms.port_no = port_no;
23105cd667b0SAlex Wang 	parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
2311a885a6b2SJohannes Berg 	parms.desired_ifindex = nla_get_s32_default(a[OVS_VPORT_ATTR_IFINDEX],
2312a885a6b2SJohannes Berg 						    0);
2313ccb1352eSJesse Gross 
2314ccb1352eSJesse Gross 	vport = new_vport(&parms);
2315ccb1352eSJesse Gross 	err = PTR_ERR(vport);
231662b9c8d0SThomas Graf 	if (IS_ERR(vport)) {
231762b9c8d0SThomas Graf 		if (err == -EAGAIN)
231862b9c8d0SThomas Graf 			goto restart;
23196093ae9aSJarno Rajahalme 		goto exit_unlock_free;
232062b9c8d0SThomas Graf 	}
2321ccb1352eSJesse Gross 
23229354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23239354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2324d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_NEW, GFP_KERNEL);
23253a927bc7SPaolo Abeni 
23266b660c41STaehee Yoo 	new_headroom = netdev_get_fwd_headroom(vport->dev);
23276b660c41STaehee Yoo 
23286b660c41STaehee Yoo 	if (new_headroom > dp->max_headroom)
23296b660c41STaehee Yoo 		ovs_update_headroom(dp, new_headroom);
23303a927bc7SPaolo Abeni 	else
23313a927bc7SPaolo Abeni 		netdev_set_rx_headroom(vport->dev, dp->max_headroom);
23323a927bc7SPaolo Abeni 
23336093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
23346093ae9aSJarno Rajahalme 	ovs_unlock();
2335ed661185SThomas Graf 
23362a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
23376093ae9aSJarno Rajahalme 	return 0;
2338ccb1352eSJesse Gross 
23396093ae9aSJarno Rajahalme exit_unlock_free:
23408e4e1713SPravin B Shelar 	ovs_unlock();
23416093ae9aSJarno Rajahalme 	kfree_skb(reply);
2342ccb1352eSJesse Gross 	return err;
2343ccb1352eSJesse Gross }
2344ccb1352eSJesse Gross 
ovs_vport_cmd_set(struct sk_buff * skb,struct genl_info * info)2345ccb1352eSJesse Gross static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
2346ccb1352eSJesse Gross {
2347ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2348ccb1352eSJesse Gross 	struct sk_buff *reply;
2349ccb1352eSJesse Gross 	struct vport *vport;
2350ccb1352eSJesse Gross 	int err;
2351ccb1352eSJesse Gross 
23526093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
23536093ae9aSJarno Rajahalme 	if (!reply)
23546093ae9aSJarno Rajahalme 		return -ENOMEM;
23556093ae9aSJarno Rajahalme 
23568e4e1713SPravin B Shelar 	ovs_lock();
2357bffcc688SJakub Kicinski 	vport = lookup_vport(sock_net(skb->sk), genl_info_userhdr(info), a);
2358ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2359ccb1352eSJesse Gross 	if (IS_ERR(vport))
23606093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2361ccb1352eSJesse Gross 
2362ccb1352eSJesse Gross 	if (a[OVS_VPORT_ATTR_TYPE] &&
2363f44f3408SJesse Gross 	    nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) {
2364ccb1352eSJesse Gross 		err = -EINVAL;
23656093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2366a9341512SJesse Gross 	}
2367a9341512SJesse Gross 
2368f44f3408SJesse Gross 	if (a[OVS_VPORT_ATTR_OPTIONS]) {
2369ccb1352eSJesse Gross 		err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
237003fbf8b3SAnsis Atteka 		if (err)
23716093ae9aSJarno Rajahalme 			goto exit_unlock_free;
2372f44f3408SJesse Gross 	}
2373a9341512SJesse Gross 
23745cd667b0SAlex Wang 
23755cd667b0SAlex Wang 	if (a[OVS_VPORT_ATTR_UPCALL_PID]) {
23765cd667b0SAlex Wang 		struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID];
23775cd667b0SAlex Wang 
23785cd667b0SAlex Wang 		err = ovs_vport_set_upcall_portids(vport, ids);
23795cd667b0SAlex Wang 		if (err)
23805cd667b0SAlex Wang 			goto exit_unlock_free;
23815cd667b0SAlex Wang 	}
2382ccb1352eSJesse Gross 
23839354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23849354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2385d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_SET, GFP_KERNEL);
2386a9341512SJesse Gross 	BUG_ON(err < 0);
2387ccb1352eSJesse Gross 
23888e4e1713SPravin B Shelar 	ovs_unlock();
23892a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
23908e4e1713SPravin B Shelar 	return 0;
2391ccb1352eSJesse Gross 
23926093ae9aSJarno Rajahalme exit_unlock_free:
23938e4e1713SPravin B Shelar 	ovs_unlock();
23946093ae9aSJarno Rajahalme 	kfree_skb(reply);
2395ccb1352eSJesse Gross 	return err;
2396ccb1352eSJesse Gross }
2397ccb1352eSJesse Gross 
ovs_vport_cmd_del(struct sk_buff * skb,struct genl_info * info)2398ccb1352eSJesse Gross static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
2399ccb1352eSJesse Gross {
24006b660c41STaehee Yoo 	bool update_headroom = false;
2401ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2402ccb1352eSJesse Gross 	struct sk_buff *reply;
24033a927bc7SPaolo Abeni 	struct datapath *dp;
2404ccb1352eSJesse Gross 	struct vport *vport;
24056b660c41STaehee Yoo 	unsigned int new_headroom;
2406ccb1352eSJesse Gross 	int err;
2407ccb1352eSJesse Gross 
24086093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
24096093ae9aSJarno Rajahalme 	if (!reply)
24106093ae9aSJarno Rajahalme 		return -ENOMEM;
24116093ae9aSJarno Rajahalme 
24128e4e1713SPravin B Shelar 	ovs_lock();
2413bffcc688SJakub Kicinski 	vport = lookup_vport(sock_net(skb->sk), genl_info_userhdr(info), a);
2414ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2415ccb1352eSJesse Gross 	if (IS_ERR(vport))
24166093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2417ccb1352eSJesse Gross 
2418ccb1352eSJesse Gross 	if (vport->port_no == OVSP_LOCAL) {
2419ccb1352eSJesse Gross 		err = -EINVAL;
24206093ae9aSJarno Rajahalme 		goto exit_unlock_free;
2421ccb1352eSJesse Gross 	}
2422ccb1352eSJesse Gross 
24239354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
24249354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2425d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_DEL, GFP_KERNEL);
24266093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
24273a927bc7SPaolo Abeni 
24283a927bc7SPaolo Abeni 	/* the vport deletion may trigger dp headroom update */
24293a927bc7SPaolo Abeni 	dp = vport->dp;
24303a927bc7SPaolo Abeni 	if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
24316b660c41STaehee Yoo 		update_headroom = true;
24326b660c41STaehee Yoo 
24333a927bc7SPaolo Abeni 	netdev_reset_rx_headroom(vport->dev);
2434ccb1352eSJesse Gross 	ovs_dp_detach_port(vport);
24353a927bc7SPaolo Abeni 
24366b660c41STaehee Yoo 	if (update_headroom) {
24376b660c41STaehee Yoo 		new_headroom = ovs_get_max_headroom(dp);
24386b660c41STaehee Yoo 
24396b660c41STaehee Yoo 		if (new_headroom < dp->max_headroom)
24406b660c41STaehee Yoo 			ovs_update_headroom(dp, new_headroom);
24416b660c41STaehee Yoo 	}
24426093ae9aSJarno Rajahalme 	ovs_unlock();
2443ccb1352eSJesse Gross 
24442a94fe48SJohannes Berg 	ovs_notify(&dp_vport_genl_family, reply, info);
24456093ae9aSJarno Rajahalme 	return 0;
2446ccb1352eSJesse Gross 
24476093ae9aSJarno Rajahalme exit_unlock_free:
24488e4e1713SPravin B Shelar 	ovs_unlock();
24496093ae9aSJarno Rajahalme 	kfree_skb(reply);
2450ccb1352eSJesse Gross 	return err;
2451ccb1352eSJesse Gross }
2452ccb1352eSJesse Gross 
ovs_vport_cmd_get(struct sk_buff * skb,struct genl_info * info)2453ccb1352eSJesse Gross static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
2454ccb1352eSJesse Gross {
2455ccb1352eSJesse Gross 	struct nlattr **a = info->attrs;
2456bffcc688SJakub Kicinski 	struct ovs_header *ovs_header = genl_info_userhdr(info);
2457ccb1352eSJesse Gross 	struct sk_buff *reply;
2458ccb1352eSJesse Gross 	struct vport *vport;
2459ccb1352eSJesse Gross 	int err;
2460ccb1352eSJesse Gross 
24616093ae9aSJarno Rajahalme 	reply = ovs_vport_cmd_alloc_info();
24626093ae9aSJarno Rajahalme 	if (!reply)
24636093ae9aSJarno Rajahalme 		return -ENOMEM;
24646093ae9aSJarno Rajahalme 
2465ccb1352eSJesse Gross 	rcu_read_lock();
246646df7b81SPravin B Shelar 	vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
2467ccb1352eSJesse Gross 	err = PTR_ERR(vport);
2468ccb1352eSJesse Gross 	if (IS_ERR(vport))
24696093ae9aSJarno Rajahalme 		goto exit_unlock_free;
24709354d452SJiri Benc 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
24719354d452SJiri Benc 				      info->snd_portid, info->snd_seq, 0,
2472d4e4fdf9SGuillaume Nault 				      OVS_VPORT_CMD_GET, GFP_ATOMIC);
24736093ae9aSJarno Rajahalme 	BUG_ON(err < 0);
2474ccb1352eSJesse Gross 	rcu_read_unlock();
2475ccb1352eSJesse Gross 
2476ccb1352eSJesse Gross 	return genlmsg_reply(reply, info);
2477ccb1352eSJesse Gross 
24786093ae9aSJarno Rajahalme exit_unlock_free:
2479ccb1352eSJesse Gross 	rcu_read_unlock();
24806093ae9aSJarno Rajahalme 	kfree_skb(reply);
2481ccb1352eSJesse Gross 	return err;
2482ccb1352eSJesse Gross }
2483ccb1352eSJesse Gross 
ovs_vport_cmd_dump(struct sk_buff * skb,struct netlink_callback * cb)2484ccb1352eSJesse Gross static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
2485ccb1352eSJesse Gross {
2486ccb1352eSJesse Gross 	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
2487ccb1352eSJesse Gross 	struct datapath *dp;
248815eac2a7SPravin B Shelar 	int bucket = cb->args[0], skip = cb->args[1];
248915eac2a7SPravin B Shelar 	int i, j = 0;
2490ccb1352eSJesse Gross 
2491ccb1352eSJesse Gross 	rcu_read_lock();
2492cc3a5ae6SAndy Zhou 	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
249342ee19e2SJarno Rajahalme 	if (!dp) {
249442ee19e2SJarno Rajahalme 		rcu_read_unlock();
249542ee19e2SJarno Rajahalme 		return -ENODEV;
249642ee19e2SJarno Rajahalme 	}
249715eac2a7SPravin B Shelar 	for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
2498ccb1352eSJesse Gross 		struct vport *vport;
2499ccb1352eSJesse Gross 
250015eac2a7SPravin B Shelar 		j = 0;
2501b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
250215eac2a7SPravin B Shelar 			if (j >= skip &&
250315eac2a7SPravin B Shelar 			    ovs_vport_cmd_fill_info(vport, skb,
25049354d452SJiri Benc 						    sock_net(skb->sk),
250515e47304SEric W. Biederman 						    NETLINK_CB(cb->skb).portid,
250615eac2a7SPravin B Shelar 						    cb->nlh->nlmsg_seq,
250715eac2a7SPravin B Shelar 						    NLM_F_MULTI,
2508d4e4fdf9SGuillaume Nault 						    OVS_VPORT_CMD_GET,
2509d4e4fdf9SGuillaume Nault 						    GFP_ATOMIC) < 0)
251015eac2a7SPravin B Shelar 				goto out;
251115eac2a7SPravin B Shelar 
251215eac2a7SPravin B Shelar 			j++;
2513ccb1352eSJesse Gross 		}
251415eac2a7SPravin B Shelar 		skip = 0;
251515eac2a7SPravin B Shelar 	}
251615eac2a7SPravin B Shelar out:
2517ccb1352eSJesse Gross 	rcu_read_unlock();
2518ccb1352eSJesse Gross 
251915eac2a7SPravin B Shelar 	cb->args[0] = i;
252015eac2a7SPravin B Shelar 	cb->args[1] = j;
2521ccb1352eSJesse Gross 
252215eac2a7SPravin B Shelar 	return skb->len;
2523ccb1352eSJesse Gross }
2524ccb1352eSJesse Gross 
ovs_dp_masks_rebalance(struct work_struct * work)2525eac87c41SEelco Chaudron static void ovs_dp_masks_rebalance(struct work_struct *work)
2526eac87c41SEelco Chaudron {
2527a65878d6SEelco Chaudron 	struct ovs_net *ovs_net = container_of(work, struct ovs_net,
2528eac87c41SEelco Chaudron 					       masks_rebalance.work);
2529a65878d6SEelco Chaudron 	struct datapath *dp;
2530eac87c41SEelco Chaudron 
2531eac87c41SEelco Chaudron 	ovs_lock();
2532a65878d6SEelco Chaudron 
2533a65878d6SEelco Chaudron 	list_for_each_entry(dp, &ovs_net->dps, list_node)
2534eac87c41SEelco Chaudron 		ovs_flow_masks_rebalance(&dp->table);
2535a65878d6SEelco Chaudron 
2536eac87c41SEelco Chaudron 	ovs_unlock();
2537eac87c41SEelco Chaudron 
2538a65878d6SEelco Chaudron 	schedule_delayed_work(&ovs_net->masks_rebalance,
2539eac87c41SEelco Chaudron 			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
2540eac87c41SEelco Chaudron }
2541eac87c41SEelco Chaudron 
25420c200ef9SPravin B Shelar static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
25430c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
25440c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
25450c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
25460c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
2547ea8564c8SLi RongQing 	[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC },
25480c200ef9SPravin B Shelar 	[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
2549a552bfa1SJakub Kicinski 	[OVS_VPORT_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
25509354d452SJiri Benc 	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
25511933ea36Swangchuanlei 	[OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED },
25520c200ef9SPravin B Shelar };
25530c200ef9SPravin B Shelar 
255466a9b928SJakub Kicinski static const struct genl_small_ops dp_vport_genl_ops[] = {
2555ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_NEW,
2556ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25574a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2558ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_new
2559ccb1352eSJesse Gross 	},
2560ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_DEL,
2561ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25624a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2563ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_del
2564ccb1352eSJesse Gross 	},
2565ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_GET,
2566ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2567ccb1352eSJesse Gross 	  .flags = 0,		    /* OK for unprivileged users. */
2568ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_get,
2569ccb1352eSJesse Gross 	  .dumpit = ovs_vport_cmd_dump
2570ccb1352eSJesse Gross 	},
2571ccb1352eSJesse Gross 	{ .cmd = OVS_VPORT_CMD_SET,
2572ef6243acSJohannes Berg 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
25734a92602aSTycho Andersen 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
2574ccb1352eSJesse Gross 	  .doit = ovs_vport_cmd_set,
2575ccb1352eSJesse Gross 	},
2576ccb1352eSJesse Gross };
2577ccb1352eSJesse Gross 
257856989f6dSJohannes Berg struct genl_family dp_vport_genl_family __ro_after_init = {
25790c200ef9SPravin B Shelar 	.hdrsize = sizeof(struct ovs_header),
25800c200ef9SPravin B Shelar 	.name = OVS_VPORT_FAMILY,
25810c200ef9SPravin B Shelar 	.version = OVS_VPORT_VERSION,
25820c200ef9SPravin B Shelar 	.maxattr = OVS_VPORT_ATTR_MAX,
25833b0f31f2SJohannes Berg 	.policy = vport_policy,
25840c200ef9SPravin B Shelar 	.netnsok = true,
25850c200ef9SPravin B Shelar 	.parallel_ops = true,
258666a9b928SJakub Kicinski 	.small_ops = dp_vport_genl_ops,
258766a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(dp_vport_genl_ops),
2588e4ba4554SJakub Kicinski 	.resv_start_op = OVS_VPORT_CMD_SET + 1,
25890c200ef9SPravin B Shelar 	.mcgrps = &ovs_dp_vport_multicast_group,
25900c200ef9SPravin B Shelar 	.n_mcgrps = 1,
2591489111e5SJohannes Berg 	.module = THIS_MODULE,
2592ccb1352eSJesse Gross };
2593ccb1352eSJesse Gross 
25940c200ef9SPravin B Shelar static struct genl_family * const dp_genl_families[] = {
25950c200ef9SPravin B Shelar 	&dp_datapath_genl_family,
25960c200ef9SPravin B Shelar 	&dp_vport_genl_family,
25970c200ef9SPravin B Shelar 	&dp_flow_genl_family,
25980c200ef9SPravin B Shelar 	&dp_packet_genl_family,
259996fbc13dSAndy Zhou 	&dp_meter_genl_family,
260011efd5cbSYi-Hung Wei #if	IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
260111efd5cbSYi-Hung Wei 	&dp_ct_limit_genl_family,
260211efd5cbSYi-Hung Wei #endif
2603ccb1352eSJesse Gross };
2604ccb1352eSJesse Gross 
dp_unregister_genl(int n_families)2605ccb1352eSJesse Gross static void dp_unregister_genl(int n_families)
2606ccb1352eSJesse Gross {
2607ccb1352eSJesse Gross 	int i;
2608ccb1352eSJesse Gross 
2609ccb1352eSJesse Gross 	for (i = 0; i < n_families; i++)
26100c200ef9SPravin B Shelar 		genl_unregister_family(dp_genl_families[i]);
2611ccb1352eSJesse Gross }
2612ccb1352eSJesse Gross 
dp_register_genl(void)261356989f6dSJohannes Berg static int __init dp_register_genl(void)
2614ccb1352eSJesse Gross {
2615ccb1352eSJesse Gross 	int err;
2616ccb1352eSJesse Gross 	int i;
2617ccb1352eSJesse Gross 
2618ccb1352eSJesse Gross 	for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
2619ccb1352eSJesse Gross 
26200c200ef9SPravin B Shelar 		err = genl_register_family(dp_genl_families[i]);
2621ccb1352eSJesse Gross 		if (err)
2622ccb1352eSJesse Gross 			goto error;
2623ccb1352eSJesse Gross 	}
2624ccb1352eSJesse Gross 
2625ccb1352eSJesse Gross 	return 0;
2626ccb1352eSJesse Gross 
2627ccb1352eSJesse Gross error:
26280c200ef9SPravin B Shelar 	dp_unregister_genl(i);
2629ccb1352eSJesse Gross 	return err;
2630ccb1352eSJesse Gross }
2631ccb1352eSJesse Gross 
ovs_init_net(struct net * net)263246df7b81SPravin B Shelar static int __net_init ovs_init_net(struct net *net)
263346df7b81SPravin B Shelar {
263446df7b81SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
2635e0afe914SEelco Chaudron 	int err;
263646df7b81SPravin B Shelar 
263746df7b81SPravin B Shelar 	INIT_LIST_HEAD(&ovs_net->dps);
26388e4e1713SPravin B Shelar 	INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
2639a65878d6SEelco Chaudron 	INIT_DELAYED_WORK(&ovs_net->masks_rebalance, ovs_dp_masks_rebalance);
2640e0afe914SEelco Chaudron 
2641e0afe914SEelco Chaudron 	err = ovs_ct_init(net);
2642e0afe914SEelco Chaudron 	if (err)
2643e0afe914SEelco Chaudron 		return err;
2644e0afe914SEelco Chaudron 
2645a65878d6SEelco Chaudron 	schedule_delayed_work(&ovs_net->masks_rebalance,
2646a65878d6SEelco Chaudron 			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
2647e0afe914SEelco Chaudron 	return 0;
264846df7b81SPravin B Shelar }
264946df7b81SPravin B Shelar 
list_vports_from_net(struct net * net,struct net * dnet,struct list_head * head)26507b4577a9SPravin B Shelar static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
26517b4577a9SPravin B Shelar 					    struct list_head *head)
26527b4577a9SPravin B Shelar {
26537b4577a9SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
26547b4577a9SPravin B Shelar 	struct datapath *dp;
26557b4577a9SPravin B Shelar 
26567b4577a9SPravin B Shelar 	list_for_each_entry(dp, &ovs_net->dps, list_node) {
26577b4577a9SPravin B Shelar 		int i;
26587b4577a9SPravin B Shelar 
26597b4577a9SPravin B Shelar 		for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
26607b4577a9SPravin B Shelar 			struct vport *vport;
26617b4577a9SPravin B Shelar 
26627b4577a9SPravin B Shelar 			hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
26637b4577a9SPravin B Shelar 				if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
26647b4577a9SPravin B Shelar 					continue;
26657b4577a9SPravin B Shelar 
2666be4ace6eSThomas Graf 				if (dev_net(vport->dev) == dnet)
26677b4577a9SPravin B Shelar 					list_add(&vport->detach_list, head);
26687b4577a9SPravin B Shelar 			}
26697b4577a9SPravin B Shelar 		}
26707b4577a9SPravin B Shelar 	}
26717b4577a9SPravin B Shelar }
26727b4577a9SPravin B Shelar 
ovs_exit_net(struct net * dnet)26737b4577a9SPravin B Shelar static void __net_exit ovs_exit_net(struct net *dnet)
267446df7b81SPravin B Shelar {
267546df7b81SPravin B Shelar 	struct datapath *dp, *dp_next;
26767b4577a9SPravin B Shelar 	struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
26777b4577a9SPravin B Shelar 	struct vport *vport, *vport_next;
26787b4577a9SPravin B Shelar 	struct net *net;
26797b4577a9SPravin B Shelar 	LIST_HEAD(head);
268046df7b81SPravin B Shelar 
26818e4e1713SPravin B Shelar 	ovs_lock();
268227de77ceSTonghao Zhang 
268327de77ceSTonghao Zhang 	ovs_ct_exit(dnet);
268427de77ceSTonghao Zhang 
268546df7b81SPravin B Shelar 	list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
268646df7b81SPravin B Shelar 		__dp_destroy(dp);
26877b4577a9SPravin B Shelar 
2688f0b07bb1SKirill Tkhai 	down_read(&net_rwsem);
26897b4577a9SPravin B Shelar 	for_each_net(net)
26907b4577a9SPravin B Shelar 		list_vports_from_net(net, dnet, &head);
2691f0b07bb1SKirill Tkhai 	up_read(&net_rwsem);
26927b4577a9SPravin B Shelar 
26937b4577a9SPravin B Shelar 	/* Detach all vports from given namespace. */
26947b4577a9SPravin B Shelar 	list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
26957b4577a9SPravin B Shelar 		list_del(&vport->detach_list);
26967b4577a9SPravin B Shelar 		ovs_dp_detach_port(vport);
26977b4577a9SPravin B Shelar 	}
26987b4577a9SPravin B Shelar 
26998e4e1713SPravin B Shelar 	ovs_unlock();
27008e4e1713SPravin B Shelar 
2701a65878d6SEelco Chaudron 	cancel_delayed_work_sync(&ovs_net->masks_rebalance);
27028e4e1713SPravin B Shelar 	cancel_work_sync(&ovs_net->dp_notify_work);
270346df7b81SPravin B Shelar }
270446df7b81SPravin B Shelar 
270546df7b81SPravin B Shelar static struct pernet_operations ovs_net_ops = {
270646df7b81SPravin B Shelar 	.init = ovs_init_net,
270746df7b81SPravin B Shelar 	.exit = ovs_exit_net,
270846df7b81SPravin B Shelar 	.id   = &ovs_net_id,
270946df7b81SPravin B Shelar 	.size = sizeof(struct ovs_net),
271046df7b81SPravin B Shelar };
271146df7b81SPravin B Shelar 
27129d802da4SAdrian Moreno static const char * const ovs_drop_reasons[] = {
271357fb6778SMenglong Dong #define S(x) [(x) & ~SKB_DROP_REASON_SUBSYS_MASK] = (#x),
27149d802da4SAdrian Moreno 	OVS_DROP_REASONS(S)
27159d802da4SAdrian Moreno #undef S
27169d802da4SAdrian Moreno };
27179d802da4SAdrian Moreno 
27189d802da4SAdrian Moreno static struct drop_reason_list drop_reason_list_ovs = {
27199d802da4SAdrian Moreno 	.reasons = ovs_drop_reasons,
27209d802da4SAdrian Moreno 	.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
27219d802da4SAdrian Moreno };
27229d802da4SAdrian Moreno 
dp_init(void)2723ccb1352eSJesse Gross static int __init dp_init(void)
2724ccb1352eSJesse Gross {
2725ccb1352eSJesse Gross 	int err;
2726ccb1352eSJesse Gross 
2727cf3266adSTonghao Zhang 	BUILD_BUG_ON(sizeof(struct ovs_skb_cb) >
2728cf3266adSTonghao Zhang 		     sizeof_field(struct sk_buff, cb));
2729ccb1352eSJesse Gross 
2730ccb1352eSJesse Gross 	pr_info("Open vSwitch switching datapath\n");
2731ccb1352eSJesse Gross 
2732971427f3SAndy Zhou 	err = action_fifos_init();
2733ccb1352eSJesse Gross 	if (err)
2734ccb1352eSJesse Gross 		goto error;
2735ccb1352eSJesse Gross 
2736971427f3SAndy Zhou 	err = ovs_internal_dev_rtnl_link_register();
2737971427f3SAndy Zhou 	if (err)
2738971427f3SAndy Zhou 		goto error_action_fifos_exit;
2739971427f3SAndy Zhou 
27405b9e7e16SJiri Pirko 	err = ovs_flow_init();
27415b9e7e16SJiri Pirko 	if (err)
27425b9e7e16SJiri Pirko 		goto error_unreg_rtnl_link;
27435b9e7e16SJiri Pirko 
2744ccb1352eSJesse Gross 	err = ovs_vport_init();
2745ccb1352eSJesse Gross 	if (err)
2746ccb1352eSJesse Gross 		goto error_flow_exit;
2747ccb1352eSJesse Gross 
274846df7b81SPravin B Shelar 	err = register_pernet_device(&ovs_net_ops);
2749ccb1352eSJesse Gross 	if (err)
2750ccb1352eSJesse Gross 		goto error_vport_exit;
2751ccb1352eSJesse Gross 
275246df7b81SPravin B Shelar 	err = register_netdevice_notifier(&ovs_dp_device_notifier);
275346df7b81SPravin B Shelar 	if (err)
275446df7b81SPravin B Shelar 		goto error_netns_exit;
275546df7b81SPravin B Shelar 
275662b9c8d0SThomas Graf 	err = ovs_netdev_init();
275762b9c8d0SThomas Graf 	if (err)
275862b9c8d0SThomas Graf 		goto error_unreg_notifier;
275962b9c8d0SThomas Graf 
2760ccb1352eSJesse Gross 	err = dp_register_genl();
2761ccb1352eSJesse Gross 	if (err < 0)
276262b9c8d0SThomas Graf 		goto error_unreg_netdev;
2763ccb1352eSJesse Gross 
27649d802da4SAdrian Moreno 	drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH,
27659d802da4SAdrian Moreno 				     &drop_reason_list_ovs);
27669d802da4SAdrian Moreno 
2767ccb1352eSJesse Gross 	return 0;
2768ccb1352eSJesse Gross 
276962b9c8d0SThomas Graf error_unreg_netdev:
277062b9c8d0SThomas Graf 	ovs_netdev_exit();
2771ccb1352eSJesse Gross error_unreg_notifier:
2772ccb1352eSJesse Gross 	unregister_netdevice_notifier(&ovs_dp_device_notifier);
277346df7b81SPravin B Shelar error_netns_exit:
277446df7b81SPravin B Shelar 	unregister_pernet_device(&ovs_net_ops);
2775ccb1352eSJesse Gross error_vport_exit:
2776ccb1352eSJesse Gross 	ovs_vport_exit();
2777ccb1352eSJesse Gross error_flow_exit:
2778ccb1352eSJesse Gross 	ovs_flow_exit();
27795b9e7e16SJiri Pirko error_unreg_rtnl_link:
27805b9e7e16SJiri Pirko 	ovs_internal_dev_rtnl_link_unregister();
2781971427f3SAndy Zhou error_action_fifos_exit:
2782971427f3SAndy Zhou 	action_fifos_exit();
2783ccb1352eSJesse Gross error:
2784ccb1352eSJesse Gross 	return err;
2785ccb1352eSJesse Gross }
2786ccb1352eSJesse Gross 
dp_cleanup(void)2787ccb1352eSJesse Gross static void dp_cleanup(void)
2788ccb1352eSJesse Gross {
2789ccb1352eSJesse Gross 	dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
279062b9c8d0SThomas Graf 	ovs_netdev_exit();
2791ccb1352eSJesse Gross 	unregister_netdevice_notifier(&ovs_dp_device_notifier);
279246df7b81SPravin B Shelar 	unregister_pernet_device(&ovs_net_ops);
27939d802da4SAdrian Moreno 	drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH);
279446df7b81SPravin B Shelar 	rcu_barrier();
2795ccb1352eSJesse Gross 	ovs_vport_exit();
2796ccb1352eSJesse Gross 	ovs_flow_exit();
27975b9e7e16SJiri Pirko 	ovs_internal_dev_rtnl_link_unregister();
2798971427f3SAndy Zhou 	action_fifos_exit();
2799ccb1352eSJesse Gross }
2800ccb1352eSJesse Gross 
2801ccb1352eSJesse Gross module_init(dp_init);
2802ccb1352eSJesse Gross module_exit(dp_cleanup);
2803ccb1352eSJesse Gross 
2804ccb1352eSJesse Gross MODULE_DESCRIPTION("Open vSwitch switching datapath");
2805ccb1352eSJesse Gross MODULE_LICENSE("GPL");
2806ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_DATAPATH_FAMILY);
2807ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY);
2808ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY);
2809ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY);
281096fbc13dSAndy Zhou MODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY);
281111efd5cbSYi-Hung Wei MODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY);
2812