X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fvport-gre.c;h=c252dcfdc0d809028df5118afa72947d973d5fcc;hb=85c9de194b9f432f7b8a66bda980cbab52a55b72;hp=680e7b34ae0f48ee31b8ad34d1f5da31956ed398;hpb=0d0673857b5b2a50f6aef62e0f042795d9893690;p=sliver-openvswitch.git diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index 680e7b34a..c252dcfdc 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -44,32 +44,30 @@ struct gre_base_hdr { __be16 protocol; }; -static int gre_hdr_len(const struct tnl_mutable_config *mutable, - const struct ovs_key_ipv4_tunnel *tun_key) +static int gre_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) { - int len; - u32 flags; - __be64 out_key; + int len = GRE_HEADER_SECTION; - tnl_get_param(mutable, tun_key, &flags, &out_key); - len = GRE_HEADER_SECTION; - - if (flags & TNL_F_CSUM) + if (tun_key->tun_flags & OVS_TNL_F_KEY) + len += GRE_HEADER_SECTION; + if (tun_key->tun_flags & OVS_TNL_F_CSUM) len += GRE_HEADER_SECTION; + return len; +} +static int gre64_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) +{ /* Set key for GRE64 tunnels, even when key if is zero. */ - if (out_key || - mutable->key.tunnel_type & TNL_T_PROTO_GRE64 || - flags & TNL_F_OUT_KEY_ACTION) { + int len = GRE_HEADER_SECTION + /* GRE Hdr */ + GRE_HEADER_SECTION + /* GRE Key */ + GRE_HEADER_SECTION; /* GRE SEQ */ + if (tun_key->tun_flags & OVS_TNL_F_CSUM) len += GRE_HEADER_SECTION; - if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64) - len += GRE_HEADER_SECTION; - } + return len; } - /* Returns the least-significant 32 bits of a __be64. */ static __be32 be64_get_low32(__be64 x) { @@ -89,39 +87,33 @@ static __be32 be64_get_high32(__be64 x) #endif } -static struct sk_buff *gre_build_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - struct dst_entry *dst, - struct sk_buff *skb, - int tunnel_hlen) +static void __gre_build_header(struct sk_buff *skb, + int tunnel_hlen, + bool is_gre64) { - u32 flags; - __be64 out_key; const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; __be32 *options = (__be32 *)(skb_network_header(skb) + tunnel_hlen - - GRE_HEADER_SECTION); + - GRE_HEADER_SECTION); struct gre_base_hdr *greh = (struct gre_base_hdr *) skb_transport_header(skb); - - tnl_get_param(mutable, tun_key, &flags, &out_key); + struct dst_entry *dst = skb_dst(skb); greh->protocol = htons(ETH_P_TEB); greh->flags = 0; /* Work backwards over the options so the checksum is last. */ - if (out_key || flags & TNL_F_OUT_KEY_ACTION || - mutable->key.tunnel_type & TNL_T_PROTO_GRE64) { + if (tun_key->tun_flags & OVS_TNL_F_KEY || is_gre64) { greh->flags |= GRE_KEY; - if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64) { + if (is_gre64) { /* Set higher 32 bits to seq. */ - *options = be64_get_high32(out_key); + *options = be64_get_high32(tun_key->tun_id); options--; greh->flags |= GRE_SEQ; } - *options = be64_get_low32(out_key); + *options = be64_get_low32(tun_key->tun_id); options--; } - if (flags & TNL_F_CSUM) { + if (tun_key->tun_flags & OVS_TNL_F_CSUM) { greh->flags |= GRE_CSUM; *options = 0; *(__sum16 *)options = csum_fold(skb_checksum(skb, @@ -137,8 +129,20 @@ static struct sk_buff *gre_build_header(const struct vport *vport, */ skb->local_df = 1; __ip_select_ident(ip_hdr(skb), dst, 0); +} - return skb; +static void gre_build_header(const struct vport *vport, + struct sk_buff *skb, + int tunnel_hlen) +{ + __gre_build_header(skb, tunnel_hlen, false); +} + +static void gre64_build_header(const struct vport *vport, + struct sk_buff *skb, + int tunnel_hlen) +{ + __gre_build_header(skb, tunnel_hlen, true); } static __be64 key_to_tunnel_id(__be32 key, __be32 seq) @@ -151,7 +155,7 @@ static __be64 key_to_tunnel_id(__be32 key, __be32 seq) } static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id, - u32 *tunnel_type) + bool *is_gre64) { /* IP and ICMP protocol handlers check that the IHL is valid. */ struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2)); @@ -183,16 +187,16 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id, if (greh->flags & GRE_SEQ) { seq = *options; - *tunnel_type = TNL_T_PROTO_GRE64; + *is_gre64 = true; } else { seq = 0; - *tunnel_type = TNL_T_PROTO_GRE; + *is_gre64 = false; } *tun_id = key_to_tunnel_id(gre_key, seq); } else { *tun_id = 0; /* Ignore GRE seq if there is no key present. */ - *tunnel_type = TNL_T_PROTO_GRE; + *is_gre64 = false; } if (greh->flags & GRE_SEQ) @@ -227,18 +231,12 @@ static bool check_checksum(struct sk_buff *skb) return (csum == 0); } -static u32 gre_flags_to_tunnel_flags(const struct tnl_mutable_config *mutable, - __be16 gre_flags, __be64 *key) +static u32 gre_flags_to_tunnel_flags(__be16 gre_flags, bool is_gre64) { u32 tunnel_flags = 0; - if (gre_flags & GRE_KEY) { - if (mutable->flags & TNL_F_IN_KEY_MATCH || - !mutable->key.daddr) - tunnel_flags = OVS_TNL_F_KEY; - else - *key = 0; - } + if (gre_flags & GRE_KEY || is_gre64) + tunnel_flags = OVS_TNL_F_KEY; if (gre_flags & GRE_CSUM) tunnel_flags |= OVS_TNL_F_CSUM; @@ -249,35 +247,38 @@ static u32 gre_flags_to_tunnel_flags(const struct tnl_mutable_config *mutable, /* Called with rcu_read_lock and BH disabled. */ static int gre_rcv(struct sk_buff *skb) { + struct ovs_net *ovs_net; struct vport *vport; - const struct tnl_mutable_config *mutable; int hdr_len; struct iphdr *iph; struct ovs_key_ipv4_tunnel tun_key; __be16 gre_flags; u32 tnl_flags; __be64 key; - u32 tunnel_type; + bool is_gre64; if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN))) goto error; if (unlikely(!check_checksum(skb))) goto error; - hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &tunnel_type); + hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &is_gre64); if (unlikely(hdr_len < 0)) goto error; - if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN))) + ovs_net = net_generic(dev_net(skb->dev), ovs_net_id); + if (is_gre64) + vport = rcu_dereference(ovs_net->vport_net.gre64_vport); + else + vport = rcu_dereference(ovs_net->vport_net.gre_vport); + if (unlikely(!vport)) goto error; - iph = ip_hdr(skb); - vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, key, - tunnel_type, &mutable); - if (unlikely(!vport)) + if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN))) goto error; - tnl_flags = gre_flags_to_tunnel_flags(mutable, gre_flags, &key); + iph = ip_hdr(skb); + tnl_flags = gre_flags_to_tunnel_flags(gre_flags, is_gre64); tnl_tun_key_init(&tun_key, iph, key, tnl_flags); OVS_CB(skb)->tun_key = &tun_key; @@ -292,30 +293,6 @@ error: return 0; } -static const struct tnl_ops gre_tnl_ops = { - .tunnel_type = TNL_T_PROTO_GRE, - .ipproto = IPPROTO_GRE, - .hdr_len = gre_hdr_len, - .build_header = gre_build_header, -}; - -static struct vport *gre_create(const struct vport_parms *parms) -{ - return ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops); -} - -static const struct tnl_ops gre64_tnl_ops = { - .tunnel_type = TNL_T_PROTO_GRE64, - .ipproto = IPPROTO_GRE, - .hdr_len = gre_hdr_len, - .build_header = gre_build_header, -}; - -static struct vport *gre_create64(const struct vport_parms *parms) -{ - return ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops); -} - static const struct net_protocol gre_protocol_handlers = { .handler = gre_rcv, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) @@ -350,28 +327,93 @@ static void gre_exit(void) inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE); } +/* GRE vport. */ +static const struct tnl_ops gre_tnl_ops = { + .ipproto = IPPROTO_GRE, + .hdr_len = gre_hdr_len, + .build_header = gre_build_header, +}; + +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; + + ovs_net = net_generic(net, ovs_net_id); + if (rtnl_dereference(ovs_net->vport_net.gre_vport)) + return ERR_PTR(-EEXIST); + + vport = ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops); + + rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport); + return vport; +} + +static void gre_tnl_destroy(struct vport *vport) +{ + 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_tnl_destroy(vport); +} + const struct vport_ops ovs_gre_vport_ops = { .type = OVS_VPORT_TYPE_GRE, .flags = VPORT_F_TUN_ID, .init = gre_init, .exit = gre_exit, .create = gre_create, - .destroy = ovs_tnl_destroy, + .destroy = gre_tnl_destroy, .get_name = ovs_tnl_get_name, - .get_options = ovs_tnl_get_options, - .set_options = ovs_tnl_set_options, .send = ovs_tnl_send, }; +/* GRE64 vport. */ +static const struct tnl_ops gre64_tnl_ops = { + .ipproto = IPPROTO_GRE, + .hdr_len = gre64_hdr_len, + .build_header = gre64_build_header, +}; + +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; + + ovs_net = net_generic(net, ovs_net_id); + if (rtnl_dereference(ovs_net->vport_net.gre64_vport)) + return ERR_PTR(-EEXIST); + + vport = ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops); + + rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport); + return vport; +} + + +static void gre64_tnl_destroy(struct vport *vport) +{ + 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_tnl_destroy(vport); +} + const struct vport_ops ovs_gre64_vport_ops = { .type = OVS_VPORT_TYPE_GRE64, .flags = VPORT_F_TUN_ID, .init = gre_init, .exit = gre_exit, - .create = gre_create64, - .destroy = ovs_tnl_destroy, + .create = gre64_create, + .destroy = gre64_tnl_destroy, .get_name = ovs_tnl_get_name, - .get_options = ovs_tnl_get_options, - .set_options = ovs_tnl_set_options, .send = ovs_tnl_send, };