diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /net/openvswitch/vport-netdev.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'net/openvswitch/vport-netdev.c')
| -rw-r--r-- | net/openvswitch/vport-netdev.c | 137 | 
1 files changed, 70 insertions, 67 deletions
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 33e6d6e2908f..f7e8dcce7ada 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -26,18 +26,24 @@  #include <linux/rtnetlink.h>  #include <linux/skbuff.h>  #include <linux/openvswitch.h> +#include <linux/export.h> -#include <net/llc.h> +#include <net/ip_tunnels.h> +#include <net/rtnetlink.h>  #include "datapath.h" +#include "vport.h"  #include "vport-internal_dev.h"  #include "vport-netdev.h"  static struct vport_ops ovs_netdev_vport_ops;  /* Must be called with rcu_read_lock. */ -static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) +static void netdev_port_receive(struct sk_buff *skb)  { +	struct vport *vport; + +	vport = ovs_netdev_get_vport(skb->dev);  	if (unlikely(!vport))  		goto error; @@ -53,10 +59,8 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)  	skb_push(skb, ETH_HLEN);  	ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); - -	ovs_vport_receive(vport, skb, NULL); +	ovs_vport_receive(vport, skb, skb_tunnel_info(skb));  	return; -  error:  	kfree_skb(skb);  } @@ -65,15 +69,11 @@ error:  static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb)  {  	struct sk_buff *skb = *pskb; -	struct vport *vport;  	if (unlikely(skb->pkt_type == PACKET_LOOPBACK))  		return RX_HANDLER_PASS; -	vport = ovs_netdev_get_vport(skb->dev); - -	netdev_port_receive(vport, skb); - +	netdev_port_receive(skb);  	return RX_HANDLER_CONSUMED;  } @@ -83,105 +83,112 @@ static struct net_device *get_dpdev(const struct datapath *dp)  	local = ovs_vport_ovsl(dp, OVSP_LOCAL);  	BUG_ON(!local); -	return netdev_vport_priv(local)->dev; +	return local->dev;  } -static struct vport *netdev_create(const struct vport_parms *parms) +struct vport *ovs_netdev_link(struct vport *vport, const char *name)  { -	struct vport *vport; -	struct netdev_vport *netdev_vport;  	int err; -	vport = ovs_vport_alloc(sizeof(struct netdev_vport), -				&ovs_netdev_vport_ops, parms); -	if (IS_ERR(vport)) { -		err = PTR_ERR(vport); -		goto error; -	} - -	netdev_vport = netdev_vport_priv(vport); - -	netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); -	if (!netdev_vport->dev) { +	vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), name); +	if (!vport->dev) {  		err = -ENODEV;  		goto error_free_vport;  	} -	if (netdev_vport->dev->flags & IFF_LOOPBACK || -	    netdev_vport->dev->type != ARPHRD_ETHER || -	    ovs_is_internal_dev(netdev_vport->dev)) { +	if (vport->dev->flags & IFF_LOOPBACK || +	    vport->dev->type != ARPHRD_ETHER || +	    ovs_is_internal_dev(vport->dev)) {  		err = -EINVAL;  		goto error_put;  	}  	rtnl_lock(); -	err = netdev_master_upper_dev_link(netdev_vport->dev, +	err = netdev_master_upper_dev_link(vport->dev,  					   get_dpdev(vport->dp));  	if (err)  		goto error_unlock; -	err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, +	err = netdev_rx_handler_register(vport->dev, netdev_frame_hook,  					 vport);  	if (err)  		goto error_master_upper_dev_unlink; -	dev_disable_lro(netdev_vport->dev); -	dev_set_promiscuity(netdev_vport->dev, 1); -	netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; +	dev_disable_lro(vport->dev); +	dev_set_promiscuity(vport->dev, 1); +	vport->dev->priv_flags |= IFF_OVS_DATAPATH;  	rtnl_unlock();  	return vport;  error_master_upper_dev_unlink: -	netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); +	netdev_upper_dev_unlink(vport->dev, get_dpdev(vport->dp));  error_unlock:  	rtnl_unlock();  error_put: -	dev_put(netdev_vport->dev); +	dev_put(vport->dev);  error_free_vport:  	ovs_vport_free(vport); -error:  	return ERR_PTR(err);  } +EXPORT_SYMBOL_GPL(ovs_netdev_link); -static void free_port_rcu(struct rcu_head *rcu) +static struct vport *netdev_create(const struct vport_parms *parms)  { -	struct netdev_vport *netdev_vport = container_of(rcu, -					struct netdev_vport, rcu); +	struct vport *vport; + +	vport = ovs_vport_alloc(0, &ovs_netdev_vport_ops, parms); +	if (IS_ERR(vport)) +		return vport; -	dev_put(netdev_vport->dev); -	ovs_vport_free(vport_from_priv(netdev_vport)); +	return ovs_netdev_link(vport, parms->name);  } -void ovs_netdev_detach_dev(struct vport *vport) +static void vport_netdev_free(struct rcu_head *rcu)  { -	struct netdev_vport *netdev_vport = netdev_vport_priv(vport); +	struct vport *vport = container_of(rcu, struct vport, rcu); + +	if (vport->dev) +		dev_put(vport->dev); +	ovs_vport_free(vport); +} +void ovs_netdev_detach_dev(struct vport *vport) +{  	ASSERT_RTNL(); -	netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; -	netdev_rx_handler_unregister(netdev_vport->dev); -	netdev_upper_dev_unlink(netdev_vport->dev, -				netdev_master_upper_dev_get(netdev_vport->dev)); -	dev_set_promiscuity(netdev_vport->dev, -1); +	vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; +	netdev_rx_handler_unregister(vport->dev); +	netdev_upper_dev_unlink(vport->dev, +				netdev_master_upper_dev_get(vport->dev)); +	dev_set_promiscuity(vport->dev, -1);  } +EXPORT_SYMBOL_GPL(ovs_netdev_detach_dev);  static void netdev_destroy(struct vport *vport)  { -	struct netdev_vport *netdev_vport = netdev_vport_priv(vport); -  	rtnl_lock(); -	if (netdev_vport->dev->priv_flags & IFF_OVS_DATAPATH) +	if (vport->dev->priv_flags & IFF_OVS_DATAPATH)  		ovs_netdev_detach_dev(vport);  	rtnl_unlock(); -	call_rcu(&netdev_vport->rcu, free_port_rcu); +	call_rcu(&vport->rcu, vport_netdev_free);  } -const char *ovs_netdev_get_name(const struct vport *vport) +void ovs_netdev_tunnel_destroy(struct vport *vport)  { -	const struct netdev_vport *netdev_vport = netdev_vport_priv(vport); -	return netdev_vport->dev->name; +	rtnl_lock(); +	if (vport->dev->priv_flags & IFF_OVS_DATAPATH) +		ovs_netdev_detach_dev(vport); + +	/* Early release so we can unregister the device */ +	dev_put(vport->dev); +	rtnl_delete_link(vport->dev); +	vport->dev = NULL; +	rtnl_unlock(); + +	call_rcu(&vport->rcu, vport_netdev_free);  } +EXPORT_SYMBOL_GPL(ovs_netdev_tunnel_destroy);  static unsigned int packet_length(const struct sk_buff *skb)  { @@ -193,29 +200,26 @@ static unsigned int packet_length(const struct sk_buff *skb)  	return length;  } -static int netdev_send(struct vport *vport, struct sk_buff *skb) +void ovs_netdev_send(struct vport *vport, struct sk_buff *skb)  { -	struct netdev_vport *netdev_vport = netdev_vport_priv(vport); -	int mtu = netdev_vport->dev->mtu; -	int len; +	int mtu = vport->dev->mtu;  	if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {  		net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", -				     netdev_vport->dev->name, +				     vport->dev->name,  				     packet_length(skb), mtu); +		vport->dev->stats.tx_errors++;  		goto drop;  	} -	skb->dev = netdev_vport->dev; -	len = skb->len; +	skb->dev = vport->dev;  	dev_queue_xmit(skb); - -	return len; +	return;  drop:  	kfree_skb(skb); -	return 0;  } +EXPORT_SYMBOL_GPL(ovs_netdev_send);  /* Returns null if this device is not attached to a datapath. */  struct vport *ovs_netdev_get_vport(struct net_device *dev) @@ -231,8 +235,7 @@ static struct vport_ops ovs_netdev_vport_ops = {  	.type		= OVS_VPORT_TYPE_NETDEV,  	.create		= netdev_create,  	.destroy	= netdev_destroy, -	.get_name	= ovs_netdev_get_name, -	.send		= netdev_send, +	.send		= ovs_netdev_send,  };  int __init ovs_netdev_init(void)  |