linux/net/openvswitch/vport-vxlan.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 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#include <linux/module.h>
  28
  29#include <net/icmp.h>
  30#include <net/ip.h>
  31#include <net/udp.h>
  32#include <net/ip_tunnels.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#include "vport-vxlan.h"
  44
  45/**
  46 * struct vxlan_port - Keeps track of open UDP ports
  47 * @vs: vxlan_sock created for the port.
  48 * @name: vport name.
  49 */
  50struct vxlan_port {
  51        struct vxlan_sock *vs;
  52        char name[IFNAMSIZ];
  53        u32 exts; /* VXLAN_F_* in <net/vxlan.h> */
  54};
  55
  56static struct vport_ops ovs_vxlan_vport_ops;
  57
  58static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
  59{
  60        return vport_priv(vport);
  61}
  62
  63/* Called with rcu_read_lock and BH disabled. */
  64static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
  65                      struct vxlan_metadata *md)
  66{
  67        struct ovs_tunnel_info tun_info;
  68        struct vxlan_port *vxlan_port;
  69        struct vport *vport = vs->data;
  70        struct iphdr *iph;
  71        struct ovs_vxlan_opts opts = {
  72                .gbp = md->gbp,
  73        };
  74        __be64 key;
  75        __be16 flags;
  76
  77        flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
  78        vxlan_port = vxlan_vport(vport);
  79        if (vxlan_port->exts & VXLAN_F_GBP && md->gbp)
  80                flags |= TUNNEL_VXLAN_OPT;
  81
  82        /* Save outer tunnel values */
  83        iph = ip_hdr(skb);
  84        key = cpu_to_be64(ntohl(md->vni) >> 8);
  85        ovs_flow_tun_info_init(&tun_info, iph,
  86                               udp_hdr(skb)->source, udp_hdr(skb)->dest,
  87                               key, flags, &opts, sizeof(opts));
  88
  89        ovs_vport_receive(vport, skb, &tun_info);
  90}
  91
  92static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
  93{
  94        struct vxlan_port *vxlan_port = vxlan_vport(vport);
  95        __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
  96
  97        if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
  98                return -EMSGSIZE;
  99
 100        if (vxlan_port->exts) {
 101                struct nlattr *exts;
 102
 103                exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
 104                if (!exts)
 105                        return -EMSGSIZE;
 106
 107                if (vxlan_port->exts & VXLAN_F_GBP &&
 108                    nla_put_flag(skb, OVS_VXLAN_EXT_GBP))
 109                        return -EMSGSIZE;
 110
 111                nla_nest_end(skb, exts);
 112        }
 113
 114        return 0;
 115}
 116
 117static void vxlan_tnl_destroy(struct vport *vport)
 118{
 119        struct vxlan_port *vxlan_port = vxlan_vport(vport);
 120
 121        vxlan_sock_release(vxlan_port->vs);
 122
 123        ovs_vport_deferred_free(vport);
 124}
 125
 126static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX+1] = {
 127        [OVS_VXLAN_EXT_GBP]     = { .type = NLA_FLAG, },
 128};
 129
 130static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr)
 131{
 132        struct nlattr *exts[OVS_VXLAN_EXT_MAX+1];
 133        struct vxlan_port *vxlan_port;
 134        int err;
 135
 136        if (nla_len(attr) < sizeof(struct nlattr))
 137                return -EINVAL;
 138
 139        err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy);
 140        if (err < 0)
 141                return err;
 142
 143        vxlan_port = vxlan_vport(vport);
 144
 145        if (exts[OVS_VXLAN_EXT_GBP])
 146                vxlan_port->exts |= VXLAN_F_GBP;
 147
 148        return 0;
 149}
 150
 151static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
 152{
 153        struct net *net = ovs_dp_get_net(parms->dp);
 154        struct nlattr *options = parms->options;
 155        struct vxlan_port *vxlan_port;
 156        struct vxlan_sock *vs;
 157        struct vport *vport;
 158        struct nlattr *a;
 159        u16 dst_port;
 160        int err;
 161
 162        if (!options) {
 163                err = -EINVAL;
 164                goto error;
 165        }
 166        a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
 167        if (a && nla_len(a) == sizeof(u16)) {
 168                dst_port = nla_get_u16(a);
 169        } else {
 170                /* Require destination port from userspace. */
 171                err = -EINVAL;
 172                goto error;
 173        }
 174
 175        vport = ovs_vport_alloc(sizeof(struct vxlan_port),
 176                                &ovs_vxlan_vport_ops, parms);
 177        if (IS_ERR(vport))
 178                return vport;
 179
 180        vxlan_port = vxlan_vport(vport);
 181        strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
 182
 183        a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION);
 184        if (a) {
 185                err = vxlan_configure_exts(vport, a);
 186                if (err) {
 187                        ovs_vport_free(vport);
 188                        goto error;
 189                }
 190        }
 191
 192        vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true,
 193                            vxlan_port->exts);
 194        if (IS_ERR(vs)) {
 195                ovs_vport_free(vport);
 196                return (void *)vs;
 197        }
 198        vxlan_port->vs = vs;
 199
 200        return vport;
 201
 202error:
 203        return ERR_PTR(err);
 204}
 205
 206static int vxlan_ext_gbp(struct sk_buff *skb)
 207{
 208        const struct ovs_tunnel_info *tun_info;
 209        const struct ovs_vxlan_opts *opts;
 210
 211        tun_info = OVS_CB(skb)->egress_tun_info;
 212        opts = tun_info->options;
 213
 214        if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT &&
 215            tun_info->options_len >= sizeof(*opts))
 216                return opts->gbp;
 217        else
 218                return 0;
 219}
 220
 221static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 222{
 223        struct net *net = ovs_dp_get_net(vport->dp);
 224        struct vxlan_port *vxlan_port = vxlan_vport(vport);
 225        struct sock *sk = vxlan_port->vs->sock->sk;
 226        __be16 dst_port = inet_sk(sk)->inet_sport;
 227        const struct ovs_key_ipv4_tunnel *tun_key;
 228        struct vxlan_metadata md = {0};
 229        struct rtable *rt;
 230        struct flowi4 fl;
 231        __be16 src_port;
 232        __be16 df;
 233        int err;
 234        u32 vxflags;
 235
 236        if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
 237                err = -EINVAL;
 238                goto error;
 239        }
 240
 241        tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
 242        rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP);
 243        if (IS_ERR(rt)) {
 244                err = PTR_ERR(rt);
 245                goto error;
 246        }
 247
 248        df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
 249                htons(IP_DF) : 0;
 250
 251        skb->ignore_df = 1;
 252
 253        src_port = udp_flow_src_port(net, skb, 0, 0, true);
 254        md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
 255        md.gbp = vxlan_ext_gbp(skb);
 256        vxflags = vxlan_port->exts |
 257                      (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0);
 258
 259        err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst,
 260                             tun_key->ipv4_tos, tun_key->ipv4_ttl, df,
 261                             src_port, dst_port,
 262                             &md, false, vxflags);
 263        if (err < 0)
 264                ip_rt_put(rt);
 265        return err;
 266error:
 267        kfree_skb(skb);
 268        return err;
 269}
 270
 271static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
 272                                     struct ovs_tunnel_info *egress_tun_info)
 273{
 274        struct net *net = ovs_dp_get_net(vport->dp);
 275        struct vxlan_port *vxlan_port = vxlan_vport(vport);
 276        __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
 277        __be16 src_port;
 278        int port_min;
 279        int port_max;
 280
 281        inet_get_local_port_range(net, &port_min, &port_max);
 282        src_port = udp_flow_src_port(net, skb, 0, 0, true);
 283
 284        return ovs_tunnel_get_egress_info(egress_tun_info, net,
 285                                          OVS_CB(skb)->egress_tun_info,
 286                                          IPPROTO_UDP, skb->mark,
 287                                          src_port, dst_port);
 288}
 289
 290static const char *vxlan_get_name(const struct vport *vport)
 291{
 292        struct vxlan_port *vxlan_port = vxlan_vport(vport);
 293        return vxlan_port->name;
 294}
 295
 296static struct vport_ops ovs_vxlan_vport_ops = {
 297        .type           = OVS_VPORT_TYPE_VXLAN,
 298        .create         = vxlan_tnl_create,
 299        .destroy        = vxlan_tnl_destroy,
 300        .get_name       = vxlan_get_name,
 301        .get_options    = vxlan_get_options,
 302        .send           = vxlan_tnl_send,
 303        .get_egress_tun_info    = vxlan_get_egress_tun_info,
 304        .owner          = THIS_MODULE,
 305};
 306
 307static int __init ovs_vxlan_tnl_init(void)
 308{
 309        return ovs_vport_ops_register(&ovs_vxlan_vport_ops);
 310}
 311
 312static void __exit ovs_vxlan_tnl_exit(void)
 313{
 314        ovs_vport_ops_unregister(&ovs_vxlan_vport_ops);
 315}
 316
 317module_init(ovs_vxlan_tnl_init);
 318module_exit(ovs_vxlan_tnl_exit);
 319
 320MODULE_DESCRIPTION("OVS: VXLAN switching port");
 321MODULE_LICENSE("GPL");
 322MODULE_ALIAS("vport-type-4");
 323