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