1c9422999SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ccb1352eSJesse Gross /* 3ad552007SBen Pfaff * Copyright (c) 2007-2014 Nicira, Inc. 4ccb1352eSJesse Gross */ 5ccb1352eSJesse Gross 6ccb1352eSJesse Gross #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7ccb1352eSJesse Gross 8ccb1352eSJesse Gross #include <linux/init.h> 9ccb1352eSJesse Gross #include <linux/module.h> 10ccb1352eSJesse Gross #include <linux/if_arp.h> 11ccb1352eSJesse Gross #include <linux/if_vlan.h> 12ccb1352eSJesse Gross #include <linux/in.h> 13ccb1352eSJesse Gross #include <linux/ip.h> 14ccb1352eSJesse Gross #include <linux/jhash.h> 15ccb1352eSJesse Gross #include <linux/delay.h> 16ccb1352eSJesse Gross #include <linux/time.h> 17ccb1352eSJesse Gross #include <linux/etherdevice.h> 18ccb1352eSJesse Gross #include <linux/genetlink.h> 19ccb1352eSJesse Gross #include <linux/kernel.h> 20ccb1352eSJesse Gross #include <linux/kthread.h> 21ccb1352eSJesse Gross #include <linux/mutex.h> 22ccb1352eSJesse Gross #include <linux/percpu.h> 23ccb1352eSJesse Gross #include <linux/rcupdate.h> 24ccb1352eSJesse Gross #include <linux/tcp.h> 25ccb1352eSJesse Gross #include <linux/udp.h> 26ccb1352eSJesse Gross #include <linux/ethtool.h> 27ccb1352eSJesse Gross #include <linux/wait.h> 28ccb1352eSJesse Gross #include <asm/div64.h> 29ccb1352eSJesse Gross #include <linux/highmem.h> 30ccb1352eSJesse Gross #include <linux/netfilter_bridge.h> 31ccb1352eSJesse Gross #include <linux/netfilter_ipv4.h> 32ccb1352eSJesse Gross #include <linux/inetdevice.h> 33ccb1352eSJesse Gross #include <linux/list.h> 34ccb1352eSJesse Gross #include <linux/openvswitch.h> 35ccb1352eSJesse Gross #include <linux/rculist.h> 36ccb1352eSJesse Gross #include <linux/dmi.h> 37ccb1352eSJesse Gross #include <net/genetlink.h> 3846df7b81SPravin B Shelar #include <net/net_namespace.h> 3946df7b81SPravin B Shelar #include <net/netns/generic.h> 40ccb1352eSJesse Gross 41ccb1352eSJesse Gross #include "datapath.h" 42ccb1352eSJesse Gross #include "flow.h" 43e80857ccSAndy Zhou #include "flow_table.h" 44e6445719SPravin B Shelar #include "flow_netlink.h" 4596fbc13dSAndy Zhou #include "meter.h" 46ccb1352eSJesse Gross #include "vport-internal_dev.h" 47cff63a52SThomas Graf #include "vport-netdev.h" 48ccb1352eSJesse Gross 49c7d03a00SAlexey Dobriyan unsigned int ovs_net_id __read_mostly; 508e4e1713SPravin B Shelar 510c200ef9SPravin B Shelar static struct genl_family dp_packet_genl_family; 520c200ef9SPravin B Shelar static struct genl_family dp_flow_genl_family; 530c200ef9SPravin B Shelar static struct genl_family dp_datapath_genl_family; 540c200ef9SPravin B Shelar 5574ed7ab9SJoe Stringer static const struct nla_policy flow_policy[]; 5674ed7ab9SJoe Stringer 5748e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_flow_multicast_group = { 5848e48a70Sstephen hemminger .name = OVS_FLOW_MCGROUP, 590c200ef9SPravin B Shelar }; 600c200ef9SPravin B Shelar 6148e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_datapath_multicast_group = { 6248e48a70Sstephen hemminger .name = OVS_DATAPATH_MCGROUP, 630c200ef9SPravin B Shelar }; 640c200ef9SPravin B Shelar 6548e48a70Sstephen hemminger static const struct genl_multicast_group ovs_dp_vport_multicast_group = { 6648e48a70Sstephen hemminger .name = OVS_VPORT_MCGROUP, 670c200ef9SPravin B Shelar }; 680c200ef9SPravin B Shelar 69fb5d1e9eSJarno Rajahalme /* Check if need to build a reply message. 70fb5d1e9eSJarno Rajahalme * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */ 719b67aa4aSSamuel Gauthier static bool ovs_must_notify(struct genl_family *family, struct genl_info *info, 729b67aa4aSSamuel Gauthier unsigned int group) 73fb5d1e9eSJarno Rajahalme { 74fb5d1e9eSJarno Rajahalme return info->nlhdr->nlmsg_flags & NLM_F_ECHO || 75f8403a2eSJohannes Berg genl_has_listeners(family, genl_info_net(info), group); 76fb5d1e9eSJarno Rajahalme } 77fb5d1e9eSJarno Rajahalme 7868eb5503SJohannes Berg static void ovs_notify(struct genl_family *family, 792a94fe48SJohannes Berg struct sk_buff *skb, struct genl_info *info) 80ed661185SThomas Graf { 8192c14d9bSJiri Benc genl_notify(family, skb, info, 0, GFP_KERNEL); 82ed661185SThomas Graf } 83ed661185SThomas Graf 8446df7b81SPravin B Shelar /** 85ccb1352eSJesse Gross * DOC: Locking: 86ccb1352eSJesse Gross * 878e4e1713SPravin B Shelar * All writes e.g. Writes to device state (add/remove datapath, port, set 888e4e1713SPravin B Shelar * operations on vports, etc.), Writes to other state (flow table 898e4e1713SPravin B Shelar * modifications, set miscellaneous datapath parameters, etc.) are protected 908e4e1713SPravin B Shelar * by ovs_lock. 91ccb1352eSJesse Gross * 92ccb1352eSJesse Gross * Reads are protected by RCU. 93ccb1352eSJesse Gross * 94ccb1352eSJesse Gross * There are a few special cases (mostly stats) that have their own 95ccb1352eSJesse Gross * synchronization but they nest under all of above and don't interact with 96ccb1352eSJesse Gross * each other. 978e4e1713SPravin B Shelar * 988e4e1713SPravin B Shelar * The RTNL lock nests inside ovs_mutex. 99ccb1352eSJesse Gross */ 100ccb1352eSJesse Gross 1018e4e1713SPravin B Shelar static DEFINE_MUTEX(ovs_mutex); 1028e4e1713SPravin B Shelar 1038e4e1713SPravin B Shelar void ovs_lock(void) 1048e4e1713SPravin B Shelar { 1058e4e1713SPravin B Shelar mutex_lock(&ovs_mutex); 1068e4e1713SPravin B Shelar } 1078e4e1713SPravin B Shelar 1088e4e1713SPravin B Shelar void ovs_unlock(void) 1098e4e1713SPravin B Shelar { 1108e4e1713SPravin B Shelar mutex_unlock(&ovs_mutex); 1118e4e1713SPravin B Shelar } 1128e4e1713SPravin B Shelar 1138e4e1713SPravin B Shelar #ifdef CONFIG_LOCKDEP 1148e4e1713SPravin B Shelar int lockdep_ovsl_is_held(void) 1158e4e1713SPravin B Shelar { 1168e4e1713SPravin B Shelar if (debug_locks) 1178e4e1713SPravin B Shelar return lockdep_is_held(&ovs_mutex); 1188e4e1713SPravin B Shelar else 1198e4e1713SPravin B Shelar return 1; 1208e4e1713SPravin B Shelar } 1218e4e1713SPravin B Shelar #endif 1228e4e1713SPravin B Shelar 123ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *); 1248055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *, 125e8eedb85SPravin B Shelar const struct sw_flow_key *, 126f2a4d086SWilliam Tu const struct dp_upcall_info *, 127f2a4d086SWilliam Tu uint32_t cutlen); 1288055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, 129e8eedb85SPravin B Shelar const struct sw_flow_key *, 130f2a4d086SWilliam Tu const struct dp_upcall_info *, 131f2a4d086SWilliam Tu uint32_t cutlen); 132ccb1352eSJesse Gross 1338e4e1713SPravin B Shelar /* Must be called with rcu_read_lock or ovs_mutex. */ 134971427f3SAndy Zhou const char *ovs_dp_name(const struct datapath *dp) 135ccb1352eSJesse Gross { 1368e4e1713SPravin B Shelar struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL); 137c9db965cSThomas Graf return ovs_vport_name(vport); 138ccb1352eSJesse Gross } 139ccb1352eSJesse Gross 14012eb18f7SThomas Graf static int get_dpifindex(const struct datapath *dp) 141ccb1352eSJesse Gross { 142ccb1352eSJesse Gross struct vport *local; 143ccb1352eSJesse Gross int ifindex; 144ccb1352eSJesse Gross 145ccb1352eSJesse Gross rcu_read_lock(); 146ccb1352eSJesse Gross 14715eac2a7SPravin B Shelar local = ovs_vport_rcu(dp, OVSP_LOCAL); 148ccb1352eSJesse Gross if (local) 149be4ace6eSThomas Graf ifindex = local->dev->ifindex; 150ccb1352eSJesse Gross else 151ccb1352eSJesse Gross ifindex = 0; 152ccb1352eSJesse Gross 153ccb1352eSJesse Gross rcu_read_unlock(); 154ccb1352eSJesse Gross 155ccb1352eSJesse Gross return ifindex; 156ccb1352eSJesse Gross } 157ccb1352eSJesse Gross 158ccb1352eSJesse Gross static void destroy_dp_rcu(struct rcu_head *rcu) 159ccb1352eSJesse Gross { 160ccb1352eSJesse Gross struct datapath *dp = container_of(rcu, struct datapath, rcu); 161ccb1352eSJesse Gross 1629b996e54SPravin B Shelar ovs_flow_tbl_destroy(&dp->table); 163ccb1352eSJesse Gross free_percpu(dp->stats_percpu); 16415eac2a7SPravin B Shelar kfree(dp->ports); 16596fbc13dSAndy Zhou ovs_meters_exit(dp); 166ccb1352eSJesse Gross kfree(dp); 167ccb1352eSJesse Gross } 168ccb1352eSJesse Gross 16915eac2a7SPravin B Shelar static struct hlist_head *vport_hash_bucket(const struct datapath *dp, 17015eac2a7SPravin B Shelar u16 port_no) 17115eac2a7SPravin B Shelar { 17215eac2a7SPravin B Shelar return &dp->ports[port_no & (DP_VPORT_HASH_BUCKETS - 1)]; 17315eac2a7SPravin B Shelar } 17415eac2a7SPravin B Shelar 175bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */ 17615eac2a7SPravin B Shelar struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no) 17715eac2a7SPravin B Shelar { 17815eac2a7SPravin B Shelar struct vport *vport; 17915eac2a7SPravin B Shelar struct hlist_head *head; 18015eac2a7SPravin B Shelar 18115eac2a7SPravin B Shelar head = vport_hash_bucket(dp, port_no); 182b67bfe0dSSasha Levin hlist_for_each_entry_rcu(vport, head, dp_hash_node) { 18315eac2a7SPravin B Shelar if (vport->port_no == port_no) 18415eac2a7SPravin B Shelar return vport; 18515eac2a7SPravin B Shelar } 18615eac2a7SPravin B Shelar return NULL; 18715eac2a7SPravin B Shelar } 18815eac2a7SPravin B Shelar 1898e4e1713SPravin B Shelar /* Called with ovs_mutex. */ 190ccb1352eSJesse Gross static struct vport *new_vport(const struct vport_parms *parms) 191ccb1352eSJesse Gross { 192ccb1352eSJesse Gross struct vport *vport; 193ccb1352eSJesse Gross 194ccb1352eSJesse Gross vport = ovs_vport_add(parms); 195ccb1352eSJesse Gross if (!IS_ERR(vport)) { 196ccb1352eSJesse Gross struct datapath *dp = parms->dp; 19715eac2a7SPravin B Shelar struct hlist_head *head = vport_hash_bucket(dp, vport->port_no); 198ccb1352eSJesse Gross 19915eac2a7SPravin B Shelar hlist_add_head_rcu(&vport->dp_hash_node, head); 200ccb1352eSJesse Gross } 201ccb1352eSJesse Gross return vport; 202ccb1352eSJesse Gross } 203ccb1352eSJesse Gross 204ccb1352eSJesse Gross void ovs_dp_detach_port(struct vport *p) 205ccb1352eSJesse Gross { 2068e4e1713SPravin B Shelar ASSERT_OVSL(); 207ccb1352eSJesse Gross 208ccb1352eSJesse Gross /* First drop references to device. */ 20915eac2a7SPravin B Shelar hlist_del_rcu(&p->dp_hash_node); 210ccb1352eSJesse Gross 211ccb1352eSJesse Gross /* Then destroy it. */ 212ccb1352eSJesse Gross ovs_vport_del(p); 213ccb1352eSJesse Gross } 214ccb1352eSJesse Gross 215ccb1352eSJesse Gross /* Must be called with rcu_read_lock. */ 2168c8b1b83SPravin B Shelar void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) 217ccb1352eSJesse Gross { 21883c8df26SPravin B Shelar const struct vport *p = OVS_CB(skb)->input_vport; 219ccb1352eSJesse Gross struct datapath *dp = p->dp; 220ccb1352eSJesse Gross struct sw_flow *flow; 221d98612b8SLorand Jakab struct sw_flow_actions *sf_acts; 222ccb1352eSJesse Gross struct dp_stats_percpu *stats; 223ccb1352eSJesse Gross u64 *stats_counter; 2241bd7116fSAndy Zhou u32 n_mask_hit; 225aa733660SYifeng Sun int error; 226ccb1352eSJesse Gross 227404f2f10SShan Wei stats = this_cpu_ptr(dp->stats_percpu); 228ccb1352eSJesse Gross 229ccb1352eSJesse Gross /* Look up flow. */ 2308c8b1b83SPravin B Shelar flow = ovs_flow_tbl_lookup_stats(&dp->table, key, &n_mask_hit); 231ccb1352eSJesse Gross if (unlikely(!flow)) { 232ccb1352eSJesse Gross struct dp_upcall_info upcall; 233ccb1352eSJesse Gross 234ccea7445SNeil McKee memset(&upcall, 0, sizeof(upcall)); 235ccb1352eSJesse Gross upcall.cmd = OVS_PACKET_CMD_MISS; 2365cd667b0SAlex Wang upcall.portid = ovs_vport_find_upcall_portid(p, skb); 2377f8a436eSJoe Stringer upcall.mru = OVS_CB(skb)->mru; 238f2a4d086SWilliam Tu error = ovs_dp_upcall(dp, skb, key, &upcall, 0); 239c5eba0b6SLi RongQing if (unlikely(error)) 240c5eba0b6SLi RongQing kfree_skb(skb); 241c5eba0b6SLi RongQing else 242ccb1352eSJesse Gross consume_skb(skb); 243ccb1352eSJesse Gross stats_counter = &stats->n_missed; 244ccb1352eSJesse Gross goto out; 245ccb1352eSJesse Gross } 246ccb1352eSJesse Gross 247d98612b8SLorand Jakab ovs_flow_stats_update(flow, key->tp.flags, skb); 248d98612b8SLorand Jakab sf_acts = rcu_dereference(flow->sf_acts); 249aa733660SYifeng Sun error = ovs_execute_actions(dp, skb, sf_acts, key); 250aa733660SYifeng Sun if (unlikely(error)) 251aa733660SYifeng Sun net_dbg_ratelimited("ovs: action execution error on datapath %s: %d\n", 252aa733660SYifeng Sun ovs_dp_name(dp), error); 253ccb1352eSJesse Gross 254e298e505SPravin B Shelar stats_counter = &stats->n_hit; 255ccb1352eSJesse Gross 256ccb1352eSJesse Gross out: 257ccb1352eSJesse Gross /* Update datapath statistics. */ 258df9d9fdfSWANG Cong u64_stats_update_begin(&stats->syncp); 259ccb1352eSJesse Gross (*stats_counter)++; 2601bd7116fSAndy Zhou stats->n_mask_hit += n_mask_hit; 261df9d9fdfSWANG Cong u64_stats_update_end(&stats->syncp); 262ccb1352eSJesse Gross } 263ccb1352eSJesse Gross 264ccb1352eSJesse Gross int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, 265e8eedb85SPravin B Shelar const struct sw_flow_key *key, 266f2a4d086SWilliam Tu const struct dp_upcall_info *upcall_info, 267f2a4d086SWilliam Tu uint32_t cutlen) 268ccb1352eSJesse Gross { 269ccb1352eSJesse Gross struct dp_stats_percpu *stats; 270ccb1352eSJesse Gross int err; 271ccb1352eSJesse Gross 27215e47304SEric W. Biederman if (upcall_info->portid == 0) { 273ccb1352eSJesse Gross err = -ENOTCONN; 274ccb1352eSJesse Gross goto err; 275ccb1352eSJesse Gross } 276ccb1352eSJesse Gross 277ccb1352eSJesse Gross if (!skb_is_gso(skb)) 278f2a4d086SWilliam Tu err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); 279ccb1352eSJesse Gross else 280f2a4d086SWilliam Tu err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); 281ccb1352eSJesse Gross if (err) 282ccb1352eSJesse Gross goto err; 283ccb1352eSJesse Gross 284ccb1352eSJesse Gross return 0; 285ccb1352eSJesse Gross 286ccb1352eSJesse Gross err: 287404f2f10SShan Wei stats = this_cpu_ptr(dp->stats_percpu); 288ccb1352eSJesse Gross 289df9d9fdfSWANG Cong u64_stats_update_begin(&stats->syncp); 290ccb1352eSJesse Gross stats->n_lost++; 291df9d9fdfSWANG Cong u64_stats_update_end(&stats->syncp); 292ccb1352eSJesse Gross 293ccb1352eSJesse Gross return err; 294ccb1352eSJesse Gross } 295ccb1352eSJesse Gross 2968055a89cSThomas Graf static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, 297e8eedb85SPravin B Shelar const struct sw_flow_key *key, 298f2a4d086SWilliam Tu const struct dp_upcall_info *upcall_info, 299f2a4d086SWilliam Tu uint32_t cutlen) 300ccb1352eSJesse Gross { 3012734166eSGustavo A. R. Silva unsigned int gso_type = skb_shinfo(skb)->gso_type; 3020c19f846SWillem de Bruijn struct sw_flow_key later_key; 303ccb1352eSJesse Gross struct sk_buff *segs, *nskb; 304ccb1352eSJesse Gross int err; 305ccb1352eSJesse Gross 3069207f9d4SKonstantin Khlebnikov BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_SGO_CB_OFFSET); 30709c5e605SThomas Graf segs = __skb_gso_segment(skb, NETIF_F_SG, false); 30892e5dfc3SPravin B Shelar if (IS_ERR(segs)) 30992e5dfc3SPravin B Shelar return PTR_ERR(segs); 310330966e5SFlorian Westphal if (segs == NULL) 311330966e5SFlorian Westphal return -EINVAL; 312ccb1352eSJesse Gross 3130c19f846SWillem de Bruijn if (gso_type & SKB_GSO_UDP) { 3140c19f846SWillem de Bruijn /* The initial flow key extracted by ovs_flow_key_extract() 3150c19f846SWillem de Bruijn * in this case is for a first fragment, so we need to 3160c19f846SWillem de Bruijn * properly mark later fragments. 3170c19f846SWillem de Bruijn */ 3180c19f846SWillem de Bruijn later_key = *key; 3190c19f846SWillem de Bruijn later_key.ip.frag = OVS_FRAG_TYPE_LATER; 3200c19f846SWillem de Bruijn } 3210c19f846SWillem de Bruijn 322e8eedb85SPravin B Shelar /* Queue all of the segments. */ 323e8eedb85SPravin B Shelar skb = segs; 324e8eedb85SPravin B Shelar do { 3250c19f846SWillem de Bruijn if (gso_type & SKB_GSO_UDP && skb != segs) 3260c19f846SWillem de Bruijn key = &later_key; 3270c19f846SWillem de Bruijn 328f2a4d086SWilliam Tu err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); 329e8eedb85SPravin B Shelar if (err) 330e8eedb85SPravin B Shelar break; 331e8eedb85SPravin B Shelar 332ccb1352eSJesse Gross } while ((skb = skb->next)); 333ccb1352eSJesse Gross 334ccb1352eSJesse Gross /* Free all of the segments. */ 335ccb1352eSJesse Gross skb = segs; 336ccb1352eSJesse Gross do { 337ccb1352eSJesse Gross nskb = skb->next; 338ccb1352eSJesse Gross if (err) 339ccb1352eSJesse Gross kfree_skb(skb); 340ccb1352eSJesse Gross else 341ccb1352eSJesse Gross consume_skb(skb); 342ccb1352eSJesse Gross } while ((skb = nskb)); 343ccb1352eSJesse Gross return err; 344ccb1352eSJesse Gross } 345ccb1352eSJesse Gross 3468f0aad6fSWenyu Zhang static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, 347494bea39SLiping Zhang unsigned int hdrlen, int actions_attrlen) 348c3ff8cfeSThomas Graf { 349c3ff8cfeSThomas Graf size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) 350bda56f14SThomas Graf + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */ 351b95e5928SWilliam Tu + nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */ 352b95e5928SWilliam Tu + nla_total_size(sizeof(unsigned int)); /* OVS_PACKET_ATTR_LEN */ 353c3ff8cfeSThomas Graf 354c3ff8cfeSThomas Graf /* OVS_PACKET_ATTR_USERDATA */ 3558f0aad6fSWenyu Zhang if (upcall_info->userdata) 3568f0aad6fSWenyu Zhang size += NLA_ALIGN(upcall_info->userdata->nla_len); 3578f0aad6fSWenyu Zhang 3588f0aad6fSWenyu Zhang /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */ 3598f0aad6fSWenyu Zhang if (upcall_info->egress_tun_info) 3608f0aad6fSWenyu Zhang size += nla_total_size(ovs_tun_key_attr_size()); 361c3ff8cfeSThomas Graf 362ccea7445SNeil McKee /* OVS_PACKET_ATTR_ACTIONS */ 363ccea7445SNeil McKee if (upcall_info->actions_len) 364494bea39SLiping Zhang size += nla_total_size(actions_attrlen); 365ccea7445SNeil McKee 3667f8a436eSJoe Stringer /* OVS_PACKET_ATTR_MRU */ 3677f8a436eSJoe Stringer if (upcall_info->mru) 3687f8a436eSJoe Stringer size += nla_total_size(sizeof(upcall_info->mru)); 3697f8a436eSJoe Stringer 370c3ff8cfeSThomas Graf return size; 371c3ff8cfeSThomas Graf } 372c3ff8cfeSThomas Graf 3737f8a436eSJoe Stringer static void pad_packet(struct datapath *dp, struct sk_buff *skb) 3747f8a436eSJoe Stringer { 3757f8a436eSJoe Stringer if (!(dp->user_features & OVS_DP_F_UNALIGNED)) { 3767f8a436eSJoe Stringer size_t plen = NLA_ALIGN(skb->len) - skb->len; 3777f8a436eSJoe Stringer 3787f8a436eSJoe Stringer if (plen > 0) 379b080db58SJohannes Berg skb_put_zero(skb, plen); 3807f8a436eSJoe Stringer } 3817f8a436eSJoe Stringer } 3827f8a436eSJoe Stringer 3838055a89cSThomas Graf static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, 384e8eedb85SPravin B Shelar const struct sw_flow_key *key, 385f2a4d086SWilliam Tu const struct dp_upcall_info *upcall_info, 386f2a4d086SWilliam Tu uint32_t cutlen) 387ccb1352eSJesse Gross { 388ccb1352eSJesse Gross struct ovs_header *upcall; 389ccb1352eSJesse Gross struct sk_buff *nskb = NULL; 3904ee45ea0SLi RongQing struct sk_buff *user_skb = NULL; /* to be queued to userspace */ 391ccb1352eSJesse Gross struct nlattr *nla; 392795449d8SThomas Graf size_t len; 393bda56f14SThomas Graf unsigned int hlen; 3948055a89cSThomas Graf int err, dp_ifindex; 3958055a89cSThomas Graf 3968055a89cSThomas Graf dp_ifindex = get_dpifindex(dp); 3978055a89cSThomas Graf if (!dp_ifindex) 3988055a89cSThomas Graf return -ENODEV; 399ccb1352eSJesse Gross 400df8a39deSJiri Pirko if (skb_vlan_tag_present(skb)) { 401ccb1352eSJesse Gross nskb = skb_clone(skb, GFP_ATOMIC); 402ccb1352eSJesse Gross if (!nskb) 403ccb1352eSJesse Gross return -ENOMEM; 404ccb1352eSJesse Gross 4055968250cSJiri Pirko nskb = __vlan_hwaccel_push_inside(nskb); 4068aa51d64SDan Carpenter if (!nskb) 407ccb1352eSJesse Gross return -ENOMEM; 408ccb1352eSJesse Gross 409ccb1352eSJesse Gross skb = nskb; 410ccb1352eSJesse Gross } 411ccb1352eSJesse Gross 412ccb1352eSJesse Gross if (nla_attr_size(skb->len) > USHRT_MAX) { 413ccb1352eSJesse Gross err = -EFBIG; 414ccb1352eSJesse Gross goto out; 415ccb1352eSJesse Gross } 416ccb1352eSJesse Gross 417bda56f14SThomas Graf /* Complete checksum if needed */ 418bda56f14SThomas Graf if (skb->ip_summed == CHECKSUM_PARTIAL && 4197529390dSDavide Caratti (err = skb_csum_hwoffload_help(skb, 0))) 420bda56f14SThomas Graf goto out; 421bda56f14SThomas Graf 422bda56f14SThomas Graf /* Older versions of OVS user space enforce alignment of the last 423bda56f14SThomas Graf * Netlink attribute to NLA_ALIGNTO which would require extensive 424bda56f14SThomas Graf * padding logic. Only perform zerocopy if padding is not required. 425bda56f14SThomas Graf */ 426bda56f14SThomas Graf if (dp->user_features & OVS_DP_F_UNALIGNED) 427bda56f14SThomas Graf hlen = skb_zerocopy_headlen(skb); 428bda56f14SThomas Graf else 429bda56f14SThomas Graf hlen = skb->len; 430bda56f14SThomas Graf 431494bea39SLiping Zhang len = upcall_msg_size(upcall_info, hlen - cutlen, 432494bea39SLiping Zhang OVS_CB(skb)->acts_origlen); 433551ddc05SFlorian Westphal user_skb = genlmsg_new(len, GFP_ATOMIC); 434ccb1352eSJesse Gross if (!user_skb) { 435ccb1352eSJesse Gross err = -ENOMEM; 436ccb1352eSJesse Gross goto out; 437ccb1352eSJesse Gross } 438ccb1352eSJesse Gross 439ccb1352eSJesse Gross upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family, 440ccb1352eSJesse Gross 0, upcall_info->cmd); 4416f19893bSKangjie Lu if (!upcall) { 4426f19893bSKangjie Lu err = -EINVAL; 4436f19893bSKangjie Lu goto out; 4446f19893bSKangjie Lu } 445ccb1352eSJesse Gross upcall->dp_ifindex = dp_ifindex; 446ccb1352eSJesse Gross 4475b4237bbSJoe Stringer err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb); 448a734d1f4SEelco Chaudron if (err) 449a734d1f4SEelco Chaudron goto out; 450ccb1352eSJesse Gross 451ccb1352eSJesse Gross if (upcall_info->userdata) 4524490108bSBen Pfaff __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA, 4534490108bSBen Pfaff nla_len(upcall_info->userdata), 4544490108bSBen Pfaff nla_data(upcall_info->userdata)); 455ccb1352eSJesse Gross 4568f0aad6fSWenyu Zhang if (upcall_info->egress_tun_info) { 457ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(user_skb, 458ae0be8deSMichal Kubecek OVS_PACKET_ATTR_EGRESS_TUN_KEY); 4590fff9bd4SKangjie Lu if (!nla) { 4600fff9bd4SKangjie Lu err = -EMSGSIZE; 4610fff9bd4SKangjie Lu goto out; 4620fff9bd4SKangjie Lu } 463fc4099f1SPravin B Shelar err = ovs_nla_put_tunnel_info(user_skb, 464fc4099f1SPravin B Shelar upcall_info->egress_tun_info); 465a734d1f4SEelco Chaudron if (err) 466a734d1f4SEelco Chaudron goto out; 467a734d1f4SEelco Chaudron 4688f0aad6fSWenyu Zhang nla_nest_end(user_skb, nla); 4698f0aad6fSWenyu Zhang } 4708f0aad6fSWenyu Zhang 471ccea7445SNeil McKee if (upcall_info->actions_len) { 472ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(user_skb, OVS_PACKET_ATTR_ACTIONS); 4730fff9bd4SKangjie Lu if (!nla) { 4740fff9bd4SKangjie Lu err = -EMSGSIZE; 4750fff9bd4SKangjie Lu goto out; 4760fff9bd4SKangjie Lu } 477ccea7445SNeil McKee err = ovs_nla_put_actions(upcall_info->actions, 478ccea7445SNeil McKee upcall_info->actions_len, 479ccea7445SNeil McKee user_skb); 480ccea7445SNeil McKee if (!err) 481ccea7445SNeil McKee nla_nest_end(user_skb, nla); 482ccea7445SNeil McKee else 483ccea7445SNeil McKee nla_nest_cancel(user_skb, nla); 484ccea7445SNeil McKee } 485ccea7445SNeil McKee 4867f8a436eSJoe Stringer /* Add OVS_PACKET_ATTR_MRU */ 4877f8a436eSJoe Stringer if (upcall_info->mru) { 4887f8a436eSJoe Stringer if (nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU, 4897f8a436eSJoe Stringer upcall_info->mru)) { 4907f8a436eSJoe Stringer err = -ENOBUFS; 4917f8a436eSJoe Stringer goto out; 4927f8a436eSJoe Stringer } 4937f8a436eSJoe Stringer pad_packet(dp, user_skb); 4947f8a436eSJoe Stringer } 4957f8a436eSJoe Stringer 496b95e5928SWilliam Tu /* Add OVS_PACKET_ATTR_LEN when packet is truncated */ 497b95e5928SWilliam Tu if (cutlen > 0) { 498b95e5928SWilliam Tu if (nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, 499b95e5928SWilliam Tu skb->len)) { 500b95e5928SWilliam Tu err = -ENOBUFS; 501b95e5928SWilliam Tu goto out; 502b95e5928SWilliam Tu } 503b95e5928SWilliam Tu pad_packet(dp, user_skb); 504b95e5928SWilliam Tu } 505b95e5928SWilliam Tu 506bda56f14SThomas Graf /* Only reserve room for attribute header, packet data is added 507bda56f14SThomas Graf * in skb_zerocopy() */ 508bda56f14SThomas Graf if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { 509bda56f14SThomas Graf err = -ENOBUFS; 510bda56f14SThomas Graf goto out; 511bda56f14SThomas Graf } 512f2a4d086SWilliam Tu nla->nla_len = nla_attr_size(skb->len - cutlen); 513ccb1352eSJesse Gross 514f2a4d086SWilliam Tu err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen); 51536d5fe6aSZoltan Kiss if (err) 51636d5fe6aSZoltan Kiss goto out; 517ccb1352eSJesse Gross 518aea0bb4fSThomas Graf /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */ 5197f8a436eSJoe Stringer pad_packet(dp, user_skb); 520aea0bb4fSThomas Graf 521bda56f14SThomas Graf ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; 522bda56f14SThomas Graf 5238055a89cSThomas Graf err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); 5244ee45ea0SLi RongQing user_skb = NULL; 525ccb1352eSJesse Gross out: 52636d5fe6aSZoltan Kiss if (err) 52736d5fe6aSZoltan Kiss skb_tx_error(skb); 5284ee45ea0SLi RongQing kfree_skb(user_skb); 529ccb1352eSJesse Gross kfree_skb(nskb); 530ccb1352eSJesse Gross return err; 531ccb1352eSJesse Gross } 532ccb1352eSJesse Gross 533ccb1352eSJesse Gross static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) 534ccb1352eSJesse Gross { 535ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 5367f8a436eSJoe Stringer struct net *net = sock_net(skb->sk); 537ccb1352eSJesse Gross struct nlattr **a = info->attrs; 538ccb1352eSJesse Gross struct sw_flow_actions *acts; 539ccb1352eSJesse Gross struct sk_buff *packet; 540ccb1352eSJesse Gross struct sw_flow *flow; 541d98612b8SLorand Jakab struct sw_flow_actions *sf_acts; 542ccb1352eSJesse Gross struct datapath *dp; 54383c8df26SPravin B Shelar struct vport *input_vport; 5447f8a436eSJoe Stringer u16 mru = 0; 545ccb1352eSJesse Gross int len; 546ccb1352eSJesse Gross int err; 5471ba39804SThomas Graf bool log = !a[OVS_PACKET_ATTR_PROBE]; 548ccb1352eSJesse Gross 549ccb1352eSJesse Gross err = -EINVAL; 550ccb1352eSJesse Gross if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || 551dded45fcSThomas Graf !a[OVS_PACKET_ATTR_ACTIONS]) 552ccb1352eSJesse Gross goto err; 553ccb1352eSJesse Gross 554ccb1352eSJesse Gross len = nla_len(a[OVS_PACKET_ATTR_PACKET]); 555ccb1352eSJesse Gross packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL); 556ccb1352eSJesse Gross err = -ENOMEM; 557ccb1352eSJesse Gross if (!packet) 558ccb1352eSJesse Gross goto err; 559ccb1352eSJesse Gross skb_reserve(packet, NET_IP_ALIGN); 560ccb1352eSJesse Gross 56132686a9dSThomas Graf nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len); 562ccb1352eSJesse Gross 5637f8a436eSJoe Stringer /* Set packet's mru */ 5647f8a436eSJoe Stringer if (a[OVS_PACKET_ATTR_MRU]) { 5657f8a436eSJoe Stringer mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]); 5667f8a436eSJoe Stringer packet->ignore_df = 1; 5677f8a436eSJoe Stringer } 5687f8a436eSJoe Stringer OVS_CB(packet)->mru = mru; 5697f8a436eSJoe Stringer 570ccb1352eSJesse Gross /* Build an sw_flow for sending this packet. */ 57123dabf88SJarno Rajahalme flow = ovs_flow_alloc(); 572ccb1352eSJesse Gross err = PTR_ERR(flow); 573ccb1352eSJesse Gross if (IS_ERR(flow)) 574ccb1352eSJesse Gross goto err_kfree_skb; 575ccb1352eSJesse Gross 576c2ac6673SJoe Stringer err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY], 577c2ac6673SJoe Stringer packet, &flow->key, log); 578ccb1352eSJesse Gross if (err) 579ccb1352eSJesse Gross goto err_flow_free; 580ccb1352eSJesse Gross 5817f8a436eSJoe Stringer err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS], 58205da5898SJarno Rajahalme &flow->key, &acts, log); 58374f84a57SPravin B Shelar if (err) 58474f84a57SPravin B Shelar goto err_flow_free; 585ccb1352eSJesse Gross 586f5796684SJesse Gross rcu_assign_pointer(flow->sf_acts, acts); 587ccb1352eSJesse Gross packet->priority = flow->key.phy.priority; 58839c7caebSAnsis Atteka packet->mark = flow->key.phy.skb_mark; 589ccb1352eSJesse Gross 590ccb1352eSJesse Gross rcu_read_lock(); 5917f8a436eSJoe Stringer dp = get_dp_rcu(net, ovs_header->dp_ifindex); 592ccb1352eSJesse Gross err = -ENODEV; 593ccb1352eSJesse Gross if (!dp) 594ccb1352eSJesse Gross goto err_unlock; 595ccb1352eSJesse Gross 59683c8df26SPravin B Shelar input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port); 59783c8df26SPravin B Shelar if (!input_vport) 59883c8df26SPravin B Shelar input_vport = ovs_vport_rcu(dp, OVSP_LOCAL); 59983c8df26SPravin B Shelar 60083c8df26SPravin B Shelar if (!input_vport) 60183c8df26SPravin B Shelar goto err_unlock; 60283c8df26SPravin B Shelar 6037f8a436eSJoe Stringer packet->dev = input_vport->dev; 60483c8df26SPravin B Shelar OVS_CB(packet)->input_vport = input_vport; 605d98612b8SLorand Jakab sf_acts = rcu_dereference(flow->sf_acts); 60683c8df26SPravin B Shelar 607ccb1352eSJesse Gross local_bh_disable(); 608d98612b8SLorand Jakab err = ovs_execute_actions(dp, packet, sf_acts, &flow->key); 609ccb1352eSJesse Gross local_bh_enable(); 610ccb1352eSJesse Gross rcu_read_unlock(); 611ccb1352eSJesse Gross 61203f0d916SAndy Zhou ovs_flow_free(flow, false); 613ccb1352eSJesse Gross return err; 614ccb1352eSJesse Gross 615ccb1352eSJesse Gross err_unlock: 616ccb1352eSJesse Gross rcu_read_unlock(); 617ccb1352eSJesse Gross err_flow_free: 61803f0d916SAndy Zhou ovs_flow_free(flow, false); 619ccb1352eSJesse Gross err_kfree_skb: 620ccb1352eSJesse Gross kfree_skb(packet); 621ccb1352eSJesse Gross err: 622ccb1352eSJesse Gross return err; 623ccb1352eSJesse Gross } 624ccb1352eSJesse Gross 625ccb1352eSJesse Gross static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { 626dded45fcSThomas Graf [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, 627ccb1352eSJesse Gross [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, 628ccb1352eSJesse Gross [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, 6291ba39804SThomas Graf [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, 6307f8a436eSJoe Stringer [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 }, 631ccb1352eSJesse Gross }; 632ccb1352eSJesse Gross 6334534de83SJohannes Berg static const struct genl_ops dp_packet_genl_ops[] = { 634ccb1352eSJesse Gross { .cmd = OVS_PACKET_CMD_EXECUTE, 635ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6364a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 637ccb1352eSJesse Gross .doit = ovs_packet_cmd_execute 638ccb1352eSJesse Gross } 639ccb1352eSJesse Gross }; 640ccb1352eSJesse Gross 64156989f6dSJohannes Berg static struct genl_family dp_packet_genl_family __ro_after_init = { 6420c200ef9SPravin B Shelar .hdrsize = sizeof(struct ovs_header), 6430c200ef9SPravin B Shelar .name = OVS_PACKET_FAMILY, 6440c200ef9SPravin B Shelar .version = OVS_PACKET_VERSION, 6450c200ef9SPravin B Shelar .maxattr = OVS_PACKET_ATTR_MAX, 6463b0f31f2SJohannes Berg .policy = packet_policy, 6470c200ef9SPravin B Shelar .netnsok = true, 6480c200ef9SPravin B Shelar .parallel_ops = true, 6490c200ef9SPravin B Shelar .ops = dp_packet_genl_ops, 6500c200ef9SPravin B Shelar .n_ops = ARRAY_SIZE(dp_packet_genl_ops), 651489111e5SJohannes Berg .module = THIS_MODULE, 6520c200ef9SPravin B Shelar }; 6530c200ef9SPravin B Shelar 65412eb18f7SThomas Graf static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats, 6551bd7116fSAndy Zhou struct ovs_dp_megaflow_stats *mega_stats) 656ccb1352eSJesse Gross { 657ccb1352eSJesse Gross int i; 658ccb1352eSJesse Gross 6591bd7116fSAndy Zhou memset(mega_stats, 0, sizeof(*mega_stats)); 6601bd7116fSAndy Zhou 661b637e498SPravin B Shelar stats->n_flows = ovs_flow_tbl_count(&dp->table); 6621bd7116fSAndy Zhou mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table); 663ccb1352eSJesse Gross 664ccb1352eSJesse Gross stats->n_hit = stats->n_missed = stats->n_lost = 0; 6651bd7116fSAndy Zhou 666ccb1352eSJesse Gross for_each_possible_cpu(i) { 667ccb1352eSJesse Gross const struct dp_stats_percpu *percpu_stats; 668ccb1352eSJesse Gross struct dp_stats_percpu local_stats; 669ccb1352eSJesse Gross unsigned int start; 670ccb1352eSJesse Gross 671ccb1352eSJesse Gross percpu_stats = per_cpu_ptr(dp->stats_percpu, i); 672ccb1352eSJesse Gross 673ccb1352eSJesse Gross do { 67457a7744eSEric W. Biederman start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); 675ccb1352eSJesse Gross local_stats = *percpu_stats; 67657a7744eSEric W. Biederman } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); 677ccb1352eSJesse Gross 678ccb1352eSJesse Gross stats->n_hit += local_stats.n_hit; 679ccb1352eSJesse Gross stats->n_missed += local_stats.n_missed; 680ccb1352eSJesse Gross stats->n_lost += local_stats.n_lost; 6811bd7116fSAndy Zhou mega_stats->n_mask_hit += local_stats.n_mask_hit; 682ccb1352eSJesse Gross } 683ccb1352eSJesse Gross } 684ccb1352eSJesse Gross 68574ed7ab9SJoe Stringer static bool should_fill_key(const struct sw_flow_id *sfid, uint32_t ufid_flags) 686c3ff8cfeSThomas Graf { 68774ed7ab9SJoe Stringer return ovs_identifier_is_ufid(sfid) && 68874ed7ab9SJoe Stringer !(ufid_flags & OVS_UFID_F_OMIT_KEY); 68974ed7ab9SJoe Stringer } 69074ed7ab9SJoe Stringer 69174ed7ab9SJoe Stringer static bool should_fill_mask(uint32_t ufid_flags) 69274ed7ab9SJoe Stringer { 69374ed7ab9SJoe Stringer return !(ufid_flags & OVS_UFID_F_OMIT_MASK); 69474ed7ab9SJoe Stringer } 69574ed7ab9SJoe Stringer 69674ed7ab9SJoe Stringer static bool should_fill_actions(uint32_t ufid_flags) 69774ed7ab9SJoe Stringer { 69874ed7ab9SJoe Stringer return !(ufid_flags & OVS_UFID_F_OMIT_ACTIONS); 69974ed7ab9SJoe Stringer } 70074ed7ab9SJoe Stringer 70174ed7ab9SJoe Stringer static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts, 70274ed7ab9SJoe Stringer const struct sw_flow_id *sfid, 70374ed7ab9SJoe Stringer uint32_t ufid_flags) 70474ed7ab9SJoe Stringer { 70574ed7ab9SJoe Stringer size_t len = NLMSG_ALIGN(sizeof(struct ovs_header)); 70674ed7ab9SJoe Stringer 70774ed7ab9SJoe Stringer /* OVS_FLOW_ATTR_UFID */ 70874ed7ab9SJoe Stringer if (sfid && ovs_identifier_is_ufid(sfid)) 70974ed7ab9SJoe Stringer len += nla_total_size(sfid->ufid_len); 71074ed7ab9SJoe Stringer 71174ed7ab9SJoe Stringer /* OVS_FLOW_ATTR_KEY */ 71274ed7ab9SJoe Stringer if (!sfid || should_fill_key(sfid, ufid_flags)) 71374ed7ab9SJoe Stringer len += nla_total_size(ovs_key_attr_size()); 71474ed7ab9SJoe Stringer 71574ed7ab9SJoe Stringer /* OVS_FLOW_ATTR_MASK */ 71674ed7ab9SJoe Stringer if (should_fill_mask(ufid_flags)) 71774ed7ab9SJoe Stringer len += nla_total_size(ovs_key_attr_size()); 71874ed7ab9SJoe Stringer 71974ed7ab9SJoe Stringer /* OVS_FLOW_ATTR_ACTIONS */ 72074ed7ab9SJoe Stringer if (should_fill_actions(ufid_flags)) 7218e2fed1cSJoe Stringer len += nla_total_size(acts->orig_len); 72274ed7ab9SJoe Stringer 72374ed7ab9SJoe Stringer return len 72466c7a5eeSNicolas Dichtel + nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ 725c3ff8cfeSThomas Graf + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ 72666c7a5eeSNicolas Dichtel + nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */ 727c3ff8cfeSThomas Graf } 728c3ff8cfeSThomas Graf 729bb6f9a70SJarno Rajahalme /* Called with ovs_mutex or RCU read lock. */ 730ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow, 731ca7105f2SJoe Stringer struct sk_buff *skb) 732ca7105f2SJoe Stringer { 733ca7105f2SJoe Stringer struct ovs_flow_stats stats; 734ca7105f2SJoe Stringer __be16 tcp_flags; 735ca7105f2SJoe Stringer unsigned long used; 73603f0d916SAndy Zhou 737e298e505SPravin B Shelar ovs_flow_stats_get(flow, &stats, &used, &tcp_flags); 7380e9796b4SJarno Rajahalme 739028d6a67SDavid S. Miller if (used && 7400238b720SNicolas Dichtel nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used), 7410238b720SNicolas Dichtel OVS_FLOW_ATTR_PAD)) 742ca7105f2SJoe Stringer return -EMSGSIZE; 743ccb1352eSJesse Gross 744028d6a67SDavid S. Miller if (stats.n_packets && 74566c7a5eeSNicolas Dichtel nla_put_64bit(skb, OVS_FLOW_ATTR_STATS, 74666c7a5eeSNicolas Dichtel sizeof(struct ovs_flow_stats), &stats, 74766c7a5eeSNicolas Dichtel OVS_FLOW_ATTR_PAD)) 748ca7105f2SJoe Stringer return -EMSGSIZE; 749ccb1352eSJesse Gross 750e298e505SPravin B Shelar if ((u8)ntohs(tcp_flags) && 751e298e505SPravin B Shelar nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags))) 752ca7105f2SJoe Stringer return -EMSGSIZE; 753ca7105f2SJoe Stringer 754ca7105f2SJoe Stringer return 0; 755ca7105f2SJoe Stringer } 756ca7105f2SJoe Stringer 757ca7105f2SJoe Stringer /* Called with ovs_mutex or RCU read lock. */ 758ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow, 759ca7105f2SJoe Stringer struct sk_buff *skb, int skb_orig_len) 760ca7105f2SJoe Stringer { 761ca7105f2SJoe Stringer struct nlattr *start; 762ca7105f2SJoe Stringer int err; 763ccb1352eSJesse Gross 764ccb1352eSJesse Gross /* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if 765ccb1352eSJesse Gross * this is the first flow to be dumped into 'skb'. This is unusual for 766ccb1352eSJesse Gross * Netlink but individual action lists can be longer than 767ccb1352eSJesse Gross * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this. 768ccb1352eSJesse Gross * The userspace caller can always fetch the actions separately if it 769ccb1352eSJesse Gross * really wants them. (Most userspace callers in fact don't care.) 770ccb1352eSJesse Gross * 771ccb1352eSJesse Gross * This can only fail for dump operations because the skb is always 772ccb1352eSJesse Gross * properly sized for single flows. 773ccb1352eSJesse Gross */ 774ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_FLOW_ATTR_ACTIONS); 77574f84a57SPravin B Shelar if (start) { 776d57170b1SPravin B Shelar const struct sw_flow_actions *sf_acts; 777d57170b1SPravin B Shelar 778663efa36SJesse Gross sf_acts = rcu_dereference_ovsl(flow->sf_acts); 779e6445719SPravin B Shelar err = ovs_nla_put_actions(sf_acts->actions, 780e6445719SPravin B Shelar sf_acts->actions_len, skb); 7810e9796b4SJarno Rajahalme 78274f84a57SPravin B Shelar if (!err) 78374f84a57SPravin B Shelar nla_nest_end(skb, start); 78474f84a57SPravin B Shelar else { 78574f84a57SPravin B Shelar if (skb_orig_len) 786ca7105f2SJoe Stringer return err; 787ccb1352eSJesse Gross 78874f84a57SPravin B Shelar nla_nest_cancel(skb, start); 78974f84a57SPravin B Shelar } 790ca7105f2SJoe Stringer } else if (skb_orig_len) { 791ca7105f2SJoe Stringer return -EMSGSIZE; 792ca7105f2SJoe Stringer } 793ca7105f2SJoe Stringer 794ca7105f2SJoe Stringer return 0; 795ca7105f2SJoe Stringer } 796ca7105f2SJoe Stringer 797ca7105f2SJoe Stringer /* Called with ovs_mutex or RCU read lock. */ 798ca7105f2SJoe Stringer static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex, 799ca7105f2SJoe Stringer struct sk_buff *skb, u32 portid, 80074ed7ab9SJoe Stringer u32 seq, u32 flags, u8 cmd, u32 ufid_flags) 801ca7105f2SJoe Stringer { 802ca7105f2SJoe Stringer const int skb_orig_len = skb->len; 803ca7105f2SJoe Stringer struct ovs_header *ovs_header; 804ca7105f2SJoe Stringer int err; 805ca7105f2SJoe Stringer 806ca7105f2SJoe Stringer ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, 807ca7105f2SJoe Stringer flags, cmd); 808ca7105f2SJoe Stringer if (!ovs_header) 809ca7105f2SJoe Stringer return -EMSGSIZE; 810ca7105f2SJoe Stringer 811ca7105f2SJoe Stringer ovs_header->dp_ifindex = dp_ifindex; 812ca7105f2SJoe Stringer 81374ed7ab9SJoe Stringer err = ovs_nla_put_identifier(flow, skb); 8145b4237bbSJoe Stringer if (err) 8155b4237bbSJoe Stringer goto error; 8165b4237bbSJoe Stringer 81774ed7ab9SJoe Stringer if (should_fill_key(&flow->id, ufid_flags)) { 81874ed7ab9SJoe Stringer err = ovs_nla_put_masked_key(flow, skb); 81974ed7ab9SJoe Stringer if (err) 82074ed7ab9SJoe Stringer goto error; 82174ed7ab9SJoe Stringer } 82274ed7ab9SJoe Stringer 82374ed7ab9SJoe Stringer if (should_fill_mask(ufid_flags)) { 8245b4237bbSJoe Stringer err = ovs_nla_put_mask(flow, skb); 825ca7105f2SJoe Stringer if (err) 826ca7105f2SJoe Stringer goto error; 82774ed7ab9SJoe Stringer } 828ca7105f2SJoe Stringer 829ca7105f2SJoe Stringer err = ovs_flow_cmd_fill_stats(flow, skb); 830ca7105f2SJoe Stringer if (err) 831ca7105f2SJoe Stringer goto error; 832ca7105f2SJoe Stringer 83374ed7ab9SJoe Stringer if (should_fill_actions(ufid_flags)) { 834ca7105f2SJoe Stringer err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len); 835ca7105f2SJoe Stringer if (err) 836ca7105f2SJoe Stringer goto error; 83774ed7ab9SJoe Stringer } 83874f84a57SPravin B Shelar 839053c095aSJohannes Berg genlmsg_end(skb, ovs_header); 840053c095aSJohannes Berg return 0; 841ccb1352eSJesse Gross 842ccb1352eSJesse Gross error: 843ccb1352eSJesse Gross genlmsg_cancel(skb, ovs_header); 844ccb1352eSJesse Gross return err; 845ccb1352eSJesse Gross } 846ccb1352eSJesse Gross 8470e9796b4SJarno Rajahalme /* May not be called with RCU read lock. */ 8480e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts, 84974ed7ab9SJoe Stringer const struct sw_flow_id *sfid, 850fb5d1e9eSJarno Rajahalme struct genl_info *info, 85174ed7ab9SJoe Stringer bool always, 85274ed7ab9SJoe Stringer uint32_t ufid_flags) 853ccb1352eSJesse Gross { 854fb5d1e9eSJarno Rajahalme struct sk_buff *skb; 85574ed7ab9SJoe Stringer size_t len; 856ccb1352eSJesse Gross 8579b67aa4aSSamuel Gauthier if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0)) 858fb5d1e9eSJarno Rajahalme return NULL; 859fb5d1e9eSJarno Rajahalme 86074ed7ab9SJoe Stringer len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags); 861551ddc05SFlorian Westphal skb = genlmsg_new(len, GFP_KERNEL); 862fb5d1e9eSJarno Rajahalme if (!skb) 863fb5d1e9eSJarno Rajahalme return ERR_PTR(-ENOMEM); 864fb5d1e9eSJarno Rajahalme 865fb5d1e9eSJarno Rajahalme return skb; 866ccb1352eSJesse Gross } 867ccb1352eSJesse Gross 8680e9796b4SJarno Rajahalme /* Called with ovs_mutex. */ 8690e9796b4SJarno Rajahalme static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, 8700e9796b4SJarno Rajahalme int dp_ifindex, 8710e9796b4SJarno Rajahalme struct genl_info *info, u8 cmd, 87274ed7ab9SJoe Stringer bool always, u32 ufid_flags) 873ccb1352eSJesse Gross { 874ccb1352eSJesse Gross struct sk_buff *skb; 875ccb1352eSJesse Gross int retval; 876ccb1352eSJesse Gross 87774ed7ab9SJoe Stringer skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), 87874ed7ab9SJoe Stringer &flow->id, info, always, ufid_flags); 879d0e992aaSHimangi Saraogi if (IS_ERR_OR_NULL(skb)) 880fb5d1e9eSJarno Rajahalme return skb; 881ccb1352eSJesse Gross 8820e9796b4SJarno Rajahalme retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, 8830e9796b4SJarno Rajahalme info->snd_portid, info->snd_seq, 0, 88474ed7ab9SJoe Stringer cmd, ufid_flags); 885ccb1352eSJesse Gross BUG_ON(retval < 0); 886ccb1352eSJesse Gross return skb; 887ccb1352eSJesse Gross } 888ccb1352eSJesse Gross 88937bdc87bSJarno Rajahalme static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) 890ccb1352eSJesse Gross { 8917f8a436eSJoe Stringer struct net *net = sock_net(skb->sk); 892ccb1352eSJesse Gross struct nlattr **a = info->attrs; 893ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 89474ed7ab9SJoe Stringer struct sw_flow *flow = NULL, *new_flow; 89503f0d916SAndy Zhou struct sw_flow_mask mask; 896ccb1352eSJesse Gross struct sk_buff *reply; 897ccb1352eSJesse Gross struct datapath *dp; 89837bdc87bSJarno Rajahalme struct sw_flow_actions *acts; 89937bdc87bSJarno Rajahalme struct sw_flow_match match; 90074ed7ab9SJoe Stringer u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); 90137bdc87bSJarno Rajahalme int error; 90205da5898SJarno Rajahalme bool log = !a[OVS_FLOW_ATTR_PROBE]; 90337bdc87bSJarno Rajahalme 904893f139bSJarno Rajahalme /* Must have key and actions. */ 90537bdc87bSJarno Rajahalme error = -EINVAL; 906426cda5cSJesse Gross if (!a[OVS_FLOW_ATTR_KEY]) { 90705da5898SJarno Rajahalme OVS_NLERR(log, "Flow key attr not present in new flow."); 90837bdc87bSJarno Rajahalme goto error; 909426cda5cSJesse Gross } 910426cda5cSJesse Gross if (!a[OVS_FLOW_ATTR_ACTIONS]) { 91105da5898SJarno Rajahalme OVS_NLERR(log, "Flow actions attr not present in new flow."); 91237bdc87bSJarno Rajahalme goto error; 913426cda5cSJesse Gross } 91437bdc87bSJarno Rajahalme 915893f139bSJarno Rajahalme /* Most of the time we need to allocate a new flow, do it before 916893f139bSJarno Rajahalme * locking. 917893f139bSJarno Rajahalme */ 918893f139bSJarno Rajahalme new_flow = ovs_flow_alloc(); 919893f139bSJarno Rajahalme if (IS_ERR(new_flow)) { 920893f139bSJarno Rajahalme error = PTR_ERR(new_flow); 921893f139bSJarno Rajahalme goto error; 922893f139bSJarno Rajahalme } 923893f139bSJarno Rajahalme 924893f139bSJarno Rajahalme /* Extract key. */ 9252279994dSpravin shelar ovs_match_init(&match, &new_flow->key, false, &mask); 926c2ac6673SJoe Stringer error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], 92705da5898SJarno Rajahalme a[OVS_FLOW_ATTR_MASK], log); 928893f139bSJarno Rajahalme if (error) 929893f139bSJarno Rajahalme goto err_kfree_flow; 930893f139bSJarno Rajahalme 93174ed7ab9SJoe Stringer /* Extract flow identifier. */ 93274ed7ab9SJoe Stringer error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], 933190aa3e7Spravin shelar &new_flow->key, log); 93474ed7ab9SJoe Stringer if (error) 93574ed7ab9SJoe Stringer goto err_kfree_flow; 936893f139bSJarno Rajahalme 937190aa3e7Spravin shelar /* unmasked key is needed to match when ufid is not used. */ 938190aa3e7Spravin shelar if (ovs_identifier_is_key(&new_flow->id)) 939190aa3e7Spravin shelar match.key = new_flow->id.unmasked_key; 940190aa3e7Spravin shelar 941190aa3e7Spravin shelar ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask); 942190aa3e7Spravin shelar 943893f139bSJarno Rajahalme /* Validate actions. */ 9447f8a436eSJoe Stringer error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS], 9457f8a436eSJoe Stringer &new_flow->key, &acts, log); 94637bdc87bSJarno Rajahalme if (error) { 94705da5898SJarno Rajahalme OVS_NLERR(log, "Flow actions may not be safe on all matching packets."); 9482fdb957dSPravin B Shelar goto err_kfree_flow; 949893f139bSJarno Rajahalme } 950893f139bSJarno Rajahalme 95174ed7ab9SJoe Stringer reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false, 95274ed7ab9SJoe Stringer ufid_flags); 953893f139bSJarno Rajahalme if (IS_ERR(reply)) { 954893f139bSJarno Rajahalme error = PTR_ERR(reply); 955893f139bSJarno Rajahalme goto err_kfree_acts; 95637bdc87bSJarno Rajahalme } 95737bdc87bSJarno Rajahalme 95837bdc87bSJarno Rajahalme ovs_lock(); 9597f8a436eSJoe Stringer dp = get_dp(net, ovs_header->dp_ifindex); 960893f139bSJarno Rajahalme if (unlikely(!dp)) { 96137bdc87bSJarno Rajahalme error = -ENODEV; 96237bdc87bSJarno Rajahalme goto err_unlock_ovs; 96337bdc87bSJarno Rajahalme } 96474ed7ab9SJoe Stringer 965893f139bSJarno Rajahalme /* Check if this is a duplicate flow */ 96674ed7ab9SJoe Stringer if (ovs_identifier_is_ufid(&new_flow->id)) 96774ed7ab9SJoe Stringer flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id); 96874ed7ab9SJoe Stringer if (!flow) 969190aa3e7Spravin shelar flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key); 970893f139bSJarno Rajahalme if (likely(!flow)) { 971893f139bSJarno Rajahalme rcu_assign_pointer(new_flow->sf_acts, acts); 97237bdc87bSJarno Rajahalme 97337bdc87bSJarno Rajahalme /* Put flow in bucket. */ 974893f139bSJarno Rajahalme error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask); 975893f139bSJarno Rajahalme if (unlikely(error)) { 97637bdc87bSJarno Rajahalme acts = NULL; 977893f139bSJarno Rajahalme goto err_unlock_ovs; 97837bdc87bSJarno Rajahalme } 979893f139bSJarno Rajahalme 980893f139bSJarno Rajahalme if (unlikely(reply)) { 981893f139bSJarno Rajahalme error = ovs_flow_cmd_fill_info(new_flow, 982893f139bSJarno Rajahalme ovs_header->dp_ifindex, 983893f139bSJarno Rajahalme reply, info->snd_portid, 984893f139bSJarno Rajahalme info->snd_seq, 0, 98574ed7ab9SJoe Stringer OVS_FLOW_CMD_NEW, 98674ed7ab9SJoe Stringer ufid_flags); 987893f139bSJarno Rajahalme BUG_ON(error < 0); 988893f139bSJarno Rajahalme } 989893f139bSJarno Rajahalme ovs_unlock(); 99037bdc87bSJarno Rajahalme } else { 99137bdc87bSJarno Rajahalme struct sw_flow_actions *old_acts; 99237bdc87bSJarno Rajahalme 99337bdc87bSJarno Rajahalme /* Bail out if we're not allowed to modify an existing flow. 99437bdc87bSJarno Rajahalme * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL 99537bdc87bSJarno Rajahalme * because Generic Netlink treats the latter as a dump 99637bdc87bSJarno Rajahalme * request. We also accept NLM_F_EXCL in case that bug ever 99737bdc87bSJarno Rajahalme * gets fixed. 99837bdc87bSJarno Rajahalme */ 999893f139bSJarno Rajahalme if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE 1000893f139bSJarno Rajahalme | NLM_F_EXCL))) { 100137bdc87bSJarno Rajahalme error = -EEXIST; 100237bdc87bSJarno Rajahalme goto err_unlock_ovs; 1003893f139bSJarno Rajahalme } 100474ed7ab9SJoe Stringer /* The flow identifier has to be the same for flow updates. 100574ed7ab9SJoe Stringer * Look for any overlapping flow. 100674ed7ab9SJoe Stringer */ 100774ed7ab9SJoe Stringer if (unlikely(!ovs_flow_cmp(flow, &match))) { 100874ed7ab9SJoe Stringer if (ovs_identifier_is_key(&flow->id)) 100974ed7ab9SJoe Stringer flow = ovs_flow_tbl_lookup_exact(&dp->table, 101074ed7ab9SJoe Stringer &match); 101174ed7ab9SJoe Stringer else /* UFID matches but key is different */ 101274ed7ab9SJoe Stringer flow = NULL; 10134a46b24eSAlex Wang if (!flow) { 10144a46b24eSAlex Wang error = -ENOENT; 101537bdc87bSJarno Rajahalme goto err_unlock_ovs; 1016893f139bSJarno Rajahalme } 10174a46b24eSAlex Wang } 101837bdc87bSJarno Rajahalme /* Update actions. */ 101937bdc87bSJarno Rajahalme old_acts = ovsl_dereference(flow->sf_acts); 102037bdc87bSJarno Rajahalme rcu_assign_pointer(flow->sf_acts, acts); 102137bdc87bSJarno Rajahalme 1022893f139bSJarno Rajahalme if (unlikely(reply)) { 1023893f139bSJarno Rajahalme error = ovs_flow_cmd_fill_info(flow, 1024893f139bSJarno Rajahalme ovs_header->dp_ifindex, 1025893f139bSJarno Rajahalme reply, info->snd_portid, 1026893f139bSJarno Rajahalme info->snd_seq, 0, 102774ed7ab9SJoe Stringer OVS_FLOW_CMD_NEW, 102874ed7ab9SJoe Stringer ufid_flags); 1029893f139bSJarno Rajahalme BUG_ON(error < 0); 1030893f139bSJarno Rajahalme } 103137bdc87bSJarno Rajahalme ovs_unlock(); 103237bdc87bSJarno Rajahalme 103334ae932aSThomas Graf ovs_nla_free_flow_actions_rcu(old_acts); 1034893f139bSJarno Rajahalme ovs_flow_free(new_flow, false); 103537bdc87bSJarno Rajahalme } 1036893f139bSJarno Rajahalme 1037893f139bSJarno Rajahalme if (reply) 1038893f139bSJarno Rajahalme ovs_notify(&dp_flow_genl_family, reply, info); 103937bdc87bSJarno Rajahalme return 0; 104037bdc87bSJarno Rajahalme 104137bdc87bSJarno Rajahalme err_unlock_ovs: 104237bdc87bSJarno Rajahalme ovs_unlock(); 1043893f139bSJarno Rajahalme kfree_skb(reply); 1044893f139bSJarno Rajahalme err_kfree_acts: 104534ae932aSThomas Graf ovs_nla_free_flow_actions(acts); 1046893f139bSJarno Rajahalme err_kfree_flow: 1047893f139bSJarno Rajahalme ovs_flow_free(new_flow, false); 104837bdc87bSJarno Rajahalme error: 104937bdc87bSJarno Rajahalme return error; 105037bdc87bSJarno Rajahalme } 105137bdc87bSJarno Rajahalme 10522fdb957dSPravin B Shelar /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */ 105326063790SArnd Bergmann static noinline_for_stack struct sw_flow_actions *get_flow_actions(struct net *net, 10547f8a436eSJoe Stringer const struct nlattr *a, 10556b205b2cSJesse Gross const struct sw_flow_key *key, 105605da5898SJarno Rajahalme const struct sw_flow_mask *mask, 105705da5898SJarno Rajahalme bool log) 10586b205b2cSJesse Gross { 10596b205b2cSJesse Gross struct sw_flow_actions *acts; 10606b205b2cSJesse Gross struct sw_flow_key masked_key; 10616b205b2cSJesse Gross int error; 10626b205b2cSJesse Gross 1063ae5f2fb1SJesse Gross ovs_flow_mask_key(&masked_key, key, true, mask); 10647f8a436eSJoe Stringer error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log); 10656b205b2cSJesse Gross if (error) { 106605da5898SJarno Rajahalme OVS_NLERR(log, 106705da5898SJarno Rajahalme "Actions may not be safe on all matching packets"); 10686b205b2cSJesse Gross return ERR_PTR(error); 10696b205b2cSJesse Gross } 10706b205b2cSJesse Gross 10716b205b2cSJesse Gross return acts; 10726b205b2cSJesse Gross } 10736b205b2cSJesse Gross 10749cc9a5cbSTonghao Zhang /* Factor out match-init and action-copy to avoid 10759cc9a5cbSTonghao Zhang * "Wframe-larger-than=1024" warning. Because mask is only 10769cc9a5cbSTonghao Zhang * used to get actions, we new a function to save some 10779cc9a5cbSTonghao Zhang * stack space. 10789cc9a5cbSTonghao Zhang * 10799cc9a5cbSTonghao Zhang * If there are not key and action attrs, we return 0 10809cc9a5cbSTonghao Zhang * directly. In the case, the caller will also not use the 10819cc9a5cbSTonghao Zhang * match as before. If there is action attr, we try to get 10829cc9a5cbSTonghao Zhang * actions and save them to *acts. Before returning from 10839cc9a5cbSTonghao Zhang * the function, we reset the match->mask pointer. Because 10849cc9a5cbSTonghao Zhang * we should not to return match object with dangling reference 10859cc9a5cbSTonghao Zhang * to mask. 10869cc9a5cbSTonghao Zhang * */ 108726063790SArnd Bergmann static noinline_for_stack int 108826063790SArnd Bergmann ovs_nla_init_match_and_action(struct net *net, 10899cc9a5cbSTonghao Zhang struct sw_flow_match *match, 10909cc9a5cbSTonghao Zhang struct sw_flow_key *key, 10919cc9a5cbSTonghao Zhang struct nlattr **a, 10929cc9a5cbSTonghao Zhang struct sw_flow_actions **acts, 10939cc9a5cbSTonghao Zhang bool log) 10949cc9a5cbSTonghao Zhang { 10959cc9a5cbSTonghao Zhang struct sw_flow_mask mask; 10969cc9a5cbSTonghao Zhang int error = 0; 10979cc9a5cbSTonghao Zhang 10989cc9a5cbSTonghao Zhang if (a[OVS_FLOW_ATTR_KEY]) { 10999cc9a5cbSTonghao Zhang ovs_match_init(match, key, true, &mask); 11009cc9a5cbSTonghao Zhang error = ovs_nla_get_match(net, match, a[OVS_FLOW_ATTR_KEY], 11019cc9a5cbSTonghao Zhang a[OVS_FLOW_ATTR_MASK], log); 11029cc9a5cbSTonghao Zhang if (error) 11039cc9a5cbSTonghao Zhang goto error; 11049cc9a5cbSTonghao Zhang } 11059cc9a5cbSTonghao Zhang 11069cc9a5cbSTonghao Zhang if (a[OVS_FLOW_ATTR_ACTIONS]) { 11079cc9a5cbSTonghao Zhang if (!a[OVS_FLOW_ATTR_KEY]) { 11089cc9a5cbSTonghao Zhang OVS_NLERR(log, 11099cc9a5cbSTonghao Zhang "Flow key attribute not present in set flow."); 11105829e62aSChristophe JAILLET error = -EINVAL; 11115829e62aSChristophe JAILLET goto error; 11129cc9a5cbSTonghao Zhang } 11139cc9a5cbSTonghao Zhang 11149cc9a5cbSTonghao Zhang *acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key, 11159cc9a5cbSTonghao Zhang &mask, log); 11169cc9a5cbSTonghao Zhang if (IS_ERR(*acts)) { 11179cc9a5cbSTonghao Zhang error = PTR_ERR(*acts); 11189cc9a5cbSTonghao Zhang goto error; 11199cc9a5cbSTonghao Zhang } 11209cc9a5cbSTonghao Zhang } 11219cc9a5cbSTonghao Zhang 11229cc9a5cbSTonghao Zhang /* On success, error is 0. */ 11239cc9a5cbSTonghao Zhang error: 11249cc9a5cbSTonghao Zhang match->mask = NULL; 11259cc9a5cbSTonghao Zhang return error; 11269cc9a5cbSTonghao Zhang } 11279cc9a5cbSTonghao Zhang 112837bdc87bSJarno Rajahalme static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) 112937bdc87bSJarno Rajahalme { 11307f8a436eSJoe Stringer struct net *net = sock_net(skb->sk); 113137bdc87bSJarno Rajahalme struct nlattr **a = info->attrs; 113237bdc87bSJarno Rajahalme struct ovs_header *ovs_header = info->userhdr; 11336b205b2cSJesse Gross struct sw_flow_key key; 113437bdc87bSJarno Rajahalme struct sw_flow *flow; 113537bdc87bSJarno Rajahalme struct sk_buff *reply = NULL; 113637bdc87bSJarno Rajahalme struct datapath *dp; 1137893f139bSJarno Rajahalme struct sw_flow_actions *old_acts = NULL, *acts = NULL; 113803f0d916SAndy Zhou struct sw_flow_match match; 113974ed7ab9SJoe Stringer struct sw_flow_id sfid; 114074ed7ab9SJoe Stringer u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); 11416f15cdbfSSamuel Gauthier int error = 0; 114205da5898SJarno Rajahalme bool log = !a[OVS_FLOW_ATTR_PROBE]; 114374ed7ab9SJoe Stringer bool ufid_present; 1144ccb1352eSJesse Gross 114574ed7ab9SJoe Stringer ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log); 11469cc9a5cbSTonghao Zhang if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) { 11476f15cdbfSSamuel Gauthier OVS_NLERR(log, 11486f15cdbfSSamuel Gauthier "Flow set message rejected, Key attribute missing."); 11499cc9a5cbSTonghao Zhang return -EINVAL; 11506f15cdbfSSamuel Gauthier } 11519cc9a5cbSTonghao Zhang 11529cc9a5cbSTonghao Zhang error = ovs_nla_init_match_and_action(net, &match, &key, a, 11539cc9a5cbSTonghao Zhang &acts, log); 1154ccb1352eSJesse Gross if (error) 1155ccb1352eSJesse Gross goto error; 1156ccb1352eSJesse Gross 11579cc9a5cbSTonghao Zhang if (acts) { 1158893f139bSJarno Rajahalme /* Can allocate before locking if have acts. */ 115974ed7ab9SJoe Stringer reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false, 116074ed7ab9SJoe Stringer ufid_flags); 1161893f139bSJarno Rajahalme if (IS_ERR(reply)) { 1162893f139bSJarno Rajahalme error = PTR_ERR(reply); 1163893f139bSJarno Rajahalme goto err_kfree_acts; 116403f0d916SAndy Zhou } 1165ccb1352eSJesse Gross } 1166ccb1352eSJesse Gross 11678e4e1713SPravin B Shelar ovs_lock(); 11687f8a436eSJoe Stringer dp = get_dp(net, ovs_header->dp_ifindex); 1169893f139bSJarno Rajahalme if (unlikely(!dp)) { 1170ccb1352eSJesse Gross error = -ENODEV; 11718e4e1713SPravin B Shelar goto err_unlock_ovs; 1172893f139bSJarno Rajahalme } 117337bdc87bSJarno Rajahalme /* Check that the flow exists. */ 117474ed7ab9SJoe Stringer if (ufid_present) 117574ed7ab9SJoe Stringer flow = ovs_flow_tbl_lookup_ufid(&dp->table, &sfid); 117674ed7ab9SJoe Stringer else 11774a46b24eSAlex Wang flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); 1178893f139bSJarno Rajahalme if (unlikely(!flow)) { 1179ccb1352eSJesse Gross error = -ENOENT; 11808e4e1713SPravin B Shelar goto err_unlock_ovs; 1181893f139bSJarno Rajahalme } 11824a46b24eSAlex Wang 1183be52c9e9SJarno Rajahalme /* Update actions, if present. */ 1184893f139bSJarno Rajahalme if (likely(acts)) { 11858e4e1713SPravin B Shelar old_acts = ovsl_dereference(flow->sf_acts); 118674f84a57SPravin B Shelar rcu_assign_pointer(flow->sf_acts, acts); 11870e9796b4SJarno Rajahalme 1188893f139bSJarno Rajahalme if (unlikely(reply)) { 1189893f139bSJarno Rajahalme error = ovs_flow_cmd_fill_info(flow, 1190893f139bSJarno Rajahalme ovs_header->dp_ifindex, 1191893f139bSJarno Rajahalme reply, info->snd_portid, 1192893f139bSJarno Rajahalme info->snd_seq, 0, 1193804fe108SYifeng Sun OVS_FLOW_CMD_SET, 119474ed7ab9SJoe Stringer ufid_flags); 1195893f139bSJarno Rajahalme BUG_ON(error < 0); 1196893f139bSJarno Rajahalme } 1197893f139bSJarno Rajahalme } else { 1198893f139bSJarno Rajahalme /* Could not alloc without acts before locking. */ 11990e9796b4SJarno Rajahalme reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, 1200804fe108SYifeng Sun info, OVS_FLOW_CMD_SET, false, 120174ed7ab9SJoe Stringer ufid_flags); 120274ed7ab9SJoe Stringer 1203b5ffe634SViresh Kumar if (IS_ERR(reply)) { 1204893f139bSJarno Rajahalme error = PTR_ERR(reply); 1205893f139bSJarno Rajahalme goto err_unlock_ovs; 1206893f139bSJarno Rajahalme } 1207893f139bSJarno Rajahalme } 1208893f139bSJarno Rajahalme 1209ccb1352eSJesse Gross /* Clear stats. */ 1210e298e505SPravin B Shelar if (a[OVS_FLOW_ATTR_CLEAR]) 1211e298e505SPravin B Shelar ovs_flow_stats_clear(flow); 12128e4e1713SPravin B Shelar ovs_unlock(); 1213ccb1352eSJesse Gross 1214893f139bSJarno Rajahalme if (reply) 12152a94fe48SJohannes Berg ovs_notify(&dp_flow_genl_family, reply, info); 1216893f139bSJarno Rajahalme if (old_acts) 121734ae932aSThomas Graf ovs_nla_free_flow_actions_rcu(old_acts); 1218fb5d1e9eSJarno Rajahalme 1219ccb1352eSJesse Gross return 0; 1220ccb1352eSJesse Gross 12218e4e1713SPravin B Shelar err_unlock_ovs: 12228e4e1713SPravin B Shelar ovs_unlock(); 1223893f139bSJarno Rajahalme kfree_skb(reply); 1224893f139bSJarno Rajahalme err_kfree_acts: 122534ae932aSThomas Graf ovs_nla_free_flow_actions(acts); 1226ccb1352eSJesse Gross error: 1227ccb1352eSJesse Gross return error; 1228ccb1352eSJesse Gross } 1229ccb1352eSJesse Gross 1230ccb1352eSJesse Gross static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) 1231ccb1352eSJesse Gross { 1232ccb1352eSJesse Gross struct nlattr **a = info->attrs; 1233ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 1234c2ac6673SJoe Stringer struct net *net = sock_net(skb->sk); 1235ccb1352eSJesse Gross struct sw_flow_key key; 1236ccb1352eSJesse Gross struct sk_buff *reply; 1237ccb1352eSJesse Gross struct sw_flow *flow; 1238ccb1352eSJesse Gross struct datapath *dp; 123903f0d916SAndy Zhou struct sw_flow_match match; 124074ed7ab9SJoe Stringer struct sw_flow_id ufid; 124174ed7ab9SJoe Stringer u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); 124274ed7ab9SJoe Stringer int err = 0; 124305da5898SJarno Rajahalme bool log = !a[OVS_FLOW_ATTR_PROBE]; 124474ed7ab9SJoe Stringer bool ufid_present; 1245ccb1352eSJesse Gross 124674ed7ab9SJoe Stringer ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); 124774ed7ab9SJoe Stringer if (a[OVS_FLOW_ATTR_KEY]) { 12482279994dSpravin shelar ovs_match_init(&match, &key, true, NULL); 1249c2ac6673SJoe Stringer err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL, 125074ed7ab9SJoe Stringer log); 125174ed7ab9SJoe Stringer } else if (!ufid_present) { 125205da5898SJarno Rajahalme OVS_NLERR(log, 125305da5898SJarno Rajahalme "Flow get message rejected, Key attribute missing."); 125474ed7ab9SJoe Stringer err = -EINVAL; 125503f0d916SAndy Zhou } 1256ccb1352eSJesse Gross if (err) 1257ccb1352eSJesse Gross return err; 1258ccb1352eSJesse Gross 12598e4e1713SPravin B Shelar ovs_lock(); 126046df7b81SPravin B Shelar dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 12618e4e1713SPravin B Shelar if (!dp) { 12628e4e1713SPravin B Shelar err = -ENODEV; 12638e4e1713SPravin B Shelar goto unlock; 12648e4e1713SPravin B Shelar } 1265ccb1352eSJesse Gross 126674ed7ab9SJoe Stringer if (ufid_present) 126774ed7ab9SJoe Stringer flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid); 126874ed7ab9SJoe Stringer else 12694a46b24eSAlex Wang flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); 12704a46b24eSAlex Wang if (!flow) { 12718e4e1713SPravin B Shelar err = -ENOENT; 12728e4e1713SPravin B Shelar goto unlock; 12738e4e1713SPravin B Shelar } 1274ccb1352eSJesse Gross 12750e9796b4SJarno Rajahalme reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info, 1276804fe108SYifeng Sun OVS_FLOW_CMD_GET, true, ufid_flags); 12778e4e1713SPravin B Shelar if (IS_ERR(reply)) { 12788e4e1713SPravin B Shelar err = PTR_ERR(reply); 12798e4e1713SPravin B Shelar goto unlock; 12808e4e1713SPravin B Shelar } 1281ccb1352eSJesse Gross 12828e4e1713SPravin B Shelar ovs_unlock(); 1283ccb1352eSJesse Gross return genlmsg_reply(reply, info); 12848e4e1713SPravin B Shelar unlock: 12858e4e1713SPravin B Shelar ovs_unlock(); 12868e4e1713SPravin B Shelar return err; 1287ccb1352eSJesse Gross } 1288ccb1352eSJesse Gross 1289ccb1352eSJesse Gross static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) 1290ccb1352eSJesse Gross { 1291ccb1352eSJesse Gross struct nlattr **a = info->attrs; 1292ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 1293c2ac6673SJoe Stringer struct net *net = sock_net(skb->sk); 1294ccb1352eSJesse Gross struct sw_flow_key key; 1295ccb1352eSJesse Gross struct sk_buff *reply; 129674ed7ab9SJoe Stringer struct sw_flow *flow = NULL; 1297ccb1352eSJesse Gross struct datapath *dp; 129803f0d916SAndy Zhou struct sw_flow_match match; 129974ed7ab9SJoe Stringer struct sw_flow_id ufid; 130074ed7ab9SJoe Stringer u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); 1301ccb1352eSJesse Gross int err; 130205da5898SJarno Rajahalme bool log = !a[OVS_FLOW_ATTR_PROBE]; 130374ed7ab9SJoe Stringer bool ufid_present; 1304ccb1352eSJesse Gross 130574ed7ab9SJoe Stringer ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); 130674ed7ab9SJoe Stringer if (a[OVS_FLOW_ATTR_KEY]) { 13072279994dSpravin shelar ovs_match_init(&match, &key, true, NULL); 1308c2ac6673SJoe Stringer err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], 1309c2ac6673SJoe Stringer NULL, log); 1310aed06778SJarno Rajahalme if (unlikely(err)) 1311aed06778SJarno Rajahalme return err; 1312aed06778SJarno Rajahalme } 1313aed06778SJarno Rajahalme 13148e4e1713SPravin B Shelar ovs_lock(); 131546df7b81SPravin B Shelar dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 1316aed06778SJarno Rajahalme if (unlikely(!dp)) { 13178e4e1713SPravin B Shelar err = -ENODEV; 13188e4e1713SPravin B Shelar goto unlock; 13198e4e1713SPravin B Shelar } 132046df7b81SPravin B Shelar 132174ed7ab9SJoe Stringer if (unlikely(!a[OVS_FLOW_ATTR_KEY] && !ufid_present)) { 1322b637e498SPravin B Shelar err = ovs_flow_tbl_flush(&dp->table); 13238e4e1713SPravin B Shelar goto unlock; 13248e4e1713SPravin B Shelar } 132503f0d916SAndy Zhou 132674ed7ab9SJoe Stringer if (ufid_present) 132774ed7ab9SJoe Stringer flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid); 132874ed7ab9SJoe Stringer else 13294a46b24eSAlex Wang flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); 13304a46b24eSAlex Wang if (unlikely(!flow)) { 13318e4e1713SPravin B Shelar err = -ENOENT; 13328e4e1713SPravin B Shelar goto unlock; 13338e4e1713SPravin B Shelar } 1334ccb1352eSJesse Gross 1335b637e498SPravin B Shelar ovs_flow_tbl_remove(&dp->table, flow); 1336aed06778SJarno Rajahalme ovs_unlock(); 1337ccb1352eSJesse Gross 1338aed06778SJarno Rajahalme reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts, 133974ed7ab9SJoe Stringer &flow->id, info, false, ufid_flags); 1340aed06778SJarno Rajahalme if (likely(reply)) { 1341b90f5aa4SEnrico Weigelt if (!IS_ERR(reply)) { 1342aed06778SJarno Rajahalme rcu_read_lock(); /*To keep RCU checker happy. */ 13430e9796b4SJarno Rajahalme err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, 13440e9796b4SJarno Rajahalme reply, info->snd_portid, 1345fb5d1e9eSJarno Rajahalme info->snd_seq, 0, 134674ed7ab9SJoe Stringer OVS_FLOW_CMD_DEL, 134774ed7ab9SJoe Stringer ufid_flags); 1348aed06778SJarno Rajahalme rcu_read_unlock(); 1349ccb1352eSJesse Gross BUG_ON(err < 0); 1350ccb1352eSJesse Gross 13512a94fe48SJohannes Berg ovs_notify(&dp_flow_genl_family, reply, info); 1352aed06778SJarno Rajahalme } else { 1353aed06778SJarno Rajahalme netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0, PTR_ERR(reply)); 1354aed06778SJarno Rajahalme } 1355aed06778SJarno Rajahalme } 1356aed06778SJarno Rajahalme 1357aed06778SJarno Rajahalme ovs_flow_free(flow, true); 1358ccb1352eSJesse Gross return 0; 13598e4e1713SPravin B Shelar unlock: 13608e4e1713SPravin B Shelar ovs_unlock(); 13618e4e1713SPravin B Shelar return err; 1362ccb1352eSJesse Gross } 1363ccb1352eSJesse Gross 1364ccb1352eSJesse Gross static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) 1365ccb1352eSJesse Gross { 136674ed7ab9SJoe Stringer struct nlattr *a[__OVS_FLOW_ATTR_MAX]; 1367ccb1352eSJesse Gross struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); 1368b637e498SPravin B Shelar struct table_instance *ti; 1369ccb1352eSJesse Gross struct datapath *dp; 137074ed7ab9SJoe Stringer u32 ufid_flags; 137174ed7ab9SJoe Stringer int err; 137274ed7ab9SJoe Stringer 13738cb08174SJohannes Berg err = genlmsg_parse_deprecated(cb->nlh, &dp_flow_genl_family, a, 1374fceb6435SJohannes Berg OVS_FLOW_ATTR_MAX, flow_policy, NULL); 137574ed7ab9SJoe Stringer if (err) 137674ed7ab9SJoe Stringer return err; 137774ed7ab9SJoe Stringer ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); 1378ccb1352eSJesse Gross 1379d57170b1SPravin B Shelar rcu_read_lock(); 1380cc3a5ae6SAndy Zhou dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex); 13818e4e1713SPravin B Shelar if (!dp) { 1382d57170b1SPravin B Shelar rcu_read_unlock(); 1383ccb1352eSJesse Gross return -ENODEV; 13848e4e1713SPravin B Shelar } 1385ccb1352eSJesse Gross 1386b637e498SPravin B Shelar ti = rcu_dereference(dp->table.ti); 1387ccb1352eSJesse Gross for (;;) { 1388ccb1352eSJesse Gross struct sw_flow *flow; 1389ccb1352eSJesse Gross u32 bucket, obj; 1390ccb1352eSJesse Gross 1391ccb1352eSJesse Gross bucket = cb->args[0]; 1392ccb1352eSJesse Gross obj = cb->args[1]; 1393b637e498SPravin B Shelar flow = ovs_flow_tbl_dump_next(ti, &bucket, &obj); 1394ccb1352eSJesse Gross if (!flow) 1395ccb1352eSJesse Gross break; 1396ccb1352eSJesse Gross 13970e9796b4SJarno Rajahalme if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb, 139815e47304SEric W. Biederman NETLINK_CB(cb->skb).portid, 1399ccb1352eSJesse Gross cb->nlh->nlmsg_seq, NLM_F_MULTI, 1400804fe108SYifeng Sun OVS_FLOW_CMD_GET, ufid_flags) < 0) 1401ccb1352eSJesse Gross break; 1402ccb1352eSJesse Gross 1403ccb1352eSJesse Gross cb->args[0] = bucket; 1404ccb1352eSJesse Gross cb->args[1] = obj; 1405ccb1352eSJesse Gross } 1406d57170b1SPravin B Shelar rcu_read_unlock(); 1407ccb1352eSJesse Gross return skb->len; 1408ccb1352eSJesse Gross } 1409ccb1352eSJesse Gross 14100c200ef9SPravin B Shelar static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { 14110c200ef9SPravin B Shelar [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED }, 141205da5898SJarno Rajahalme [OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED }, 14130c200ef9SPravin B Shelar [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, 14140c200ef9SPravin B Shelar [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, 141505da5898SJarno Rajahalme [OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG }, 141674ed7ab9SJoe Stringer [OVS_FLOW_ATTR_UFID] = { .type = NLA_UNSPEC, .len = 1 }, 141774ed7ab9SJoe Stringer [OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 }, 14180c200ef9SPravin B Shelar }; 14190c200ef9SPravin B Shelar 142048e48a70Sstephen hemminger static const struct genl_ops dp_flow_genl_ops[] = { 1421ccb1352eSJesse Gross { .cmd = OVS_FLOW_CMD_NEW, 1422ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 14234a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 142437bdc87bSJarno Rajahalme .doit = ovs_flow_cmd_new 1425ccb1352eSJesse Gross }, 1426ccb1352eSJesse Gross { .cmd = OVS_FLOW_CMD_DEL, 1427ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 14284a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 1429ccb1352eSJesse Gross .doit = ovs_flow_cmd_del 1430ccb1352eSJesse Gross }, 1431ccb1352eSJesse Gross { .cmd = OVS_FLOW_CMD_GET, 1432ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 1433ccb1352eSJesse Gross .flags = 0, /* OK for unprivileged users. */ 1434ccb1352eSJesse Gross .doit = ovs_flow_cmd_get, 1435ccb1352eSJesse Gross .dumpit = ovs_flow_cmd_dump 1436ccb1352eSJesse Gross }, 1437ccb1352eSJesse Gross { .cmd = OVS_FLOW_CMD_SET, 1438ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 14394a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 144037bdc87bSJarno Rajahalme .doit = ovs_flow_cmd_set, 1441ccb1352eSJesse Gross }, 1442ccb1352eSJesse Gross }; 1443ccb1352eSJesse Gross 144456989f6dSJohannes Berg static struct genl_family dp_flow_genl_family __ro_after_init = { 1445ccb1352eSJesse Gross .hdrsize = sizeof(struct ovs_header), 14460c200ef9SPravin B Shelar .name = OVS_FLOW_FAMILY, 14470c200ef9SPravin B Shelar .version = OVS_FLOW_VERSION, 14480c200ef9SPravin B Shelar .maxattr = OVS_FLOW_ATTR_MAX, 14493b0f31f2SJohannes Berg .policy = flow_policy, 14503a4e0d6aSPravin B Shelar .netnsok = true, 14513a4e0d6aSPravin B Shelar .parallel_ops = true, 14520c200ef9SPravin B Shelar .ops = dp_flow_genl_ops, 14530c200ef9SPravin B Shelar .n_ops = ARRAY_SIZE(dp_flow_genl_ops), 14540c200ef9SPravin B Shelar .mcgrps = &ovs_dp_flow_multicast_group, 14550c200ef9SPravin B Shelar .n_mcgrps = 1, 1456489111e5SJohannes Berg .module = THIS_MODULE, 1457ccb1352eSJesse Gross }; 1458ccb1352eSJesse Gross 1459c3ff8cfeSThomas Graf static size_t ovs_dp_cmd_msg_size(void) 1460c3ff8cfeSThomas Graf { 1461c3ff8cfeSThomas Graf size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); 1462c3ff8cfeSThomas Graf 1463c3ff8cfeSThomas Graf msgsize += nla_total_size(IFNAMSIZ); 146466c7a5eeSNicolas Dichtel msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats)); 146566c7a5eeSNicolas Dichtel msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats)); 146645fb9c35SDaniele Di Proietto msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */ 1467c3ff8cfeSThomas Graf 1468c3ff8cfeSThomas Graf return msgsize; 1469c3ff8cfeSThomas Graf } 1470c3ff8cfeSThomas Graf 14718ec609d8SPravin B Shelar /* Called with ovs_mutex. */ 1472ccb1352eSJesse Gross static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, 147315e47304SEric W. Biederman u32 portid, u32 seq, u32 flags, u8 cmd) 1474ccb1352eSJesse Gross { 1475ccb1352eSJesse Gross struct ovs_header *ovs_header; 1476ccb1352eSJesse Gross struct ovs_dp_stats dp_stats; 14771bd7116fSAndy Zhou struct ovs_dp_megaflow_stats dp_megaflow_stats; 1478ccb1352eSJesse Gross int err; 1479ccb1352eSJesse Gross 148015e47304SEric W. Biederman ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family, 1481ccb1352eSJesse Gross flags, cmd); 1482ccb1352eSJesse Gross if (!ovs_header) 1483ccb1352eSJesse Gross goto error; 1484ccb1352eSJesse Gross 1485ccb1352eSJesse Gross ovs_header->dp_ifindex = get_dpifindex(dp); 1486ccb1352eSJesse Gross 1487ccb1352eSJesse Gross err = nla_put_string(skb, OVS_DP_ATTR_NAME, ovs_dp_name(dp)); 1488ccb1352eSJesse Gross if (err) 1489ccb1352eSJesse Gross goto nla_put_failure; 1490ccb1352eSJesse Gross 14911bd7116fSAndy Zhou get_dp_stats(dp, &dp_stats, &dp_megaflow_stats); 149266c7a5eeSNicolas Dichtel if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), 149366c7a5eeSNicolas Dichtel &dp_stats, OVS_DP_ATTR_PAD)) 14941bd7116fSAndy Zhou goto nla_put_failure; 14951bd7116fSAndy Zhou 149666c7a5eeSNicolas Dichtel if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS, 14971bd7116fSAndy Zhou sizeof(struct ovs_dp_megaflow_stats), 149866c7a5eeSNicolas Dichtel &dp_megaflow_stats, OVS_DP_ATTR_PAD)) 1499028d6a67SDavid S. Miller goto nla_put_failure; 1500ccb1352eSJesse Gross 150143d4be9cSThomas Graf if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features)) 150243d4be9cSThomas Graf goto nla_put_failure; 150343d4be9cSThomas Graf 1504053c095aSJohannes Berg genlmsg_end(skb, ovs_header); 1505053c095aSJohannes Berg return 0; 1506ccb1352eSJesse Gross 1507ccb1352eSJesse Gross nla_put_failure: 1508ccb1352eSJesse Gross genlmsg_cancel(skb, ovs_header); 1509ccb1352eSJesse Gross error: 1510ccb1352eSJesse Gross return -EMSGSIZE; 1511ccb1352eSJesse Gross } 1512ccb1352eSJesse Gross 1513263ea090SFlorian Westphal static struct sk_buff *ovs_dp_cmd_alloc_info(void) 1514ccb1352eSJesse Gross { 1515551ddc05SFlorian Westphal return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL); 1516ccb1352eSJesse Gross } 1517ccb1352eSJesse Gross 1518bb6f9a70SJarno Rajahalme /* Called with rcu_read_lock or ovs_mutex. */ 151946df7b81SPravin B Shelar static struct datapath *lookup_datapath(struct net *net, 152012eb18f7SThomas Graf const struct ovs_header *ovs_header, 1521ccb1352eSJesse Gross struct nlattr *a[OVS_DP_ATTR_MAX + 1]) 1522ccb1352eSJesse Gross { 1523ccb1352eSJesse Gross struct datapath *dp; 1524ccb1352eSJesse Gross 1525ccb1352eSJesse Gross if (!a[OVS_DP_ATTR_NAME]) 152646df7b81SPravin B Shelar dp = get_dp(net, ovs_header->dp_ifindex); 1527ccb1352eSJesse Gross else { 1528ccb1352eSJesse Gross struct vport *vport; 1529ccb1352eSJesse Gross 153046df7b81SPravin B Shelar vport = ovs_vport_locate(net, nla_data(a[OVS_DP_ATTR_NAME])); 1531ccb1352eSJesse Gross dp = vport && vport->port_no == OVSP_LOCAL ? vport->dp : NULL; 1532ccb1352eSJesse Gross } 1533ccb1352eSJesse Gross return dp ? dp : ERR_PTR(-ENODEV); 1534ccb1352eSJesse Gross } 1535ccb1352eSJesse Gross 153644da5ae5SThomas Graf static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *info) 153744da5ae5SThomas Graf { 153844da5ae5SThomas Graf struct datapath *dp; 153944da5ae5SThomas Graf 154044da5ae5SThomas Graf dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 15413c7eacfcSJiri Pirko if (IS_ERR(dp)) 154244da5ae5SThomas Graf return; 154344da5ae5SThomas Graf 154444da5ae5SThomas Graf WARN(dp->user_features, "Dropping previously announced user features\n"); 154544da5ae5SThomas Graf dp->user_features = 0; 154644da5ae5SThomas Graf } 154744da5ae5SThomas Graf 154895a7233cSPaul Blakey DEFINE_STATIC_KEY_FALSE(tc_recirc_sharing_support); 154995a7233cSPaul Blakey 155095a7233cSPaul Blakey static int ovs_dp_change(struct datapath *dp, struct nlattr *a[]) 155143d4be9cSThomas Graf { 155295a7233cSPaul Blakey u32 user_features = 0; 155395a7233cSPaul Blakey 155495a7233cSPaul Blakey if (a[OVS_DP_ATTR_USER_FEATURES]) { 155595a7233cSPaul Blakey user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]); 155695a7233cSPaul Blakey 155795a7233cSPaul Blakey if (user_features & ~(OVS_DP_F_VPORT_PIDS | 155895a7233cSPaul Blakey OVS_DP_F_UNALIGNED | 155995a7233cSPaul Blakey OVS_DP_F_TC_RECIRC_SHARING)) 156095a7233cSPaul Blakey return -EOPNOTSUPP; 156195a7233cSPaul Blakey 156295a7233cSPaul Blakey #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT) 156395a7233cSPaul Blakey if (user_features & OVS_DP_F_TC_RECIRC_SHARING) 156495a7233cSPaul Blakey return -EOPNOTSUPP; 156595a7233cSPaul Blakey #endif 156695a7233cSPaul Blakey } 156795a7233cSPaul Blakey 156895a7233cSPaul Blakey dp->user_features = user_features; 156995a7233cSPaul Blakey 157095a7233cSPaul Blakey if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) 157195a7233cSPaul Blakey static_branch_enable(&tc_recirc_sharing_support); 157295a7233cSPaul Blakey else 157395a7233cSPaul Blakey static_branch_disable(&tc_recirc_sharing_support); 157495a7233cSPaul Blakey 157595a7233cSPaul Blakey return 0; 157643d4be9cSThomas Graf } 157743d4be9cSThomas Graf 1578ccb1352eSJesse Gross static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) 1579ccb1352eSJesse Gross { 1580ccb1352eSJesse Gross struct nlattr **a = info->attrs; 1581ccb1352eSJesse Gross struct vport_parms parms; 1582ccb1352eSJesse Gross struct sk_buff *reply; 1583ccb1352eSJesse Gross struct datapath *dp; 1584ccb1352eSJesse Gross struct vport *vport; 158546df7b81SPravin B Shelar struct ovs_net *ovs_net; 158615eac2a7SPravin B Shelar int err, i; 1587ccb1352eSJesse Gross 1588ccb1352eSJesse Gross err = -EINVAL; 1589ccb1352eSJesse Gross if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID]) 1590ccb1352eSJesse Gross goto err; 1591ccb1352eSJesse Gross 1592263ea090SFlorian Westphal reply = ovs_dp_cmd_alloc_info(); 15936093ae9aSJarno Rajahalme if (!reply) 15946093ae9aSJarno Rajahalme return -ENOMEM; 1595ccb1352eSJesse Gross 1596ccb1352eSJesse Gross err = -ENOMEM; 1597ccb1352eSJesse Gross dp = kzalloc(sizeof(*dp), GFP_KERNEL); 1598ccb1352eSJesse Gross if (dp == NULL) 15996093ae9aSJarno Rajahalme goto err_free_reply; 160046df7b81SPravin B Shelar 1601efd7ef1cSEric W. Biederman ovs_dp_set_net(dp, sock_net(skb->sk)); 1602ccb1352eSJesse Gross 1603ccb1352eSJesse Gross /* Allocate table. */ 1604b637e498SPravin B Shelar err = ovs_flow_tbl_init(&dp->table); 1605b637e498SPravin B Shelar if (err) 1606ccb1352eSJesse Gross goto err_free_dp; 1607ccb1352eSJesse Gross 16081c213bd2SWANG Cong dp->stats_percpu = netdev_alloc_pcpu_stats(struct dp_stats_percpu); 1609ccb1352eSJesse Gross if (!dp->stats_percpu) { 1610ccb1352eSJesse Gross err = -ENOMEM; 1611ccb1352eSJesse Gross goto err_destroy_table; 1612ccb1352eSJesse Gross } 1613ccb1352eSJesse Gross 16146da2ec56SKees Cook dp->ports = kmalloc_array(DP_VPORT_HASH_BUCKETS, 16156da2ec56SKees Cook sizeof(struct hlist_head), 161615eac2a7SPravin B Shelar GFP_KERNEL); 161715eac2a7SPravin B Shelar if (!dp->ports) { 161815eac2a7SPravin B Shelar err = -ENOMEM; 161915eac2a7SPravin B Shelar goto err_destroy_percpu; 162015eac2a7SPravin B Shelar } 162115eac2a7SPravin B Shelar 162215eac2a7SPravin B Shelar for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) 162315eac2a7SPravin B Shelar INIT_HLIST_HEAD(&dp->ports[i]); 162415eac2a7SPravin B Shelar 162596fbc13dSAndy Zhou err = ovs_meters_init(dp); 162696fbc13dSAndy Zhou if (err) 162796fbc13dSAndy Zhou goto err_destroy_ports_array; 162896fbc13dSAndy Zhou 1629ccb1352eSJesse Gross /* Set up our datapath device. */ 1630ccb1352eSJesse Gross parms.name = nla_data(a[OVS_DP_ATTR_NAME]); 1631ccb1352eSJesse Gross parms.type = OVS_VPORT_TYPE_INTERNAL; 1632ccb1352eSJesse Gross parms.options = NULL; 1633ccb1352eSJesse Gross parms.dp = dp; 1634ccb1352eSJesse Gross parms.port_no = OVSP_LOCAL; 16355cd667b0SAlex Wang parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID]; 1636ccb1352eSJesse Gross 163795a7233cSPaul Blakey err = ovs_dp_change(dp, a); 163895a7233cSPaul Blakey if (err) 163995a7233cSPaul Blakey goto err_destroy_meters; 164043d4be9cSThomas Graf 16416093ae9aSJarno Rajahalme /* So far only local changes have been made, now need the lock. */ 16426093ae9aSJarno Rajahalme ovs_lock(); 16436093ae9aSJarno Rajahalme 1644ccb1352eSJesse Gross vport = new_vport(&parms); 1645ccb1352eSJesse Gross if (IS_ERR(vport)) { 1646ccb1352eSJesse Gross err = PTR_ERR(vport); 1647ccb1352eSJesse Gross if (err == -EBUSY) 1648ccb1352eSJesse Gross err = -EEXIST; 1649ccb1352eSJesse Gross 165044da5ae5SThomas Graf if (err == -EEXIST) { 165144da5ae5SThomas Graf /* An outdated user space instance that does not understand 165244da5ae5SThomas Graf * the concept of user_features has attempted to create a new 165344da5ae5SThomas Graf * datapath and is likely to reuse it. Drop all user features. 165444da5ae5SThomas Graf */ 165544da5ae5SThomas Graf if (info->genlhdr->version < OVS_DP_VER_FEATURES) 165644da5ae5SThomas Graf ovs_dp_reset_user_features(skb, info); 165744da5ae5SThomas Graf } 165844da5ae5SThomas Graf 165996fbc13dSAndy Zhou goto err_destroy_meters; 1660ccb1352eSJesse Gross } 1661ccb1352eSJesse Gross 16626093ae9aSJarno Rajahalme err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, 16636093ae9aSJarno Rajahalme info->snd_seq, 0, OVS_DP_CMD_NEW); 16646093ae9aSJarno Rajahalme BUG_ON(err < 0); 1665ccb1352eSJesse Gross 166646df7b81SPravin B Shelar ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id); 166759a35d60SPravin B Shelar list_add_tail_rcu(&dp->list_node, &ovs_net->dps); 16688e4e1713SPravin B Shelar 16698e4e1713SPravin B Shelar ovs_unlock(); 1670ccb1352eSJesse Gross 16712a94fe48SJohannes Berg ovs_notify(&dp_datapath_genl_family, reply, info); 1672ccb1352eSJesse Gross return 0; 1673ccb1352eSJesse Gross 167496fbc13dSAndy Zhou err_destroy_meters: 16756093ae9aSJarno Rajahalme ovs_unlock(); 167696fbc13dSAndy Zhou ovs_meters_exit(dp); 167796fbc13dSAndy Zhou err_destroy_ports_array: 167815eac2a7SPravin B Shelar kfree(dp->ports); 1679ccb1352eSJesse Gross err_destroy_percpu: 1680ccb1352eSJesse Gross free_percpu(dp->stats_percpu); 1681ccb1352eSJesse Gross err_destroy_table: 16829b996e54SPravin B Shelar ovs_flow_tbl_destroy(&dp->table); 1683ccb1352eSJesse Gross err_free_dp: 1684ccb1352eSJesse Gross kfree(dp); 16856093ae9aSJarno Rajahalme err_free_reply: 16866093ae9aSJarno Rajahalme kfree_skb(reply); 1687ccb1352eSJesse Gross err: 1688ccb1352eSJesse Gross return err; 1689ccb1352eSJesse Gross } 1690ccb1352eSJesse Gross 16918e4e1713SPravin B Shelar /* Called with ovs_mutex. */ 169246df7b81SPravin B Shelar static void __dp_destroy(struct datapath *dp) 1693ccb1352eSJesse Gross { 169415eac2a7SPravin B Shelar int i; 1695ccb1352eSJesse Gross 169615eac2a7SPravin B Shelar for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { 169715eac2a7SPravin B Shelar struct vport *vport; 1698b67bfe0dSSasha Levin struct hlist_node *n; 169915eac2a7SPravin B Shelar 1700b67bfe0dSSasha Levin hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) 1701ccb1352eSJesse Gross if (vport->port_no != OVSP_LOCAL) 1702ccb1352eSJesse Gross ovs_dp_detach_port(vport); 170315eac2a7SPravin B Shelar } 1704ccb1352eSJesse Gross 170559a35d60SPravin B Shelar list_del_rcu(&dp->list_node); 1706ccb1352eSJesse Gross 17078e4e1713SPravin B Shelar /* OVSP_LOCAL is datapath internal port. We need to make sure that 1708e80857ccSAndy Zhou * all ports in datapath are destroyed first before freeing datapath. 1709ccb1352eSJesse Gross */ 17108e4e1713SPravin B Shelar ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL)); 1711ccb1352eSJesse Gross 1712e80857ccSAndy Zhou /* RCU destroy the flow table */ 1713ccb1352eSJesse Gross call_rcu(&dp->rcu, destroy_dp_rcu); 171446df7b81SPravin B Shelar } 171546df7b81SPravin B Shelar 171646df7b81SPravin B Shelar static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) 171746df7b81SPravin B Shelar { 171846df7b81SPravin B Shelar struct sk_buff *reply; 171946df7b81SPravin B Shelar struct datapath *dp; 172046df7b81SPravin B Shelar int err; 172146df7b81SPravin B Shelar 1722263ea090SFlorian Westphal reply = ovs_dp_cmd_alloc_info(); 17236093ae9aSJarno Rajahalme if (!reply) 17246093ae9aSJarno Rajahalme return -ENOMEM; 17256093ae9aSJarno Rajahalme 17268e4e1713SPravin B Shelar ovs_lock(); 172746df7b81SPravin B Shelar dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 172846df7b81SPravin B Shelar err = PTR_ERR(dp); 172946df7b81SPravin B Shelar if (IS_ERR(dp)) 17306093ae9aSJarno Rajahalme goto err_unlock_free; 173146df7b81SPravin B Shelar 17326093ae9aSJarno Rajahalme err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, 17336093ae9aSJarno Rajahalme info->snd_seq, 0, OVS_DP_CMD_DEL); 17346093ae9aSJarno Rajahalme BUG_ON(err < 0); 173546df7b81SPravin B Shelar 173646df7b81SPravin B Shelar __dp_destroy(dp); 17378e4e1713SPravin B Shelar ovs_unlock(); 1738ccb1352eSJesse Gross 17392a94fe48SJohannes Berg ovs_notify(&dp_datapath_genl_family, reply, info); 1740ccb1352eSJesse Gross 1741ccb1352eSJesse Gross return 0; 17426093ae9aSJarno Rajahalme 17436093ae9aSJarno Rajahalme err_unlock_free: 17448e4e1713SPravin B Shelar ovs_unlock(); 17456093ae9aSJarno Rajahalme kfree_skb(reply); 17468e4e1713SPravin B Shelar return err; 1747ccb1352eSJesse Gross } 1748ccb1352eSJesse Gross 1749ccb1352eSJesse Gross static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) 1750ccb1352eSJesse Gross { 1751ccb1352eSJesse Gross struct sk_buff *reply; 1752ccb1352eSJesse Gross struct datapath *dp; 1753ccb1352eSJesse Gross int err; 1754ccb1352eSJesse Gross 1755263ea090SFlorian Westphal reply = ovs_dp_cmd_alloc_info(); 17566093ae9aSJarno Rajahalme if (!reply) 17576093ae9aSJarno Rajahalme return -ENOMEM; 17586093ae9aSJarno Rajahalme 17598e4e1713SPravin B Shelar ovs_lock(); 176046df7b81SPravin B Shelar dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 17618e4e1713SPravin B Shelar err = PTR_ERR(dp); 1762ccb1352eSJesse Gross if (IS_ERR(dp)) 17636093ae9aSJarno Rajahalme goto err_unlock_free; 1764ccb1352eSJesse Gross 176595a7233cSPaul Blakey err = ovs_dp_change(dp, info->attrs); 176695a7233cSPaul Blakey if (err) 176795a7233cSPaul Blakey goto err_unlock_free; 176843d4be9cSThomas Graf 17696093ae9aSJarno Rajahalme err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, 1770804fe108SYifeng Sun info->snd_seq, 0, OVS_DP_CMD_SET); 17716093ae9aSJarno Rajahalme BUG_ON(err < 0); 1772ccb1352eSJesse Gross 17738e4e1713SPravin B Shelar ovs_unlock(); 17742a94fe48SJohannes Berg ovs_notify(&dp_datapath_genl_family, reply, info); 1775ccb1352eSJesse Gross 1776ccb1352eSJesse Gross return 0; 17776093ae9aSJarno Rajahalme 17786093ae9aSJarno Rajahalme err_unlock_free: 17798e4e1713SPravin B Shelar ovs_unlock(); 17806093ae9aSJarno Rajahalme kfree_skb(reply); 17818e4e1713SPravin B Shelar return err; 1782ccb1352eSJesse Gross } 1783ccb1352eSJesse Gross 1784ccb1352eSJesse Gross static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info) 1785ccb1352eSJesse Gross { 1786ccb1352eSJesse Gross struct sk_buff *reply; 1787ccb1352eSJesse Gross struct datapath *dp; 17888e4e1713SPravin B Shelar int err; 1789ccb1352eSJesse Gross 1790263ea090SFlorian Westphal reply = ovs_dp_cmd_alloc_info(); 17916093ae9aSJarno Rajahalme if (!reply) 17926093ae9aSJarno Rajahalme return -ENOMEM; 17936093ae9aSJarno Rajahalme 17948ec609d8SPravin B Shelar ovs_lock(); 179546df7b81SPravin B Shelar dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 17968e4e1713SPravin B Shelar if (IS_ERR(dp)) { 17978e4e1713SPravin B Shelar err = PTR_ERR(dp); 17986093ae9aSJarno Rajahalme goto err_unlock_free; 17998e4e1713SPravin B Shelar } 18006093ae9aSJarno Rajahalme err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, 1801804fe108SYifeng Sun info->snd_seq, 0, OVS_DP_CMD_GET); 18026093ae9aSJarno Rajahalme BUG_ON(err < 0); 18038ec609d8SPravin B Shelar ovs_unlock(); 1804ccb1352eSJesse Gross 1805ccb1352eSJesse Gross return genlmsg_reply(reply, info); 18068e4e1713SPravin B Shelar 18076093ae9aSJarno Rajahalme err_unlock_free: 18088ec609d8SPravin B Shelar ovs_unlock(); 18096093ae9aSJarno Rajahalme kfree_skb(reply); 18108e4e1713SPravin B Shelar return err; 1811ccb1352eSJesse Gross } 1812ccb1352eSJesse Gross 1813ccb1352eSJesse Gross static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) 1814ccb1352eSJesse Gross { 181546df7b81SPravin B Shelar struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id); 1816ccb1352eSJesse Gross struct datapath *dp; 1817ccb1352eSJesse Gross int skip = cb->args[0]; 1818ccb1352eSJesse Gross int i = 0; 1819ccb1352eSJesse Gross 18208ec609d8SPravin B Shelar ovs_lock(); 18218ec609d8SPravin B Shelar list_for_each_entry(dp, &ovs_net->dps, list_node) { 182277676fdbSBen Pfaff if (i >= skip && 182315e47304SEric W. Biederman ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid, 1824ccb1352eSJesse Gross cb->nlh->nlmsg_seq, NLM_F_MULTI, 1825804fe108SYifeng Sun OVS_DP_CMD_GET) < 0) 1826ccb1352eSJesse Gross break; 1827ccb1352eSJesse Gross i++; 1828ccb1352eSJesse Gross } 18298ec609d8SPravin B Shelar ovs_unlock(); 1830ccb1352eSJesse Gross 1831ccb1352eSJesse Gross cb->args[0] = i; 1832ccb1352eSJesse Gross 1833ccb1352eSJesse Gross return skb->len; 1834ccb1352eSJesse Gross } 1835ccb1352eSJesse Gross 18360c200ef9SPravin B Shelar static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { 18370c200ef9SPravin B Shelar [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, 18380c200ef9SPravin B Shelar [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, 18390c200ef9SPravin B Shelar [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, 18400c200ef9SPravin B Shelar }; 18410c200ef9SPravin B Shelar 184248e48a70Sstephen hemminger static const struct genl_ops dp_datapath_genl_ops[] = { 1843ccb1352eSJesse Gross { .cmd = OVS_DP_CMD_NEW, 1844ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 18454a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 1846ccb1352eSJesse Gross .doit = ovs_dp_cmd_new 1847ccb1352eSJesse Gross }, 1848ccb1352eSJesse Gross { .cmd = OVS_DP_CMD_DEL, 1849ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 18504a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 1851ccb1352eSJesse Gross .doit = ovs_dp_cmd_del 1852ccb1352eSJesse Gross }, 1853ccb1352eSJesse Gross { .cmd = OVS_DP_CMD_GET, 1854ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 1855ccb1352eSJesse Gross .flags = 0, /* OK for unprivileged users. */ 1856ccb1352eSJesse Gross .doit = ovs_dp_cmd_get, 1857ccb1352eSJesse Gross .dumpit = ovs_dp_cmd_dump 1858ccb1352eSJesse Gross }, 1859ccb1352eSJesse Gross { .cmd = OVS_DP_CMD_SET, 1860ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 18614a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 1862ccb1352eSJesse Gross .doit = ovs_dp_cmd_set, 1863ccb1352eSJesse Gross }, 1864ccb1352eSJesse Gross }; 1865ccb1352eSJesse Gross 186656989f6dSJohannes Berg static struct genl_family dp_datapath_genl_family __ro_after_init = { 1867ccb1352eSJesse Gross .hdrsize = sizeof(struct ovs_header), 18680c200ef9SPravin B Shelar .name = OVS_DATAPATH_FAMILY, 18690c200ef9SPravin B Shelar .version = OVS_DATAPATH_VERSION, 18700c200ef9SPravin B Shelar .maxattr = OVS_DP_ATTR_MAX, 18713b0f31f2SJohannes Berg .policy = datapath_policy, 18723a4e0d6aSPravin B Shelar .netnsok = true, 18733a4e0d6aSPravin B Shelar .parallel_ops = true, 18740c200ef9SPravin B Shelar .ops = dp_datapath_genl_ops, 18750c200ef9SPravin B Shelar .n_ops = ARRAY_SIZE(dp_datapath_genl_ops), 18760c200ef9SPravin B Shelar .mcgrps = &ovs_dp_datapath_multicast_group, 18770c200ef9SPravin B Shelar .n_mcgrps = 1, 1878489111e5SJohannes Berg .module = THIS_MODULE, 1879ccb1352eSJesse Gross }; 1880ccb1352eSJesse Gross 18818e4e1713SPravin B Shelar /* Called with ovs_mutex or RCU read lock. */ 1882ccb1352eSJesse Gross static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, 18839354d452SJiri Benc struct net *net, u32 portid, u32 seq, 18849354d452SJiri Benc u32 flags, u8 cmd) 1885ccb1352eSJesse Gross { 1886ccb1352eSJesse Gross struct ovs_header *ovs_header; 1887ccb1352eSJesse Gross struct ovs_vport_stats vport_stats; 1888ccb1352eSJesse Gross int err; 1889ccb1352eSJesse Gross 189015e47304SEric W. Biederman ovs_header = genlmsg_put(skb, portid, seq, &dp_vport_genl_family, 1891ccb1352eSJesse Gross flags, cmd); 1892ccb1352eSJesse Gross if (!ovs_header) 1893ccb1352eSJesse Gross return -EMSGSIZE; 1894ccb1352eSJesse Gross 1895ccb1352eSJesse Gross ovs_header->dp_ifindex = get_dpifindex(vport->dp); 1896ccb1352eSJesse Gross 1897028d6a67SDavid S. Miller if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || 1898028d6a67SDavid S. Miller nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || 18995cd667b0SAlex Wang nla_put_string(skb, OVS_VPORT_ATTR_NAME, 19009354d452SJiri Benc ovs_vport_name(vport)) || 19019354d452SJiri Benc nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex)) 1902028d6a67SDavid S. Miller goto nla_put_failure; 1903ccb1352eSJesse Gross 19049354d452SJiri Benc if (!net_eq(net, dev_net(vport->dev))) { 19059354d452SJiri Benc int id = peernet2id_alloc(net, dev_net(vport->dev)); 19069354d452SJiri Benc 19079354d452SJiri Benc if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id)) 19089354d452SJiri Benc goto nla_put_failure; 19099354d452SJiri Benc } 19109354d452SJiri Benc 1911ccb1352eSJesse Gross ovs_vport_get_stats(vport, &vport_stats); 191266c7a5eeSNicolas Dichtel if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS, 191366c7a5eeSNicolas Dichtel sizeof(struct ovs_vport_stats), &vport_stats, 191466c7a5eeSNicolas Dichtel OVS_VPORT_ATTR_PAD)) 1915028d6a67SDavid S. Miller goto nla_put_failure; 1916ccb1352eSJesse Gross 19175cd667b0SAlex Wang if (ovs_vport_get_upcall_portids(vport, skb)) 19185cd667b0SAlex Wang goto nla_put_failure; 19195cd667b0SAlex Wang 1920ccb1352eSJesse Gross err = ovs_vport_get_options(vport, skb); 1921ccb1352eSJesse Gross if (err == -EMSGSIZE) 1922ccb1352eSJesse Gross goto error; 1923ccb1352eSJesse Gross 1924053c095aSJohannes Berg genlmsg_end(skb, ovs_header); 1925053c095aSJohannes Berg return 0; 1926ccb1352eSJesse Gross 1927ccb1352eSJesse Gross nla_put_failure: 1928ccb1352eSJesse Gross err = -EMSGSIZE; 1929ccb1352eSJesse Gross error: 1930ccb1352eSJesse Gross genlmsg_cancel(skb, ovs_header); 1931ccb1352eSJesse Gross return err; 1932ccb1352eSJesse Gross } 1933ccb1352eSJesse Gross 19346093ae9aSJarno Rajahalme static struct sk_buff *ovs_vport_cmd_alloc_info(void) 19356093ae9aSJarno Rajahalme { 19366093ae9aSJarno Rajahalme return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 19376093ae9aSJarno Rajahalme } 19386093ae9aSJarno Rajahalme 19396093ae9aSJarno Rajahalme /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ 19409354d452SJiri Benc struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, 19419354d452SJiri Benc u32 portid, u32 seq, u8 cmd) 1942ccb1352eSJesse Gross { 1943ccb1352eSJesse Gross struct sk_buff *skb; 1944ccb1352eSJesse Gross int retval; 1945ccb1352eSJesse Gross 1946ccb1352eSJesse Gross skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1947ccb1352eSJesse Gross if (!skb) 1948ccb1352eSJesse Gross return ERR_PTR(-ENOMEM); 1949ccb1352eSJesse Gross 19509354d452SJiri Benc retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd); 1951a9341512SJesse Gross BUG_ON(retval < 0); 1952a9341512SJesse Gross 1953ccb1352eSJesse Gross return skb; 1954ccb1352eSJesse Gross } 1955ccb1352eSJesse Gross 19568e4e1713SPravin B Shelar /* Called with ovs_mutex or RCU read lock. */ 195746df7b81SPravin B Shelar static struct vport *lookup_vport(struct net *net, 195812eb18f7SThomas Graf const struct ovs_header *ovs_header, 1959ccb1352eSJesse Gross struct nlattr *a[OVS_VPORT_ATTR_MAX + 1]) 1960ccb1352eSJesse Gross { 1961ccb1352eSJesse Gross struct datapath *dp; 1962ccb1352eSJesse Gross struct vport *vport; 1963ccb1352eSJesse Gross 19649354d452SJiri Benc if (a[OVS_VPORT_ATTR_IFINDEX]) 19659354d452SJiri Benc return ERR_PTR(-EOPNOTSUPP); 1966ccb1352eSJesse Gross if (a[OVS_VPORT_ATTR_NAME]) { 196746df7b81SPravin B Shelar vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME])); 1968ccb1352eSJesse Gross if (!vport) 1969ccb1352eSJesse Gross return ERR_PTR(-ENODEV); 1970651a68eaSBen Pfaff if (ovs_header->dp_ifindex && 1971651a68eaSBen Pfaff ovs_header->dp_ifindex != get_dpifindex(vport->dp)) 1972651a68eaSBen Pfaff return ERR_PTR(-ENODEV); 1973ccb1352eSJesse Gross return vport; 1974ccb1352eSJesse Gross } else if (a[OVS_VPORT_ATTR_PORT_NO]) { 1975ccb1352eSJesse Gross u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]); 1976ccb1352eSJesse Gross 1977ccb1352eSJesse Gross if (port_no >= DP_MAX_PORTS) 1978ccb1352eSJesse Gross return ERR_PTR(-EFBIG); 1979ccb1352eSJesse Gross 198046df7b81SPravin B Shelar dp = get_dp(net, ovs_header->dp_ifindex); 1981ccb1352eSJesse Gross if (!dp) 1982ccb1352eSJesse Gross return ERR_PTR(-ENODEV); 1983ccb1352eSJesse Gross 19848e4e1713SPravin B Shelar vport = ovs_vport_ovsl_rcu(dp, port_no); 1985ccb1352eSJesse Gross if (!vport) 198614408dbaSJarno Rajahalme return ERR_PTR(-ENODEV); 1987ccb1352eSJesse Gross return vport; 1988ccb1352eSJesse Gross } else 1989ccb1352eSJesse Gross return ERR_PTR(-EINVAL); 19909354d452SJiri Benc 1991ccb1352eSJesse Gross } 1992ccb1352eSJesse Gross 19936b660c41STaehee Yoo static unsigned int ovs_get_max_headroom(struct datapath *dp) 19943a927bc7SPaolo Abeni { 19956b660c41STaehee Yoo unsigned int dev_headroom, max_headroom = 0; 19963a927bc7SPaolo Abeni struct net_device *dev; 19973a927bc7SPaolo Abeni struct vport *vport; 19983a927bc7SPaolo Abeni int i; 19993a927bc7SPaolo Abeni 20003a927bc7SPaolo Abeni for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { 20013a927bc7SPaolo Abeni hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) { 20023a927bc7SPaolo Abeni dev = vport->dev; 20033a927bc7SPaolo Abeni dev_headroom = netdev_get_fwd_headroom(dev); 20043a927bc7SPaolo Abeni if (dev_headroom > max_headroom) 20053a927bc7SPaolo Abeni max_headroom = dev_headroom; 20063a927bc7SPaolo Abeni } 20073a927bc7SPaolo Abeni } 20083a927bc7SPaolo Abeni 20096b660c41STaehee Yoo return max_headroom; 20106b660c41STaehee Yoo } 20116b660c41STaehee Yoo 20126b660c41STaehee Yoo /* Called with ovs_mutex */ 20136b660c41STaehee Yoo static void ovs_update_headroom(struct datapath *dp, unsigned int new_headroom) 20146b660c41STaehee Yoo { 20156b660c41STaehee Yoo struct vport *vport; 20166b660c41STaehee Yoo int i; 20176b660c41STaehee Yoo 20186b660c41STaehee Yoo dp->max_headroom = new_headroom; 20193a927bc7SPaolo Abeni for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) 20203a927bc7SPaolo Abeni hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) 20216b660c41STaehee Yoo netdev_set_rx_headroom(vport->dev, new_headroom); 20223a927bc7SPaolo Abeni } 20233a927bc7SPaolo Abeni 2024ccb1352eSJesse Gross static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) 2025ccb1352eSJesse Gross { 2026ccb1352eSJesse Gross struct nlattr **a = info->attrs; 2027ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 2028ccb1352eSJesse Gross struct vport_parms parms; 2029ccb1352eSJesse Gross struct sk_buff *reply; 2030ccb1352eSJesse Gross struct vport *vport; 2031ccb1352eSJesse Gross struct datapath *dp; 20326b660c41STaehee Yoo unsigned int new_headroom; 2033ccb1352eSJesse Gross u32 port_no; 2034ccb1352eSJesse Gross int err; 2035ccb1352eSJesse Gross 2036ccb1352eSJesse Gross if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] || 2037ccb1352eSJesse Gross !a[OVS_VPORT_ATTR_UPCALL_PID]) 20386093ae9aSJarno Rajahalme return -EINVAL; 20399354d452SJiri Benc if (a[OVS_VPORT_ATTR_IFINDEX]) 20409354d452SJiri Benc return -EOPNOTSUPP; 20416093ae9aSJarno Rajahalme 20426093ae9aSJarno Rajahalme port_no = a[OVS_VPORT_ATTR_PORT_NO] 20436093ae9aSJarno Rajahalme ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0; 20446093ae9aSJarno Rajahalme if (port_no >= DP_MAX_PORTS) 20456093ae9aSJarno Rajahalme return -EFBIG; 20466093ae9aSJarno Rajahalme 20476093ae9aSJarno Rajahalme reply = ovs_vport_cmd_alloc_info(); 20486093ae9aSJarno Rajahalme if (!reply) 20496093ae9aSJarno Rajahalme return -ENOMEM; 2050ccb1352eSJesse Gross 20518e4e1713SPravin B Shelar ovs_lock(); 205262b9c8d0SThomas Graf restart: 205346df7b81SPravin B Shelar dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 2054ccb1352eSJesse Gross err = -ENODEV; 2055ccb1352eSJesse Gross if (!dp) 20566093ae9aSJarno Rajahalme goto exit_unlock_free; 2057ccb1352eSJesse Gross 20586093ae9aSJarno Rajahalme if (port_no) { 20598e4e1713SPravin B Shelar vport = ovs_vport_ovsl(dp, port_no); 2060ccb1352eSJesse Gross err = -EBUSY; 2061ccb1352eSJesse Gross if (vport) 20626093ae9aSJarno Rajahalme goto exit_unlock_free; 2063ccb1352eSJesse Gross } else { 2064ccb1352eSJesse Gross for (port_no = 1; ; port_no++) { 2065ccb1352eSJesse Gross if (port_no >= DP_MAX_PORTS) { 2066ccb1352eSJesse Gross err = -EFBIG; 20676093ae9aSJarno Rajahalme goto exit_unlock_free; 2068ccb1352eSJesse Gross } 20698e4e1713SPravin B Shelar vport = ovs_vport_ovsl(dp, port_no); 2070ccb1352eSJesse Gross if (!vport) 2071ccb1352eSJesse Gross break; 2072ccb1352eSJesse Gross } 2073ccb1352eSJesse Gross } 2074ccb1352eSJesse Gross 2075ccb1352eSJesse Gross parms.name = nla_data(a[OVS_VPORT_ATTR_NAME]); 2076ccb1352eSJesse Gross parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]); 2077ccb1352eSJesse Gross parms.options = a[OVS_VPORT_ATTR_OPTIONS]; 2078ccb1352eSJesse Gross parms.dp = dp; 2079ccb1352eSJesse Gross parms.port_no = port_no; 20805cd667b0SAlex Wang parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID]; 2081ccb1352eSJesse Gross 2082ccb1352eSJesse Gross vport = new_vport(&parms); 2083ccb1352eSJesse Gross err = PTR_ERR(vport); 208462b9c8d0SThomas Graf if (IS_ERR(vport)) { 208562b9c8d0SThomas Graf if (err == -EAGAIN) 208662b9c8d0SThomas Graf goto restart; 20876093ae9aSJarno Rajahalme goto exit_unlock_free; 208862b9c8d0SThomas Graf } 2089ccb1352eSJesse Gross 20909354d452SJiri Benc err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), 20919354d452SJiri Benc info->snd_portid, info->snd_seq, 0, 20929354d452SJiri Benc OVS_VPORT_CMD_NEW); 20933a927bc7SPaolo Abeni 20946b660c41STaehee Yoo new_headroom = netdev_get_fwd_headroom(vport->dev); 20956b660c41STaehee Yoo 20966b660c41STaehee Yoo if (new_headroom > dp->max_headroom) 20976b660c41STaehee Yoo ovs_update_headroom(dp, new_headroom); 20983a927bc7SPaolo Abeni else 20993a927bc7SPaolo Abeni netdev_set_rx_headroom(vport->dev, dp->max_headroom); 21003a927bc7SPaolo Abeni 21016093ae9aSJarno Rajahalme BUG_ON(err < 0); 21026093ae9aSJarno Rajahalme ovs_unlock(); 2103ed661185SThomas Graf 21042a94fe48SJohannes Berg ovs_notify(&dp_vport_genl_family, reply, info); 21056093ae9aSJarno Rajahalme return 0; 2106ccb1352eSJesse Gross 21076093ae9aSJarno Rajahalme exit_unlock_free: 21088e4e1713SPravin B Shelar ovs_unlock(); 21096093ae9aSJarno Rajahalme kfree_skb(reply); 2110ccb1352eSJesse Gross return err; 2111ccb1352eSJesse Gross } 2112ccb1352eSJesse Gross 2113ccb1352eSJesse Gross static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) 2114ccb1352eSJesse Gross { 2115ccb1352eSJesse Gross struct nlattr **a = info->attrs; 2116ccb1352eSJesse Gross struct sk_buff *reply; 2117ccb1352eSJesse Gross struct vport *vport; 2118ccb1352eSJesse Gross int err; 2119ccb1352eSJesse Gross 21206093ae9aSJarno Rajahalme reply = ovs_vport_cmd_alloc_info(); 21216093ae9aSJarno Rajahalme if (!reply) 21226093ae9aSJarno Rajahalme return -ENOMEM; 21236093ae9aSJarno Rajahalme 21248e4e1713SPravin B Shelar ovs_lock(); 212546df7b81SPravin B Shelar vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); 2126ccb1352eSJesse Gross err = PTR_ERR(vport); 2127ccb1352eSJesse Gross if (IS_ERR(vport)) 21286093ae9aSJarno Rajahalme goto exit_unlock_free; 2129ccb1352eSJesse Gross 2130ccb1352eSJesse Gross if (a[OVS_VPORT_ATTR_TYPE] && 2131f44f3408SJesse Gross nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) { 2132ccb1352eSJesse Gross err = -EINVAL; 21336093ae9aSJarno Rajahalme goto exit_unlock_free; 2134a9341512SJesse Gross } 2135a9341512SJesse Gross 2136f44f3408SJesse Gross if (a[OVS_VPORT_ATTR_OPTIONS]) { 2137ccb1352eSJesse Gross err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]); 213803fbf8b3SAnsis Atteka if (err) 21396093ae9aSJarno Rajahalme goto exit_unlock_free; 2140f44f3408SJesse Gross } 2141a9341512SJesse Gross 21425cd667b0SAlex Wang 21435cd667b0SAlex Wang if (a[OVS_VPORT_ATTR_UPCALL_PID]) { 21445cd667b0SAlex Wang struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID]; 21455cd667b0SAlex Wang 21465cd667b0SAlex Wang err = ovs_vport_set_upcall_portids(vport, ids); 21475cd667b0SAlex Wang if (err) 21485cd667b0SAlex Wang goto exit_unlock_free; 21495cd667b0SAlex Wang } 2150ccb1352eSJesse Gross 21519354d452SJiri Benc err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), 21529354d452SJiri Benc info->snd_portid, info->snd_seq, 0, 2153804fe108SYifeng Sun OVS_VPORT_CMD_SET); 2154a9341512SJesse Gross BUG_ON(err < 0); 2155ccb1352eSJesse Gross 21568e4e1713SPravin B Shelar ovs_unlock(); 21572a94fe48SJohannes Berg ovs_notify(&dp_vport_genl_family, reply, info); 21588e4e1713SPravin B Shelar return 0; 2159ccb1352eSJesse Gross 21606093ae9aSJarno Rajahalme exit_unlock_free: 21618e4e1713SPravin B Shelar ovs_unlock(); 21626093ae9aSJarno Rajahalme kfree_skb(reply); 2163ccb1352eSJesse Gross return err; 2164ccb1352eSJesse Gross } 2165ccb1352eSJesse Gross 2166ccb1352eSJesse Gross static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) 2167ccb1352eSJesse Gross { 21686b660c41STaehee Yoo bool update_headroom = false; 2169ccb1352eSJesse Gross struct nlattr **a = info->attrs; 2170ccb1352eSJesse Gross struct sk_buff *reply; 21713a927bc7SPaolo Abeni struct datapath *dp; 2172ccb1352eSJesse Gross struct vport *vport; 21736b660c41STaehee Yoo unsigned int new_headroom; 2174ccb1352eSJesse Gross int err; 2175ccb1352eSJesse Gross 21766093ae9aSJarno Rajahalme reply = ovs_vport_cmd_alloc_info(); 21776093ae9aSJarno Rajahalme if (!reply) 21786093ae9aSJarno Rajahalme return -ENOMEM; 21796093ae9aSJarno Rajahalme 21808e4e1713SPravin B Shelar ovs_lock(); 218146df7b81SPravin B Shelar vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); 2182ccb1352eSJesse Gross err = PTR_ERR(vport); 2183ccb1352eSJesse Gross if (IS_ERR(vport)) 21846093ae9aSJarno Rajahalme goto exit_unlock_free; 2185ccb1352eSJesse Gross 2186ccb1352eSJesse Gross if (vport->port_no == OVSP_LOCAL) { 2187ccb1352eSJesse Gross err = -EINVAL; 21886093ae9aSJarno Rajahalme goto exit_unlock_free; 2189ccb1352eSJesse Gross } 2190ccb1352eSJesse Gross 21919354d452SJiri Benc err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), 21929354d452SJiri Benc info->snd_portid, info->snd_seq, 0, 21939354d452SJiri Benc OVS_VPORT_CMD_DEL); 21946093ae9aSJarno Rajahalme BUG_ON(err < 0); 21953a927bc7SPaolo Abeni 21963a927bc7SPaolo Abeni /* the vport deletion may trigger dp headroom update */ 21973a927bc7SPaolo Abeni dp = vport->dp; 21983a927bc7SPaolo Abeni if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom) 21996b660c41STaehee Yoo update_headroom = true; 22006b660c41STaehee Yoo 22013a927bc7SPaolo Abeni netdev_reset_rx_headroom(vport->dev); 2202ccb1352eSJesse Gross ovs_dp_detach_port(vport); 22033a927bc7SPaolo Abeni 22046b660c41STaehee Yoo if (update_headroom) { 22056b660c41STaehee Yoo new_headroom = ovs_get_max_headroom(dp); 22066b660c41STaehee Yoo 22076b660c41STaehee Yoo if (new_headroom < dp->max_headroom) 22086b660c41STaehee Yoo ovs_update_headroom(dp, new_headroom); 22096b660c41STaehee Yoo } 22106093ae9aSJarno Rajahalme ovs_unlock(); 2211ccb1352eSJesse Gross 22122a94fe48SJohannes Berg ovs_notify(&dp_vport_genl_family, reply, info); 22136093ae9aSJarno Rajahalme return 0; 2214ccb1352eSJesse Gross 22156093ae9aSJarno Rajahalme exit_unlock_free: 22168e4e1713SPravin B Shelar ovs_unlock(); 22176093ae9aSJarno Rajahalme kfree_skb(reply); 2218ccb1352eSJesse Gross return err; 2219ccb1352eSJesse Gross } 2220ccb1352eSJesse Gross 2221ccb1352eSJesse Gross static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info) 2222ccb1352eSJesse Gross { 2223ccb1352eSJesse Gross struct nlattr **a = info->attrs; 2224ccb1352eSJesse Gross struct ovs_header *ovs_header = info->userhdr; 2225ccb1352eSJesse Gross struct sk_buff *reply; 2226ccb1352eSJesse Gross struct vport *vport; 2227ccb1352eSJesse Gross int err; 2228ccb1352eSJesse Gross 22296093ae9aSJarno Rajahalme reply = ovs_vport_cmd_alloc_info(); 22306093ae9aSJarno Rajahalme if (!reply) 22316093ae9aSJarno Rajahalme return -ENOMEM; 22326093ae9aSJarno Rajahalme 2233ccb1352eSJesse Gross rcu_read_lock(); 223446df7b81SPravin B Shelar vport = lookup_vport(sock_net(skb->sk), ovs_header, a); 2235ccb1352eSJesse Gross err = PTR_ERR(vport); 2236ccb1352eSJesse Gross if (IS_ERR(vport)) 22376093ae9aSJarno Rajahalme goto exit_unlock_free; 22389354d452SJiri Benc err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), 22399354d452SJiri Benc info->snd_portid, info->snd_seq, 0, 2240804fe108SYifeng Sun OVS_VPORT_CMD_GET); 22416093ae9aSJarno Rajahalme BUG_ON(err < 0); 2242ccb1352eSJesse Gross rcu_read_unlock(); 2243ccb1352eSJesse Gross 2244ccb1352eSJesse Gross return genlmsg_reply(reply, info); 2245ccb1352eSJesse Gross 22466093ae9aSJarno Rajahalme exit_unlock_free: 2247ccb1352eSJesse Gross rcu_read_unlock(); 22486093ae9aSJarno Rajahalme kfree_skb(reply); 2249ccb1352eSJesse Gross return err; 2250ccb1352eSJesse Gross } 2251ccb1352eSJesse Gross 2252ccb1352eSJesse Gross static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) 2253ccb1352eSJesse Gross { 2254ccb1352eSJesse Gross struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); 2255ccb1352eSJesse Gross struct datapath *dp; 225615eac2a7SPravin B Shelar int bucket = cb->args[0], skip = cb->args[1]; 225715eac2a7SPravin B Shelar int i, j = 0; 2258ccb1352eSJesse Gross 2259ccb1352eSJesse Gross rcu_read_lock(); 2260cc3a5ae6SAndy Zhou dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex); 226142ee19e2SJarno Rajahalme if (!dp) { 226242ee19e2SJarno Rajahalme rcu_read_unlock(); 226342ee19e2SJarno Rajahalme return -ENODEV; 226442ee19e2SJarno Rajahalme } 226515eac2a7SPravin B Shelar for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) { 2266ccb1352eSJesse Gross struct vport *vport; 2267ccb1352eSJesse Gross 226815eac2a7SPravin B Shelar j = 0; 2269b67bfe0dSSasha Levin hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) { 227015eac2a7SPravin B Shelar if (j >= skip && 227115eac2a7SPravin B Shelar ovs_vport_cmd_fill_info(vport, skb, 22729354d452SJiri Benc sock_net(skb->sk), 227315e47304SEric W. Biederman NETLINK_CB(cb->skb).portid, 227415eac2a7SPravin B Shelar cb->nlh->nlmsg_seq, 227515eac2a7SPravin B Shelar NLM_F_MULTI, 2276804fe108SYifeng Sun OVS_VPORT_CMD_GET) < 0) 227715eac2a7SPravin B Shelar goto out; 227815eac2a7SPravin B Shelar 227915eac2a7SPravin B Shelar j++; 2280ccb1352eSJesse Gross } 228115eac2a7SPravin B Shelar skip = 0; 228215eac2a7SPravin B Shelar } 228315eac2a7SPravin B Shelar out: 2284ccb1352eSJesse Gross rcu_read_unlock(); 2285ccb1352eSJesse Gross 228615eac2a7SPravin B Shelar cb->args[0] = i; 228715eac2a7SPravin B Shelar cb->args[1] = j; 2288ccb1352eSJesse Gross 228915eac2a7SPravin B Shelar return skb->len; 2290ccb1352eSJesse Gross } 2291ccb1352eSJesse Gross 22920c200ef9SPravin B Shelar static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { 22930c200ef9SPravin B Shelar [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, 22940c200ef9SPravin B Shelar [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, 22950c200ef9SPravin B Shelar [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, 22960c200ef9SPravin B Shelar [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, 2297*ea8564c8SLi RongQing [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC }, 22980c200ef9SPravin B Shelar [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, 22999354d452SJiri Benc [OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 }, 23009354d452SJiri Benc [OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 }, 23010c200ef9SPravin B Shelar }; 23020c200ef9SPravin B Shelar 230348e48a70Sstephen hemminger static const struct genl_ops dp_vport_genl_ops[] = { 2304ccb1352eSJesse Gross { .cmd = OVS_VPORT_CMD_NEW, 2305ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 23064a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 2307ccb1352eSJesse Gross .doit = ovs_vport_cmd_new 2308ccb1352eSJesse Gross }, 2309ccb1352eSJesse Gross { .cmd = OVS_VPORT_CMD_DEL, 2310ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 23114a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 2312ccb1352eSJesse Gross .doit = ovs_vport_cmd_del 2313ccb1352eSJesse Gross }, 2314ccb1352eSJesse Gross { .cmd = OVS_VPORT_CMD_GET, 2315ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 2316ccb1352eSJesse Gross .flags = 0, /* OK for unprivileged users. */ 2317ccb1352eSJesse Gross .doit = ovs_vport_cmd_get, 2318ccb1352eSJesse Gross .dumpit = ovs_vport_cmd_dump 2319ccb1352eSJesse Gross }, 2320ccb1352eSJesse Gross { .cmd = OVS_VPORT_CMD_SET, 2321ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 23224a92602aSTycho Andersen .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ 2323ccb1352eSJesse Gross .doit = ovs_vport_cmd_set, 2324ccb1352eSJesse Gross }, 2325ccb1352eSJesse Gross }; 2326ccb1352eSJesse Gross 232756989f6dSJohannes Berg struct genl_family dp_vport_genl_family __ro_after_init = { 23280c200ef9SPravin B Shelar .hdrsize = sizeof(struct ovs_header), 23290c200ef9SPravin B Shelar .name = OVS_VPORT_FAMILY, 23300c200ef9SPravin B Shelar .version = OVS_VPORT_VERSION, 23310c200ef9SPravin B Shelar .maxattr = OVS_VPORT_ATTR_MAX, 23323b0f31f2SJohannes Berg .policy = vport_policy, 23330c200ef9SPravin B Shelar .netnsok = true, 23340c200ef9SPravin B Shelar .parallel_ops = true, 23350c200ef9SPravin B Shelar .ops = dp_vport_genl_ops, 23360c200ef9SPravin B Shelar .n_ops = ARRAY_SIZE(dp_vport_genl_ops), 23370c200ef9SPravin B Shelar .mcgrps = &ovs_dp_vport_multicast_group, 23380c200ef9SPravin B Shelar .n_mcgrps = 1, 2339489111e5SJohannes Berg .module = THIS_MODULE, 2340ccb1352eSJesse Gross }; 2341ccb1352eSJesse Gross 23420c200ef9SPravin B Shelar static struct genl_family * const dp_genl_families[] = { 23430c200ef9SPravin B Shelar &dp_datapath_genl_family, 23440c200ef9SPravin B Shelar &dp_vport_genl_family, 23450c200ef9SPravin B Shelar &dp_flow_genl_family, 23460c200ef9SPravin B Shelar &dp_packet_genl_family, 234796fbc13dSAndy Zhou &dp_meter_genl_family, 234811efd5cbSYi-Hung Wei #if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) 234911efd5cbSYi-Hung Wei &dp_ct_limit_genl_family, 235011efd5cbSYi-Hung Wei #endif 2351ccb1352eSJesse Gross }; 2352ccb1352eSJesse Gross 2353ccb1352eSJesse Gross static void dp_unregister_genl(int n_families) 2354ccb1352eSJesse Gross { 2355ccb1352eSJesse Gross int i; 2356ccb1352eSJesse Gross 2357ccb1352eSJesse Gross for (i = 0; i < n_families; i++) 23580c200ef9SPravin B Shelar genl_unregister_family(dp_genl_families[i]); 2359ccb1352eSJesse Gross } 2360ccb1352eSJesse Gross 236156989f6dSJohannes Berg static int __init dp_register_genl(void) 2362ccb1352eSJesse Gross { 2363ccb1352eSJesse Gross int err; 2364ccb1352eSJesse Gross int i; 2365ccb1352eSJesse Gross 2366ccb1352eSJesse Gross for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) { 2367ccb1352eSJesse Gross 23680c200ef9SPravin B Shelar err = genl_register_family(dp_genl_families[i]); 2369ccb1352eSJesse Gross if (err) 2370ccb1352eSJesse Gross goto error; 2371ccb1352eSJesse Gross } 2372ccb1352eSJesse Gross 2373ccb1352eSJesse Gross return 0; 2374ccb1352eSJesse Gross 2375ccb1352eSJesse Gross error: 23760c200ef9SPravin B Shelar dp_unregister_genl(i); 2377ccb1352eSJesse Gross return err; 2378ccb1352eSJesse Gross } 2379ccb1352eSJesse Gross 238046df7b81SPravin B Shelar static int __net_init ovs_init_net(struct net *net) 238146df7b81SPravin B Shelar { 238246df7b81SPravin B Shelar struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 238346df7b81SPravin B Shelar 238446df7b81SPravin B Shelar INIT_LIST_HEAD(&ovs_net->dps); 23858e4e1713SPravin B Shelar INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq); 238611efd5cbSYi-Hung Wei return ovs_ct_init(net); 238746df7b81SPravin B Shelar } 238846df7b81SPravin B Shelar 23897b4577a9SPravin B Shelar static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, 23907b4577a9SPravin B Shelar struct list_head *head) 23917b4577a9SPravin B Shelar { 23927b4577a9SPravin B Shelar struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 23937b4577a9SPravin B Shelar struct datapath *dp; 23947b4577a9SPravin B Shelar 23957b4577a9SPravin B Shelar list_for_each_entry(dp, &ovs_net->dps, list_node) { 23967b4577a9SPravin B Shelar int i; 23977b4577a9SPravin B Shelar 23987b4577a9SPravin B Shelar for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { 23997b4577a9SPravin B Shelar struct vport *vport; 24007b4577a9SPravin B Shelar 24017b4577a9SPravin B Shelar hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) { 24027b4577a9SPravin B Shelar if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL) 24037b4577a9SPravin B Shelar continue; 24047b4577a9SPravin B Shelar 2405be4ace6eSThomas Graf if (dev_net(vport->dev) == dnet) 24067b4577a9SPravin B Shelar list_add(&vport->detach_list, head); 24077b4577a9SPravin B Shelar } 24087b4577a9SPravin B Shelar } 24097b4577a9SPravin B Shelar } 24107b4577a9SPravin B Shelar } 24117b4577a9SPravin B Shelar 24127b4577a9SPravin B Shelar static void __net_exit ovs_exit_net(struct net *dnet) 241346df7b81SPravin B Shelar { 241446df7b81SPravin B Shelar struct datapath *dp, *dp_next; 24157b4577a9SPravin B Shelar struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id); 24167b4577a9SPravin B Shelar struct vport *vport, *vport_next; 24177b4577a9SPravin B Shelar struct net *net; 24187b4577a9SPravin B Shelar LIST_HEAD(head); 241946df7b81SPravin B Shelar 2420c2ac6673SJoe Stringer ovs_ct_exit(dnet); 24218e4e1713SPravin B Shelar ovs_lock(); 242246df7b81SPravin B Shelar list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node) 242346df7b81SPravin B Shelar __dp_destroy(dp); 24247b4577a9SPravin B Shelar 2425f0b07bb1SKirill Tkhai down_read(&net_rwsem); 24267b4577a9SPravin B Shelar for_each_net(net) 24277b4577a9SPravin B Shelar list_vports_from_net(net, dnet, &head); 2428f0b07bb1SKirill Tkhai up_read(&net_rwsem); 24297b4577a9SPravin B Shelar 24307b4577a9SPravin B Shelar /* Detach all vports from given namespace. */ 24317b4577a9SPravin B Shelar list_for_each_entry_safe(vport, vport_next, &head, detach_list) { 24327b4577a9SPravin B Shelar list_del(&vport->detach_list); 24337b4577a9SPravin B Shelar ovs_dp_detach_port(vport); 24347b4577a9SPravin B Shelar } 24357b4577a9SPravin B Shelar 24368e4e1713SPravin B Shelar ovs_unlock(); 24378e4e1713SPravin B Shelar 24388e4e1713SPravin B Shelar cancel_work_sync(&ovs_net->dp_notify_work); 243946df7b81SPravin B Shelar } 244046df7b81SPravin B Shelar 244146df7b81SPravin B Shelar static struct pernet_operations ovs_net_ops = { 244246df7b81SPravin B Shelar .init = ovs_init_net, 244346df7b81SPravin B Shelar .exit = ovs_exit_net, 244446df7b81SPravin B Shelar .id = &ovs_net_id, 244546df7b81SPravin B Shelar .size = sizeof(struct ovs_net), 244646df7b81SPravin B Shelar }; 244746df7b81SPravin B Shelar 2448ccb1352eSJesse Gross static int __init dp_init(void) 2449ccb1352eSJesse Gross { 2450ccb1352eSJesse Gross int err; 2451ccb1352eSJesse Gross 24523523b29bSYOSHIFUJI Hideaki / 吉藤英明 BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb)); 2453ccb1352eSJesse Gross 2454ccb1352eSJesse Gross pr_info("Open vSwitch switching datapath\n"); 2455ccb1352eSJesse Gross 2456971427f3SAndy Zhou err = action_fifos_init(); 2457ccb1352eSJesse Gross if (err) 2458ccb1352eSJesse Gross goto error; 2459ccb1352eSJesse Gross 2460971427f3SAndy Zhou err = ovs_internal_dev_rtnl_link_register(); 2461971427f3SAndy Zhou if (err) 2462971427f3SAndy Zhou goto error_action_fifos_exit; 2463971427f3SAndy Zhou 24645b9e7e16SJiri Pirko err = ovs_flow_init(); 24655b9e7e16SJiri Pirko if (err) 24665b9e7e16SJiri Pirko goto error_unreg_rtnl_link; 24675b9e7e16SJiri Pirko 2468ccb1352eSJesse Gross err = ovs_vport_init(); 2469ccb1352eSJesse Gross if (err) 2470ccb1352eSJesse Gross goto error_flow_exit; 2471ccb1352eSJesse Gross 247246df7b81SPravin B Shelar err = register_pernet_device(&ovs_net_ops); 2473ccb1352eSJesse Gross if (err) 2474ccb1352eSJesse Gross goto error_vport_exit; 2475ccb1352eSJesse Gross 247646df7b81SPravin B Shelar err = register_netdevice_notifier(&ovs_dp_device_notifier); 247746df7b81SPravin B Shelar if (err) 247846df7b81SPravin B Shelar goto error_netns_exit; 247946df7b81SPravin B Shelar 248062b9c8d0SThomas Graf err = ovs_netdev_init(); 248162b9c8d0SThomas Graf if (err) 248262b9c8d0SThomas Graf goto error_unreg_notifier; 248362b9c8d0SThomas Graf 2484ccb1352eSJesse Gross err = dp_register_genl(); 2485ccb1352eSJesse Gross if (err < 0) 248662b9c8d0SThomas Graf goto error_unreg_netdev; 2487ccb1352eSJesse Gross 2488ccb1352eSJesse Gross return 0; 2489ccb1352eSJesse Gross 249062b9c8d0SThomas Graf error_unreg_netdev: 249162b9c8d0SThomas Graf ovs_netdev_exit(); 2492ccb1352eSJesse Gross error_unreg_notifier: 2493ccb1352eSJesse Gross unregister_netdevice_notifier(&ovs_dp_device_notifier); 249446df7b81SPravin B Shelar error_netns_exit: 249546df7b81SPravin B Shelar unregister_pernet_device(&ovs_net_ops); 2496ccb1352eSJesse Gross error_vport_exit: 2497ccb1352eSJesse Gross ovs_vport_exit(); 2498ccb1352eSJesse Gross error_flow_exit: 2499ccb1352eSJesse Gross ovs_flow_exit(); 25005b9e7e16SJiri Pirko error_unreg_rtnl_link: 25015b9e7e16SJiri Pirko ovs_internal_dev_rtnl_link_unregister(); 2502971427f3SAndy Zhou error_action_fifos_exit: 2503971427f3SAndy Zhou action_fifos_exit(); 2504ccb1352eSJesse Gross error: 2505ccb1352eSJesse Gross return err; 2506ccb1352eSJesse Gross } 2507ccb1352eSJesse Gross 2508ccb1352eSJesse Gross static void dp_cleanup(void) 2509ccb1352eSJesse Gross { 2510ccb1352eSJesse Gross dp_unregister_genl(ARRAY_SIZE(dp_genl_families)); 251162b9c8d0SThomas Graf ovs_netdev_exit(); 2512ccb1352eSJesse Gross unregister_netdevice_notifier(&ovs_dp_device_notifier); 251346df7b81SPravin B Shelar unregister_pernet_device(&ovs_net_ops); 251446df7b81SPravin B Shelar rcu_barrier(); 2515ccb1352eSJesse Gross ovs_vport_exit(); 2516ccb1352eSJesse Gross ovs_flow_exit(); 25175b9e7e16SJiri Pirko ovs_internal_dev_rtnl_link_unregister(); 2518971427f3SAndy Zhou action_fifos_exit(); 2519ccb1352eSJesse Gross } 2520ccb1352eSJesse Gross 2521ccb1352eSJesse Gross module_init(dp_init); 2522ccb1352eSJesse Gross module_exit(dp_cleanup); 2523ccb1352eSJesse Gross 2524ccb1352eSJesse Gross MODULE_DESCRIPTION("Open vSwitch switching datapath"); 2525ccb1352eSJesse Gross MODULE_LICENSE("GPL"); 2526ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_DATAPATH_FAMILY); 2527ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY); 2528ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY); 2529ed227099SThadeu Lima de Souza Cascardo MODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY); 253096fbc13dSAndy Zhou MODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY); 253111efd5cbSYi-Hung Wei MODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY); 2532