X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=datapath%2Fvport-gre.c;h=50aaba5931405d7f5a7742e8b3d89bb1a3da55e0;hb=968eec593cc61690c9e0ed97450c4889258381af;hp=a49002f41582cad86eddf727eb8fb1465f388fd2;hpb=07ac71eaa8a2892a0028a27049a51a88b756ea9b;p=cascardo%2Fovs.git diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index a49002f41..50aaba593 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2012 Nicira, Inc. + * Copyright (c) 2007-2015 Nicira, 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 @@ -16,8 +16,6 @@ * 02110-1301, USA */ -#include -#if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -26,17 +24,14 @@ #include #include #include -#include -#include #include #include #include #include #include +#include #include #include -#include -#include #include #include @@ -44,320 +39,79 @@ #include #include #include +#include +#include #include #include "datapath.h" #include "vport.h" +#include "vport-netdev.h" -/* Returns the least-significant 32 bits of a __be64. */ -static __be32 be64_get_low32(__be64 x) -{ -#ifdef __BIG_ENDIAN - return (__force __be32)x; -#else - return (__force __be32)((__force u64)x >> 32); -#endif -} - -static __be16 filter_tnl_flags(__be16 flags) -{ - return flags & (TUNNEL_CSUM | TUNNEL_KEY); -} +static struct vport_ops ovs_gre_vport_ops; -static struct sk_buff *__build_header(struct sk_buff *skb, - int tunnel_hlen, - __be32 seq, __be16 gre64_flag) +static struct vport *gre_tnl_create(const struct vport_parms *parms) { - const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; - struct tnl_ptk_info tpi; - - skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); - if (IS_ERR(skb)) - return NULL; - - tpi.flags = filter_tnl_flags(tun_key->tun_flags) | gre64_flag; - - tpi.proto = htons(ETH_P_TEB); - tpi.key = be64_get_low32(tun_key->tun_id); - tpi.seq = seq; - gre_build_header(skb, &tpi, tunnel_hlen); - - return skb; -} - -static __be64 key_to_tunnel_id(__be32 key, __be32 seq) -{ -#ifdef __BIG_ENDIAN - return (__force __be64)((__force u64)seq << 32 | (__force u32)key); -#else - return (__force __be64)((__force u64)key << 32 | (__force u32)seq); -#endif -} - -/* Called with rcu_read_lock and BH disabled. */ -static int gre_rcv(struct sk_buff *skb, - const struct tnl_ptk_info *tpi) -{ - struct ovs_key_ipv4_tunnel tun_key; - struct ovs_net *ovs_net; + struct net *net = ovs_dp_get_net(parms->dp); + struct net_device *dev; struct vport *vport; - __be64 key; - - ovs_net = net_generic(dev_net(skb->dev), ovs_net_id); - if ((tpi->flags & TUNNEL_KEY) && (tpi->flags & TUNNEL_SEQ)) - vport = rcu_dereference(ovs_net->vport_net.gre64_vport); - else - vport = rcu_dereference(ovs_net->vport_net.gre_vport); - if (unlikely(!vport)) - return PACKET_REJECT; - key = key_to_tunnel_id(tpi->key, tpi->seq); - ovs_flow_tun_key_init(&tun_key, ip_hdr(skb), key, filter_tnl_flags(tpi->flags)); - - ovs_vport_receive(vport, skb, &tun_key); - return PACKET_RCVD; -} - -static int __send(struct vport *vport, struct sk_buff *skb, - int tunnel_hlen, - __be32 seq, __be16 gre64_flag) -{ - struct net *net = ovs_dp_get_net(vport->dp); - struct rtable *rt; - int min_headroom; - __be16 df; - __be32 saddr; - int err; - - /* Route lookup */ - saddr = OVS_CB(skb)->tun_key->ipv4_src; - rt = find_route(ovs_dp_get_net(vport->dp), - &saddr, - OVS_CB(skb)->tun_key->ipv4_dst, - IPPROTO_GRE, - OVS_CB(skb)->tun_key->ipv4_tos, - skb->mark); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto error; - } - - min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len - + tunnel_hlen + sizeof(struct iphdr) - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); - - if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { - int head_delta = SKB_DATA_ALIGN(min_headroom - - skb_headroom(skb) + - 16); - err = pskb_expand_head(skb, max_t(int, head_delta, 0), - 0, GFP_ATOMIC); - if (unlikely(err)) - goto err_free_rt; - } - - if (vlan_tx_tag_present(skb)) { - if (unlikely(!__vlan_put_tag(skb, - skb->vlan_proto, - vlan_tx_tag_get(skb)))) { - err = -ENOMEM; - goto err_free_rt; - } - vlan_set_tci(skb, 0); - } - - /* Push Tunnel header. */ - skb = __build_header(skb, tunnel_hlen, seq, gre64_flag); - if (unlikely(!skb)) { - err = 0; - goto err_free_rt; + vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + rtnl_lock(); + dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); } - df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? - htons(IP_DF) : 0; - - skb->local_df = 1; - - return iptunnel_xmit(net, rt, skb, saddr, - OVS_CB(skb)->tun_key->ipv4_dst, IPPROTO_GRE, - OVS_CB(skb)->tun_key->ipv4_tos, - OVS_CB(skb)->tun_key->ipv4_ttl, df); -err_free_rt: - ip_rt_put(rt); -error: - return err; -} - -static struct gre_cisco_protocol gre_protocol = { - .handler = gre_rcv, - .priority = 1, -}; - -static int gre_ports; -static int gre_init(void) -{ - int err; - - gre_ports++; - if (gre_ports > 1) - return 0; - - err = gre_cisco_register(&gre_protocol); - if (err) - pr_warn("cannot register gre protocol handler\n"); + dev_change_flags(dev, dev->flags | IFF_UP); + rtnl_unlock(); - return err; -} - -static void gre_exit(void) -{ - gre_ports--; - if (gre_ports > 0) - return; - - gre_cisco_unregister(&gre_protocol); -} - -static const char *gre_get_name(const struct vport *vport) -{ - return vport_priv(vport); + return vport; } static struct vport *gre_create(const struct vport_parms *parms) { - struct net *net = ovs_dp_get_net(parms->dp); - struct ovs_net *ovs_net; struct vport *vport; - int err; - - err = gre_init(); - if (err) - return ERR_PTR(err); - - ovs_net = net_generic(net, ovs_net_id); - if (ovsl_dereference(ovs_net->vport_net.gre_vport)) { - vport = ERR_PTR(-EEXIST); - goto error; - } - vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre_vport_ops, parms); + vport = gre_tnl_create(parms); if (IS_ERR(vport)) - goto error; - - strncpy(vport_priv(vport), parms->name, IFNAMSIZ); - rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport); - return vport; + return vport; -error: - gre_exit(); - return vport; + return ovs_netdev_link(vport, parms->name); } -static void gre_tnl_destroy(struct vport *vport) +static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, + struct dp_upcall_info *upcall) { - struct net *net = ovs_dp_get_net(vport->dp); - struct ovs_net *ovs_net; - - ovs_net = net_generic(net, ovs_net_id); - - rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL); - ovs_vport_deferred_free(vport); - gre_exit(); -} - -static int gre_send(struct vport *vport, struct sk_buff *skb) -{ - int hlen; - - if (unlikely(!OVS_CB(skb)->tun_key)) - return -EINVAL; - - hlen = ip_gre_calc_hlen(OVS_CB(skb)->tun_key->tun_flags); - - return __send(vport, skb, hlen, 0, 0); + return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp), + skb, IPPROTO_GRE, 0, 0); } -const struct vport_ops ovs_gre_vport_ops = { +static struct vport_ops ovs_gre_vport_ops = { .type = OVS_VPORT_TYPE_GRE, .create = gre_create, - .destroy = gre_tnl_destroy, - .get_name = gre_get_name, - .send = gre_send, + .send = gre_fb_xmit, + .get_egress_tun_info = gre_get_egress_tun_info, + .destroy = ovs_netdev_tunnel_destroy, }; -/* GRE64 vport. */ -static struct vport *gre64_create(const struct vport_parms *parms) -{ - struct net *net = ovs_dp_get_net(parms->dp); - struct ovs_net *ovs_net; - struct vport *vport; - int err; - - err = gre_init(); - if (err) - return ERR_PTR(err); - - ovs_net = net_generic(net, ovs_net_id); - if (ovsl_dereference(ovs_net->vport_net.gre64_vport)) { - vport = ERR_PTR(-EEXIST); - goto error; - } - - vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre64_vport_ops, parms); - if (IS_ERR(vport)) - goto error; - - strncpy(vport_priv(vport), parms->name, IFNAMSIZ); - rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport); - return vport; -error: - gre_exit(); - return vport; -} - -static void gre64_tnl_destroy(struct vport *vport) +static int __init ovs_gre_tnl_init(void) { - struct net *net = ovs_dp_get_net(vport->dp); - struct ovs_net *ovs_net; - - ovs_net = net_generic(net, ovs_net_id); - - rcu_assign_pointer(ovs_net->vport_net.gre64_vport, NULL); - ovs_vport_deferred_free(vport); - gre_exit(); + return ovs_vport_ops_register(&ovs_gre_vport_ops); } -static __be32 be64_get_high32(__be64 x) +static void __exit ovs_gre_tnl_exit(void) { -#ifdef __BIG_ENDIAN - return (__force __be32)((__force u64)x >> 32); -#else - return (__force __be32)x; -#endif + ovs_vport_ops_unregister(&ovs_gre_vport_ops); } -static int gre64_send(struct vport *vport, struct sk_buff *skb) -{ - int hlen = GRE_HEADER_SECTION + /* GRE Hdr */ - GRE_HEADER_SECTION + /* GRE Key */ - GRE_HEADER_SECTION; /* GRE SEQ */ - __be32 seq; +module_init(ovs_gre_tnl_init); +module_exit(ovs_gre_tnl_exit); - if (unlikely(!OVS_CB(skb)->tun_key)) - return -EINVAL; - - if (OVS_CB(skb)->tun_key->tun_flags & TUNNEL_CSUM) - hlen += GRE_HEADER_SECTION; - - seq = be64_get_high32(OVS_CB(skb)->tun_key->tun_id); - return __send(vport, skb, hlen, seq, (TUNNEL_KEY|TUNNEL_SEQ)); -} - -const struct vport_ops ovs_gre64_vport_ops = { - .type = OVS_VPORT_TYPE_GRE64, - .create = gre64_create, - .destroy = gre64_tnl_destroy, - .get_name = gre_get_name, - .send = gre64_send, -}; -#endif +MODULE_DESCRIPTION("OVS: GRE switching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-3");