linux/net/openvswitch/vport-gre.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2007-2013 Nicira, Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of version 2 of the GNU General Public
   6 * License as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful, but
   9 * WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11 * General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software
  15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16 * 02110-1301, USA
  17 */
  18
  19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20
  21#include <linux/if.h>
  22#include <linux/skbuff.h>
  23#include <linux/ip.h>
  24#include <linux/if_tunnel.h>
  25#include <linux/if_vlan.h>
  26#include <linux/in.h>
  27#include <linux/in_route.h>
  28#include <linux/inetdevice.h>
  29#include <linux/jhash.h>
  30#include <linux/list.h>
  31#include <linux/kernel.h>
  32#include <linux/workqueue.h>
  33#include <linux/rculist.h>
  34#include <net/route.h>
  35#include <net/xfrm.h>
  36
  37#include <net/icmp.h>
  38#include <net/ip.h>
  39#include <net/ip_tunnels.h>
  40#include <net/gre.h>
  41#include <net/net_namespace.h>
  42#include <net/netns/generic.h>
  43#include <net/protocol.h>
  44
  45#include "datapath.h"
  46#include "vport.h"
  47
  48/* Returns the least-significant 32 bits of a __be64. */
  49static __be32 be64_get_low32(__be64 x)
  50{
  51#ifdef __BIG_ENDIAN
  52        return (__force __be32)x;
  53#else
  54        return (__force __be32)((__force u64)x >> 32);
  55#endif
  56}
  57
  58static __be16 filter_tnl_flags(__be16 flags)
  59{
  60        return flags & (TUNNEL_CSUM | TUNNEL_KEY);
  61}
  62
  63static struct sk_buff *__build_header(struct sk_buff *skb,
  64                                      int tunnel_hlen)
  65{
  66        const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
  67        struct tnl_ptk_info tpi;
  68
  69        skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM));
  70        if (IS_ERR(skb))
  71                return NULL;
  72
  73        tpi.flags = filter_tnl_flags(tun_key->tun_flags);
  74        tpi.proto = htons(ETH_P_TEB);
  75        tpi.key = be64_get_low32(tun_key->tun_id);
  76        tpi.seq = 0;
  77        gre_build_header(skb, &tpi, tunnel_hlen);
  78
  79        return skb;
  80}
  81
  82static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
  83{
  84#ifdef __BIG_ENDIAN
  85        return (__force __be64)((__force u64)seq << 32 | (__force u32)key);
  86#else
  87        return (__force __be64)((__force u64)key << 32 | (__force u32)seq);
  88#endif
  89}
  90
  91/* Called with rcu_read_lock and BH disabled. */
  92static int gre_rcv(struct sk_buff *skb,
  93                   const struct tnl_ptk_info *tpi)
  94{
  95        struct ovs_key_ipv4_tunnel tun_key;
  96        struct ovs_net *ovs_net;
  97        struct vport *vport;
  98        __be64 key;
  99
 100        ovs_net = net_generic(dev_net(skb->dev), ovs_net_id);
 101        vport = rcu_dereference(ovs_net->vport_net.gre_vport);
 102        if (unlikely(!vport))
 103                return PACKET_REJECT;
 104
 105        key = key_to_tunnel_id(tpi->key, tpi->seq);
 106        ovs_flow_tun_key_init(&tun_key, ip_hdr(skb), key,
 107                              filter_tnl_flags(tpi->flags));
 108
 109        ovs_vport_receive(vport, skb, &tun_key);
 110        return PACKET_RCVD;
 111}
 112
 113static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
 114{
 115        struct net *net = ovs_dp_get_net(vport->dp);
 116        struct flowi4 fl;
 117        struct rtable *rt;
 118        int min_headroom;
 119        int tunnel_hlen;
 120        __be16 df;
 121        int err;
 122
 123        if (unlikely(!OVS_CB(skb)->tun_key)) {
 124                err = -EINVAL;
 125                goto error;
 126        }
 127
 128        /* Route lookup */
 129        memset(&fl, 0, sizeof(fl));
 130        fl.daddr = OVS_CB(skb)->tun_key->ipv4_dst;
 131        fl.saddr = OVS_CB(skb)->tun_key->ipv4_src;
 132        fl.flowi4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos);
 133        fl.flowi4_mark = skb->mark;
 134        fl.flowi4_proto = IPPROTO_GRE;
 135
 136        rt = ip_route_output_key(net, &fl);
 137        if (IS_ERR(rt))
 138                return PTR_ERR(rt);
 139
 140        tunnel_hlen = ip_gre_calc_hlen(OVS_CB(skb)->tun_key->tun_flags);
 141
 142        min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 143                        + tunnel_hlen + sizeof(struct iphdr)
 144                        + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
 145        if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
 146                int head_delta = SKB_DATA_ALIGN(min_headroom -
 147                                                skb_headroom(skb) +
 148                                                16);
 149                err = pskb_expand_head(skb, max_t(int, head_delta, 0),
 150                                        0, GFP_ATOMIC);
 151                if (unlikely(err))
 152                        goto err_free_rt;
 153        }
 154
 155        if (vlan_tx_tag_present(skb)) {
 156                if (unlikely(!__vlan_put_tag(skb,
 157                                             skb->vlan_proto,
 158                                             vlan_tx_tag_get(skb)))) {
 159                        err = -ENOMEM;
 160                        goto err_free_rt;
 161                }
 162                skb->vlan_tci = 0;
 163        }
 164
 165        /* Push Tunnel header. */
 166        skb = __build_header(skb, tunnel_hlen);
 167        if (unlikely(!skb)) {
 168                err = 0;
 169                goto err_free_rt;
 170        }
 171
 172        df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
 173                htons(IP_DF) : 0;
 174
 175        skb->local_df = 1;
 176
 177        return iptunnel_xmit(rt, skb, fl.saddr,
 178                             OVS_CB(skb)->tun_key->ipv4_dst, IPPROTO_GRE,
 179                             OVS_CB(skb)->tun_key->ipv4_tos,
 180                             OVS_CB(skb)->tun_key->ipv4_ttl, df, false);
 181err_free_rt:
 182        ip_rt_put(rt);
 183error:
 184        return err;
 185}
 186
 187static struct gre_cisco_protocol gre_protocol = {
 188        .handler        = gre_rcv,
 189        .priority       = 1,
 190};
 191
 192static int gre_ports;
 193static int gre_init(void)
 194{
 195        int err;
 196
 197        gre_ports++;
 198        if (gre_ports > 1)
 199                return 0;
 200
 201        err = gre_cisco_register(&gre_protocol);
 202        if (err)
 203                pr_warn("cannot register gre protocol handler\n");
 204
 205        return err;
 206}
 207
 208static void gre_exit(void)
 209{
 210        gre_ports--;
 211        if (gre_ports > 0)
 212                return;
 213
 214        gre_cisco_unregister(&gre_protocol);
 215}
 216
 217static const char *gre_get_name(const struct vport *vport)
 218{
 219        return vport_priv(vport);
 220}
 221
 222static struct vport *gre_create(const struct vport_parms *parms)
 223{
 224        struct net *net = ovs_dp_get_net(parms->dp);
 225        struct ovs_net *ovs_net;
 226        struct vport *vport;
 227        int err;
 228
 229        err = gre_init();
 230        if (err)
 231                return ERR_PTR(err);
 232
 233        ovs_net = net_generic(net, ovs_net_id);
 234        if (ovsl_dereference(ovs_net->vport_net.gre_vport)) {
 235                vport = ERR_PTR(-EEXIST);
 236                goto error;
 237        }
 238
 239        vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre_vport_ops, parms);
 240        if (IS_ERR(vport))
 241                goto error;
 242
 243        strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
 244        rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport);
 245        return vport;
 246
 247error:
 248        gre_exit();
 249        return vport;
 250}
 251
 252static void gre_tnl_destroy(struct vport *vport)
 253{
 254        struct net *net = ovs_dp_get_net(vport->dp);
 255        struct ovs_net *ovs_net;
 256
 257        ovs_net = net_generic(net, ovs_net_id);
 258
 259        rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL);
 260        ovs_vport_deferred_free(vport);
 261        gre_exit();
 262}
 263
 264const struct vport_ops ovs_gre_vport_ops = {
 265        .type           = OVS_VPORT_TYPE_GRE,
 266        .create         = gre_create,
 267        .destroy        = gre_tnl_destroy,
 268        .get_name       = gre_get_name,
 269        .send           = gre_tnl_send,
 270};
 271