Commit 58264848a5a7b91195f43c4729072e8cc980288d

Authored by Pravin B Shelar
Committed by David S. Miller
1 parent 1eaa81785a

openvswitch: Add vxlan tunneling support.

Following patch adds vxlan vport type for openvswitch using
vxlan api. So now there is vxlan dependency for openvswitch.

CC: Jesse Gross <jesse@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 6 changed files with 236 additions and 0 deletions Side-by-side Diff

include/uapi/linux/openvswitch.h
... ... @@ -165,6 +165,7 @@
165 165 OVS_VPORT_TYPE_NETDEV, /* network device */
166 166 OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
167 167 OVS_VPORT_TYPE_GRE, /* GRE tunnel. */
  168 + OVS_VPORT_TYPE_VXLAN, /* VXLAN tunnel. */
168 169 __OVS_VPORT_TYPE_MAX
169 170 };
170 171  
... ... @@ -210,6 +211,16 @@
210 211 };
211 212  
212 213 #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
  214 +
  215 +/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
  216 + */
  217 +enum {
  218 + OVS_TUNNEL_ATTR_UNSPEC,
  219 + OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
  220 + __OVS_TUNNEL_ATTR_MAX
  221 +};
  222 +
  223 +#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1)
213 224  
214 225 /* Flows. */
215 226  
net/openvswitch/Kconfig
... ... @@ -40,4 +40,17 @@
40 40 Say N to exclude this support and reduce the binary size.
41 41  
42 42 If unsure, say Y.
  43 +
  44 +config OPENVSWITCH_VXLAN
  45 + bool "Open vSwitch VXLAN tunneling support"
  46 + depends on INET
  47 + depends on OPENVSWITCH
  48 + depends on VXLAN && !(OPENVSWITCH=y && VXLAN=m)
  49 + default y
  50 + ---help---
  51 + If you say Y here, then the Open vSwitch will be able create vxlan vport.
  52 +
  53 + Say N to exclude this support and reduce the binary size.
  54 +
  55 + If unsure, say Y.
net/openvswitch/Makefile
... ... @@ -13,4 +13,8 @@
13 13 vport-gre.o \
14 14 vport-internal_dev.o \
15 15 vport-netdev.o
  16 +
  17 +ifneq ($(CONFIG_OPENVSWITCH_VXLAN),)
  18 +openvswitch-y += vport-vxlan.o
  19 +endif
