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