2014-10-04 02:35:33 +04:00
/*
* Copyright ( c ) 2014 Nicira , Inc .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# 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>
# include <linux/if_vlan.h>
2014-10-22 19:29:06 +04:00
# include <linux/module.h>
2014-10-04 02:35:33 +04:00
# include <net/geneve.h>
# include <net/icmp.h>
# include <net/ip.h>
# include <net/route.h>
# include <net/udp.h>
# include <net/xfrm.h>
# include "datapath.h"
# include "vport.h"
2015-08-27 09:46:53 +03:00
# include "vport-netdev.h"
2014-10-04 02:35:33 +04:00
2014-10-22 19:29:06 +04:00
static struct vport_ops ovs_geneve_vport_ops ;
2014-10-04 02:35:33 +04:00
/**
* struct geneve_port - Keeps track of open UDP ports
2015-08-27 09:46:53 +03:00
* @ dst_port : destination port .
2014-10-04 02:35:33 +04:00
*/
struct geneve_port {
2015-08-27 09:46:53 +03:00
u16 port_no ;
2014-10-04 02:35:33 +04:00
} ;
static inline struct geneve_port * geneve_vport ( const struct vport * vport )
{
return vport_priv ( vport ) ;
}
static int geneve_get_options ( const struct vport * vport ,
struct sk_buff * skb )
{
struct geneve_port * geneve_port = geneve_vport ( vport ) ;
2015-08-27 09:46:53 +03:00
if ( nla_put_u16 ( skb , OVS_TUNNEL_ATTR_DST_PORT , geneve_port - > port_no ) )
2014-10-04 02:35:33 +04:00
return - EMSGSIZE ;
return 0 ;
}
static struct vport * geneve_tnl_create ( const struct vport_parms * parms )
{
struct net * net = ovs_dp_get_net ( parms - > dp ) ;
struct nlattr * options = parms - > options ;
struct geneve_port * geneve_port ;
2015-08-27 09:46:53 +03:00
struct net_device * dev ;
2014-10-04 02:35:33 +04:00
struct vport * vport ;
struct nlattr * a ;
u16 dst_port ;
2015-08-27 09:46:53 +03:00
int err ;
2014-10-04 02:35:33 +04:00
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 geneve_port ) ,
& ovs_geneve_vport_ops , parms ) ;
if ( IS_ERR ( vport ) )
return vport ;
geneve_port = geneve_vport ( vport ) ;
2015-08-27 09:46:53 +03:00
geneve_port - > port_no = dst_port ;
2014-10-04 02:35:33 +04:00
2015-08-27 09:46:53 +03:00
rtnl_lock ( ) ;
dev = geneve_dev_create_fb ( net , parms - > name , NET_NAME_USER , dst_port ) ;
if ( IS_ERR ( dev ) ) {
rtnl_unlock ( ) ;
2014-10-04 02:35:33 +04:00
ovs_vport_free ( vport ) ;
2015-08-27 09:46:53 +03:00
return ERR_CAST ( dev ) ;
2014-10-04 02:35:33 +04:00
}
2015-08-27 09:46:53 +03:00
dev_change_flags ( dev , dev - > flags | IFF_UP ) ;
rtnl_unlock ( ) ;
2014-10-04 02:35:33 +04:00
return vport ;
error :
return ERR_PTR ( err ) ;
}
2015-08-27 09:46:53 +03:00
static struct vport * geneve_create ( const struct vport_parms * parms )
2014-10-04 02:35:33 +04:00
{
2015-08-27 09:46:53 +03:00
struct vport * vport ;
2014-10-04 02:35:33 +04:00
2015-08-27 09:46:53 +03:00
vport = geneve_tnl_create ( parms ) ;
if ( IS_ERR ( vport ) )
return vport ;
2014-11-06 17:51:24 +03:00
2015-08-27 09:46:53 +03:00
return ovs_netdev_link ( vport , parms - > name ) ;
2014-11-06 17:51:24 +03:00
}
2014-10-22 19:29:06 +04:00
static struct vport_ops ovs_geneve_vport_ops = {
2014-10-04 02:35:33 +04:00
. type = OVS_VPORT_TYPE_GENEVE ,
2015-08-27 09:46:53 +03:00
. create = geneve_create ,
. destroy = ovs_netdev_tunnel_destroy ,
2014-10-04 02:35:33 +04:00
. get_options = geneve_get_options ,
2015-10-21 09:00:10 +03:00
. send = dev_queue_xmit ,
2014-10-22 19:29:06 +04:00
. owner = THIS_MODULE ,
2014-10-04 02:35:33 +04:00
} ;
2014-10-22 19:29:06 +04:00
static int __init ovs_geneve_tnl_init ( void )
{
return ovs_vport_ops_register ( & ovs_geneve_vport_ops ) ;
}
static void __exit ovs_geneve_tnl_exit ( void )
{
ovs_vport_ops_unregister ( & ovs_geneve_vport_ops ) ;
}
module_init ( ovs_geneve_tnl_init ) ;
module_exit ( ovs_geneve_tnl_exit ) ;
MODULE_DESCRIPTION ( " OVS: Geneve swiching port " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " vport-type-5 " ) ;