net/openvswitch/vport-vxlan.c
  1 +/*
  2 + * Copyright (c) 2013 Nicira, Inc.
  3 + * Copyright (c) 2013 Cisco Systems, Inc.
  4 + *
  5 + * This program is free software; you can redistribute it and/or
  6 + * modify it under the terms of version 2 of the GNU General Public
  7 + * License as published by the Free Software Foundation.
  8 + *
  9 + * This program is distributed in the hope that it will be useful, but
  10 + * WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12 + * General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program; if not, write to the Free Software
  16 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17 + * 02110-1301, USA
  18 + */
  19 +
  20 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  21 +
  22 +#include <linux/in.h>
  23 +#include <linux/ip.h>
  24 +#include <linux/net.h>
  25 +#include <linux/rculist.h>
  26 +#include <linux/udp.h>
  27 +
  28 +#include <net/icmp.h>
  29 +#include <net/ip.h>
  30 +#include <net/udp.h>
  31 +#include <net/ip_tunnels.h>
  32 +#include <net/udp.h>
  33 +#include <net/rtnetlink.h>
  34 +#include <net/route.h>
  35 +#include <net/dsfield.h>
  36 +#include <net/inet_ecn.h>
  37 +#include <net/net_namespace.h>
  38 +#include <net/netns/generic.h>
  39 +#include <net/vxlan.h>
  40 +
  41 +#include "datapath.h"
  42 +#include "vport.h"
  43 +
  44 +/**
  45 + * struct vxlan_port - Keeps track of open UDP ports
  46 + * @vs: vxlan_sock created for the port.
  47 + * @name: vport name.
  48 + */
  49 +struct vxlan_port {
  50 + struct vxlan_sock *vs;
  51 + char name[IFNAMSIZ];
  52 +};
  53 +
  54 +static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
  55 +{
  56 + return vport_priv(vport);
  57 +}
  58 +
  59 +/* Called with rcu_read_lock and BH disabled. */
  60 +static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni)
  61 +{
  62 + struct ovs_key_ipv4_tunnel tun_key;
  63 + struct vport *vport = vs->data;
  64 + struct iphdr *iph;
  65 + __be64 key;
  66 +
  67 + /* Save outer tunnel values */
  68 + iph = ip_hdr(skb);
  69 + key = cpu_to_be64(ntohl(vx_vni) >> 8);
  70 + ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY);
  71 +
  72 + ovs_vport_receive(vport, skb, &tun_key);
  73 +}
  74 +
  75 +static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
  76 +{
  77 + struct vxlan_port *vxlan_port = vxlan_vport(vport);
  78 + __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
  79 +
  80 + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
  81 + return -EMSGSIZE;
  82 + return 0;
  83 +}
  84 +
  85 +static void vxlan_tnl_destroy(struct vport *vport)
  86 +{
  87 + struct vxlan_port *vxlan_port = vxlan_vport(vport);
  88 +
  89 + vxlan_sock_release(vxlan_port->vs);
  90 +
  91 + ovs_vport_deferred_free(vport);
  92 +}
  93 +
  94 +static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
  95 +{
  96 + struct net *net = ovs_dp_get_net(parms->dp);
  97 + struct nlattr *options = parms->options;
  98 + struct vxlan_port *vxlan_port;
  99 + struct vxlan_sock *vs;
  100 + struct vport *vport;
  101 + struct nlattr *a;
  102 + u16 dst_port;
  103 + int err;
  104 +
  105 + if (!options) {
  106 + err = -EINVAL;
  107 + goto error;
  108 + }
  109 + a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
  110 + if (a && nla_len(a) == sizeof(u16)) {
  111 + dst_port = nla_get_u16(a);
  112 + } else {
  113 + /* Require destination port from userspace. */
  114 + err = -EINVAL;
  115 + goto error;
  116 + }
  117 +
  118 + vport = ovs_vport_alloc(sizeof(struct vxlan_port),
  119 + &ovs_vxlan_vport_ops, parms);
  120 + if (IS_ERR(vport))
  121 + return vport;
  122 +
  123 + vxlan_port = vxlan_vport(vport);
  124 + strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
  125 +
  126 + vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true);
  127 + if (IS_ERR(vs)) {
  128 + ovs_vport_free(vport);
  129 + return (void *)vs;
  130 + }
  131 + vxlan_port->vs = vs;
  132 +
  133 + return vport;
  134 +
  135 +error:
  136 + return ERR_PTR(err);
  137 +}
  138 +
  139 +static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
  140 +{
  141 + struct net *net = ovs_dp_get_net(vport->dp);
  142 + struct vxlan_port *vxlan_port = vxlan_vport(vport);
  143 + __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
  144 + struct rtable *rt;
  145 + struct flowi4 fl;
  146 + __be16 src_port;
  147 + int port_min;
  148 + int port_max;
  149 + __be16 df;
  150 + int err;
  151 +
  152 + if (unlikely(!OVS_CB(skb)->tun_key)) {
  153 + err = -EINVAL;
  154 + goto error;
  155 + }
  156 +
  157 + /* Route lookup */
  158 + memset(&fl, 0, sizeof(fl));
  159 + fl.daddr = OVS_CB(skb)->tun_key->ipv4_dst;
  160 + fl.saddr = OVS_CB(skb)->tun_key->ipv4_src;
  161 + fl.flowi4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos);
  162 + fl.flowi4_mark = skb->mark;
  163 + fl.flowi4_proto = IPPROTO_UDP;
  164 +
  165 + rt = ip_route_output_key(net, &fl);
  166 + if (IS_ERR(rt)) {
  167 + err = PTR_ERR(rt);
  168 + goto error;
  169 + }
  170 +
  171 + df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
  172 + htons(IP_DF) : 0;
  173 +
  174 + skb->local_df = 1;
  175 +
  176 + inet_get_local_port_range(&port_min, &port_max);
  177 + src_port = vxlan_src_port(port_min, port_max, skb);
  178 +
  179 + err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb,
  180 + fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst,
  181 + OVS_CB(skb)->tun_key->ipv4_tos,
  182 + OVS_CB(skb)->tun_key->ipv4_ttl, df,
  183 + src_port, dst_port,
  184 + htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8));
  185 + if (err < 0)
  186 + ip_rt_put(rt);
  187 +error:
  188 + return err;
  189 +}
  190 +
  191 +static const char *vxlan_get_name(const struct vport *vport)
  192 +{
  193 + struct vxlan_port *vxlan_port = vxlan_vport(vport);
  194 + return vxlan_port->name;
  195 +}
  196 +
  197 +const struct vport_ops ovs_vxlan_vport_ops = {
  198 + .type = OVS_VPORT_TYPE_VXLAN,
  199 + .create = vxlan_tnl_create,
  200 + .destroy = vxlan_tnl_destroy,
  201 + .get_name = vxlan_get_name,
  202 + .get_options = vxlan_get_options,
  203 + .send = vxlan_tnl_send,
  204 +};
net/openvswitch/vport.c
... ... @@ -42,6 +42,9 @@
42 42 #ifdef CONFIG_OPENVSWITCH_GRE
43 43 &ovs_gre_vport_ops,
44 44 #endif
  45 +#ifdef CONFIG_OPENVSWITCH_VXLAN
  46 + &ovs_vxlan_vport_ops,
  47 +#endif
45 48 };
46 49  
47 50 /* Protected by RCU read lock for reading, ovs_mutex for writing. */
net/openvswitch/vport.h
... ... @@ -199,6 +199,7 @@
199 199 extern const struct vport_ops ovs_netdev_vport_ops;
200 200 extern const struct vport_ops ovs_internal_vport_ops;
201 201 extern const struct vport_ops ovs_gre_vport_ops;
  202 +extern const struct vport_ops ovs_vxlan_vport_ops;
202 203  
203 204 static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
204 205 const void *start, unsigned int len)