2013-08-19 11:23:34 -07:00
/*
2014-09-15 19:28:44 -07:00
* Copyright ( c ) 2014 Nicira , Inc .
2013-08-19 11:23:34 -07:00
* Copyright ( c ) 2013 Cisco Systems , Inc .
*
* 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/in.h>
# include <linux/ip.h>
# include <linux/net.h>
# include <linux/rculist.h>
# include <linux/udp.h>
2014-10-22 17:29:06 +02:00
# include <linux/module.h>
2013-08-19 11:23:34 -07:00
# include <net/icmp.h>
# include <net/ip.h>
# include <net/udp.h>
# include <net/ip_tunnels.h>
# include <net/rtnetlink.h>
# include <net/route.h>
# include <net/dsfield.h>
# include <net/inet_ecn.h>
# include <net/net_namespace.h>
# include <net/netns/generic.h>
# include <net/vxlan.h>
# include "datapath.h"
# include "vport.h"
/**
* struct vxlan_port - Keeps track of open UDP ports
* @ vs : vxlan_sock created for the port .
* @ name : vport name .
*/
struct vxlan_port {
struct vxlan_sock * vs ;
char name [ IFNAMSIZ ] ;
} ;
2014-10-22 17:29:06 +02:00
static struct vport_ops ovs_vxlan_vport_ops ;
2013-08-19 11:23:34 -07:00
static inline struct vxlan_port * vxlan_vport ( const struct vport * vport )
{
return vport_priv ( vport ) ;
}
/* Called with rcu_read_lock and BH disabled. */
static void vxlan_rcv ( struct vxlan_sock * vs , struct sk_buff * skb , __be32 vx_vni )
{
2014-10-03 15:35:31 -07:00
struct ovs_tunnel_info tun_info ;
2013-08-19 11:23:34 -07:00
struct vport * vport = vs - > data ;
struct iphdr * iph ;
__be64 key ;
/* Save outer tunnel values */
iph = ip_hdr ( skb ) ;
key = cpu_to_be64 ( ntohl ( vx_vni ) > > 8 ) ;
2014-11-06 06:51:24 -08:00
ovs_flow_tun_info_init ( & tun_info , iph ,
udp_hdr ( skb ) - > source , udp_hdr ( skb ) - > dest ,
key , TUNNEL_KEY , NULL , 0 ) ;
2013-08-19 11:23:34 -07:00
2014-10-03 15:35:31 -07:00
ovs_vport_receive ( vport , skb , & tun_info ) ;
2013-08-19 11:23:34 -07:00
}
static int vxlan_get_options ( const struct vport * vport , struct sk_buff * skb )
{
struct vxlan_port * vxlan_port = vxlan_vport ( vport ) ;
__be16 dst_port = inet_sk ( vxlan_port - > vs - > sock - > sk ) - > inet_sport ;
if ( nla_put_u16 ( skb , OVS_TUNNEL_ATTR_DST_PORT , ntohs ( dst_port ) ) )
return - EMSGSIZE ;
return 0 ;
}
static void vxlan_tnl_destroy ( struct vport * vport )
{
struct vxlan_port * vxlan_port = vxlan_vport ( vport ) ;
vxlan_sock_release ( vxlan_port - > vs ) ;
ovs_vport_deferred_free ( vport ) ;
}
static struct vport * vxlan_tnl_create ( const struct vport_parms * parms )
{
struct net * net = ovs_dp_get_net ( parms - > dp ) ;
struct nlattr * options = parms - > options ;
struct vxlan_port * vxlan_port ;
struct vxlan_sock * vs ;
struct vport * vport ;
struct nlattr * a ;
u16 dst_port ;
int err ;
if ( ! options ) {
err = - EINVAL ;
goto error ;
}
a = nla_find_nested ( options , OVS_TUNNEL_ATTR_DST_PORT ) ;
if ( a & & nla_len ( a ) = = sizeof ( u16 ) ) {
dst_port = nla_get_u16 ( a ) ;
} else {
/* Require destination port from userspace. */
err = - EINVAL ;
goto error ;
}
vport = ovs_vport_alloc ( sizeof ( struct vxlan_port ) ,
& ovs_vxlan_vport_ops , parms ) ;
if ( IS_ERR ( vport ) )
return vport ;
vxlan_port = vxlan_vport ( vport ) ;
strncpy ( vxlan_port - > name , parms - > name , IFNAMSIZ ) ;
2014-06-04 17:20:29 -07:00
vs = vxlan_sock_add ( net , htons ( dst_port ) , vxlan_rcv , vport , true , 0 ) ;
2013-08-19 11:23:34 -07:00
if ( IS_ERR ( vs ) ) {
ovs_vport_free ( vport ) ;
return ( void * ) vs ;
}
vxlan_port - > vs = vs ;
return vport ;
error :
return ERR_PTR ( err ) ;
}
static int vxlan_tnl_send ( struct vport * vport , struct sk_buff * skb )
{
struct net * net = ovs_dp_get_net ( vport - > dp ) ;
struct vxlan_port * vxlan_port = vxlan_vport ( vport ) ;
__be16 dst_port = inet_sk ( vxlan_port - > vs - > sock - > sk ) - > inet_sport ;
2014-09-15 19:28:44 -07:00
struct ovs_key_ipv4_tunnel * tun_key ;
2013-08-19 11:23:34 -07:00
struct rtable * rt ;
struct flowi4 fl ;
__be16 src_port ;
__be16 df ;
int err ;
2014-10-03 15:35:31 -07:00
if ( unlikely ( ! OVS_CB ( skb ) - > egress_tun_info ) ) {
2013-08-19 11:23:34 -07:00
err = - EINVAL ;
goto error ;
}
2014-10-03 15:35:31 -07:00
tun_key = & OVS_CB ( skb ) - > egress_tun_info - > tunnel ;
2013-08-19 11:23:34 -07:00
/* Route lookup */
memset ( & fl , 0 , sizeof ( fl ) ) ;
2014-09-15 19:28:44 -07:00
fl . daddr = tun_key - > ipv4_dst ;
fl . saddr = tun_key - > ipv4_src ;
fl . flowi4_tos = RT_TOS ( tun_key - > ipv4_tos ) ;
2013-08-19 11:23:34 -07:00
fl . flowi4_mark = skb - > mark ;
fl . flowi4_proto = IPPROTO_UDP ;
rt = ip_route_output_key ( net , & fl ) ;
if ( IS_ERR ( rt ) ) {
err = PTR_ERR ( rt ) ;
goto error ;
}
2014-09-15 19:28:44 -07:00
df = tun_key - > tun_flags & TUNNEL_DONT_FRAGMENT ?
2013-08-19 11:23:34 -07:00
htons ( IP_DF ) : 0 ;
2014-05-04 16:39:18 -07:00
skb - > ignore_df = 1 ;
2013-08-19 11:23:34 -07:00
2014-07-01 21:32:49 -07:00
src_port = udp_flow_src_port ( net , skb , 0 , 0 , true ) ;
2013-08-19 11:23:34 -07:00
2013-09-02 15:34:55 +02:00
err = vxlan_xmit_skb ( vxlan_port - > vs , rt , skb ,
2014-09-15 19:28:44 -07:00
fl . saddr , tun_key - > ipv4_dst ,
tun_key - > ipv4_tos , tun_key - > ipv4_ttl , df ,
2013-08-19 11:23:34 -07:00
src_port , dst_port ,
2014-09-15 19:28:44 -07:00
htonl ( be64_to_cpu ( tun_key - > tun_id ) < < 8 ) ,
2014-04-24 10:02:49 +02:00
false ) ;
2013-08-19 11:23:34 -07:00
if ( err < 0 )
ip_rt_put ( rt ) ;
error :
return err ;
}
2014-11-06 06:51:24 -08:00
static int vxlan_get_egress_tun_info ( struct vport * vport , struct sk_buff * skb ,
struct ovs_tunnel_info * egress_tun_info )
{
struct net * net = ovs_dp_get_net ( vport - > dp ) ;
struct vxlan_port * vxlan_port = vxlan_vport ( vport ) ;
__be16 dst_port = inet_sk ( vxlan_port - > vs - > sock - > sk ) - > inet_sport ;
__be16 src_port ;
int port_min ;
int port_max ;
inet_get_local_port_range ( net , & port_min , & port_max ) ;
src_port = udp_flow_src_port ( net , skb , 0 , 0 , true ) ;
return ovs_tunnel_get_egress_info ( egress_tun_info , net ,
OVS_CB ( skb ) - > egress_tun_info ,
IPPROTO_UDP , skb - > mark ,
src_port , dst_port ) ;
}
2013-08-19 11:23:34 -07:00
static const char * vxlan_get_name ( const struct vport * vport )
{
struct vxlan_port * vxlan_port = vxlan_vport ( vport ) ;
return vxlan_port - > name ;
}
2014-10-22 17:29:06 +02:00
static struct vport_ops ovs_vxlan_vport_ops = {
2013-08-19 11:23:34 -07:00
. type = OVS_VPORT_TYPE_VXLAN ,
. create = vxlan_tnl_create ,
. destroy = vxlan_tnl_destroy ,
. get_name = vxlan_get_name ,
. get_options = vxlan_get_options ,
. send = vxlan_tnl_send ,
2014-11-06 06:51:24 -08:00
. get_egress_tun_info = vxlan_get_egress_tun_info ,
2014-10-22 17:29:06 +02:00
. owner = THIS_MODULE ,
2013-08-19 11:23:34 -07:00
} ;
2014-10-22 17:29:06 +02:00
static int __init ovs_vxlan_tnl_init ( void )
{
return ovs_vport_ops_register ( & ovs_vxlan_vport_ops ) ;
}
static void __exit ovs_vxlan_tnl_exit ( void )
{
ovs_vport_ops_unregister ( & ovs_vxlan_vport_ops ) ;
}
module_init ( ovs_vxlan_tnl_init ) ;
module_exit ( ovs_vxlan_tnl_exit ) ;
MODULE_DESCRIPTION ( " OVS: VXLAN switching port " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " vport-type-4 " ) ;