162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2007-2014 Nicira, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/etherdevice.h>
762306a36Sopenharmony_ci#include <linux/if.h>
862306a36Sopenharmony_ci#include <linux/if_vlan.h>
962306a36Sopenharmony_ci#include <linux/jhash.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/list.h>
1262306a36Sopenharmony_ci#include <linux/mutex.h>
1362306a36Sopenharmony_ci#include <linux/percpu.h>
1462306a36Sopenharmony_ci#include <linux/rcupdate.h>
1562306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1662306a36Sopenharmony_ci#include <linux/compat.h>
1762306a36Sopenharmony_ci#include <net/net_namespace.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "datapath.h"
2162306a36Sopenharmony_ci#include "vport.h"
2262306a36Sopenharmony_ci#include "vport-internal_dev.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic LIST_HEAD(vport_ops_list);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Protected by RCU read lock for reading, ovs_mutex for writing. */
2762306a36Sopenharmony_cistatic struct hlist_head *dev_table;
2862306a36Sopenharmony_ci#define VPORT_HASH_BUCKETS 1024
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/**
3162306a36Sopenharmony_ci *	ovs_vport_init - initialize vport subsystem
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Called at module load time to initialize the vport subsystem.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ciint ovs_vport_init(void)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	dev_table = kcalloc(VPORT_HASH_BUCKETS, sizeof(struct hlist_head),
3862306a36Sopenharmony_ci			    GFP_KERNEL);
3962306a36Sopenharmony_ci	if (!dev_table)
4062306a36Sopenharmony_ci		return -ENOMEM;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return 0;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci *	ovs_vport_exit - shutdown vport subsystem
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * Called at module exit time to shutdown the vport subsystem.
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_civoid ovs_vport_exit(void)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	kfree(dev_table);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic struct hlist_head *hash_bucket(const struct net *net, const char *name)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	unsigned int hash = jhash(name, strlen(name), (unsigned long) net);
5862306a36Sopenharmony_ci	return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciint __ovs_vport_ops_register(struct vport_ops *ops)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int err = -EEXIST;
6462306a36Sopenharmony_ci	struct vport_ops *o;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	ovs_lock();
6762306a36Sopenharmony_ci	list_for_each_entry(o, &vport_ops_list, list)
6862306a36Sopenharmony_ci		if (ops->type == o->type)
6962306a36Sopenharmony_ci			goto errout;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	list_add_tail(&ops->list, &vport_ops_list);
7262306a36Sopenharmony_ci	err = 0;
7362306a36Sopenharmony_cierrout:
7462306a36Sopenharmony_ci	ovs_unlock();
7562306a36Sopenharmony_ci	return err;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__ovs_vport_ops_register);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid ovs_vport_ops_unregister(struct vport_ops *ops)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	ovs_lock();
8262306a36Sopenharmony_ci	list_del(&ops->list);
8362306a36Sopenharmony_ci	ovs_unlock();
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ovs_vport_ops_unregister);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/**
8862306a36Sopenharmony_ci *	ovs_vport_locate - find a port that has already been created
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * @net: network namespace
9162306a36Sopenharmony_ci * @name: name of port to find
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Must be called with ovs or RCU read lock.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_cistruct vport *ovs_vport_locate(const struct net *net, const char *name)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct hlist_head *bucket = hash_bucket(net, name);
9862306a36Sopenharmony_ci	struct vport *vport;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	hlist_for_each_entry_rcu(vport, bucket, hash_node,
10162306a36Sopenharmony_ci				 lockdep_ovsl_is_held())
10262306a36Sopenharmony_ci		if (!strcmp(name, ovs_vport_name(vport)) &&
10362306a36Sopenharmony_ci		    net_eq(ovs_dp_get_net(vport->dp), net))
10462306a36Sopenharmony_ci			return vport;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return NULL;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci *	ovs_vport_alloc - allocate and initialize new vport
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * @priv_size: Size of private data area to allocate.
11362306a36Sopenharmony_ci * @ops: vport device ops
11462306a36Sopenharmony_ci * @parms: information about new vport.
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Allocate and initialize a new vport defined by @ops.  The vport will contain
11762306a36Sopenharmony_ci * a private data area of size @priv_size that can be accessed using
11862306a36Sopenharmony_ci * vport_priv().  Some parameters of the vport will be initialized from @parms.
11962306a36Sopenharmony_ci * @vports that are no longer needed should be released with
12062306a36Sopenharmony_ci * vport_free().
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_cistruct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
12362306a36Sopenharmony_ci			      const struct vport_parms *parms)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct vport *vport;
12662306a36Sopenharmony_ci	size_t alloc_size;
12762306a36Sopenharmony_ci	int err;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	alloc_size = sizeof(struct vport);
13062306a36Sopenharmony_ci	if (priv_size) {
13162306a36Sopenharmony_ci		alloc_size = ALIGN(alloc_size, VPORT_ALIGN);
13262306a36Sopenharmony_ci		alloc_size += priv_size;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	vport = kzalloc(alloc_size, GFP_KERNEL);
13662306a36Sopenharmony_ci	if (!vport)
13762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
14062306a36Sopenharmony_ci	if (!vport->upcall_stats) {
14162306a36Sopenharmony_ci		err = -ENOMEM;
14262306a36Sopenharmony_ci		goto err_kfree_vport;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	vport->dp = parms->dp;
14662306a36Sopenharmony_ci	vport->port_no = parms->port_no;
14762306a36Sopenharmony_ci	vport->ops = ops;
14862306a36Sopenharmony_ci	INIT_HLIST_NODE(&vport->dp_hash_node);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) {
15162306a36Sopenharmony_ci		err = -EINVAL;
15262306a36Sopenharmony_ci		goto err_free_percpu;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return vport;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cierr_free_percpu:
15862306a36Sopenharmony_ci	free_percpu(vport->upcall_stats);
15962306a36Sopenharmony_cierr_kfree_vport:
16062306a36Sopenharmony_ci	kfree(vport);
16162306a36Sopenharmony_ci	return ERR_PTR(err);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ovs_vport_alloc);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/**
16662306a36Sopenharmony_ci *	ovs_vport_free - uninitialize and free vport
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci * @vport: vport to free
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Frees a vport allocated with vport_alloc() when it is no longer needed.
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * The caller must ensure that an RCU grace period has passed since the last
17362306a36Sopenharmony_ci * time @vport was in a datapath.
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_civoid ovs_vport_free(struct vport *vport)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	/* vport is freed from RCU callback or error path, Therefore
17862306a36Sopenharmony_ci	 * it is safe to use raw dereference.
17962306a36Sopenharmony_ci	 */
18062306a36Sopenharmony_ci	kfree(rcu_dereference_raw(vport->upcall_portids));
18162306a36Sopenharmony_ci	free_percpu(vport->upcall_stats);
18262306a36Sopenharmony_ci	kfree(vport);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ovs_vport_free);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic struct vport_ops *ovs_vport_lookup(const struct vport_parms *parms)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct vport_ops *ops;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	list_for_each_entry(ops, &vport_ops_list, list)
19162306a36Sopenharmony_ci		if (ops->type == parms->type)
19262306a36Sopenharmony_ci			return ops;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return NULL;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/**
19862306a36Sopenharmony_ci *	ovs_vport_add - add vport device (for kernel callers)
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * @parms: Information about new vport.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * Creates a new vport with the specified configuration (which is dependent on
20362306a36Sopenharmony_ci * device type).  ovs_mutex must be held.
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cistruct vport *ovs_vport_add(const struct vport_parms *parms)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct vport_ops *ops;
20862306a36Sopenharmony_ci	struct vport *vport;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ops = ovs_vport_lookup(parms);
21162306a36Sopenharmony_ci	if (ops) {
21262306a36Sopenharmony_ci		struct hlist_head *bucket;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		if (!try_module_get(ops->owner))
21562306a36Sopenharmony_ci			return ERR_PTR(-EAFNOSUPPORT);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		vport = ops->create(parms);
21862306a36Sopenharmony_ci		if (IS_ERR(vport)) {
21962306a36Sopenharmony_ci			module_put(ops->owner);
22062306a36Sopenharmony_ci			return vport;
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		bucket = hash_bucket(ovs_dp_get_net(vport->dp),
22462306a36Sopenharmony_ci				     ovs_vport_name(vport));
22562306a36Sopenharmony_ci		hlist_add_head_rcu(&vport->hash_node, bucket);
22662306a36Sopenharmony_ci		return vport;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Unlock to attempt module load and return -EAGAIN if load
23062306a36Sopenharmony_ci	 * was successful as we need to restart the port addition
23162306a36Sopenharmony_ci	 * workflow.
23262306a36Sopenharmony_ci	 */
23362306a36Sopenharmony_ci	ovs_unlock();
23462306a36Sopenharmony_ci	request_module("vport-type-%d", parms->type);
23562306a36Sopenharmony_ci	ovs_lock();
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (!ovs_vport_lookup(parms))
23862306a36Sopenharmony_ci		return ERR_PTR(-EAFNOSUPPORT);
23962306a36Sopenharmony_ci	else
24062306a36Sopenharmony_ci		return ERR_PTR(-EAGAIN);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/**
24462306a36Sopenharmony_ci *	ovs_vport_set_options - modify existing vport device (for kernel callers)
24562306a36Sopenharmony_ci *
24662306a36Sopenharmony_ci * @vport: vport to modify.
24762306a36Sopenharmony_ci * @options: New configuration.
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * Modifies an existing device with the specified configuration (which is
25062306a36Sopenharmony_ci * dependent on device type).  ovs_mutex must be held.
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_ciint ovs_vport_set_options(struct vport *vport, struct nlattr *options)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	if (!vport->ops->set_options)
25562306a36Sopenharmony_ci		return -EOPNOTSUPP;
25662306a36Sopenharmony_ci	return vport->ops->set_options(vport, options);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/**
26062306a36Sopenharmony_ci *	ovs_vport_del - delete existing vport device
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * @vport: vport to delete.
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * Detaches @vport from its datapath and destroys it.  ovs_mutex must
26562306a36Sopenharmony_ci * be held.
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_civoid ovs_vport_del(struct vport *vport)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	hlist_del_rcu(&vport->hash_node);
27062306a36Sopenharmony_ci	module_put(vport->ops->owner);
27162306a36Sopenharmony_ci	vport->ops->destroy(vport);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/**
27562306a36Sopenharmony_ci *	ovs_vport_get_stats - retrieve device stats
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * @vport: vport from which to retrieve the stats
27862306a36Sopenharmony_ci * @stats: location to store stats
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * Retrieves transmit, receive, and error stats for the given device.
28162306a36Sopenharmony_ci *
28262306a36Sopenharmony_ci * Must be called with ovs_mutex or rcu_read_lock.
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_civoid ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	const struct rtnl_link_stats64 *dev_stats;
28762306a36Sopenharmony_ci	struct rtnl_link_stats64 temp;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	dev_stats = dev_get_stats(vport->dev, &temp);
29062306a36Sopenharmony_ci	stats->rx_errors  = dev_stats->rx_errors;
29162306a36Sopenharmony_ci	stats->tx_errors  = dev_stats->tx_errors;
29262306a36Sopenharmony_ci	stats->tx_dropped = dev_stats->tx_dropped;
29362306a36Sopenharmony_ci	stats->rx_dropped = dev_stats->rx_dropped;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	stats->rx_bytes	  = dev_stats->rx_bytes;
29662306a36Sopenharmony_ci	stats->rx_packets = dev_stats->rx_packets;
29762306a36Sopenharmony_ci	stats->tx_bytes	  = dev_stats->tx_bytes;
29862306a36Sopenharmony_ci	stats->tx_packets = dev_stats->tx_packets;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/**
30262306a36Sopenharmony_ci *	ovs_vport_get_upcall_stats - retrieve upcall stats
30362306a36Sopenharmony_ci *
30462306a36Sopenharmony_ci * @vport: vport from which to retrieve the stats.
30562306a36Sopenharmony_ci * @skb: sk_buff where upcall stats should be appended.
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci * Retrieves upcall stats for the given device.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Must be called with ovs_mutex or rcu_read_lock.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_ciint ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct nlattr *nla;
31462306a36Sopenharmony_ci	int i;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	__u64 tx_success = 0;
31762306a36Sopenharmony_ci	__u64 tx_fail = 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	for_each_possible_cpu(i) {
32062306a36Sopenharmony_ci		const struct vport_upcall_stats_percpu *stats;
32162306a36Sopenharmony_ci		unsigned int start;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		stats = per_cpu_ptr(vport->upcall_stats, i);
32462306a36Sopenharmony_ci		do {
32562306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&stats->syncp);
32662306a36Sopenharmony_ci			tx_success += u64_stats_read(&stats->n_success);
32762306a36Sopenharmony_ci			tx_fail += u64_stats_read(&stats->n_fail);
32862306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&stats->syncp, start));
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_UPCALL_STATS);
33262306a36Sopenharmony_ci	if (!nla)
33362306a36Sopenharmony_ci		return -EMSGSIZE;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_SUCCESS, tx_success,
33662306a36Sopenharmony_ci			      OVS_VPORT_ATTR_PAD)) {
33762306a36Sopenharmony_ci		nla_nest_cancel(skb, nla);
33862306a36Sopenharmony_ci		return -EMSGSIZE;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_FAIL, tx_fail,
34262306a36Sopenharmony_ci			      OVS_VPORT_ATTR_PAD)) {
34362306a36Sopenharmony_ci		nla_nest_cancel(skb, nla);
34462306a36Sopenharmony_ci		return -EMSGSIZE;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci	nla_nest_end(skb, nla);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/**
35262306a36Sopenharmony_ci *	ovs_vport_get_options - retrieve device options
35362306a36Sopenharmony_ci *
35462306a36Sopenharmony_ci * @vport: vport from which to retrieve the options.
35562306a36Sopenharmony_ci * @skb: sk_buff where options should be appended.
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * Retrieves the configuration of the given device, appending an
35862306a36Sopenharmony_ci * %OVS_VPORT_ATTR_OPTIONS attribute that in turn contains nested
35962306a36Sopenharmony_ci * vport-specific attributes to @skb.
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room, or another
36262306a36Sopenharmony_ci * negative error code if a real error occurred.  If an error occurs, @skb is
36362306a36Sopenharmony_ci * left unmodified.
36462306a36Sopenharmony_ci *
36562306a36Sopenharmony_ci * Must be called with ovs_mutex or rcu_read_lock.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_ciint ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct nlattr *nla;
37062306a36Sopenharmony_ci	int err;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!vport->ops->get_options)
37362306a36Sopenharmony_ci		return 0;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_OPTIONS);
37662306a36Sopenharmony_ci	if (!nla)
37762306a36Sopenharmony_ci		return -EMSGSIZE;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	err = vport->ops->get_options(vport, skb);
38062306a36Sopenharmony_ci	if (err) {
38162306a36Sopenharmony_ci		nla_nest_cancel(skb, nla);
38262306a36Sopenharmony_ci		return err;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	nla_nest_end(skb, nla);
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/**
39062306a36Sopenharmony_ci *	ovs_vport_set_upcall_portids - set upcall portids of @vport.
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * @vport: vport to modify.
39362306a36Sopenharmony_ci * @ids: new configuration, an array of port ids.
39462306a36Sopenharmony_ci *
39562306a36Sopenharmony_ci * Sets the vport's upcall_portids to @ids.
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed
39862306a36Sopenharmony_ci * as an array of U32.
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * Must be called with ovs_mutex.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_ciint ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct vport_portids *old, *vport_portids;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (!nla_len(ids) || nla_len(ids) % sizeof(u32))
40762306a36Sopenharmony_ci		return -EINVAL;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	old = ovsl_dereference(vport->upcall_portids);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids),
41262306a36Sopenharmony_ci				GFP_KERNEL);
41362306a36Sopenharmony_ci	if (!vport_portids)
41462306a36Sopenharmony_ci		return -ENOMEM;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	vport_portids->n_ids = nla_len(ids) / sizeof(u32);
41762306a36Sopenharmony_ci	vport_portids->rn_ids = reciprocal_value(vport_portids->n_ids);
41862306a36Sopenharmony_ci	nla_memcpy(vport_portids->ids, ids, nla_len(ids));
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	rcu_assign_pointer(vport->upcall_portids, vport_portids);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (old)
42362306a36Sopenharmony_ci		kfree_rcu(old, rcu);
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/**
42862306a36Sopenharmony_ci *	ovs_vport_get_upcall_portids - get the upcall_portids of @vport.
42962306a36Sopenharmony_ci *
43062306a36Sopenharmony_ci * @vport: vport from which to retrieve the portids.
43162306a36Sopenharmony_ci * @skb: sk_buff where portids should be appended.
43262306a36Sopenharmony_ci *
43362306a36Sopenharmony_ci * Retrieves the configuration of the given vport, appending the
43462306a36Sopenharmony_ci * %OVS_VPORT_ATTR_UPCALL_PID attribute which is the array of upcall
43562306a36Sopenharmony_ci * portids to @skb.
43662306a36Sopenharmony_ci *
43762306a36Sopenharmony_ci * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room.
43862306a36Sopenharmony_ci * If an error occurs, @skb is left unmodified.  Must be called with
43962306a36Sopenharmony_ci * ovs_mutex or rcu_read_lock.
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_ciint ovs_vport_get_upcall_portids(const struct vport *vport,
44262306a36Sopenharmony_ci				 struct sk_buff *skb)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct vport_portids *ids;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ids = rcu_dereference_ovsl(vport->upcall_portids);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (vport->dp->user_features & OVS_DP_F_VPORT_PIDS)
44962306a36Sopenharmony_ci		return nla_put(skb, OVS_VPORT_ATTR_UPCALL_PID,
45062306a36Sopenharmony_ci			       ids->n_ids * sizeof(u32), (void *)ids->ids);
45162306a36Sopenharmony_ci	else
45262306a36Sopenharmony_ci		return nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, ids->ids[0]);
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/**
45662306a36Sopenharmony_ci *	ovs_vport_find_upcall_portid - find the upcall portid to send upcall.
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * @vport: vport from which the missed packet is received.
45962306a36Sopenharmony_ci * @skb: skb that the missed packet was received.
46062306a36Sopenharmony_ci *
46162306a36Sopenharmony_ci * Uses the skb_get_hash() to select the upcall portid to send the
46262306a36Sopenharmony_ci * upcall.
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci * Returns the portid of the target socket.  Must be called with rcu_read_lock.
46562306a36Sopenharmony_ci */
46662306a36Sopenharmony_ciu32 ovs_vport_find_upcall_portid(const struct vport *vport,
46762306a36Sopenharmony_ci				 struct sk_buff *skb)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct vport_portids *ids;
47062306a36Sopenharmony_ci	u32 ids_index;
47162306a36Sopenharmony_ci	u32 hash;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	ids = rcu_dereference(vport->upcall_portids);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* If there is only one portid, select it in the fast-path. */
47662306a36Sopenharmony_ci	if (ids->n_ids == 1)
47762306a36Sopenharmony_ci		return ids->ids[0];
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	hash = skb_get_hash(skb);
48062306a36Sopenharmony_ci	ids_index = hash - ids->n_ids * reciprocal_divide(hash, ids->rn_ids);
48162306a36Sopenharmony_ci	return ids->ids[ids_index];
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**
48562306a36Sopenharmony_ci *	ovs_vport_receive - pass up received packet to the datapath for processing
48662306a36Sopenharmony_ci *
48762306a36Sopenharmony_ci * @vport: vport that received the packet
48862306a36Sopenharmony_ci * @skb: skb that was received
48962306a36Sopenharmony_ci * @tun_info: tunnel (if any) that carried packet
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci * Must be called with rcu_read_lock.  The packet cannot be shared and
49262306a36Sopenharmony_ci * skb->data should point to the Ethernet header.
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_ciint ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
49562306a36Sopenharmony_ci		      const struct ip_tunnel_info *tun_info)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct sw_flow_key key;
49862306a36Sopenharmony_ci	int error;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	OVS_CB(skb)->input_vport = vport;
50162306a36Sopenharmony_ci	OVS_CB(skb)->mru = 0;
50262306a36Sopenharmony_ci	OVS_CB(skb)->cutlen = 0;
50362306a36Sopenharmony_ci	if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
50462306a36Sopenharmony_ci		u32 mark;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		mark = skb->mark;
50762306a36Sopenharmony_ci		skb_scrub_packet(skb, true);
50862306a36Sopenharmony_ci		skb->mark = mark;
50962306a36Sopenharmony_ci		tun_info = NULL;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Extract flow from 'skb' into 'key'. */
51362306a36Sopenharmony_ci	error = ovs_flow_key_extract(tun_info, skb, &key);
51462306a36Sopenharmony_ci	if (unlikely(error)) {
51562306a36Sopenharmony_ci		kfree_skb(skb);
51662306a36Sopenharmony_ci		return error;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	ovs_dp_process_packet(skb, &key);
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int packet_length(const struct sk_buff *skb,
52362306a36Sopenharmony_ci			 struct net_device *dev)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	int length = skb->len - dev->hard_header_len;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (!skb_vlan_tag_present(skb) &&
52862306a36Sopenharmony_ci	    eth_type_vlan(skb->protocol))
52962306a36Sopenharmony_ci		length -= VLAN_HLEN;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* Don't subtract for multiple VLAN tags. Most (all?) drivers allow
53262306a36Sopenharmony_ci	 * (ETH_LEN + VLAN_HLEN) in addition to the mtu value, but almost none
53362306a36Sopenharmony_ci	 * account for 802.1ad. e.g. is_skb_forwardable().
53462306a36Sopenharmony_ci	 */
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return length > 0 ? length : 0;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_civoid ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	int mtu = vport->dev->mtu;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	switch (vport->dev->type) {
54462306a36Sopenharmony_ci	case ARPHRD_NONE:
54562306a36Sopenharmony_ci		if (mac_proto == MAC_PROTO_ETHERNET) {
54662306a36Sopenharmony_ci			skb_reset_network_header(skb);
54762306a36Sopenharmony_ci			skb_reset_mac_len(skb);
54862306a36Sopenharmony_ci			skb->protocol = htons(ETH_P_TEB);
54962306a36Sopenharmony_ci		} else if (mac_proto != MAC_PROTO_NONE) {
55062306a36Sopenharmony_ci			WARN_ON_ONCE(1);
55162306a36Sopenharmony_ci			goto drop;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci	case ARPHRD_ETHER:
55562306a36Sopenharmony_ci		if (mac_proto != MAC_PROTO_ETHERNET)
55662306a36Sopenharmony_ci			goto drop;
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	default:
55962306a36Sopenharmony_ci		goto drop;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (unlikely(packet_length(skb, vport->dev) > mtu &&
56362306a36Sopenharmony_ci		     !skb_is_gso(skb))) {
56462306a36Sopenharmony_ci		vport->dev->stats.tx_errors++;
56562306a36Sopenharmony_ci		if (vport->dev->flags & IFF_UP)
56662306a36Sopenharmony_ci			net_warn_ratelimited("%s: dropped over-mtu packet: "
56762306a36Sopenharmony_ci					     "%d > %d\n", vport->dev->name,
56862306a36Sopenharmony_ci					     packet_length(skb, vport->dev),
56962306a36Sopenharmony_ci					     mtu);
57062306a36Sopenharmony_ci		goto drop;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	skb->dev = vport->dev;
57462306a36Sopenharmony_ci	skb_clear_tstamp(skb);
57562306a36Sopenharmony_ci	vport->ops->send(skb);
57662306a36Sopenharmony_ci	return;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cidrop:
57962306a36Sopenharmony_ci	kfree_skb(skb);
58062306a36Sopenharmony_ci}
581