2011-10-26 06:26:31 +04:00
/*
2012-05-04 05:55:23 +04:00
* Copyright ( c ) 2007 - 2012 Nicira , Inc .
2011-10-26 06:26:31 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/if_arp.h>
# include <linux/if_bridge.h>
# include <linux/if_vlan.h>
# include <linux/kernel.h>
# include <linux/llc.h>
# include <linux/rtnetlink.h>
# include <linux/skbuff.h>
2013-07-26 16:01:54 +04:00
# include <linux/openvswitch.h>
2015-07-29 14:52:06 +03:00
# include <linux/export.h>
2011-10-26 06:26:31 +04:00
2015-07-21 11:44:06 +03:00
# include <net/ip_tunnels.h>
# include <net/rtnetlink.h>
2011-10-26 06:26:31 +04:00
# include "datapath.h"
2015-07-21 11:44:06 +03:00
# include "vport.h"
2011-10-26 06:26:31 +04:00
# include "vport-internal_dev.h"
# include "vport-netdev.h"
2014-10-22 19:29:06 +04:00
static struct vport_ops ovs_netdev_vport_ops ;
2011-10-26 06:26:31 +04:00
/* Must be called with rcu_read_lock. */
static void netdev_port_receive ( struct vport * vport , struct sk_buff * skb )
{
2013-01-22 11:57:26 +04:00
if ( unlikely ( ! vport ) )
goto error ;
if ( unlikely ( skb_warn_if_lro ( skb ) ) )
goto error ;
2011-10-26 06:26:31 +04:00
/* Make our own copy of the packet. Otherwise we will mangle the
* packet for anyone who came before us ( e . g . tcpdump via AF_PACKET ) .
2013-02-22 15:41:26 +04:00
*/
2011-10-26 06:26:31 +04:00
skb = skb_share_check ( skb , GFP_ATOMIC ) ;
if ( unlikely ( ! skb ) )
return ;
skb_push ( skb , ETH_HLEN ) ;
2013-06-13 22:11:44 +04:00
ovs_skb_postpush_rcsum ( skb , skb - > data , ETH_HLEN ) ;
2015-07-23 14:04:44 +03:00
ovs_vport_receive ( vport , skb , skb_tunnel_info ( skb , AF_INET ) ) ;
2013-01-22 11:57:26 +04:00
return ;
error :
kfree_skb ( skb ) ;
2011-10-26 06:26:31 +04:00
}
/* Called with rcu_read_lock and bottom-halves disabled. */
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 ) ;
return RX_HANDLER_CONSUMED ;
}
2014-11-06 17:58:52 +03:00
static struct net_device * get_dpdev ( const struct datapath * dp )
2013-07-26 16:01:54 +04:00
{
struct vport * local ;
local = ovs_vport_ovsl ( dp , OVSP_LOCAL ) ;
BUG_ON ( ! local ) ;
2015-07-21 11:44:04 +03:00
return local - > dev ;
2013-07-26 16:01:54 +04:00
}
2015-07-29 14:52:06 +03:00
struct vport * ovs_netdev_link ( struct vport * vport , const char * name )
2011-10-26 06:26:31 +04:00
{
int err ;
2015-07-21 11:44:04 +03:00
vport - > dev = dev_get_by_name ( ovs_dp_get_net ( vport - > dp ) , name ) ;
if ( ! vport - > dev ) {
2011-10-26 06:26:31 +04:00
err = - ENODEV ;
goto error_free_vport ;
}
2015-07-21 11:44:04 +03:00
if ( vport - > dev - > flags & IFF_LOOPBACK | |
vport - > dev - > type ! = ARPHRD_ETHER | |
ovs_is_internal_dev ( vport - > dev ) ) {
2011-10-26 06:26:31 +04:00
err = - EINVAL ;
goto error_put ;
}
2013-04-16 00:23:03 +04:00
rtnl_lock ( ) ;
2015-07-21 11:44:04 +03:00
err = netdev_master_upper_dev_link ( vport - > dev ,
2013-07-26 16:01:54 +04:00
get_dpdev ( vport - > dp ) ) ;
if ( err )
goto error_unlock ;
2015-07-21 11:44:04 +03:00
err = netdev_rx_handler_register ( vport - > dev , netdev_frame_hook ,
2011-10-26 06:26:31 +04:00
vport ) ;
if ( err )
2013-07-26 16:01:54 +04:00
goto error_master_upper_dev_unlink ;
2011-10-26 06:26:31 +04:00
2015-07-21 11:44:04 +03:00
dev_disable_lro ( vport - > dev ) ;
dev_set_promiscuity ( vport - > dev , 1 ) ;
vport - > dev - > priv_flags | = IFF_OVS_DATAPATH ;
2013-04-16 00:23:03 +04:00
rtnl_unlock ( ) ;
2011-10-26 06:26:31 +04:00
return vport ;
2013-07-26 16:01:54 +04:00
error_master_upper_dev_unlink :
2015-07-21 11:44:04 +03:00
netdev_upper_dev_unlink ( vport - > dev , get_dpdev ( vport - > dp ) ) ;
2013-04-16 00:23:03 +04:00
error_unlock :
rtnl_unlock ( ) ;
2011-10-26 06:26:31 +04:00
error_put :
2015-07-21 11:44:04 +03:00
dev_put ( vport - > dev ) ;
2011-10-26 06:26:31 +04:00
error_free_vport :
ovs_vport_free ( vport ) ;
return ERR_PTR ( err ) ;
}
2015-07-29 14:52:06 +03:00
EXPORT_SYMBOL_GPL ( ovs_netdev_link ) ;
2011-10-26 06:26:31 +04:00
2015-07-21 11:44:04 +03:00
static struct vport * netdev_create ( const struct vport_parms * parms )
{
struct vport * vport ;
vport = ovs_vport_alloc ( 0 , & ovs_netdev_vport_ops , parms ) ;
if ( IS_ERR ( vport ) )
return vport ;
2015-07-29 14:52:06 +03:00
return ovs_netdev_link ( vport , parms - > name ) ;
2015-07-21 11:44:04 +03:00
}
2015-07-29 14:52:06 +03:00
void ovs_vport_free_rcu ( struct rcu_head * rcu )
2012-11-29 02:01:52 +04:00
{
2015-07-21 11:44:04 +03:00
struct vport * vport = container_of ( rcu , struct vport , rcu ) ;
2012-11-29 02:01:52 +04:00
2015-07-21 11:44:06 +03:00
if ( vport - > dev )
dev_put ( vport - > dev ) ;
2015-07-21 11:44:04 +03:00
ovs_vport_free ( vport ) ;
2012-11-29 02:01:52 +04:00
}
2015-07-29 14:52:06 +03:00
EXPORT_SYMBOL_GPL ( ovs_vport_free_rcu ) ;
2012-11-29 02:01:52 +04:00
2013-10-16 01:54:11 +04:00
void ovs_netdev_detach_dev ( struct vport * vport )
2011-10-26 06:26:31 +04:00
{
2013-10-16 01:54:11 +04:00
ASSERT_RTNL ( ) ;
2015-07-21 11:44:04 +03:00
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 ) ;
2013-10-16 01:54:11 +04:00
}
2015-07-29 14:52:06 +03:00
EXPORT_SYMBOL_GPL ( ovs_netdev_detach_dev ) ;
2013-10-16 01:54:11 +04:00
static void netdev_destroy ( struct vport * vport )
{
rtnl_lock ( ) ;
2015-07-21 11:44:04 +03:00
if ( vport - > dev - > priv_flags & IFF_OVS_DATAPATH )
2013-10-16 01:54:11 +04:00
ovs_netdev_detach_dev ( vport ) ;
2013-04-16 00:23:03 +04:00
rtnl_unlock ( ) ;
2011-10-26 06:26:31 +04:00
2015-07-29 14:52:06 +03:00
call_rcu ( & vport - > rcu , ovs_vport_free_rcu ) ;
2011-10-26 06:26:31 +04:00
}
2012-04-15 09:58:06 +04:00
static unsigned int packet_length ( const struct sk_buff * skb )
2011-10-26 06:26:31 +04:00
{
2012-04-15 09:58:06 +04:00
unsigned int length = skb - > len - ETH_HLEN ;
2011-10-26 06:26:31 +04:00
if ( skb - > protocol = = htons ( ETH_P_8021Q ) )
length - = VLAN_HLEN ;
return length ;
}
2015-07-29 14:52:06 +03:00
int ovs_netdev_send ( struct vport * vport , struct sk_buff * skb )
2011-10-26 06:26:31 +04:00
{
2015-07-21 11:44:04 +03:00
int mtu = vport - > dev - > mtu ;
2011-10-26 06:26:31 +04:00
int len ;
if ( unlikely ( packet_length ( skb ) > mtu & & ! skb_is_gso ( skb ) ) ) {
2012-05-14 01:56:26 +04:00
net_warn_ratelimited ( " %s: dropped over-mtu packet: %d > %d \n " ,
2015-07-21 11:44:04 +03:00
vport - > dev - > name ,
2012-05-14 01:56:26 +04:00
packet_length ( skb ) , mtu ) ;
2013-05-13 19:22:34 +04:00
goto drop ;
2011-10-26 06:26:31 +04:00
}
2015-07-21 11:44:04 +03:00
skb - > dev = vport - > dev ;
2011-10-26 06:26:31 +04:00
len = skb - > len ;
dev_queue_xmit ( skb ) ;
return len ;
2013-05-13 19:22:34 +04:00
drop :
2011-10-26 06:26:31 +04:00
kfree_skb ( skb ) ;
return 0 ;
}
2015-07-29 14:52:06 +03:00
EXPORT_SYMBOL_GPL ( ovs_netdev_send ) ;
2011-10-26 06:26:31 +04:00
/* Returns null if this device is not attached to a datapath. */
struct vport * ovs_netdev_get_vport ( struct net_device * dev )
{
if ( likely ( dev - > priv_flags & IFF_OVS_DATAPATH ) )
return ( struct vport * )
rcu_dereference_rtnl ( dev - > rx_handler_data ) ;
else
return NULL ;
}
2014-10-22 19:29:06 +04:00
static struct vport_ops ovs_netdev_vport_ops = {
2011-10-26 06:26:31 +04:00
. type = OVS_VPORT_TYPE_NETDEV ,
. create = netdev_create ,
. destroy = netdev_destroy ,
2015-07-29 14:52:06 +03:00
. send = ovs_netdev_send ,
2011-10-26 06:26:31 +04:00
} ;
2014-10-22 19:29:06 +04:00
int __init ovs_netdev_init ( void )
{
2015-07-29 14:52:06 +03:00
return ovs_vport_ops_register ( & ovs_netdev_vport_ops ) ;
2014-10-22 19:29:06 +04:00
}
void ovs_netdev_exit ( void )
{
ovs_vport_ops_unregister ( & ovs_netdev_vport_ops ) ;
}