18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2014 Nicira, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
118c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
128c2ecf20Sopenharmony_ci#include <linux/in.h>
138c2ecf20Sopenharmony_ci#include <linux/ip.h>
148c2ecf20Sopenharmony_ci#include <linux/jhash.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/time.h>
178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/genetlink.h>
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/kthread.h>
218c2ecf20Sopenharmony_ci#include <linux/mutex.h>
228c2ecf20Sopenharmony_ci#include <linux/percpu.h>
238c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
248c2ecf20Sopenharmony_ci#include <linux/tcp.h>
258c2ecf20Sopenharmony_ci#include <linux/udp.h>
268c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
278c2ecf20Sopenharmony_ci#include <linux/wait.h>
288c2ecf20Sopenharmony_ci#include <asm/div64.h>
298c2ecf20Sopenharmony_ci#include <linux/highmem.h>
308c2ecf20Sopenharmony_ci#include <linux/netfilter_bridge.h>
318c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4.h>
328c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
338c2ecf20Sopenharmony_ci#include <linux/list.h>
348c2ecf20Sopenharmony_ci#include <linux/openvswitch.h>
358c2ecf20Sopenharmony_ci#include <linux/rculist.h>
368c2ecf20Sopenharmony_ci#include <linux/dmi.h>
378c2ecf20Sopenharmony_ci#include <net/genetlink.h>
388c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
398c2ecf20Sopenharmony_ci#include <net/netns/generic.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "datapath.h"
428c2ecf20Sopenharmony_ci#include "flow.h"
438c2ecf20Sopenharmony_ci#include "flow_table.h"
448c2ecf20Sopenharmony_ci#include "flow_netlink.h"
458c2ecf20Sopenharmony_ci#include "meter.h"
468c2ecf20Sopenharmony_ci#include "vport-internal_dev.h"
478c2ecf20Sopenharmony_ci#include "vport-netdev.h"
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciunsigned int ovs_net_id __read_mostly;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic struct genl_family dp_packet_genl_family;
528c2ecf20Sopenharmony_cistatic struct genl_family dp_flow_genl_family;
538c2ecf20Sopenharmony_cistatic struct genl_family dp_datapath_genl_family;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic const struct nla_policy flow_policy[];
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const struct genl_multicast_group ovs_dp_flow_multicast_group = {
588c2ecf20Sopenharmony_ci	.name = OVS_FLOW_MCGROUP,
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const struct genl_multicast_group ovs_dp_datapath_multicast_group = {
628c2ecf20Sopenharmony_ci	.name = OVS_DATAPATH_MCGROUP,
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const struct genl_multicast_group ovs_dp_vport_multicast_group = {
668c2ecf20Sopenharmony_ci	.name = OVS_VPORT_MCGROUP,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* Check if need to build a reply message.
708c2ecf20Sopenharmony_ci * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */
718c2ecf20Sopenharmony_cistatic bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
728c2ecf20Sopenharmony_ci			    unsigned int group)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
758c2ecf20Sopenharmony_ci	       genl_has_listeners(family, genl_info_net(info), group);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void ovs_notify(struct genl_family *family,
798c2ecf20Sopenharmony_ci		       struct sk_buff *skb, struct genl_info *info)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	genl_notify(family, skb, info, 0, GFP_KERNEL);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/**
858c2ecf20Sopenharmony_ci * DOC: Locking:
868c2ecf20Sopenharmony_ci *
878c2ecf20Sopenharmony_ci * All writes e.g. Writes to device state (add/remove datapath, port, set
888c2ecf20Sopenharmony_ci * operations on vports, etc.), Writes to other state (flow table
898c2ecf20Sopenharmony_ci * modifications, set miscellaneous datapath parameters, etc.) are protected
908c2ecf20Sopenharmony_ci * by ovs_lock.
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * Reads are protected by RCU.
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * There are a few special cases (mostly stats) that have their own
958c2ecf20Sopenharmony_ci * synchronization but they nest under all of above and don't interact with
968c2ecf20Sopenharmony_ci * each other.
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * The RTNL lock nests inside ovs_mutex.
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ovs_mutex);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_civoid ovs_lock(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	mutex_lock(&ovs_mutex);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_civoid ovs_unlock(void)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	mutex_unlock(&ovs_mutex);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#ifdef CONFIG_LOCKDEP
1148c2ecf20Sopenharmony_ciint lockdep_ovsl_is_held(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	if (debug_locks)
1178c2ecf20Sopenharmony_ci		return lockdep_is_held(&ovs_mutex);
1188c2ecf20Sopenharmony_ci	else
1198c2ecf20Sopenharmony_ci		return 1;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci#endif
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic struct vport *new_vport(const struct vport_parms *);
1248c2ecf20Sopenharmony_cistatic int queue_gso_packets(struct datapath *dp, struct sk_buff *,
1258c2ecf20Sopenharmony_ci			     const struct sw_flow_key *,
1268c2ecf20Sopenharmony_ci			     const struct dp_upcall_info *,
1278c2ecf20Sopenharmony_ci			     uint32_t cutlen);
1288c2ecf20Sopenharmony_cistatic int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
1298c2ecf20Sopenharmony_ci				  const struct sw_flow_key *,
1308c2ecf20Sopenharmony_ci				  const struct dp_upcall_info *,
1318c2ecf20Sopenharmony_ci				  uint32_t cutlen);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void ovs_dp_masks_rebalance(struct work_struct *work);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/* Must be called with rcu_read_lock or ovs_mutex. */
1368c2ecf20Sopenharmony_ciconst char *ovs_dp_name(const struct datapath *dp)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
1398c2ecf20Sopenharmony_ci	return ovs_vport_name(vport);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int get_dpifindex(const struct datapath *dp)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct vport *local;
1458c2ecf20Sopenharmony_ci	int ifindex;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	rcu_read_lock();
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	local = ovs_vport_rcu(dp, OVSP_LOCAL);
1508c2ecf20Sopenharmony_ci	if (local)
1518c2ecf20Sopenharmony_ci		ifindex = local->dev->ifindex;
1528c2ecf20Sopenharmony_ci	else
1538c2ecf20Sopenharmony_ci		ifindex = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	rcu_read_unlock();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return ifindex;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void destroy_dp_rcu(struct rcu_head *rcu)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct datapath *dp = container_of(rcu, struct datapath, rcu);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	ovs_flow_tbl_destroy(&dp->table);
1658c2ecf20Sopenharmony_ci	free_percpu(dp->stats_percpu);
1668c2ecf20Sopenharmony_ci	kfree(dp->ports);
1678c2ecf20Sopenharmony_ci	ovs_meters_exit(dp);
1688c2ecf20Sopenharmony_ci	kfree(dp);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic struct hlist_head *vport_hash_bucket(const struct datapath *dp,
1728c2ecf20Sopenharmony_ci					    u16 port_no)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	return &dp->ports[port_no & (DP_VPORT_HASH_BUCKETS - 1)];
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
1788c2ecf20Sopenharmony_cistruct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct vport *vport;
1818c2ecf20Sopenharmony_ci	struct hlist_head *head;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	head = vport_hash_bucket(dp, port_no);
1848c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(vport, head, dp_hash_node,
1858c2ecf20Sopenharmony_ci				 lockdep_ovsl_is_held()) {
1868c2ecf20Sopenharmony_ci		if (vport->port_no == port_no)
1878c2ecf20Sopenharmony_ci			return vport;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	return NULL;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/* Called with ovs_mutex. */
1938c2ecf20Sopenharmony_cistatic struct vport *new_vport(const struct vport_parms *parms)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct vport *vport;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	vport = ovs_vport_add(parms);
1988c2ecf20Sopenharmony_ci	if (!IS_ERR(vport)) {
1998c2ecf20Sopenharmony_ci		struct datapath *dp = parms->dp;
2008c2ecf20Sopenharmony_ci		struct hlist_head *head = vport_hash_bucket(dp, vport->port_no);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&vport->dp_hash_node, head);
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci	return vport;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_civoid ovs_dp_detach_port(struct vport *p)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	ASSERT_OVSL();
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* First drop references to device. */
2128c2ecf20Sopenharmony_ci	hlist_del_rcu(&p->dp_hash_node);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* Then destroy it. */
2158c2ecf20Sopenharmony_ci	ovs_vport_del(p);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci/* Must be called with rcu_read_lock. */
2198c2ecf20Sopenharmony_civoid ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	const struct vport *p = OVS_CB(skb)->input_vport;
2228c2ecf20Sopenharmony_ci	struct datapath *dp = p->dp;
2238c2ecf20Sopenharmony_ci	struct sw_flow *flow;
2248c2ecf20Sopenharmony_ci	struct sw_flow_actions *sf_acts;
2258c2ecf20Sopenharmony_ci	struct dp_stats_percpu *stats;
2268c2ecf20Sopenharmony_ci	u64 *stats_counter;
2278c2ecf20Sopenharmony_ci	u32 n_mask_hit;
2288c2ecf20Sopenharmony_ci	u32 n_cache_hit;
2298c2ecf20Sopenharmony_ci	int error;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	stats = this_cpu_ptr(dp->stats_percpu);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Look up flow. */
2348c2ecf20Sopenharmony_ci	flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb),
2358c2ecf20Sopenharmony_ci					 &n_mask_hit, &n_cache_hit);
2368c2ecf20Sopenharmony_ci	if (unlikely(!flow)) {
2378c2ecf20Sopenharmony_ci		struct dp_upcall_info upcall;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		memset(&upcall, 0, sizeof(upcall));
2408c2ecf20Sopenharmony_ci		upcall.cmd = OVS_PACKET_CMD_MISS;
2418c2ecf20Sopenharmony_ci		upcall.portid = ovs_vport_find_upcall_portid(p, skb);
2428c2ecf20Sopenharmony_ci		upcall.mru = OVS_CB(skb)->mru;
2438c2ecf20Sopenharmony_ci		error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
2448c2ecf20Sopenharmony_ci		switch (error) {
2458c2ecf20Sopenharmony_ci		case 0:
2468c2ecf20Sopenharmony_ci		case -EAGAIN:
2478c2ecf20Sopenharmony_ci		case -ERESTARTSYS:
2488c2ecf20Sopenharmony_ci		case -EINTR:
2498c2ecf20Sopenharmony_ci			consume_skb(skb);
2508c2ecf20Sopenharmony_ci			break;
2518c2ecf20Sopenharmony_ci		default:
2528c2ecf20Sopenharmony_ci			kfree_skb(skb);
2538c2ecf20Sopenharmony_ci			break;
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci		stats_counter = &stats->n_missed;
2568c2ecf20Sopenharmony_ci		goto out;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	ovs_flow_stats_update(flow, key->tp.flags, skb);
2608c2ecf20Sopenharmony_ci	sf_acts = rcu_dereference(flow->sf_acts);
2618c2ecf20Sopenharmony_ci	error = ovs_execute_actions(dp, skb, sf_acts, key);
2628c2ecf20Sopenharmony_ci	if (unlikely(error))
2638c2ecf20Sopenharmony_ci		net_dbg_ratelimited("ovs: action execution error on datapath %s: %d\n",
2648c2ecf20Sopenharmony_ci				    ovs_dp_name(dp), error);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	stats_counter = &stats->n_hit;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ciout:
2698c2ecf20Sopenharmony_ci	/* Update datapath statistics. */
2708c2ecf20Sopenharmony_ci	u64_stats_update_begin(&stats->syncp);
2718c2ecf20Sopenharmony_ci	(*stats_counter)++;
2728c2ecf20Sopenharmony_ci	stats->n_mask_hit += n_mask_hit;
2738c2ecf20Sopenharmony_ci	stats->n_cache_hit += n_cache_hit;
2748c2ecf20Sopenharmony_ci	u64_stats_update_end(&stats->syncp);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ciint ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
2788c2ecf20Sopenharmony_ci		  const struct sw_flow_key *key,
2798c2ecf20Sopenharmony_ci		  const struct dp_upcall_info *upcall_info,
2808c2ecf20Sopenharmony_ci		  uint32_t cutlen)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct dp_stats_percpu *stats;
2838c2ecf20Sopenharmony_ci	int err;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (upcall_info->portid == 0) {
2868c2ecf20Sopenharmony_ci		err = -ENOTCONN;
2878c2ecf20Sopenharmony_ci		goto err;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (!skb_is_gso(skb))
2918c2ecf20Sopenharmony_ci		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
2928c2ecf20Sopenharmony_ci	else
2938c2ecf20Sopenharmony_ci		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);
2948c2ecf20Sopenharmony_ci	if (err)
2958c2ecf20Sopenharmony_ci		goto err;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cierr:
3008c2ecf20Sopenharmony_ci	stats = this_cpu_ptr(dp->stats_percpu);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	u64_stats_update_begin(&stats->syncp);
3038c2ecf20Sopenharmony_ci	stats->n_lost++;
3048c2ecf20Sopenharmony_ci	u64_stats_update_end(&stats->syncp);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return err;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
3108c2ecf20Sopenharmony_ci			     const struct sw_flow_key *key,
3118c2ecf20Sopenharmony_ci			     const struct dp_upcall_info *upcall_info,
3128c2ecf20Sopenharmony_ci			     uint32_t cutlen)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	unsigned int gso_type = skb_shinfo(skb)->gso_type;
3158c2ecf20Sopenharmony_ci	struct sw_flow_key later_key;
3168c2ecf20Sopenharmony_ci	struct sk_buff *segs, *nskb;
3178c2ecf20Sopenharmony_ci	int err;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_GSO_CB_OFFSET);
3208c2ecf20Sopenharmony_ci	segs = __skb_gso_segment(skb, NETIF_F_SG, false);
3218c2ecf20Sopenharmony_ci	if (IS_ERR(segs))
3228c2ecf20Sopenharmony_ci		return PTR_ERR(segs);
3238c2ecf20Sopenharmony_ci	if (segs == NULL)
3248c2ecf20Sopenharmony_ci		return -EINVAL;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (gso_type & SKB_GSO_UDP) {
3278c2ecf20Sopenharmony_ci		/* The initial flow key extracted by ovs_flow_key_extract()
3288c2ecf20Sopenharmony_ci		 * in this case is for a first fragment, so we need to
3298c2ecf20Sopenharmony_ci		 * properly mark later fragments.
3308c2ecf20Sopenharmony_ci		 */
3318c2ecf20Sopenharmony_ci		later_key = *key;
3328c2ecf20Sopenharmony_ci		later_key.ip.frag = OVS_FRAG_TYPE_LATER;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Queue all of the segments. */
3368c2ecf20Sopenharmony_ci	skb_list_walk_safe(segs, skb, nskb) {
3378c2ecf20Sopenharmony_ci		if (gso_type & SKB_GSO_UDP && skb != segs)
3388c2ecf20Sopenharmony_ci			key = &later_key;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
3418c2ecf20Sopenharmony_ci		if (err)
3428c2ecf20Sopenharmony_ci			break;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* Free all of the segments. */
3478c2ecf20Sopenharmony_ci	skb_list_walk_safe(segs, skb, nskb) {
3488c2ecf20Sopenharmony_ci		if (err)
3498c2ecf20Sopenharmony_ci			kfree_skb(skb);
3508c2ecf20Sopenharmony_ci		else
3518c2ecf20Sopenharmony_ci			consume_skb(skb);
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci	return err;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
3578c2ecf20Sopenharmony_ci			      unsigned int hdrlen, int actions_attrlen)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
3608c2ecf20Sopenharmony_ci		+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
3618c2ecf20Sopenharmony_ci		+ nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */
3628c2ecf20Sopenharmony_ci		+ nla_total_size(sizeof(unsigned int)) /* OVS_PACKET_ATTR_LEN */
3638c2ecf20Sopenharmony_ci		+ nla_total_size(sizeof(u64)); /* OVS_PACKET_ATTR_HASH */
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* OVS_PACKET_ATTR_USERDATA */
3668c2ecf20Sopenharmony_ci	if (upcall_info->userdata)
3678c2ecf20Sopenharmony_ci		size += NLA_ALIGN(upcall_info->userdata->nla_len);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
3708c2ecf20Sopenharmony_ci	if (upcall_info->egress_tun_info)
3718c2ecf20Sopenharmony_ci		size += nla_total_size(ovs_tun_key_attr_size());
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* OVS_PACKET_ATTR_ACTIONS */
3748c2ecf20Sopenharmony_ci	if (upcall_info->actions_len)
3758c2ecf20Sopenharmony_ci		size += nla_total_size(actions_attrlen);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* OVS_PACKET_ATTR_MRU */
3788c2ecf20Sopenharmony_ci	if (upcall_info->mru)
3798c2ecf20Sopenharmony_ci		size += nla_total_size(sizeof(upcall_info->mru));
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return size;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic void pad_packet(struct datapath *dp, struct sk_buff *skb)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
3878c2ecf20Sopenharmony_ci		size_t plen = NLA_ALIGN(skb->len) - skb->len;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		if (plen > 0)
3908c2ecf20Sopenharmony_ci			skb_put_zero(skb, plen);
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
3958c2ecf20Sopenharmony_ci				  const struct sw_flow_key *key,
3968c2ecf20Sopenharmony_ci				  const struct dp_upcall_info *upcall_info,
3978c2ecf20Sopenharmony_ci				  uint32_t cutlen)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct ovs_header *upcall;
4008c2ecf20Sopenharmony_ci	struct sk_buff *nskb = NULL;
4018c2ecf20Sopenharmony_ci	struct sk_buff *user_skb = NULL; /* to be queued to userspace */
4028c2ecf20Sopenharmony_ci	struct nlattr *nla;
4038c2ecf20Sopenharmony_ci	size_t len;
4048c2ecf20Sopenharmony_ci	unsigned int hlen;
4058c2ecf20Sopenharmony_ci	int err, dp_ifindex;
4068c2ecf20Sopenharmony_ci	u64 hash;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	dp_ifindex = get_dpifindex(dp);
4098c2ecf20Sopenharmony_ci	if (!dp_ifindex)
4108c2ecf20Sopenharmony_ci		return -ENODEV;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
4138c2ecf20Sopenharmony_ci		nskb = skb_clone(skb, GFP_ATOMIC);
4148c2ecf20Sopenharmony_ci		if (!nskb)
4158c2ecf20Sopenharmony_ci			return -ENOMEM;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		nskb = __vlan_hwaccel_push_inside(nskb);
4188c2ecf20Sopenharmony_ci		if (!nskb)
4198c2ecf20Sopenharmony_ci			return -ENOMEM;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		skb = nskb;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (nla_attr_size(skb->len) > USHRT_MAX) {
4258c2ecf20Sopenharmony_ci		err = -EFBIG;
4268c2ecf20Sopenharmony_ci		goto out;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* Complete checksum if needed */
4308c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL &&
4318c2ecf20Sopenharmony_ci	    (err = skb_csum_hwoffload_help(skb, 0)))
4328c2ecf20Sopenharmony_ci		goto out;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* Older versions of OVS user space enforce alignment of the last
4358c2ecf20Sopenharmony_ci	 * Netlink attribute to NLA_ALIGNTO which would require extensive
4368c2ecf20Sopenharmony_ci	 * padding logic. Only perform zerocopy if padding is not required.
4378c2ecf20Sopenharmony_ci	 */
4388c2ecf20Sopenharmony_ci	if (dp->user_features & OVS_DP_F_UNALIGNED)
4398c2ecf20Sopenharmony_ci		hlen = skb_zerocopy_headlen(skb);
4408c2ecf20Sopenharmony_ci	else
4418c2ecf20Sopenharmony_ci		hlen = skb->len;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	len = upcall_msg_size(upcall_info, hlen - cutlen,
4448c2ecf20Sopenharmony_ci			      OVS_CB(skb)->acts_origlen);
4458c2ecf20Sopenharmony_ci	user_skb = genlmsg_new(len, GFP_ATOMIC);
4468c2ecf20Sopenharmony_ci	if (!user_skb) {
4478c2ecf20Sopenharmony_ci		err = -ENOMEM;
4488c2ecf20Sopenharmony_ci		goto out;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
4528c2ecf20Sopenharmony_ci			     0, upcall_info->cmd);
4538c2ecf20Sopenharmony_ci	if (!upcall) {
4548c2ecf20Sopenharmony_ci		err = -EINVAL;
4558c2ecf20Sopenharmony_ci		goto out;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci	upcall->dp_ifindex = dp_ifindex;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb);
4608c2ecf20Sopenharmony_ci	if (err)
4618c2ecf20Sopenharmony_ci		goto out;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (upcall_info->userdata)
4648c2ecf20Sopenharmony_ci		__nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
4658c2ecf20Sopenharmony_ci			  nla_len(upcall_info->userdata),
4668c2ecf20Sopenharmony_ci			  nla_data(upcall_info->userdata));
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (upcall_info->egress_tun_info) {
4698c2ecf20Sopenharmony_ci		nla = nla_nest_start_noflag(user_skb,
4708c2ecf20Sopenharmony_ci					    OVS_PACKET_ATTR_EGRESS_TUN_KEY);
4718c2ecf20Sopenharmony_ci		if (!nla) {
4728c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
4738c2ecf20Sopenharmony_ci			goto out;
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci		err = ovs_nla_put_tunnel_info(user_skb,
4768c2ecf20Sopenharmony_ci					      upcall_info->egress_tun_info);
4778c2ecf20Sopenharmony_ci		if (err)
4788c2ecf20Sopenharmony_ci			goto out;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		nla_nest_end(user_skb, nla);
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (upcall_info->actions_len) {
4848c2ecf20Sopenharmony_ci		nla = nla_nest_start_noflag(user_skb, OVS_PACKET_ATTR_ACTIONS);
4858c2ecf20Sopenharmony_ci		if (!nla) {
4868c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
4878c2ecf20Sopenharmony_ci			goto out;
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci		err = ovs_nla_put_actions(upcall_info->actions,
4908c2ecf20Sopenharmony_ci					  upcall_info->actions_len,
4918c2ecf20Sopenharmony_ci					  user_skb);
4928c2ecf20Sopenharmony_ci		if (!err)
4938c2ecf20Sopenharmony_ci			nla_nest_end(user_skb, nla);
4948c2ecf20Sopenharmony_ci		else
4958c2ecf20Sopenharmony_ci			nla_nest_cancel(user_skb, nla);
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* Add OVS_PACKET_ATTR_MRU */
4998c2ecf20Sopenharmony_ci	if (upcall_info->mru &&
5008c2ecf20Sopenharmony_ci	    nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU, upcall_info->mru)) {
5018c2ecf20Sopenharmony_ci		err = -ENOBUFS;
5028c2ecf20Sopenharmony_ci		goto out;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* Add OVS_PACKET_ATTR_LEN when packet is truncated */
5068c2ecf20Sopenharmony_ci	if (cutlen > 0 &&
5078c2ecf20Sopenharmony_ci	    nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
5088c2ecf20Sopenharmony_ci		err = -ENOBUFS;
5098c2ecf20Sopenharmony_ci		goto out;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	/* Add OVS_PACKET_ATTR_HASH */
5138c2ecf20Sopenharmony_ci	hash = skb_get_hash_raw(skb);
5148c2ecf20Sopenharmony_ci	if (skb->sw_hash)
5158c2ecf20Sopenharmony_ci		hash |= OVS_PACKET_HASH_SW_BIT;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (skb->l4_hash)
5188c2ecf20Sopenharmony_ci		hash |= OVS_PACKET_HASH_L4_BIT;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (nla_put(user_skb, OVS_PACKET_ATTR_HASH, sizeof (u64), &hash)) {
5218c2ecf20Sopenharmony_ci		err = -ENOBUFS;
5228c2ecf20Sopenharmony_ci		goto out;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* Only reserve room for attribute header, packet data is added
5268c2ecf20Sopenharmony_ci	 * in skb_zerocopy() */
5278c2ecf20Sopenharmony_ci	if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
5288c2ecf20Sopenharmony_ci		err = -ENOBUFS;
5298c2ecf20Sopenharmony_ci		goto out;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci	nla->nla_len = nla_attr_size(skb->len - cutlen);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
5348c2ecf20Sopenharmony_ci	if (err)
5358c2ecf20Sopenharmony_ci		goto out;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
5388c2ecf20Sopenharmony_ci	pad_packet(dp, user_skb);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
5438c2ecf20Sopenharmony_ci	user_skb = NULL;
5448c2ecf20Sopenharmony_ciout:
5458c2ecf20Sopenharmony_ci	if (err)
5468c2ecf20Sopenharmony_ci		skb_tx_error(skb);
5478c2ecf20Sopenharmony_ci	consume_skb(user_skb);
5488c2ecf20Sopenharmony_ci	consume_skb(nskb);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return err;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
5568c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
5578c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
5588c2ecf20Sopenharmony_ci	struct sw_flow_actions *acts;
5598c2ecf20Sopenharmony_ci	struct sk_buff *packet;
5608c2ecf20Sopenharmony_ci	struct sw_flow *flow;
5618c2ecf20Sopenharmony_ci	struct sw_flow_actions *sf_acts;
5628c2ecf20Sopenharmony_ci	struct datapath *dp;
5638c2ecf20Sopenharmony_ci	struct vport *input_vport;
5648c2ecf20Sopenharmony_ci	u16 mru = 0;
5658c2ecf20Sopenharmony_ci	u64 hash;
5668c2ecf20Sopenharmony_ci	int len;
5678c2ecf20Sopenharmony_ci	int err;
5688c2ecf20Sopenharmony_ci	bool log = !a[OVS_PACKET_ATTR_PROBE];
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	err = -EINVAL;
5718c2ecf20Sopenharmony_ci	if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
5728c2ecf20Sopenharmony_ci	    !a[OVS_PACKET_ATTR_ACTIONS])
5738c2ecf20Sopenharmony_ci		goto err;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	len = nla_len(a[OVS_PACKET_ATTR_PACKET]);
5768c2ecf20Sopenharmony_ci	packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL);
5778c2ecf20Sopenharmony_ci	err = -ENOMEM;
5788c2ecf20Sopenharmony_ci	if (!packet)
5798c2ecf20Sopenharmony_ci		goto err;
5808c2ecf20Sopenharmony_ci	skb_reserve(packet, NET_IP_ALIGN);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* Set packet's mru */
5858c2ecf20Sopenharmony_ci	if (a[OVS_PACKET_ATTR_MRU]) {
5868c2ecf20Sopenharmony_ci		mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
5878c2ecf20Sopenharmony_ci		packet->ignore_df = 1;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	OVS_CB(packet)->mru = mru;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (a[OVS_PACKET_ATTR_HASH]) {
5928c2ecf20Sopenharmony_ci		hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		__skb_set_hash(packet, hash & 0xFFFFFFFFULL,
5958c2ecf20Sopenharmony_ci			       !!(hash & OVS_PACKET_HASH_SW_BIT),
5968c2ecf20Sopenharmony_ci			       !!(hash & OVS_PACKET_HASH_L4_BIT));
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* Build an sw_flow for sending this packet. */
6008c2ecf20Sopenharmony_ci	flow = ovs_flow_alloc();
6018c2ecf20Sopenharmony_ci	err = PTR_ERR(flow);
6028c2ecf20Sopenharmony_ci	if (IS_ERR(flow))
6038c2ecf20Sopenharmony_ci		goto err_kfree_skb;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY],
6068c2ecf20Sopenharmony_ci					     packet, &flow->key, log);
6078c2ecf20Sopenharmony_ci	if (err)
6088c2ecf20Sopenharmony_ci		goto err_flow_free;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS],
6118c2ecf20Sopenharmony_ci				   &flow->key, &acts, log);
6128c2ecf20Sopenharmony_ci	if (err)
6138c2ecf20Sopenharmony_ci		goto err_flow_free;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	rcu_assign_pointer(flow->sf_acts, acts);
6168c2ecf20Sopenharmony_ci	packet->priority = flow->key.phy.priority;
6178c2ecf20Sopenharmony_ci	packet->mark = flow->key.phy.skb_mark;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	rcu_read_lock();
6208c2ecf20Sopenharmony_ci	dp = get_dp_rcu(net, ovs_header->dp_ifindex);
6218c2ecf20Sopenharmony_ci	err = -ENODEV;
6228c2ecf20Sopenharmony_ci	if (!dp)
6238c2ecf20Sopenharmony_ci		goto err_unlock;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port);
6268c2ecf20Sopenharmony_ci	if (!input_vport)
6278c2ecf20Sopenharmony_ci		input_vport = ovs_vport_rcu(dp, OVSP_LOCAL);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!input_vport)
6308c2ecf20Sopenharmony_ci		goto err_unlock;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	packet->dev = input_vport->dev;
6338c2ecf20Sopenharmony_ci	OVS_CB(packet)->input_vport = input_vport;
6348c2ecf20Sopenharmony_ci	sf_acts = rcu_dereference(flow->sf_acts);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	local_bh_disable();
6378c2ecf20Sopenharmony_ci	err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
6388c2ecf20Sopenharmony_ci	local_bh_enable();
6398c2ecf20Sopenharmony_ci	rcu_read_unlock();
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	ovs_flow_free(flow, false);
6428c2ecf20Sopenharmony_ci	return err;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cierr_unlock:
6458c2ecf20Sopenharmony_ci	rcu_read_unlock();
6468c2ecf20Sopenharmony_cierr_flow_free:
6478c2ecf20Sopenharmony_ci	ovs_flow_free(flow, false);
6488c2ecf20Sopenharmony_cierr_kfree_skb:
6498c2ecf20Sopenharmony_ci	kfree_skb(packet);
6508c2ecf20Sopenharmony_cierr:
6518c2ecf20Sopenharmony_ci	return err;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
6558c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
6568c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
6578c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
6588c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
6598c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
6608c2ecf20Sopenharmony_ci	[OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
6618c2ecf20Sopenharmony_ci};
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic const struct genl_small_ops dp_packet_genl_ops[] = {
6648c2ecf20Sopenharmony_ci	{ .cmd = OVS_PACKET_CMD_EXECUTE,
6658c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6668c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
6678c2ecf20Sopenharmony_ci	  .doit = ovs_packet_cmd_execute
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci};
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic struct genl_family dp_packet_genl_family __ro_after_init = {
6728c2ecf20Sopenharmony_ci	.hdrsize = sizeof(struct ovs_header),
6738c2ecf20Sopenharmony_ci	.name = OVS_PACKET_FAMILY,
6748c2ecf20Sopenharmony_ci	.version = OVS_PACKET_VERSION,
6758c2ecf20Sopenharmony_ci	.maxattr = OVS_PACKET_ATTR_MAX,
6768c2ecf20Sopenharmony_ci	.policy = packet_policy,
6778c2ecf20Sopenharmony_ci	.netnsok = true,
6788c2ecf20Sopenharmony_ci	.parallel_ops = true,
6798c2ecf20Sopenharmony_ci	.small_ops = dp_packet_genl_ops,
6808c2ecf20Sopenharmony_ci	.n_small_ops = ARRAY_SIZE(dp_packet_genl_ops),
6818c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
6828c2ecf20Sopenharmony_ci};
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats,
6858c2ecf20Sopenharmony_ci			 struct ovs_dp_megaflow_stats *mega_stats)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	int i;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	memset(mega_stats, 0, sizeof(*mega_stats));
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	stats->n_flows = ovs_flow_tbl_count(&dp->table);
6928c2ecf20Sopenharmony_ci	mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	stats->n_hit = stats->n_missed = stats->n_lost = 0;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
6978c2ecf20Sopenharmony_ci		const struct dp_stats_percpu *percpu_stats;
6988c2ecf20Sopenharmony_ci		struct dp_stats_percpu local_stats;
6998c2ecf20Sopenharmony_ci		unsigned int start;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		percpu_stats = per_cpu_ptr(dp->stats_percpu, i);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		do {
7048c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
7058c2ecf20Sopenharmony_ci			local_stats = *percpu_stats;
7068c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		stats->n_hit += local_stats.n_hit;
7098c2ecf20Sopenharmony_ci		stats->n_missed += local_stats.n_missed;
7108c2ecf20Sopenharmony_ci		stats->n_lost += local_stats.n_lost;
7118c2ecf20Sopenharmony_ci		mega_stats->n_mask_hit += local_stats.n_mask_hit;
7128c2ecf20Sopenharmony_ci		mega_stats->n_cache_hit += local_stats.n_cache_hit;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic bool should_fill_key(const struct sw_flow_id *sfid, uint32_t ufid_flags)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	return ovs_identifier_is_ufid(sfid) &&
7198c2ecf20Sopenharmony_ci	       !(ufid_flags & OVS_UFID_F_OMIT_KEY);
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic bool should_fill_mask(uint32_t ufid_flags)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	return !(ufid_flags & OVS_UFID_F_OMIT_MASK);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic bool should_fill_actions(uint32_t ufid_flags)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	return !(ufid_flags & OVS_UFID_F_OMIT_ACTIONS);
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistatic size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
7338c2ecf20Sopenharmony_ci				    const struct sw_flow_id *sfid,
7348c2ecf20Sopenharmony_ci				    uint32_t ufid_flags)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	size_t len = NLMSG_ALIGN(sizeof(struct ovs_header));
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	/* OVS_FLOW_ATTR_UFID, or unmasked flow key as fallback
7398c2ecf20Sopenharmony_ci	 * see ovs_nla_put_identifier()
7408c2ecf20Sopenharmony_ci	 */
7418c2ecf20Sopenharmony_ci	if (sfid && ovs_identifier_is_ufid(sfid))
7428c2ecf20Sopenharmony_ci		len += nla_total_size(sfid->ufid_len);
7438c2ecf20Sopenharmony_ci	else
7448c2ecf20Sopenharmony_ci		len += nla_total_size(ovs_key_attr_size());
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/* OVS_FLOW_ATTR_KEY */
7478c2ecf20Sopenharmony_ci	if (!sfid || should_fill_key(sfid, ufid_flags))
7488c2ecf20Sopenharmony_ci		len += nla_total_size(ovs_key_attr_size());
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* OVS_FLOW_ATTR_MASK */
7518c2ecf20Sopenharmony_ci	if (should_fill_mask(ufid_flags))
7528c2ecf20Sopenharmony_ci		len += nla_total_size(ovs_key_attr_size());
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/* OVS_FLOW_ATTR_ACTIONS */
7558c2ecf20Sopenharmony_ci	if (should_fill_actions(ufid_flags))
7568c2ecf20Sopenharmony_ci		len += nla_total_size(acts->orig_len);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return len
7598c2ecf20Sopenharmony_ci		+ nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
7608c2ecf20Sopenharmony_ci		+ nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
7618c2ecf20Sopenharmony_ci		+ nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
7658c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
7668c2ecf20Sopenharmony_ci				   struct sk_buff *skb)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct ovs_flow_stats stats;
7698c2ecf20Sopenharmony_ci	__be16 tcp_flags;
7708c2ecf20Sopenharmony_ci	unsigned long used;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (used &&
7758c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used),
7768c2ecf20Sopenharmony_ci			      OVS_FLOW_ATTR_PAD))
7778c2ecf20Sopenharmony_ci		return -EMSGSIZE;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (stats.n_packets &&
7808c2ecf20Sopenharmony_ci	    nla_put_64bit(skb, OVS_FLOW_ATTR_STATS,
7818c2ecf20Sopenharmony_ci			  sizeof(struct ovs_flow_stats), &stats,
7828c2ecf20Sopenharmony_ci			  OVS_FLOW_ATTR_PAD))
7838c2ecf20Sopenharmony_ci		return -EMSGSIZE;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	if ((u8)ntohs(tcp_flags) &&
7868c2ecf20Sopenharmony_ci	     nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
7878c2ecf20Sopenharmony_ci		return -EMSGSIZE;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	return 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
7938c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_fill_actions(const struct sw_flow *flow,
7948c2ecf20Sopenharmony_ci				     struct sk_buff *skb, int skb_orig_len)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct nlattr *start;
7978c2ecf20Sopenharmony_ci	int err;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
8008c2ecf20Sopenharmony_ci	 * this is the first flow to be dumped into 'skb'.  This is unusual for
8018c2ecf20Sopenharmony_ci	 * Netlink but individual action lists can be longer than
8028c2ecf20Sopenharmony_ci	 * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this.
8038c2ecf20Sopenharmony_ci	 * The userspace caller can always fetch the actions separately if it
8048c2ecf20Sopenharmony_ci	 * really wants them.  (Most userspace callers in fact don't care.)
8058c2ecf20Sopenharmony_ci	 *
8068c2ecf20Sopenharmony_ci	 * This can only fail for dump operations because the skb is always
8078c2ecf20Sopenharmony_ci	 * properly sized for single flows.
8088c2ecf20Sopenharmony_ci	 */
8098c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_FLOW_ATTR_ACTIONS);
8108c2ecf20Sopenharmony_ci	if (start) {
8118c2ecf20Sopenharmony_ci		const struct sw_flow_actions *sf_acts;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		sf_acts = rcu_dereference_ovsl(flow->sf_acts);
8148c2ecf20Sopenharmony_ci		err = ovs_nla_put_actions(sf_acts->actions,
8158c2ecf20Sopenharmony_ci					  sf_acts->actions_len, skb);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci		if (!err)
8188c2ecf20Sopenharmony_ci			nla_nest_end(skb, start);
8198c2ecf20Sopenharmony_ci		else {
8208c2ecf20Sopenharmony_ci			if (skb_orig_len)
8218c2ecf20Sopenharmony_ci				return err;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci			nla_nest_cancel(skb, start);
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci	} else if (skb_orig_len) {
8268c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	return 0;
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
8338c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
8348c2ecf20Sopenharmony_ci				  struct sk_buff *skb, u32 portid,
8358c2ecf20Sopenharmony_ci				  u32 seq, u32 flags, u8 cmd, u32 ufid_flags)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	const int skb_orig_len = skb->len;
8388c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header;
8398c2ecf20Sopenharmony_ci	int err;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family,
8428c2ecf20Sopenharmony_ci				 flags, cmd);
8438c2ecf20Sopenharmony_ci	if (!ovs_header)
8448c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	ovs_header->dp_ifindex = dp_ifindex;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	err = ovs_nla_put_identifier(flow, skb);
8498c2ecf20Sopenharmony_ci	if (err)
8508c2ecf20Sopenharmony_ci		goto error;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (should_fill_key(&flow->id, ufid_flags)) {
8538c2ecf20Sopenharmony_ci		err = ovs_nla_put_masked_key(flow, skb);
8548c2ecf20Sopenharmony_ci		if (err)
8558c2ecf20Sopenharmony_ci			goto error;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (should_fill_mask(ufid_flags)) {
8598c2ecf20Sopenharmony_ci		err = ovs_nla_put_mask(flow, skb);
8608c2ecf20Sopenharmony_ci		if (err)
8618c2ecf20Sopenharmony_ci			goto error;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	err = ovs_flow_cmd_fill_stats(flow, skb);
8658c2ecf20Sopenharmony_ci	if (err)
8668c2ecf20Sopenharmony_ci		goto error;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (should_fill_actions(ufid_flags)) {
8698c2ecf20Sopenharmony_ci		err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len);
8708c2ecf20Sopenharmony_ci		if (err)
8718c2ecf20Sopenharmony_ci			goto error;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	genlmsg_end(skb, ovs_header);
8758c2ecf20Sopenharmony_ci	return 0;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cierror:
8788c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, ovs_header);
8798c2ecf20Sopenharmony_ci	return err;
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci/* May not be called with RCU read lock. */
8838c2ecf20Sopenharmony_cistatic struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts,
8848c2ecf20Sopenharmony_ci					       const struct sw_flow_id *sfid,
8858c2ecf20Sopenharmony_ci					       struct genl_info *info,
8868c2ecf20Sopenharmony_ci					       bool always,
8878c2ecf20Sopenharmony_ci					       uint32_t ufid_flags)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8908c2ecf20Sopenharmony_ci	size_t len;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0))
8938c2ecf20Sopenharmony_ci		return NULL;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
8968c2ecf20Sopenharmony_ci	skb = genlmsg_new(len, GFP_KERNEL);
8978c2ecf20Sopenharmony_ci	if (!skb)
8988c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	return skb;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci/* Called with ovs_mutex. */
9048c2ecf20Sopenharmony_cistatic struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
9058c2ecf20Sopenharmony_ci					       int dp_ifindex,
9068c2ecf20Sopenharmony_ci					       struct genl_info *info, u8 cmd,
9078c2ecf20Sopenharmony_ci					       bool always, u32 ufid_flags)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9108c2ecf20Sopenharmony_ci	int retval;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts),
9138c2ecf20Sopenharmony_ci				      &flow->id, info, always, ufid_flags);
9148c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(skb))
9158c2ecf20Sopenharmony_ci		return skb;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
9188c2ecf20Sopenharmony_ci					info->snd_portid, info->snd_seq, 0,
9198c2ecf20Sopenharmony_ci					cmd, ufid_flags);
9208c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(retval < 0)) {
9218c2ecf20Sopenharmony_ci		kfree_skb(skb);
9228c2ecf20Sopenharmony_ci		skb = ERR_PTR(retval);
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci	return skb;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
9308c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
9318c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
9328c2ecf20Sopenharmony_ci	struct sw_flow *flow = NULL, *new_flow;
9338c2ecf20Sopenharmony_ci	struct sw_flow_mask mask;
9348c2ecf20Sopenharmony_ci	struct sk_buff *reply;
9358c2ecf20Sopenharmony_ci	struct datapath *dp;
9368c2ecf20Sopenharmony_ci	struct sw_flow_key *key;
9378c2ecf20Sopenharmony_ci	struct sw_flow_actions *acts;
9388c2ecf20Sopenharmony_ci	struct sw_flow_match match;
9398c2ecf20Sopenharmony_ci	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
9408c2ecf20Sopenharmony_ci	int error;
9418c2ecf20Sopenharmony_ci	bool log = !a[OVS_FLOW_ATTR_PROBE];
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* Must have key and actions. */
9448c2ecf20Sopenharmony_ci	error = -EINVAL;
9458c2ecf20Sopenharmony_ci	if (!a[OVS_FLOW_ATTR_KEY]) {
9468c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Flow key attr not present in new flow.");
9478c2ecf20Sopenharmony_ci		goto error;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci	if (!a[OVS_FLOW_ATTR_ACTIONS]) {
9508c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Flow actions attr not present in new flow.");
9518c2ecf20Sopenharmony_ci		goto error;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* Most of the time we need to allocate a new flow, do it before
9558c2ecf20Sopenharmony_ci	 * locking.
9568c2ecf20Sopenharmony_ci	 */
9578c2ecf20Sopenharmony_ci	new_flow = ovs_flow_alloc();
9588c2ecf20Sopenharmony_ci	if (IS_ERR(new_flow)) {
9598c2ecf20Sopenharmony_ci		error = PTR_ERR(new_flow);
9608c2ecf20Sopenharmony_ci		goto error;
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	/* Extract key. */
9648c2ecf20Sopenharmony_ci	key = kzalloc(sizeof(*key), GFP_KERNEL);
9658c2ecf20Sopenharmony_ci	if (!key) {
9668c2ecf20Sopenharmony_ci		error = -ENOMEM;
9678c2ecf20Sopenharmony_ci		goto err_kfree_flow;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	ovs_match_init(&match, key, false, &mask);
9718c2ecf20Sopenharmony_ci	error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
9728c2ecf20Sopenharmony_ci				  a[OVS_FLOW_ATTR_MASK], log);
9738c2ecf20Sopenharmony_ci	if (error)
9748c2ecf20Sopenharmony_ci		goto err_kfree_key;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	ovs_flow_mask_key(&new_flow->key, key, true, &mask);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	/* Extract flow identifier. */
9798c2ecf20Sopenharmony_ci	error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
9808c2ecf20Sopenharmony_ci				       key, log);
9818c2ecf20Sopenharmony_ci	if (error)
9828c2ecf20Sopenharmony_ci		goto err_kfree_key;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	/* Validate actions. */
9858c2ecf20Sopenharmony_ci	error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
9868c2ecf20Sopenharmony_ci				     &new_flow->key, &acts, log);
9878c2ecf20Sopenharmony_ci	if (error) {
9888c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
9898c2ecf20Sopenharmony_ci		goto err_kfree_key;
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
9938c2ecf20Sopenharmony_ci					ufid_flags);
9948c2ecf20Sopenharmony_ci	if (IS_ERR(reply)) {
9958c2ecf20Sopenharmony_ci		error = PTR_ERR(reply);
9968c2ecf20Sopenharmony_ci		goto err_kfree_acts;
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	ovs_lock();
10008c2ecf20Sopenharmony_ci	dp = get_dp(net, ovs_header->dp_ifindex);
10018c2ecf20Sopenharmony_ci	if (unlikely(!dp)) {
10028c2ecf20Sopenharmony_ci		error = -ENODEV;
10038c2ecf20Sopenharmony_ci		goto err_unlock_ovs;
10048c2ecf20Sopenharmony_ci	}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	/* Check if this is a duplicate flow */
10078c2ecf20Sopenharmony_ci	if (ovs_identifier_is_ufid(&new_flow->id))
10088c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
10098c2ecf20Sopenharmony_ci	if (!flow)
10108c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup(&dp->table, key);
10118c2ecf20Sopenharmony_ci	if (likely(!flow)) {
10128c2ecf20Sopenharmony_ci		rcu_assign_pointer(new_flow->sf_acts, acts);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		/* Put flow in bucket. */
10158c2ecf20Sopenharmony_ci		error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
10168c2ecf20Sopenharmony_ci		if (unlikely(error)) {
10178c2ecf20Sopenharmony_ci			acts = NULL;
10188c2ecf20Sopenharmony_ci			goto err_unlock_ovs;
10198c2ecf20Sopenharmony_ci		}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci		if (unlikely(reply)) {
10228c2ecf20Sopenharmony_ci			error = ovs_flow_cmd_fill_info(new_flow,
10238c2ecf20Sopenharmony_ci						       ovs_header->dp_ifindex,
10248c2ecf20Sopenharmony_ci						       reply, info->snd_portid,
10258c2ecf20Sopenharmony_ci						       info->snd_seq, 0,
10268c2ecf20Sopenharmony_ci						       OVS_FLOW_CMD_NEW,
10278c2ecf20Sopenharmony_ci						       ufid_flags);
10288c2ecf20Sopenharmony_ci			BUG_ON(error < 0);
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci		ovs_unlock();
10318c2ecf20Sopenharmony_ci	} else {
10328c2ecf20Sopenharmony_ci		struct sw_flow_actions *old_acts;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		/* Bail out if we're not allowed to modify an existing flow.
10358c2ecf20Sopenharmony_ci		 * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
10368c2ecf20Sopenharmony_ci		 * because Generic Netlink treats the latter as a dump
10378c2ecf20Sopenharmony_ci		 * request.  We also accept NLM_F_EXCL in case that bug ever
10388c2ecf20Sopenharmony_ci		 * gets fixed.
10398c2ecf20Sopenharmony_ci		 */
10408c2ecf20Sopenharmony_ci		if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
10418c2ecf20Sopenharmony_ci							 | NLM_F_EXCL))) {
10428c2ecf20Sopenharmony_ci			error = -EEXIST;
10438c2ecf20Sopenharmony_ci			goto err_unlock_ovs;
10448c2ecf20Sopenharmony_ci		}
10458c2ecf20Sopenharmony_ci		/* The flow identifier has to be the same for flow updates.
10468c2ecf20Sopenharmony_ci		 * Look for any overlapping flow.
10478c2ecf20Sopenharmony_ci		 */
10488c2ecf20Sopenharmony_ci		if (unlikely(!ovs_flow_cmp(flow, &match))) {
10498c2ecf20Sopenharmony_ci			if (ovs_identifier_is_key(&flow->id))
10508c2ecf20Sopenharmony_ci				flow = ovs_flow_tbl_lookup_exact(&dp->table,
10518c2ecf20Sopenharmony_ci								 &match);
10528c2ecf20Sopenharmony_ci			else /* UFID matches but key is different */
10538c2ecf20Sopenharmony_ci				flow = NULL;
10548c2ecf20Sopenharmony_ci			if (!flow) {
10558c2ecf20Sopenharmony_ci				error = -ENOENT;
10568c2ecf20Sopenharmony_ci				goto err_unlock_ovs;
10578c2ecf20Sopenharmony_ci			}
10588c2ecf20Sopenharmony_ci		}
10598c2ecf20Sopenharmony_ci		/* Update actions. */
10608c2ecf20Sopenharmony_ci		old_acts = ovsl_dereference(flow->sf_acts);
10618c2ecf20Sopenharmony_ci		rcu_assign_pointer(flow->sf_acts, acts);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		if (unlikely(reply)) {
10648c2ecf20Sopenharmony_ci			error = ovs_flow_cmd_fill_info(flow,
10658c2ecf20Sopenharmony_ci						       ovs_header->dp_ifindex,
10668c2ecf20Sopenharmony_ci						       reply, info->snd_portid,
10678c2ecf20Sopenharmony_ci						       info->snd_seq, 0,
10688c2ecf20Sopenharmony_ci						       OVS_FLOW_CMD_NEW,
10698c2ecf20Sopenharmony_ci						       ufid_flags);
10708c2ecf20Sopenharmony_ci			BUG_ON(error < 0);
10718c2ecf20Sopenharmony_ci		}
10728c2ecf20Sopenharmony_ci		ovs_unlock();
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci		ovs_nla_free_flow_actions_rcu(old_acts);
10758c2ecf20Sopenharmony_ci		ovs_flow_free(new_flow, false);
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (reply)
10798c2ecf20Sopenharmony_ci		ovs_notify(&dp_flow_genl_family, reply, info);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	kfree(key);
10828c2ecf20Sopenharmony_ci	return 0;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_cierr_unlock_ovs:
10858c2ecf20Sopenharmony_ci	ovs_unlock();
10868c2ecf20Sopenharmony_ci	kfree_skb(reply);
10878c2ecf20Sopenharmony_cierr_kfree_acts:
10888c2ecf20Sopenharmony_ci	ovs_nla_free_flow_actions(acts);
10898c2ecf20Sopenharmony_cierr_kfree_key:
10908c2ecf20Sopenharmony_ci	kfree(key);
10918c2ecf20Sopenharmony_cierr_kfree_flow:
10928c2ecf20Sopenharmony_ci	ovs_flow_free(new_flow, false);
10938c2ecf20Sopenharmony_cierror:
10948c2ecf20Sopenharmony_ci	return error;
10958c2ecf20Sopenharmony_ci}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci/* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
10988c2ecf20Sopenharmony_cistatic noinline_for_stack
10998c2ecf20Sopenharmony_cistruct sw_flow_actions *get_flow_actions(struct net *net,
11008c2ecf20Sopenharmony_ci					 const struct nlattr *a,
11018c2ecf20Sopenharmony_ci					 const struct sw_flow_key *key,
11028c2ecf20Sopenharmony_ci					 const struct sw_flow_mask *mask,
11038c2ecf20Sopenharmony_ci					 bool log)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	struct sw_flow_actions *acts;
11068c2ecf20Sopenharmony_ci	struct sw_flow_key masked_key;
11078c2ecf20Sopenharmony_ci	int error;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	ovs_flow_mask_key(&masked_key, key, true, mask);
11108c2ecf20Sopenharmony_ci	error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
11118c2ecf20Sopenharmony_ci	if (error) {
11128c2ecf20Sopenharmony_ci		OVS_NLERR(log,
11138c2ecf20Sopenharmony_ci			  "Actions may not be safe on all matching packets");
11148c2ecf20Sopenharmony_ci		return ERR_PTR(error);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return acts;
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/* Factor out match-init and action-copy to avoid
11218c2ecf20Sopenharmony_ci * "Wframe-larger-than=1024" warning. Because mask is only
11228c2ecf20Sopenharmony_ci * used to get actions, we new a function to save some
11238c2ecf20Sopenharmony_ci * stack space.
11248c2ecf20Sopenharmony_ci *
11258c2ecf20Sopenharmony_ci * If there are not key and action attrs, we return 0
11268c2ecf20Sopenharmony_ci * directly. In the case, the caller will also not use the
11278c2ecf20Sopenharmony_ci * match as before. If there is action attr, we try to get
11288c2ecf20Sopenharmony_ci * actions and save them to *acts. Before returning from
11298c2ecf20Sopenharmony_ci * the function, we reset the match->mask pointer. Because
11308c2ecf20Sopenharmony_ci * we should not to return match object with dangling reference
11318c2ecf20Sopenharmony_ci * to mask.
11328c2ecf20Sopenharmony_ci * */
11338c2ecf20Sopenharmony_cistatic noinline_for_stack int
11348c2ecf20Sopenharmony_ciovs_nla_init_match_and_action(struct net *net,
11358c2ecf20Sopenharmony_ci			      struct sw_flow_match *match,
11368c2ecf20Sopenharmony_ci			      struct sw_flow_key *key,
11378c2ecf20Sopenharmony_ci			      struct nlattr **a,
11388c2ecf20Sopenharmony_ci			      struct sw_flow_actions **acts,
11398c2ecf20Sopenharmony_ci			      bool log)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct sw_flow_mask mask;
11428c2ecf20Sopenharmony_ci	int error = 0;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	if (a[OVS_FLOW_ATTR_KEY]) {
11458c2ecf20Sopenharmony_ci		ovs_match_init(match, key, true, &mask);
11468c2ecf20Sopenharmony_ci		error = ovs_nla_get_match(net, match, a[OVS_FLOW_ATTR_KEY],
11478c2ecf20Sopenharmony_ci					  a[OVS_FLOW_ATTR_MASK], log);
11488c2ecf20Sopenharmony_ci		if (error)
11498c2ecf20Sopenharmony_ci			goto error;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (a[OVS_FLOW_ATTR_ACTIONS]) {
11538c2ecf20Sopenharmony_ci		if (!a[OVS_FLOW_ATTR_KEY]) {
11548c2ecf20Sopenharmony_ci			OVS_NLERR(log,
11558c2ecf20Sopenharmony_ci				  "Flow key attribute not present in set flow.");
11568c2ecf20Sopenharmony_ci			error = -EINVAL;
11578c2ecf20Sopenharmony_ci			goto error;
11588c2ecf20Sopenharmony_ci		}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci		*acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key,
11618c2ecf20Sopenharmony_ci					 &mask, log);
11628c2ecf20Sopenharmony_ci		if (IS_ERR(*acts)) {
11638c2ecf20Sopenharmony_ci			error = PTR_ERR(*acts);
11648c2ecf20Sopenharmony_ci			goto error;
11658c2ecf20Sopenharmony_ci		}
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	/* On success, error is 0. */
11698c2ecf20Sopenharmony_cierror:
11708c2ecf20Sopenharmony_ci	match->mask = NULL;
11718c2ecf20Sopenharmony_ci	return error;
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
11778c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
11788c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
11798c2ecf20Sopenharmony_ci	struct sw_flow_key key;
11808c2ecf20Sopenharmony_ci	struct sw_flow *flow;
11818c2ecf20Sopenharmony_ci	struct sk_buff *reply = NULL;
11828c2ecf20Sopenharmony_ci	struct datapath *dp;
11838c2ecf20Sopenharmony_ci	struct sw_flow_actions *old_acts = NULL, *acts = NULL;
11848c2ecf20Sopenharmony_ci	struct sw_flow_match match;
11858c2ecf20Sopenharmony_ci	struct sw_flow_id sfid;
11868c2ecf20Sopenharmony_ci	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
11878c2ecf20Sopenharmony_ci	int error = 0;
11888c2ecf20Sopenharmony_ci	bool log = !a[OVS_FLOW_ATTR_PROBE];
11898c2ecf20Sopenharmony_ci	bool ufid_present;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
11928c2ecf20Sopenharmony_ci	if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) {
11938c2ecf20Sopenharmony_ci		OVS_NLERR(log,
11948c2ecf20Sopenharmony_ci			  "Flow set message rejected, Key attribute missing.");
11958c2ecf20Sopenharmony_ci		return -EINVAL;
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	error = ovs_nla_init_match_and_action(net, &match, &key, a,
11998c2ecf20Sopenharmony_ci					      &acts, log);
12008c2ecf20Sopenharmony_ci	if (error)
12018c2ecf20Sopenharmony_ci		goto error;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (acts) {
12048c2ecf20Sopenharmony_ci		/* Can allocate before locking if have acts. */
12058c2ecf20Sopenharmony_ci		reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false,
12068c2ecf20Sopenharmony_ci						ufid_flags);
12078c2ecf20Sopenharmony_ci		if (IS_ERR(reply)) {
12088c2ecf20Sopenharmony_ci			error = PTR_ERR(reply);
12098c2ecf20Sopenharmony_ci			goto err_kfree_acts;
12108c2ecf20Sopenharmony_ci		}
12118c2ecf20Sopenharmony_ci	}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	ovs_lock();
12148c2ecf20Sopenharmony_ci	dp = get_dp(net, ovs_header->dp_ifindex);
12158c2ecf20Sopenharmony_ci	if (unlikely(!dp)) {
12168c2ecf20Sopenharmony_ci		error = -ENODEV;
12178c2ecf20Sopenharmony_ci		goto err_unlock_ovs;
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci	/* Check that the flow exists. */
12208c2ecf20Sopenharmony_ci	if (ufid_present)
12218c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &sfid);
12228c2ecf20Sopenharmony_ci	else
12238c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
12248c2ecf20Sopenharmony_ci	if (unlikely(!flow)) {
12258c2ecf20Sopenharmony_ci		error = -ENOENT;
12268c2ecf20Sopenharmony_ci		goto err_unlock_ovs;
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/* Update actions, if present. */
12308c2ecf20Sopenharmony_ci	if (likely(acts)) {
12318c2ecf20Sopenharmony_ci		old_acts = ovsl_dereference(flow->sf_acts);
12328c2ecf20Sopenharmony_ci		rcu_assign_pointer(flow->sf_acts, acts);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci		if (unlikely(reply)) {
12358c2ecf20Sopenharmony_ci			error = ovs_flow_cmd_fill_info(flow,
12368c2ecf20Sopenharmony_ci						       ovs_header->dp_ifindex,
12378c2ecf20Sopenharmony_ci						       reply, info->snd_portid,
12388c2ecf20Sopenharmony_ci						       info->snd_seq, 0,
12398c2ecf20Sopenharmony_ci						       OVS_FLOW_CMD_SET,
12408c2ecf20Sopenharmony_ci						       ufid_flags);
12418c2ecf20Sopenharmony_ci			BUG_ON(error < 0);
12428c2ecf20Sopenharmony_ci		}
12438c2ecf20Sopenharmony_ci	} else {
12448c2ecf20Sopenharmony_ci		/* Could not alloc without acts before locking. */
12458c2ecf20Sopenharmony_ci		reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
12468c2ecf20Sopenharmony_ci						info, OVS_FLOW_CMD_SET, false,
12478c2ecf20Sopenharmony_ci						ufid_flags);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci		if (IS_ERR(reply)) {
12508c2ecf20Sopenharmony_ci			error = PTR_ERR(reply);
12518c2ecf20Sopenharmony_ci			goto err_unlock_ovs;
12528c2ecf20Sopenharmony_ci		}
12538c2ecf20Sopenharmony_ci	}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	/* Clear stats. */
12568c2ecf20Sopenharmony_ci	if (a[OVS_FLOW_ATTR_CLEAR])
12578c2ecf20Sopenharmony_ci		ovs_flow_stats_clear(flow);
12588c2ecf20Sopenharmony_ci	ovs_unlock();
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	if (reply)
12618c2ecf20Sopenharmony_ci		ovs_notify(&dp_flow_genl_family, reply, info);
12628c2ecf20Sopenharmony_ci	if (old_acts)
12638c2ecf20Sopenharmony_ci		ovs_nla_free_flow_actions_rcu(old_acts);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	return 0;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cierr_unlock_ovs:
12688c2ecf20Sopenharmony_ci	ovs_unlock();
12698c2ecf20Sopenharmony_ci	kfree_skb(reply);
12708c2ecf20Sopenharmony_cierr_kfree_acts:
12718c2ecf20Sopenharmony_ci	ovs_nla_free_flow_actions(acts);
12728c2ecf20Sopenharmony_cierror:
12738c2ecf20Sopenharmony_ci	return error;
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
12798c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
12808c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
12818c2ecf20Sopenharmony_ci	struct sw_flow_key key;
12828c2ecf20Sopenharmony_ci	struct sk_buff *reply;
12838c2ecf20Sopenharmony_ci	struct sw_flow *flow;
12848c2ecf20Sopenharmony_ci	struct datapath *dp;
12858c2ecf20Sopenharmony_ci	struct sw_flow_match match;
12868c2ecf20Sopenharmony_ci	struct sw_flow_id ufid;
12878c2ecf20Sopenharmony_ci	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
12888c2ecf20Sopenharmony_ci	int err = 0;
12898c2ecf20Sopenharmony_ci	bool log = !a[OVS_FLOW_ATTR_PROBE];
12908c2ecf20Sopenharmony_ci	bool ufid_present;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
12938c2ecf20Sopenharmony_ci	if (a[OVS_FLOW_ATTR_KEY]) {
12948c2ecf20Sopenharmony_ci		ovs_match_init(&match, &key, true, NULL);
12958c2ecf20Sopenharmony_ci		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
12968c2ecf20Sopenharmony_ci					log);
12978c2ecf20Sopenharmony_ci	} else if (!ufid_present) {
12988c2ecf20Sopenharmony_ci		OVS_NLERR(log,
12998c2ecf20Sopenharmony_ci			  "Flow get message rejected, Key attribute missing.");
13008c2ecf20Sopenharmony_ci		err = -EINVAL;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci	if (err)
13038c2ecf20Sopenharmony_ci		return err;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	ovs_lock();
13068c2ecf20Sopenharmony_ci	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
13078c2ecf20Sopenharmony_ci	if (!dp) {
13088c2ecf20Sopenharmony_ci		err = -ENODEV;
13098c2ecf20Sopenharmony_ci		goto unlock;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (ufid_present)
13138c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
13148c2ecf20Sopenharmony_ci	else
13158c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
13168c2ecf20Sopenharmony_ci	if (!flow) {
13178c2ecf20Sopenharmony_ci		err = -ENOENT;
13188c2ecf20Sopenharmony_ci		goto unlock;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
13228c2ecf20Sopenharmony_ci					OVS_FLOW_CMD_GET, true, ufid_flags);
13238c2ecf20Sopenharmony_ci	if (IS_ERR(reply)) {
13248c2ecf20Sopenharmony_ci		err = PTR_ERR(reply);
13258c2ecf20Sopenharmony_ci		goto unlock;
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	ovs_unlock();
13298c2ecf20Sopenharmony_ci	return genlmsg_reply(reply, info);
13308c2ecf20Sopenharmony_ciunlock:
13318c2ecf20Sopenharmony_ci	ovs_unlock();
13328c2ecf20Sopenharmony_ci	return err;
13338c2ecf20Sopenharmony_ci}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
13368c2ecf20Sopenharmony_ci{
13378c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
13388c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
13398c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
13408c2ecf20Sopenharmony_ci	struct sw_flow_key key;
13418c2ecf20Sopenharmony_ci	struct sk_buff *reply;
13428c2ecf20Sopenharmony_ci	struct sw_flow *flow = NULL;
13438c2ecf20Sopenharmony_ci	struct datapath *dp;
13448c2ecf20Sopenharmony_ci	struct sw_flow_match match;
13458c2ecf20Sopenharmony_ci	struct sw_flow_id ufid;
13468c2ecf20Sopenharmony_ci	u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
13478c2ecf20Sopenharmony_ci	int err;
13488c2ecf20Sopenharmony_ci	bool log = !a[OVS_FLOW_ATTR_PROBE];
13498c2ecf20Sopenharmony_ci	bool ufid_present;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
13528c2ecf20Sopenharmony_ci	if (a[OVS_FLOW_ATTR_KEY]) {
13538c2ecf20Sopenharmony_ci		ovs_match_init(&match, &key, true, NULL);
13548c2ecf20Sopenharmony_ci		err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
13558c2ecf20Sopenharmony_ci					NULL, log);
13568c2ecf20Sopenharmony_ci		if (unlikely(err))
13578c2ecf20Sopenharmony_ci			return err;
13588c2ecf20Sopenharmony_ci	}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	ovs_lock();
13618c2ecf20Sopenharmony_ci	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
13628c2ecf20Sopenharmony_ci	if (unlikely(!dp)) {
13638c2ecf20Sopenharmony_ci		err = -ENODEV;
13648c2ecf20Sopenharmony_ci		goto unlock;
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (unlikely(!a[OVS_FLOW_ATTR_KEY] && !ufid_present)) {
13688c2ecf20Sopenharmony_ci		err = ovs_flow_tbl_flush(&dp->table);
13698c2ecf20Sopenharmony_ci		goto unlock;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	if (ufid_present)
13738c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid);
13748c2ecf20Sopenharmony_ci	else
13758c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
13768c2ecf20Sopenharmony_ci	if (unlikely(!flow)) {
13778c2ecf20Sopenharmony_ci		err = -ENOENT;
13788c2ecf20Sopenharmony_ci		goto unlock;
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	ovs_flow_tbl_remove(&dp->table, flow);
13828c2ecf20Sopenharmony_ci	ovs_unlock();
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts,
13858c2ecf20Sopenharmony_ci					&flow->id, info, false, ufid_flags);
13868c2ecf20Sopenharmony_ci	if (likely(reply)) {
13878c2ecf20Sopenharmony_ci		if (!IS_ERR(reply)) {
13888c2ecf20Sopenharmony_ci			rcu_read_lock();	/*To keep RCU checker happy. */
13898c2ecf20Sopenharmony_ci			err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
13908c2ecf20Sopenharmony_ci						     reply, info->snd_portid,
13918c2ecf20Sopenharmony_ci						     info->snd_seq, 0,
13928c2ecf20Sopenharmony_ci						     OVS_FLOW_CMD_DEL,
13938c2ecf20Sopenharmony_ci						     ufid_flags);
13948c2ecf20Sopenharmony_ci			rcu_read_unlock();
13958c2ecf20Sopenharmony_ci			if (WARN_ON_ONCE(err < 0)) {
13968c2ecf20Sopenharmony_ci				kfree_skb(reply);
13978c2ecf20Sopenharmony_ci				goto out_free;
13988c2ecf20Sopenharmony_ci			}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci			ovs_notify(&dp_flow_genl_family, reply, info);
14018c2ecf20Sopenharmony_ci		} else {
14028c2ecf20Sopenharmony_ci			netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
14038c2ecf20Sopenharmony_ci					PTR_ERR(reply));
14048c2ecf20Sopenharmony_ci		}
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ciout_free:
14088c2ecf20Sopenharmony_ci	ovs_flow_free(flow, true);
14098c2ecf20Sopenharmony_ci	return 0;
14108c2ecf20Sopenharmony_ciunlock:
14118c2ecf20Sopenharmony_ci	ovs_unlock();
14128c2ecf20Sopenharmony_ci	return err;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistatic int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	struct nlattr *a[__OVS_FLOW_ATTR_MAX];
14188c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
14198c2ecf20Sopenharmony_ci	struct table_instance *ti;
14208c2ecf20Sopenharmony_ci	struct datapath *dp;
14218c2ecf20Sopenharmony_ci	u32 ufid_flags;
14228c2ecf20Sopenharmony_ci	int err;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	err = genlmsg_parse_deprecated(cb->nlh, &dp_flow_genl_family, a,
14258c2ecf20Sopenharmony_ci				       OVS_FLOW_ATTR_MAX, flow_policy, NULL);
14268c2ecf20Sopenharmony_ci	if (err)
14278c2ecf20Sopenharmony_ci		return err;
14288c2ecf20Sopenharmony_ci	ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	rcu_read_lock();
14318c2ecf20Sopenharmony_ci	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
14328c2ecf20Sopenharmony_ci	if (!dp) {
14338c2ecf20Sopenharmony_ci		rcu_read_unlock();
14348c2ecf20Sopenharmony_ci		return -ENODEV;
14358c2ecf20Sopenharmony_ci	}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	ti = rcu_dereference(dp->table.ti);
14388c2ecf20Sopenharmony_ci	for (;;) {
14398c2ecf20Sopenharmony_ci		struct sw_flow *flow;
14408c2ecf20Sopenharmony_ci		u32 bucket, obj;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		bucket = cb->args[0];
14438c2ecf20Sopenharmony_ci		obj = cb->args[1];
14448c2ecf20Sopenharmony_ci		flow = ovs_flow_tbl_dump_next(ti, &bucket, &obj);
14458c2ecf20Sopenharmony_ci		if (!flow)
14468c2ecf20Sopenharmony_ci			break;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci		if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
14498c2ecf20Sopenharmony_ci					   NETLINK_CB(cb->skb).portid,
14508c2ecf20Sopenharmony_ci					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
14518c2ecf20Sopenharmony_ci					   OVS_FLOW_CMD_GET, ufid_flags) < 0)
14528c2ecf20Sopenharmony_ci			break;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		cb->args[0] = bucket;
14558c2ecf20Sopenharmony_ci		cb->args[1] = obj;
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci	rcu_read_unlock();
14588c2ecf20Sopenharmony_ci	return skb->len;
14598c2ecf20Sopenharmony_ci}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_cistatic const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
14628c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
14638c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED },
14648c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
14658c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
14668c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG },
14678c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_UFID] = { .type = NLA_UNSPEC, .len = 1 },
14688c2ecf20Sopenharmony_ci	[OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
14698c2ecf20Sopenharmony_ci};
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic const struct genl_small_ops dp_flow_genl_ops[] = {
14728c2ecf20Sopenharmony_ci	{ .cmd = OVS_FLOW_CMD_NEW,
14738c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14748c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
14758c2ecf20Sopenharmony_ci	  .doit = ovs_flow_cmd_new
14768c2ecf20Sopenharmony_ci	},
14778c2ecf20Sopenharmony_ci	{ .cmd = OVS_FLOW_CMD_DEL,
14788c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14798c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
14808c2ecf20Sopenharmony_ci	  .doit = ovs_flow_cmd_del
14818c2ecf20Sopenharmony_ci	},
14828c2ecf20Sopenharmony_ci	{ .cmd = OVS_FLOW_CMD_GET,
14838c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14848c2ecf20Sopenharmony_ci	  .flags = 0,		    /* OK for unprivileged users. */
14858c2ecf20Sopenharmony_ci	  .doit = ovs_flow_cmd_get,
14868c2ecf20Sopenharmony_ci	  .dumpit = ovs_flow_cmd_dump
14878c2ecf20Sopenharmony_ci	},
14888c2ecf20Sopenharmony_ci	{ .cmd = OVS_FLOW_CMD_SET,
14898c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14908c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
14918c2ecf20Sopenharmony_ci	  .doit = ovs_flow_cmd_set,
14928c2ecf20Sopenharmony_ci	},
14938c2ecf20Sopenharmony_ci};
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_cistatic struct genl_family dp_flow_genl_family __ro_after_init = {
14968c2ecf20Sopenharmony_ci	.hdrsize = sizeof(struct ovs_header),
14978c2ecf20Sopenharmony_ci	.name = OVS_FLOW_FAMILY,
14988c2ecf20Sopenharmony_ci	.version = OVS_FLOW_VERSION,
14998c2ecf20Sopenharmony_ci	.maxattr = OVS_FLOW_ATTR_MAX,
15008c2ecf20Sopenharmony_ci	.policy = flow_policy,
15018c2ecf20Sopenharmony_ci	.netnsok = true,
15028c2ecf20Sopenharmony_ci	.parallel_ops = true,
15038c2ecf20Sopenharmony_ci	.small_ops = dp_flow_genl_ops,
15048c2ecf20Sopenharmony_ci	.n_small_ops = ARRAY_SIZE(dp_flow_genl_ops),
15058c2ecf20Sopenharmony_ci	.mcgrps = &ovs_dp_flow_multicast_group,
15068c2ecf20Sopenharmony_ci	.n_mcgrps = 1,
15078c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
15088c2ecf20Sopenharmony_ci};
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_cistatic size_t ovs_dp_cmd_msg_size(void)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	msgsize += nla_total_size(IFNAMSIZ);
15158c2ecf20Sopenharmony_ci	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
15168c2ecf20Sopenharmony_ci	msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
15178c2ecf20Sopenharmony_ci	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
15188c2ecf20Sopenharmony_ci	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE */
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	return msgsize;
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci/* Called with ovs_mutex. */
15248c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
15258c2ecf20Sopenharmony_ci				u32 portid, u32 seq, u32 flags, u8 cmd)
15268c2ecf20Sopenharmony_ci{
15278c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header;
15288c2ecf20Sopenharmony_ci	struct ovs_dp_stats dp_stats;
15298c2ecf20Sopenharmony_ci	struct ovs_dp_megaflow_stats dp_megaflow_stats;
15308c2ecf20Sopenharmony_ci	int err;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family,
15338c2ecf20Sopenharmony_ci				 flags, cmd);
15348c2ecf20Sopenharmony_ci	if (!ovs_header)
15358c2ecf20Sopenharmony_ci		goto error;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	ovs_header->dp_ifindex = get_dpifindex(dp);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	err = nla_put_string(skb, OVS_DP_ATTR_NAME, ovs_dp_name(dp));
15408c2ecf20Sopenharmony_ci	if (err)
15418c2ecf20Sopenharmony_ci		goto nla_put_failure;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	get_dp_stats(dp, &dp_stats, &dp_megaflow_stats);
15448c2ecf20Sopenharmony_ci	if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
15458c2ecf20Sopenharmony_ci			  &dp_stats, OVS_DP_ATTR_PAD))
15468c2ecf20Sopenharmony_ci		goto nla_put_failure;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
15498c2ecf20Sopenharmony_ci			  sizeof(struct ovs_dp_megaflow_stats),
15508c2ecf20Sopenharmony_ci			  &dp_megaflow_stats, OVS_DP_ATTR_PAD))
15518c2ecf20Sopenharmony_ci		goto nla_put_failure;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
15548c2ecf20Sopenharmony_ci		goto nla_put_failure;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_DP_ATTR_MASKS_CACHE_SIZE,
15578c2ecf20Sopenharmony_ci			ovs_flow_tbl_masks_cache_size(&dp->table)))
15588c2ecf20Sopenharmony_ci		goto nla_put_failure;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	genlmsg_end(skb, ovs_header);
15618c2ecf20Sopenharmony_ci	return 0;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_cinla_put_failure:
15648c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, ovs_header);
15658c2ecf20Sopenharmony_cierror:
15668c2ecf20Sopenharmony_ci	return -EMSGSIZE;
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic struct sk_buff *ovs_dp_cmd_alloc_info(void)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
15728c2ecf20Sopenharmony_ci}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci/* Called with rcu_read_lock or ovs_mutex. */
15758c2ecf20Sopenharmony_cistatic struct datapath *lookup_datapath(struct net *net,
15768c2ecf20Sopenharmony_ci					const struct ovs_header *ovs_header,
15778c2ecf20Sopenharmony_ci					struct nlattr *a[OVS_DP_ATTR_MAX + 1])
15788c2ecf20Sopenharmony_ci{
15798c2ecf20Sopenharmony_ci	struct datapath *dp;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	if (!a[OVS_DP_ATTR_NAME])
15828c2ecf20Sopenharmony_ci		dp = get_dp(net, ovs_header->dp_ifindex);
15838c2ecf20Sopenharmony_ci	else {
15848c2ecf20Sopenharmony_ci		struct vport *vport;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci		vport = ovs_vport_locate(net, nla_data(a[OVS_DP_ATTR_NAME]));
15878c2ecf20Sopenharmony_ci		dp = vport && vport->port_no == OVSP_LOCAL ? vport->dp : NULL;
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ci	return dp ? dp : ERR_PTR(-ENODEV);
15908c2ecf20Sopenharmony_ci}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_cistatic void ovs_dp_reset_user_features(struct sk_buff *skb,
15938c2ecf20Sopenharmony_ci				       struct genl_info *info)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct datapath *dp;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	dp = lookup_datapath(sock_net(skb->sk), info->userhdr,
15988c2ecf20Sopenharmony_ci			     info->attrs);
15998c2ecf20Sopenharmony_ci	if (IS_ERR(dp))
16008c2ecf20Sopenharmony_ci		return;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	pr_warn("%s: Dropping previously announced user features\n",
16038c2ecf20Sopenharmony_ci		ovs_dp_name(dp));
16048c2ecf20Sopenharmony_ci	dp->user_features = 0;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_cistatic int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	u32 user_features = 0;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (a[OVS_DP_ATTR_USER_FEATURES]) {
16148c2ecf20Sopenharmony_ci		user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci		if (user_features & ~(OVS_DP_F_VPORT_PIDS |
16178c2ecf20Sopenharmony_ci				      OVS_DP_F_UNALIGNED |
16188c2ecf20Sopenharmony_ci				      OVS_DP_F_TC_RECIRC_SHARING))
16198c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
16228c2ecf20Sopenharmony_ci		if (user_features & OVS_DP_F_TC_RECIRC_SHARING)
16238c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
16248c2ecf20Sopenharmony_ci#endif
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	if (a[OVS_DP_ATTR_MASKS_CACHE_SIZE]) {
16288c2ecf20Sopenharmony_ci		int err;
16298c2ecf20Sopenharmony_ci		u32 cache_size;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci		cache_size = nla_get_u32(a[OVS_DP_ATTR_MASKS_CACHE_SIZE]);
16328c2ecf20Sopenharmony_ci		err = ovs_flow_tbl_masks_cache_resize(&dp->table, cache_size);
16338c2ecf20Sopenharmony_ci		if (err)
16348c2ecf20Sopenharmony_ci			return err;
16358c2ecf20Sopenharmony_ci	}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	dp->user_features = user_features;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
16408c2ecf20Sopenharmony_ci		static_branch_enable(&tc_recirc_sharing_support);
16418c2ecf20Sopenharmony_ci	else
16428c2ecf20Sopenharmony_ci		static_branch_disable(&tc_recirc_sharing_support);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	return 0;
16458c2ecf20Sopenharmony_ci}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_cistatic int ovs_dp_stats_init(struct datapath *dp)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	dp->stats_percpu = netdev_alloc_pcpu_stats(struct dp_stats_percpu);
16508c2ecf20Sopenharmony_ci	if (!dp->stats_percpu)
16518c2ecf20Sopenharmony_ci		return -ENOMEM;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	return 0;
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_cistatic int ovs_dp_vport_init(struct datapath *dp)
16578c2ecf20Sopenharmony_ci{
16588c2ecf20Sopenharmony_ci	int i;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	dp->ports = kmalloc_array(DP_VPORT_HASH_BUCKETS,
16618c2ecf20Sopenharmony_ci				  sizeof(struct hlist_head),
16628c2ecf20Sopenharmony_ci				  GFP_KERNEL);
16638c2ecf20Sopenharmony_ci	if (!dp->ports)
16648c2ecf20Sopenharmony_ci		return -ENOMEM;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
16678c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&dp->ports[i]);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	return 0;
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
16738c2ecf20Sopenharmony_ci{
16748c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
16758c2ecf20Sopenharmony_ci	struct vport_parms parms;
16768c2ecf20Sopenharmony_ci	struct sk_buff *reply;
16778c2ecf20Sopenharmony_ci	struct datapath *dp;
16788c2ecf20Sopenharmony_ci	struct vport *vport;
16798c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net;
16808c2ecf20Sopenharmony_ci	int err;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	err = -EINVAL;
16838c2ecf20Sopenharmony_ci	if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
16848c2ecf20Sopenharmony_ci		goto err;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	reply = ovs_dp_cmd_alloc_info();
16878c2ecf20Sopenharmony_ci	if (!reply)
16888c2ecf20Sopenharmony_ci		return -ENOMEM;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	err = -ENOMEM;
16918c2ecf20Sopenharmony_ci	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
16928c2ecf20Sopenharmony_ci	if (dp == NULL)
16938c2ecf20Sopenharmony_ci		goto err_destroy_reply;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	ovs_dp_set_net(dp, sock_net(skb->sk));
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	/* Allocate table. */
16988c2ecf20Sopenharmony_ci	err = ovs_flow_tbl_init(&dp->table);
16998c2ecf20Sopenharmony_ci	if (err)
17008c2ecf20Sopenharmony_ci		goto err_destroy_dp;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	err = ovs_dp_stats_init(dp);
17038c2ecf20Sopenharmony_ci	if (err)
17048c2ecf20Sopenharmony_ci		goto err_destroy_table;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	err = ovs_dp_vport_init(dp);
17078c2ecf20Sopenharmony_ci	if (err)
17088c2ecf20Sopenharmony_ci		goto err_destroy_stats;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	err = ovs_meters_init(dp);
17118c2ecf20Sopenharmony_ci	if (err)
17128c2ecf20Sopenharmony_ci		goto err_destroy_ports;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	/* Set up our datapath device. */
17158c2ecf20Sopenharmony_ci	parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
17168c2ecf20Sopenharmony_ci	parms.type = OVS_VPORT_TYPE_INTERNAL;
17178c2ecf20Sopenharmony_ci	parms.options = NULL;
17188c2ecf20Sopenharmony_ci	parms.dp = dp;
17198c2ecf20Sopenharmony_ci	parms.port_no = OVSP_LOCAL;
17208c2ecf20Sopenharmony_ci	parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	/* So far only local changes have been made, now need the lock. */
17238c2ecf20Sopenharmony_ci	ovs_lock();
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	err = ovs_dp_change(dp, a);
17268c2ecf20Sopenharmony_ci	if (err)
17278c2ecf20Sopenharmony_ci		goto err_unlock_and_destroy_meters;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	vport = new_vport(&parms);
17308c2ecf20Sopenharmony_ci	if (IS_ERR(vport)) {
17318c2ecf20Sopenharmony_ci		err = PTR_ERR(vport);
17328c2ecf20Sopenharmony_ci		if (err == -EBUSY)
17338c2ecf20Sopenharmony_ci			err = -EEXIST;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci		if (err == -EEXIST) {
17368c2ecf20Sopenharmony_ci			/* An outdated user space instance that does not understand
17378c2ecf20Sopenharmony_ci			 * the concept of user_features has attempted to create a new
17388c2ecf20Sopenharmony_ci			 * datapath and is likely to reuse it. Drop all user features.
17398c2ecf20Sopenharmony_ci			 */
17408c2ecf20Sopenharmony_ci			if (info->genlhdr->version < OVS_DP_VER_FEATURES)
17418c2ecf20Sopenharmony_ci				ovs_dp_reset_user_features(skb, info);
17428c2ecf20Sopenharmony_ci		}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci		goto err_unlock_and_destroy_meters;
17458c2ecf20Sopenharmony_ci	}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
17488c2ecf20Sopenharmony_ci				   info->snd_seq, 0, OVS_DP_CMD_NEW);
17498c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
17528c2ecf20Sopenharmony_ci	list_add_tail_rcu(&dp->list_node, &ovs_net->dps);
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	ovs_unlock();
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	ovs_notify(&dp_datapath_genl_family, reply, info);
17578c2ecf20Sopenharmony_ci	return 0;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_cierr_unlock_and_destroy_meters:
17608c2ecf20Sopenharmony_ci	ovs_unlock();
17618c2ecf20Sopenharmony_ci	ovs_meters_exit(dp);
17628c2ecf20Sopenharmony_cierr_destroy_ports:
17638c2ecf20Sopenharmony_ci	kfree(dp->ports);
17648c2ecf20Sopenharmony_cierr_destroy_stats:
17658c2ecf20Sopenharmony_ci	free_percpu(dp->stats_percpu);
17668c2ecf20Sopenharmony_cierr_destroy_table:
17678c2ecf20Sopenharmony_ci	ovs_flow_tbl_destroy(&dp->table);
17688c2ecf20Sopenharmony_cierr_destroy_dp:
17698c2ecf20Sopenharmony_ci	kfree(dp);
17708c2ecf20Sopenharmony_cierr_destroy_reply:
17718c2ecf20Sopenharmony_ci	kfree_skb(reply);
17728c2ecf20Sopenharmony_cierr:
17738c2ecf20Sopenharmony_ci	return err;
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci/* Called with ovs_mutex. */
17778c2ecf20Sopenharmony_cistatic void __dp_destroy(struct datapath *dp)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	struct flow_table *table = &dp->table;
17808c2ecf20Sopenharmony_ci	int i;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
17838c2ecf20Sopenharmony_ci		struct vport *vport;
17848c2ecf20Sopenharmony_ci		struct hlist_node *n;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node)
17878c2ecf20Sopenharmony_ci			if (vport->port_no != OVSP_LOCAL)
17888c2ecf20Sopenharmony_ci				ovs_dp_detach_port(vport);
17898c2ecf20Sopenharmony_ci	}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	list_del_rcu(&dp->list_node);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	/* OVSP_LOCAL is datapath internal port. We need to make sure that
17948c2ecf20Sopenharmony_ci	 * all ports in datapath are destroyed first before freeing datapath.
17958c2ecf20Sopenharmony_ci	 */
17968c2ecf20Sopenharmony_ci	ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	/* Flush sw_flow in the tables. RCU cb only releases resource
17998c2ecf20Sopenharmony_ci	 * such as dp, ports and tables. That may avoid some issues
18008c2ecf20Sopenharmony_ci	 * such as RCU usage warning.
18018c2ecf20Sopenharmony_ci	 */
18028c2ecf20Sopenharmony_ci	table_instance_flow_flush(table, ovsl_dereference(table->ti),
18038c2ecf20Sopenharmony_ci				  ovsl_dereference(table->ufid_ti));
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	/* RCU destroy the ports, meters and flow tables. */
18068c2ecf20Sopenharmony_ci	call_rcu(&dp->rcu, destroy_dp_rcu);
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
18108c2ecf20Sopenharmony_ci{
18118c2ecf20Sopenharmony_ci	struct sk_buff *reply;
18128c2ecf20Sopenharmony_ci	struct datapath *dp;
18138c2ecf20Sopenharmony_ci	int err;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	reply = ovs_dp_cmd_alloc_info();
18168c2ecf20Sopenharmony_ci	if (!reply)
18178c2ecf20Sopenharmony_ci		return -ENOMEM;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	ovs_lock();
18208c2ecf20Sopenharmony_ci	dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
18218c2ecf20Sopenharmony_ci	err = PTR_ERR(dp);
18228c2ecf20Sopenharmony_ci	if (IS_ERR(dp))
18238c2ecf20Sopenharmony_ci		goto err_unlock_free;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18268c2ecf20Sopenharmony_ci				   info->snd_seq, 0, OVS_DP_CMD_DEL);
18278c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	__dp_destroy(dp);
18308c2ecf20Sopenharmony_ci	ovs_unlock();
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	ovs_notify(&dp_datapath_genl_family, reply, info);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	return 0;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_cierr_unlock_free:
18378c2ecf20Sopenharmony_ci	ovs_unlock();
18388c2ecf20Sopenharmony_ci	kfree_skb(reply);
18398c2ecf20Sopenharmony_ci	return err;
18408c2ecf20Sopenharmony_ci}
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
18438c2ecf20Sopenharmony_ci{
18448c2ecf20Sopenharmony_ci	struct sk_buff *reply;
18458c2ecf20Sopenharmony_ci	struct datapath *dp;
18468c2ecf20Sopenharmony_ci	int err;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	reply = ovs_dp_cmd_alloc_info();
18498c2ecf20Sopenharmony_ci	if (!reply)
18508c2ecf20Sopenharmony_ci		return -ENOMEM;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	ovs_lock();
18538c2ecf20Sopenharmony_ci	dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
18548c2ecf20Sopenharmony_ci	err = PTR_ERR(dp);
18558c2ecf20Sopenharmony_ci	if (IS_ERR(dp))
18568c2ecf20Sopenharmony_ci		goto err_unlock_free;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	err = ovs_dp_change(dp, info->attrs);
18598c2ecf20Sopenharmony_ci	if (err)
18608c2ecf20Sopenharmony_ci		goto err_unlock_free;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18638c2ecf20Sopenharmony_ci				   info->snd_seq, 0, OVS_DP_CMD_SET);
18648c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	ovs_unlock();
18678c2ecf20Sopenharmony_ci	ovs_notify(&dp_datapath_genl_family, reply, info);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	return 0;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_cierr_unlock_free:
18728c2ecf20Sopenharmony_ci	ovs_unlock();
18738c2ecf20Sopenharmony_ci	kfree_skb(reply);
18748c2ecf20Sopenharmony_ci	return err;
18758c2ecf20Sopenharmony_ci}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
18788c2ecf20Sopenharmony_ci{
18798c2ecf20Sopenharmony_ci	struct sk_buff *reply;
18808c2ecf20Sopenharmony_ci	struct datapath *dp;
18818c2ecf20Sopenharmony_ci	int err;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	reply = ovs_dp_cmd_alloc_info();
18848c2ecf20Sopenharmony_ci	if (!reply)
18858c2ecf20Sopenharmony_ci		return -ENOMEM;
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	ovs_lock();
18888c2ecf20Sopenharmony_ci	dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
18898c2ecf20Sopenharmony_ci	if (IS_ERR(dp)) {
18908c2ecf20Sopenharmony_ci		err = PTR_ERR(dp);
18918c2ecf20Sopenharmony_ci		goto err_unlock_free;
18928c2ecf20Sopenharmony_ci	}
18938c2ecf20Sopenharmony_ci	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18948c2ecf20Sopenharmony_ci				   info->snd_seq, 0, OVS_DP_CMD_GET);
18958c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
18968c2ecf20Sopenharmony_ci	ovs_unlock();
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	return genlmsg_reply(reply, info);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_cierr_unlock_free:
19018c2ecf20Sopenharmony_ci	ovs_unlock();
19028c2ecf20Sopenharmony_ci	kfree_skb(reply);
19038c2ecf20Sopenharmony_ci	return err;
19048c2ecf20Sopenharmony_ci}
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_cistatic int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id);
19098c2ecf20Sopenharmony_ci	struct datapath *dp;
19108c2ecf20Sopenharmony_ci	int skip = cb->args[0];
19118c2ecf20Sopenharmony_ci	int i = 0;
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	ovs_lock();
19148c2ecf20Sopenharmony_ci	list_for_each_entry(dp, &ovs_net->dps, list_node) {
19158c2ecf20Sopenharmony_ci		if (i >= skip &&
19168c2ecf20Sopenharmony_ci		    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
19178c2ecf20Sopenharmony_ci					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
19188c2ecf20Sopenharmony_ci					 OVS_DP_CMD_GET) < 0)
19198c2ecf20Sopenharmony_ci			break;
19208c2ecf20Sopenharmony_ci		i++;
19218c2ecf20Sopenharmony_ci	}
19228c2ecf20Sopenharmony_ci	ovs_unlock();
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	cb->args[0] = i;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	return skb->len;
19278c2ecf20Sopenharmony_ci}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_cistatic const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
19308c2ecf20Sopenharmony_ci	[OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
19318c2ecf20Sopenharmony_ci	[OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
19328c2ecf20Sopenharmony_ci	[OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
19338c2ecf20Sopenharmony_ci	[OVS_DP_ATTR_MASKS_CACHE_SIZE] =  NLA_POLICY_RANGE(NLA_U32, 0,
19348c2ecf20Sopenharmony_ci		PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
19358c2ecf20Sopenharmony_ci};
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_cistatic const struct genl_small_ops dp_datapath_genl_ops[] = {
19388c2ecf20Sopenharmony_ci	{ .cmd = OVS_DP_CMD_NEW,
19398c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
19408c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
19418c2ecf20Sopenharmony_ci	  .doit = ovs_dp_cmd_new
19428c2ecf20Sopenharmony_ci	},
19438c2ecf20Sopenharmony_ci	{ .cmd = OVS_DP_CMD_DEL,
19448c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
19458c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
19468c2ecf20Sopenharmony_ci	  .doit = ovs_dp_cmd_del
19478c2ecf20Sopenharmony_ci	},
19488c2ecf20Sopenharmony_ci	{ .cmd = OVS_DP_CMD_GET,
19498c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
19508c2ecf20Sopenharmony_ci	  .flags = 0,		    /* OK for unprivileged users. */
19518c2ecf20Sopenharmony_ci	  .doit = ovs_dp_cmd_get,
19528c2ecf20Sopenharmony_ci	  .dumpit = ovs_dp_cmd_dump
19538c2ecf20Sopenharmony_ci	},
19548c2ecf20Sopenharmony_ci	{ .cmd = OVS_DP_CMD_SET,
19558c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
19568c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
19578c2ecf20Sopenharmony_ci	  .doit = ovs_dp_cmd_set,
19588c2ecf20Sopenharmony_ci	},
19598c2ecf20Sopenharmony_ci};
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_cistatic struct genl_family dp_datapath_genl_family __ro_after_init = {
19628c2ecf20Sopenharmony_ci	.hdrsize = sizeof(struct ovs_header),
19638c2ecf20Sopenharmony_ci	.name = OVS_DATAPATH_FAMILY,
19648c2ecf20Sopenharmony_ci	.version = OVS_DATAPATH_VERSION,
19658c2ecf20Sopenharmony_ci	.maxattr = OVS_DP_ATTR_MAX,
19668c2ecf20Sopenharmony_ci	.policy = datapath_policy,
19678c2ecf20Sopenharmony_ci	.netnsok = true,
19688c2ecf20Sopenharmony_ci	.parallel_ops = true,
19698c2ecf20Sopenharmony_ci	.small_ops = dp_datapath_genl_ops,
19708c2ecf20Sopenharmony_ci	.n_small_ops = ARRAY_SIZE(dp_datapath_genl_ops),
19718c2ecf20Sopenharmony_ci	.mcgrps = &ovs_dp_datapath_multicast_group,
19728c2ecf20Sopenharmony_ci	.n_mcgrps = 1,
19738c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
19748c2ecf20Sopenharmony_ci};
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
19778c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
19788c2ecf20Sopenharmony_ci				   struct net *net, u32 portid, u32 seq,
19798c2ecf20Sopenharmony_ci				   u32 flags, u8 cmd, gfp_t gfp)
19808c2ecf20Sopenharmony_ci{
19818c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header;
19828c2ecf20Sopenharmony_ci	struct ovs_vport_stats vport_stats;
19838c2ecf20Sopenharmony_ci	int err;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	ovs_header = genlmsg_put(skb, portid, seq, &dp_vport_genl_family,
19868c2ecf20Sopenharmony_ci				 flags, cmd);
19878c2ecf20Sopenharmony_ci	if (!ovs_header)
19888c2ecf20Sopenharmony_ci		return -EMSGSIZE;
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	ovs_header->dp_ifindex = get_dpifindex(vport->dp);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
19938c2ecf20Sopenharmony_ci	    nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
19948c2ecf20Sopenharmony_ci	    nla_put_string(skb, OVS_VPORT_ATTR_NAME,
19958c2ecf20Sopenharmony_ci			   ovs_vport_name(vport)) ||
19968c2ecf20Sopenharmony_ci	    nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex))
19978c2ecf20Sopenharmony_ci		goto nla_put_failure;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	if (!net_eq(net, dev_net(vport->dev))) {
20008c2ecf20Sopenharmony_ci		int id = peernet2id_alloc(net, dev_net(vport->dev), gfp);
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci		if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
20038c2ecf20Sopenharmony_ci			goto nla_put_failure;
20048c2ecf20Sopenharmony_ci	}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	ovs_vport_get_stats(vport, &vport_stats);
20078c2ecf20Sopenharmony_ci	if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
20088c2ecf20Sopenharmony_ci			  sizeof(struct ovs_vport_stats), &vport_stats,
20098c2ecf20Sopenharmony_ci			  OVS_VPORT_ATTR_PAD))
20108c2ecf20Sopenharmony_ci		goto nla_put_failure;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	if (ovs_vport_get_upcall_portids(vport, skb))
20138c2ecf20Sopenharmony_ci		goto nla_put_failure;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	err = ovs_vport_get_options(vport, skb);
20168c2ecf20Sopenharmony_ci	if (err == -EMSGSIZE)
20178c2ecf20Sopenharmony_ci		goto error;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	genlmsg_end(skb, ovs_header);
20208c2ecf20Sopenharmony_ci	return 0;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cinla_put_failure:
20238c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
20248c2ecf20Sopenharmony_cierror:
20258c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, ovs_header);
20268c2ecf20Sopenharmony_ci	return err;
20278c2ecf20Sopenharmony_ci}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_cistatic struct sk_buff *ovs_vport_cmd_alloc_info(void)
20308c2ecf20Sopenharmony_ci{
20318c2ecf20Sopenharmony_ci	return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
20358c2ecf20Sopenharmony_cistruct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
20368c2ecf20Sopenharmony_ci					 u32 portid, u32 seq, u8 cmd)
20378c2ecf20Sopenharmony_ci{
20388c2ecf20Sopenharmony_ci	struct sk_buff *skb;
20398c2ecf20Sopenharmony_ci	int retval;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
20428c2ecf20Sopenharmony_ci	if (!skb)
20438c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd,
20468c2ecf20Sopenharmony_ci					 GFP_KERNEL);
20478c2ecf20Sopenharmony_ci	BUG_ON(retval < 0);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	return skb;
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
20538c2ecf20Sopenharmony_cistatic struct vport *lookup_vport(struct net *net,
20548c2ecf20Sopenharmony_ci				  const struct ovs_header *ovs_header,
20558c2ecf20Sopenharmony_ci				  struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
20568c2ecf20Sopenharmony_ci{
20578c2ecf20Sopenharmony_ci	struct datapath *dp;
20588c2ecf20Sopenharmony_ci	struct vport *vport;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_IFINDEX])
20618c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
20628c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_NAME]) {
20638c2ecf20Sopenharmony_ci		vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME]));
20648c2ecf20Sopenharmony_ci		if (!vport)
20658c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
20668c2ecf20Sopenharmony_ci		if (ovs_header->dp_ifindex &&
20678c2ecf20Sopenharmony_ci		    ovs_header->dp_ifindex != get_dpifindex(vport->dp))
20688c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
20698c2ecf20Sopenharmony_ci		return vport;
20708c2ecf20Sopenharmony_ci	} else if (a[OVS_VPORT_ATTR_PORT_NO]) {
20718c2ecf20Sopenharmony_ci		u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci		if (port_no >= DP_MAX_PORTS)
20748c2ecf20Sopenharmony_ci			return ERR_PTR(-EFBIG);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci		dp = get_dp(net, ovs_header->dp_ifindex);
20778c2ecf20Sopenharmony_ci		if (!dp)
20788c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci		vport = ovs_vport_ovsl_rcu(dp, port_no);
20818c2ecf20Sopenharmony_ci		if (!vport)
20828c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
20838c2ecf20Sopenharmony_ci		return vport;
20848c2ecf20Sopenharmony_ci	} else
20858c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_cistatic unsigned int ovs_get_max_headroom(struct datapath *dp)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	unsigned int dev_headroom, max_headroom = 0;
20928c2ecf20Sopenharmony_ci	struct net_device *dev;
20938c2ecf20Sopenharmony_ci	struct vport *vport;
20948c2ecf20Sopenharmony_ci	int i;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
20978c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
20988c2ecf20Sopenharmony_ci					 lockdep_ovsl_is_held()) {
20998c2ecf20Sopenharmony_ci			dev = vport->dev;
21008c2ecf20Sopenharmony_ci			dev_headroom = netdev_get_fwd_headroom(dev);
21018c2ecf20Sopenharmony_ci			if (dev_headroom > max_headroom)
21028c2ecf20Sopenharmony_ci				max_headroom = dev_headroom;
21038c2ecf20Sopenharmony_ci		}
21048c2ecf20Sopenharmony_ci	}
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	return max_headroom;
21078c2ecf20Sopenharmony_ci}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci/* Called with ovs_mutex */
21108c2ecf20Sopenharmony_cistatic void ovs_update_headroom(struct datapath *dp, unsigned int new_headroom)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	struct vport *vport;
21138c2ecf20Sopenharmony_ci	int i;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	dp->max_headroom = new_headroom;
21168c2ecf20Sopenharmony_ci	for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
21178c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node,
21188c2ecf20Sopenharmony_ci					 lockdep_ovsl_is_held())
21198c2ecf20Sopenharmony_ci			netdev_set_rx_headroom(vport->dev, new_headroom);
21208c2ecf20Sopenharmony_ci	}
21218c2ecf20Sopenharmony_ci}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
21248c2ecf20Sopenharmony_ci{
21258c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
21268c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
21278c2ecf20Sopenharmony_ci	struct vport_parms parms;
21288c2ecf20Sopenharmony_ci	struct sk_buff *reply;
21298c2ecf20Sopenharmony_ci	struct vport *vport;
21308c2ecf20Sopenharmony_ci	struct datapath *dp;
21318c2ecf20Sopenharmony_ci	unsigned int new_headroom;
21328c2ecf20Sopenharmony_ci	u32 port_no;
21338c2ecf20Sopenharmony_ci	int err;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
21368c2ecf20Sopenharmony_ci	    !a[OVS_VPORT_ATTR_UPCALL_PID])
21378c2ecf20Sopenharmony_ci		return -EINVAL;
21388c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_IFINDEX])
21398c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	port_no = a[OVS_VPORT_ATTR_PORT_NO]
21428c2ecf20Sopenharmony_ci		? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
21438c2ecf20Sopenharmony_ci	if (port_no >= DP_MAX_PORTS)
21448c2ecf20Sopenharmony_ci		return -EFBIG;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	reply = ovs_vport_cmd_alloc_info();
21478c2ecf20Sopenharmony_ci	if (!reply)
21488c2ecf20Sopenharmony_ci		return -ENOMEM;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	ovs_lock();
21518c2ecf20Sopenharmony_cirestart:
21528c2ecf20Sopenharmony_ci	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
21538c2ecf20Sopenharmony_ci	err = -ENODEV;
21548c2ecf20Sopenharmony_ci	if (!dp)
21558c2ecf20Sopenharmony_ci		goto exit_unlock_free;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	if (port_no) {
21588c2ecf20Sopenharmony_ci		vport = ovs_vport_ovsl(dp, port_no);
21598c2ecf20Sopenharmony_ci		err = -EBUSY;
21608c2ecf20Sopenharmony_ci		if (vport)
21618c2ecf20Sopenharmony_ci			goto exit_unlock_free;
21628c2ecf20Sopenharmony_ci	} else {
21638c2ecf20Sopenharmony_ci		for (port_no = 1; ; port_no++) {
21648c2ecf20Sopenharmony_ci			if (port_no >= DP_MAX_PORTS) {
21658c2ecf20Sopenharmony_ci				err = -EFBIG;
21668c2ecf20Sopenharmony_ci				goto exit_unlock_free;
21678c2ecf20Sopenharmony_ci			}
21688c2ecf20Sopenharmony_ci			vport = ovs_vport_ovsl(dp, port_no);
21698c2ecf20Sopenharmony_ci			if (!vport)
21708c2ecf20Sopenharmony_ci				break;
21718c2ecf20Sopenharmony_ci		}
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	parms.name = nla_data(a[OVS_VPORT_ATTR_NAME]);
21758c2ecf20Sopenharmony_ci	parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]);
21768c2ecf20Sopenharmony_ci	parms.options = a[OVS_VPORT_ATTR_OPTIONS];
21778c2ecf20Sopenharmony_ci	parms.dp = dp;
21788c2ecf20Sopenharmony_ci	parms.port_no = port_no;
21798c2ecf20Sopenharmony_ci	parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	vport = new_vport(&parms);
21828c2ecf20Sopenharmony_ci	err = PTR_ERR(vport);
21838c2ecf20Sopenharmony_ci	if (IS_ERR(vport)) {
21848c2ecf20Sopenharmony_ci		if (err == -EAGAIN)
21858c2ecf20Sopenharmony_ci			goto restart;
21868c2ecf20Sopenharmony_ci		goto exit_unlock_free;
21878c2ecf20Sopenharmony_ci	}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21908c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0,
21918c2ecf20Sopenharmony_ci				      OVS_VPORT_CMD_NEW, GFP_KERNEL);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	new_headroom = netdev_get_fwd_headroom(vport->dev);
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	if (new_headroom > dp->max_headroom)
21968c2ecf20Sopenharmony_ci		ovs_update_headroom(dp, new_headroom);
21978c2ecf20Sopenharmony_ci	else
21988c2ecf20Sopenharmony_ci		netdev_set_rx_headroom(vport->dev, dp->max_headroom);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
22018c2ecf20Sopenharmony_ci	ovs_unlock();
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	ovs_notify(&dp_vport_genl_family, reply, info);
22048c2ecf20Sopenharmony_ci	return 0;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ciexit_unlock_free:
22078c2ecf20Sopenharmony_ci	ovs_unlock();
22088c2ecf20Sopenharmony_ci	kfree_skb(reply);
22098c2ecf20Sopenharmony_ci	return err;
22108c2ecf20Sopenharmony_ci}
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
22138c2ecf20Sopenharmony_ci{
22148c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
22158c2ecf20Sopenharmony_ci	struct sk_buff *reply;
22168c2ecf20Sopenharmony_ci	struct vport *vport;
22178c2ecf20Sopenharmony_ci	int err;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	reply = ovs_vport_cmd_alloc_info();
22208c2ecf20Sopenharmony_ci	if (!reply)
22218c2ecf20Sopenharmony_ci		return -ENOMEM;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	ovs_lock();
22248c2ecf20Sopenharmony_ci	vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
22258c2ecf20Sopenharmony_ci	err = PTR_ERR(vport);
22268c2ecf20Sopenharmony_ci	if (IS_ERR(vport))
22278c2ecf20Sopenharmony_ci		goto exit_unlock_free;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_TYPE] &&
22308c2ecf20Sopenharmony_ci	    nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) {
22318c2ecf20Sopenharmony_ci		err = -EINVAL;
22328c2ecf20Sopenharmony_ci		goto exit_unlock_free;
22338c2ecf20Sopenharmony_ci	}
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_OPTIONS]) {
22368c2ecf20Sopenharmony_ci		err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
22378c2ecf20Sopenharmony_ci		if (err)
22388c2ecf20Sopenharmony_ci			goto exit_unlock_free;
22398c2ecf20Sopenharmony_ci	}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	if (a[OVS_VPORT_ATTR_UPCALL_PID]) {
22438c2ecf20Sopenharmony_ci		struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID];
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci		err = ovs_vport_set_upcall_portids(vport, ids);
22468c2ecf20Sopenharmony_ci		if (err)
22478c2ecf20Sopenharmony_ci			goto exit_unlock_free;
22488c2ecf20Sopenharmony_ci	}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
22518c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0,
22528c2ecf20Sopenharmony_ci				      OVS_VPORT_CMD_SET, GFP_KERNEL);
22538c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	ovs_unlock();
22568c2ecf20Sopenharmony_ci	ovs_notify(&dp_vport_genl_family, reply, info);
22578c2ecf20Sopenharmony_ci	return 0;
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ciexit_unlock_free:
22608c2ecf20Sopenharmony_ci	ovs_unlock();
22618c2ecf20Sopenharmony_ci	kfree_skb(reply);
22628c2ecf20Sopenharmony_ci	return err;
22638c2ecf20Sopenharmony_ci}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
22668c2ecf20Sopenharmony_ci{
22678c2ecf20Sopenharmony_ci	bool update_headroom = false;
22688c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
22698c2ecf20Sopenharmony_ci	struct sk_buff *reply;
22708c2ecf20Sopenharmony_ci	struct datapath *dp;
22718c2ecf20Sopenharmony_ci	struct vport *vport;
22728c2ecf20Sopenharmony_ci	unsigned int new_headroom;
22738c2ecf20Sopenharmony_ci	int err;
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci	reply = ovs_vport_cmd_alloc_info();
22768c2ecf20Sopenharmony_ci	if (!reply)
22778c2ecf20Sopenharmony_ci		return -ENOMEM;
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	ovs_lock();
22808c2ecf20Sopenharmony_ci	vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
22818c2ecf20Sopenharmony_ci	err = PTR_ERR(vport);
22828c2ecf20Sopenharmony_ci	if (IS_ERR(vport))
22838c2ecf20Sopenharmony_ci		goto exit_unlock_free;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	if (vport->port_no == OVSP_LOCAL) {
22868c2ecf20Sopenharmony_ci		err = -EINVAL;
22878c2ecf20Sopenharmony_ci		goto exit_unlock_free;
22888c2ecf20Sopenharmony_ci	}
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
22918c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0,
22928c2ecf20Sopenharmony_ci				      OVS_VPORT_CMD_DEL, GFP_KERNEL);
22938c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	/* the vport deletion may trigger dp headroom update */
22968c2ecf20Sopenharmony_ci	dp = vport->dp;
22978c2ecf20Sopenharmony_ci	if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
22988c2ecf20Sopenharmony_ci		update_headroom = true;
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	netdev_reset_rx_headroom(vport->dev);
23018c2ecf20Sopenharmony_ci	ovs_dp_detach_port(vport);
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	if (update_headroom) {
23048c2ecf20Sopenharmony_ci		new_headroom = ovs_get_max_headroom(dp);
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		if (new_headroom < dp->max_headroom)
23078c2ecf20Sopenharmony_ci			ovs_update_headroom(dp, new_headroom);
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci	ovs_unlock();
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	ovs_notify(&dp_vport_genl_family, reply, info);
23128c2ecf20Sopenharmony_ci	return 0;
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ciexit_unlock_free:
23158c2ecf20Sopenharmony_ci	ovs_unlock();
23168c2ecf20Sopenharmony_ci	kfree_skb(reply);
23178c2ecf20Sopenharmony_ci	return err;
23188c2ecf20Sopenharmony_ci}
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
23218c2ecf20Sopenharmony_ci{
23228c2ecf20Sopenharmony_ci	struct nlattr **a = info->attrs;
23238c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = info->userhdr;
23248c2ecf20Sopenharmony_ci	struct sk_buff *reply;
23258c2ecf20Sopenharmony_ci	struct vport *vport;
23268c2ecf20Sopenharmony_ci	int err;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	reply = ovs_vport_cmd_alloc_info();
23298c2ecf20Sopenharmony_ci	if (!reply)
23308c2ecf20Sopenharmony_ci		return -ENOMEM;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	rcu_read_lock();
23338c2ecf20Sopenharmony_ci	vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
23348c2ecf20Sopenharmony_ci	err = PTR_ERR(vport);
23358c2ecf20Sopenharmony_ci	if (IS_ERR(vport))
23368c2ecf20Sopenharmony_ci		goto exit_unlock_free;
23378c2ecf20Sopenharmony_ci	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23388c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0,
23398c2ecf20Sopenharmony_ci				      OVS_VPORT_CMD_GET, GFP_ATOMIC);
23408c2ecf20Sopenharmony_ci	BUG_ON(err < 0);
23418c2ecf20Sopenharmony_ci	rcu_read_unlock();
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	return genlmsg_reply(reply, info);
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ciexit_unlock_free:
23468c2ecf20Sopenharmony_ci	rcu_read_unlock();
23478c2ecf20Sopenharmony_ci	kfree_skb(reply);
23488c2ecf20Sopenharmony_ci	return err;
23498c2ecf20Sopenharmony_ci}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_cistatic int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
23548c2ecf20Sopenharmony_ci	struct datapath *dp;
23558c2ecf20Sopenharmony_ci	int bucket = cb->args[0], skip = cb->args[1];
23568c2ecf20Sopenharmony_ci	int i, j = 0;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	rcu_read_lock();
23598c2ecf20Sopenharmony_ci	dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
23608c2ecf20Sopenharmony_ci	if (!dp) {
23618c2ecf20Sopenharmony_ci		rcu_read_unlock();
23628c2ecf20Sopenharmony_ci		return -ENODEV;
23638c2ecf20Sopenharmony_ci	}
23648c2ecf20Sopenharmony_ci	for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
23658c2ecf20Sopenharmony_ci		struct vport *vport;
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci		j = 0;
23688c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
23698c2ecf20Sopenharmony_ci			if (j >= skip &&
23708c2ecf20Sopenharmony_ci			    ovs_vport_cmd_fill_info(vport, skb,
23718c2ecf20Sopenharmony_ci						    sock_net(skb->sk),
23728c2ecf20Sopenharmony_ci						    NETLINK_CB(cb->skb).portid,
23738c2ecf20Sopenharmony_ci						    cb->nlh->nlmsg_seq,
23748c2ecf20Sopenharmony_ci						    NLM_F_MULTI,
23758c2ecf20Sopenharmony_ci						    OVS_VPORT_CMD_GET,
23768c2ecf20Sopenharmony_ci						    GFP_ATOMIC) < 0)
23778c2ecf20Sopenharmony_ci				goto out;
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci			j++;
23808c2ecf20Sopenharmony_ci		}
23818c2ecf20Sopenharmony_ci		skip = 0;
23828c2ecf20Sopenharmony_ci	}
23838c2ecf20Sopenharmony_ciout:
23848c2ecf20Sopenharmony_ci	rcu_read_unlock();
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	cb->args[0] = i;
23878c2ecf20Sopenharmony_ci	cb->args[1] = j;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	return skb->len;
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_cistatic void ovs_dp_masks_rebalance(struct work_struct *work)
23938c2ecf20Sopenharmony_ci{
23948c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net = container_of(work, struct ovs_net,
23958c2ecf20Sopenharmony_ci					       masks_rebalance.work);
23968c2ecf20Sopenharmony_ci	struct datapath *dp;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	ovs_lock();
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	list_for_each_entry(dp, &ovs_net->dps, list_node)
24018c2ecf20Sopenharmony_ci		ovs_flow_masks_rebalance(&dp->table);
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	ovs_unlock();
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	schedule_delayed_work(&ovs_net->masks_rebalance,
24068c2ecf20Sopenharmony_ci			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
24078c2ecf20Sopenharmony_ci}
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_cistatic const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
24108c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
24118c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
24128c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
24138c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
24148c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC },
24158c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
24168c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 },
24178c2ecf20Sopenharmony_ci	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
24188c2ecf20Sopenharmony_ci};
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_cistatic const struct genl_small_ops dp_vport_genl_ops[] = {
24218c2ecf20Sopenharmony_ci	{ .cmd = OVS_VPORT_CMD_NEW,
24228c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
24238c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
24248c2ecf20Sopenharmony_ci	  .doit = ovs_vport_cmd_new
24258c2ecf20Sopenharmony_ci	},
24268c2ecf20Sopenharmony_ci	{ .cmd = OVS_VPORT_CMD_DEL,
24278c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
24288c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
24298c2ecf20Sopenharmony_ci	  .doit = ovs_vport_cmd_del
24308c2ecf20Sopenharmony_ci	},
24318c2ecf20Sopenharmony_ci	{ .cmd = OVS_VPORT_CMD_GET,
24328c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
24338c2ecf20Sopenharmony_ci	  .flags = 0,		    /* OK for unprivileged users. */
24348c2ecf20Sopenharmony_ci	  .doit = ovs_vport_cmd_get,
24358c2ecf20Sopenharmony_ci	  .dumpit = ovs_vport_cmd_dump
24368c2ecf20Sopenharmony_ci	},
24378c2ecf20Sopenharmony_ci	{ .cmd = OVS_VPORT_CMD_SET,
24388c2ecf20Sopenharmony_ci	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
24398c2ecf20Sopenharmony_ci	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
24408c2ecf20Sopenharmony_ci	  .doit = ovs_vport_cmd_set,
24418c2ecf20Sopenharmony_ci	},
24428c2ecf20Sopenharmony_ci};
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_cistruct genl_family dp_vport_genl_family __ro_after_init = {
24458c2ecf20Sopenharmony_ci	.hdrsize = sizeof(struct ovs_header),
24468c2ecf20Sopenharmony_ci	.name = OVS_VPORT_FAMILY,
24478c2ecf20Sopenharmony_ci	.version = OVS_VPORT_VERSION,
24488c2ecf20Sopenharmony_ci	.maxattr = OVS_VPORT_ATTR_MAX,
24498c2ecf20Sopenharmony_ci	.policy = vport_policy,
24508c2ecf20Sopenharmony_ci	.netnsok = true,
24518c2ecf20Sopenharmony_ci	.parallel_ops = true,
24528c2ecf20Sopenharmony_ci	.small_ops = dp_vport_genl_ops,
24538c2ecf20Sopenharmony_ci	.n_small_ops = ARRAY_SIZE(dp_vport_genl_ops),
24548c2ecf20Sopenharmony_ci	.mcgrps = &ovs_dp_vport_multicast_group,
24558c2ecf20Sopenharmony_ci	.n_mcgrps = 1,
24568c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
24578c2ecf20Sopenharmony_ci};
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_cistatic struct genl_family * const dp_genl_families[] = {
24608c2ecf20Sopenharmony_ci	&dp_datapath_genl_family,
24618c2ecf20Sopenharmony_ci	&dp_vport_genl_family,
24628c2ecf20Sopenharmony_ci	&dp_flow_genl_family,
24638c2ecf20Sopenharmony_ci	&dp_packet_genl_family,
24648c2ecf20Sopenharmony_ci	&dp_meter_genl_family,
24658c2ecf20Sopenharmony_ci#if	IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
24668c2ecf20Sopenharmony_ci	&dp_ct_limit_genl_family,
24678c2ecf20Sopenharmony_ci#endif
24688c2ecf20Sopenharmony_ci};
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_cistatic void dp_unregister_genl(int n_families)
24718c2ecf20Sopenharmony_ci{
24728c2ecf20Sopenharmony_ci	int i;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	for (i = 0; i < n_families; i++)
24758c2ecf20Sopenharmony_ci		genl_unregister_family(dp_genl_families[i]);
24768c2ecf20Sopenharmony_ci}
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_cistatic int __init dp_register_genl(void)
24798c2ecf20Sopenharmony_ci{
24808c2ecf20Sopenharmony_ci	int err;
24818c2ecf20Sopenharmony_ci	int i;
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci		err = genl_register_family(dp_genl_families[i]);
24868c2ecf20Sopenharmony_ci		if (err)
24878c2ecf20Sopenharmony_ci			goto error;
24888c2ecf20Sopenharmony_ci	}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	return 0;
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_cierror:
24938c2ecf20Sopenharmony_ci	dp_unregister_genl(i);
24948c2ecf20Sopenharmony_ci	return err;
24958c2ecf20Sopenharmony_ci}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_cistatic int __net_init ovs_init_net(struct net *net)
24988c2ecf20Sopenharmony_ci{
24998c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
25008c2ecf20Sopenharmony_ci	int err;
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ovs_net->dps);
25038c2ecf20Sopenharmony_ci	INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
25048c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&ovs_net->masks_rebalance, ovs_dp_masks_rebalance);
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	err = ovs_ct_init(net);
25078c2ecf20Sopenharmony_ci	if (err)
25088c2ecf20Sopenharmony_ci		return err;
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	schedule_delayed_work(&ovs_net->masks_rebalance,
25118c2ecf20Sopenharmony_ci			      msecs_to_jiffies(DP_MASKS_REBALANCE_INTERVAL));
25128c2ecf20Sopenharmony_ci	return 0;
25138c2ecf20Sopenharmony_ci}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_cistatic void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
25168c2ecf20Sopenharmony_ci					    struct list_head *head)
25178c2ecf20Sopenharmony_ci{
25188c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
25198c2ecf20Sopenharmony_ci	struct datapath *dp;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	list_for_each_entry(dp, &ovs_net->dps, list_node) {
25228c2ecf20Sopenharmony_ci		int i;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci		for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
25258c2ecf20Sopenharmony_ci			struct vport *vport;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci			hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
25288c2ecf20Sopenharmony_ci				if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
25298c2ecf20Sopenharmony_ci					continue;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci				if (dev_net(vport->dev) == dnet)
25328c2ecf20Sopenharmony_ci					list_add(&vport->detach_list, head);
25338c2ecf20Sopenharmony_ci			}
25348c2ecf20Sopenharmony_ci		}
25358c2ecf20Sopenharmony_ci	}
25368c2ecf20Sopenharmony_ci}
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_cistatic void __net_exit ovs_exit_net(struct net *dnet)
25398c2ecf20Sopenharmony_ci{
25408c2ecf20Sopenharmony_ci	struct datapath *dp, *dp_next;
25418c2ecf20Sopenharmony_ci	struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
25428c2ecf20Sopenharmony_ci	struct vport *vport, *vport_next;
25438c2ecf20Sopenharmony_ci	struct net *net;
25448c2ecf20Sopenharmony_ci	LIST_HEAD(head);
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	ovs_lock();
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	ovs_ct_exit(dnet);
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
25518c2ecf20Sopenharmony_ci		__dp_destroy(dp);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	down_read(&net_rwsem);
25548c2ecf20Sopenharmony_ci	for_each_net(net)
25558c2ecf20Sopenharmony_ci		list_vports_from_net(net, dnet, &head);
25568c2ecf20Sopenharmony_ci	up_read(&net_rwsem);
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci	/* Detach all vports from given namespace. */
25598c2ecf20Sopenharmony_ci	list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
25608c2ecf20Sopenharmony_ci		list_del(&vport->detach_list);
25618c2ecf20Sopenharmony_ci		ovs_dp_detach_port(vport);
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	ovs_unlock();
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&ovs_net->masks_rebalance);
25678c2ecf20Sopenharmony_ci	cancel_work_sync(&ovs_net->dp_notify_work);
25688c2ecf20Sopenharmony_ci}
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_cistatic struct pernet_operations ovs_net_ops = {
25718c2ecf20Sopenharmony_ci	.init = ovs_init_net,
25728c2ecf20Sopenharmony_ci	.exit = ovs_exit_net,
25738c2ecf20Sopenharmony_ci	.id   = &ovs_net_id,
25748c2ecf20Sopenharmony_ci	.size = sizeof(struct ovs_net),
25758c2ecf20Sopenharmony_ci};
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_cistatic int __init dp_init(void)
25788c2ecf20Sopenharmony_ci{
25798c2ecf20Sopenharmony_ci	int err;
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct ovs_skb_cb) >
25828c2ecf20Sopenharmony_ci		     sizeof_field(struct sk_buff, cb));
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	pr_info("Open vSwitch switching datapath\n");
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	err = action_fifos_init();
25878c2ecf20Sopenharmony_ci	if (err)
25888c2ecf20Sopenharmony_ci		goto error;
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	err = ovs_internal_dev_rtnl_link_register();
25918c2ecf20Sopenharmony_ci	if (err)
25928c2ecf20Sopenharmony_ci		goto error_action_fifos_exit;
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	err = ovs_flow_init();
25958c2ecf20Sopenharmony_ci	if (err)
25968c2ecf20Sopenharmony_ci		goto error_unreg_rtnl_link;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	err = ovs_vport_init();
25998c2ecf20Sopenharmony_ci	if (err)
26008c2ecf20Sopenharmony_ci		goto error_flow_exit;
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci	err = register_pernet_device(&ovs_net_ops);
26038c2ecf20Sopenharmony_ci	if (err)
26048c2ecf20Sopenharmony_ci		goto error_vport_exit;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	err = register_netdevice_notifier(&ovs_dp_device_notifier);
26078c2ecf20Sopenharmony_ci	if (err)
26088c2ecf20Sopenharmony_ci		goto error_netns_exit;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	err = ovs_netdev_init();
26118c2ecf20Sopenharmony_ci	if (err)
26128c2ecf20Sopenharmony_ci		goto error_unreg_notifier;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	err = dp_register_genl();
26158c2ecf20Sopenharmony_ci	if (err < 0)
26168c2ecf20Sopenharmony_ci		goto error_unreg_netdev;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	return 0;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_cierror_unreg_netdev:
26218c2ecf20Sopenharmony_ci	ovs_netdev_exit();
26228c2ecf20Sopenharmony_cierror_unreg_notifier:
26238c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&ovs_dp_device_notifier);
26248c2ecf20Sopenharmony_cierror_netns_exit:
26258c2ecf20Sopenharmony_ci	unregister_pernet_device(&ovs_net_ops);
26268c2ecf20Sopenharmony_cierror_vport_exit:
26278c2ecf20Sopenharmony_ci	ovs_vport_exit();
26288c2ecf20Sopenharmony_cierror_flow_exit:
26298c2ecf20Sopenharmony_ci	ovs_flow_exit();
26308c2ecf20Sopenharmony_cierror_unreg_rtnl_link:
26318c2ecf20Sopenharmony_ci	ovs_internal_dev_rtnl_link_unregister();
26328c2ecf20Sopenharmony_cierror_action_fifos_exit:
26338c2ecf20Sopenharmony_ci	action_fifos_exit();
26348c2ecf20Sopenharmony_cierror:
26358c2ecf20Sopenharmony_ci	return err;
26368c2ecf20Sopenharmony_ci}
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_cistatic void dp_cleanup(void)
26398c2ecf20Sopenharmony_ci{
26408c2ecf20Sopenharmony_ci	dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
26418c2ecf20Sopenharmony_ci	ovs_netdev_exit();
26428c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&ovs_dp_device_notifier);
26438c2ecf20Sopenharmony_ci	unregister_pernet_device(&ovs_net_ops);
26448c2ecf20Sopenharmony_ci	rcu_barrier();
26458c2ecf20Sopenharmony_ci	ovs_vport_exit();
26468c2ecf20Sopenharmony_ci	ovs_flow_exit();
26478c2ecf20Sopenharmony_ci	ovs_internal_dev_rtnl_link_unregister();
26488c2ecf20Sopenharmony_ci	action_fifos_exit();
26498c2ecf20Sopenharmony_ci}
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_cimodule_init(dp_init);
26528c2ecf20Sopenharmony_cimodule_exit(dp_cleanup);
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Open vSwitch switching datapath");
26558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
26568c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_DATAPATH_FAMILY);
26578c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY);
26588c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY);
26598c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY);
26608c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY);
26618c2ecf20Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY);
2662