The use of these flags in the tnl_mutable_config structure are no longer correct as a tunnel device may be used to transmit packets for many different tunnels.
This change restores the checksum and out key behavior of tunneling. Cc: Kyle Mestery <kmest...@cisco.com> Signed-of-by: Simon Horman <ho...@verge.net.au> --- v5 * No Change v4 * No Change v3 * Initial posting --- datapath/tunnel.c | 58 ++++++++++++++++++++++++------------------------- datapath/tunnel.h | 12 +++------- datapath/vport-capwap.c | 28 ++++++++++++------------ datapath/vport-gre.c | 33 ++++++++++++++-------------- 4 files changed, 63 insertions(+), 68 deletions(-) diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 80eb12c..d0f777a 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -485,7 +485,7 @@ bool ovs_tnl_frag_needed(struct vport *vport, static bool check_mtu(struct sk_buff *skb, struct vport *vport, - const struct tnl_mutable_config *mutable, + const struct tnl_mutable_config *mutable, int tun_hlen, const struct rtable *rt, __be16 *frag_offp) { bool df_inherit = mutable->flags & TNL_F_DF_INHERIT; @@ -509,10 +509,7 @@ static bool check_mtu(struct sk_buff *skb, eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) vlan_header = VLAN_HLEN; - mtu = dst_mtu(&rt_dst(rt)) - - ETH_HLEN - - mutable->tunnel_hlen - - vlan_header; + mtu = dst_mtu(&rt_dst(rt)) - ETH_HLEN - tun_hlen - vlan_header; } if (skb->protocol == htons(ETH_P_IP)) { @@ -552,11 +549,10 @@ static bool check_mtu(struct sk_buff *skb, } static void create_tunnel_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - const struct rtable *rt, void *header) + const struct rtable *rt, struct sk_buff *skb) { struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - struct iphdr *iph = header; + struct iphdr *iph = (struct iphdr *)skb->data; iph->version = 4; iph->ihl = sizeof(struct iphdr) >> 2; @@ -567,7 +563,7 @@ static void create_tunnel_header(const struct vport *vport, if (!iph->ttl) iph->ttl = ip4_dst_hoplimit(&rt_dst(rt)); - tnl_vport->tnl_ops->build_header(vport, mutable, iph + 1); + tnl_vport->tnl_ops->build_header(vport, skb); } #ifdef HAVE_RT_GENID @@ -640,16 +636,14 @@ static bool need_linearize(const struct sk_buff *skb) return false; } -static struct sk_buff *handle_offloads(struct sk_buff *skb, - const struct tnl_mutable_config *mutable, +static struct sk_buff *handle_offloads(struct sk_buff *skb, int tun_hlen, const struct rtable *rt) { int min_headroom; int err; min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len - + mutable->tunnel_hlen - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + tun_hlen + (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 - @@ -702,15 +696,14 @@ error: return ERR_PTR(err); } -static int send_frags(struct sk_buff *skb, - const struct tnl_mutable_config *mutable) +static int send_frags(struct sk_buff *skb, int tun_hlen) { int sent_len; sent_len = 0; while (skb) { struct sk_buff *next = skb->next; - int frag_len = skb->len - mutable->tunnel_hlen; + int frag_len = skb->len - tun_hlen; int err; skb->next = NULL; @@ -735,6 +728,14 @@ free_frags: return sent_len; } +static int tunnel_hlen(struct tnl_vport *tnl_vport, struct sk_buff *skb) +{ + int tun_hlen = tnl_vport->tnl_ops->hdr_len(skb); + if (tun_hlen < 0) + return tun_hlen; + return tun_hlen + sizeof(struct iphdr); +} + int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) { struct tnl_vport *tnl_vport = tnl_vport_priv(vport); @@ -748,6 +749,7 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) u8 ttl; u8 inner_tos; u8 tos; + int tun_hlen; if (!OVS_CB(skb)->tun_key) goto error_free; @@ -805,13 +807,17 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) skb_dst_drop(skb); skb_clear_rxhash(skb); + tun_hlen = tunnel_hlen(tnl_vport, skb); + if (unlikely(tun_hlen < 0)) + goto error; + /* Offloading */ - skb = handle_offloads(skb, mutable, rt); + skb = handle_offloads(skb, tun_hlen, rt); if (IS_ERR(skb)) goto error; /* MTU */ - if (unlikely(!check_mtu(skb, vport, mutable, rt, &frag_off))) { + if (unlikely(!check_mtu(skb, vport, mutable, tun_hlen, rt, &frag_off))) { err = VPORT_E_TX_DROPPED; goto error_free; } @@ -820,7 +826,7 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) * If we are over the MTU, allow the IP stack to handle fragmentation. * Fragmentation is a slow path anyways. */ - if (unlikely(skb->len + mutable->tunnel_hlen > dst_mtu(&rt_dst(rt)))) { + if (unlikely(skb->len + tun_hlen > dst_mtu(&rt_dst(rt)))) { unattached_dst = &rt_dst(rt); dst_hold(unattached_dst); } @@ -845,8 +851,8 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) if (unlikely(vlan_deaccel_tag(skb))) goto next; - skb_push(skb, mutable->tunnel_hlen); - create_tunnel_header(vport, mutable, rt, skb->data); + skb_push(skb, tun_hlen); + create_tunnel_header(vport, rt, skb); skb_reset_network_header(skb); if (next_skb) @@ -863,12 +869,12 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) iph->frag_off = frag_off; ip_select_ident(iph, &rt_dst(rt), NULL); - skb = tnl_vport->tnl_ops->update_header(vport, mutable, + skb = tnl_vport->tnl_ops->update_header(vport, tun_hlen, &rt_dst(rt), skb); if (unlikely(!skb)) goto next; - sent_len += send_frags(skb, mutable); + sent_len += send_frags(skb, tun_hlen); next: skb = next_skb; } @@ -900,12 +906,6 @@ static int tnl_set_config(struct net *net, port_key_set_net(&mutable->key, net); mutable->key.tunnel_type = tnl_ops->tunnel_type; - mutable->tunnel_hlen = tnl_ops->hdr_len(mutable); - if (mutable->tunnel_hlen < 0) - return mutable->tunnel_hlen; - - mutable->tunnel_hlen += sizeof(struct iphdr); - old_vport = port_table_lookup(&mutable->key); if (old_vport && old_vport != cur_vport) return -EEXIST; diff --git a/datapath/tunnel.h b/datapath/tunnel.h index 06eaafc..2f657eb 100644 --- a/datapath/tunnel.h +++ b/datapath/tunnel.h @@ -84,10 +84,8 @@ static inline void port_key_set_net(struct port_lookup_key *key, struct net *net * attributes. * @rcu: RCU callback head for deferred destruction. * @seq: Sequence number for distinguishing configuration versions. - * @tunnel_hlen: Tunnel header length. * @eth_addr: Source address for packets generated by tunnel itself * (e.g. ICMP fragmentation needed messages). - * @out_key: Key to use on output, 0 if this tunnel has no fixed output key. * @flags: TNL_F_* flags. */ struct tnl_mutable_config { @@ -96,12 +94,9 @@ struct tnl_mutable_config { unsigned seq; - unsigned tunnel_hlen; - unsigned char eth_addr[ETH_ALEN]; /* Configured via OVS_TUNNEL_ATTR_* attributes. */ - __be64 out_key; u32 flags; }; @@ -114,7 +109,7 @@ struct tnl_ops { * build_header() (i.e. excludes the IP header). Returns a negative * error code if the configuration is invalid. */ - int (*hdr_len)(const struct tnl_mutable_config *); + int (*hdr_len)(struct sk_buff *skb); /* * Builds the static portion of the tunnel header, which is stored in @@ -124,8 +119,7 @@ struct tnl_ops { * in some circumstances caching is disabled and this function will be * called for every packet, so try not to make it too slow. */ - void (*build_header)(const struct vport *, - const struct tnl_mutable_config *, void *header); + void (*build_header)(const struct vport *, struct sk_buff *); /* * Updates the cached header of a packet to match the actual packet @@ -136,7 +130,7 @@ struct tnl_ops { * of fragmentation). */ struct sk_buff *(*update_header)(const struct vport *, - const struct tnl_mutable_config *, + int tun_hlen, struct dst_entry *, struct sk_buff *); }; diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c index a180b87..102a207 100644 --- a/datapath/vport-capwap.c +++ b/datapath/vport-capwap.c @@ -155,16 +155,17 @@ static struct inet_frags frag_state = { .secret_interval = CAPWAP_FRAG_SECRET_INTERVAL, }; -static int capwap_hdr_len(const struct tnl_mutable_config *mutable) +static int capwap_hdr_len(struct sk_buff *skb) { int size = CAPWAP_MIN_HLEN; /* CAPWAP has no checksums. */ - if (mutable->flags & TNL_F_CSUM) + if (OVS_CB(skb)->tun_key->tun_flags & TNL_F_CSUM) { return -EINVAL; /* if keys are specified, then add WSI field */ - if (mutable->out_key || (mutable->flags & TNL_F_OUT_KEY_ACTION)) { + if (OVS_CB(skb)->tun_key->tun_id || + OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) size += sizeof(struct capwaphdr_wsi) + sizeof(struct capwaphdr_wsi_key); } @@ -172,11 +173,10 @@ static int capwap_hdr_len(const struct tnl_mutable_config *mutable) return size; } -static void capwap_build_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - void *header) +static void capwap_build_header(const struct vport *vport, struct sk_buff *skb) { - struct udphdr *udph = header; + struct iphdr *iph = (struct iphdr *)skb->data; + struct udphdr *udph = (struct udphdr *)(iph + 1); struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1); udph->source = htons(CAPWAP_SRC_PORT); @@ -186,7 +186,8 @@ static void capwap_build_header(const struct vport *vport, cwh->frag_id = 0; cwh->frag_off = 0; - if (mutable->out_key || (mutable->flags & TNL_F_OUT_KEY_ACTION)) { + if (OVS_CB(skb)->tun_key->tun_id || + OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) { struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1); cwh->begin = CAPWAP_KEYED; @@ -197,9 +198,9 @@ static void capwap_build_header(const struct vport *vport, wsi->flags = CAPWAP_WSI_F_KEY64; wsi->reserved_padding = 0; - if (mutable->out_key) { + if (OVS_CB(skb)->tun_key->tun_id) { struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1); - opt->key = mutable->out_key; + opt->key = OVS_CB(skb)->tun_key->tun_id; } } else { /* make packet readable by old capwap code */ @@ -208,13 +209,12 @@ static void capwap_build_header(const struct vport *vport, } static struct sk_buff *capwap_update_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - struct dst_entry *dst, + int tun_hlen, struct dst_entry *dst, struct sk_buff *skb) { struct udphdr *udph = udp_hdr(skb); - if (mutable->flags & TNL_F_OUT_KEY_ACTION) { + if (OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) { /* first field in WSI is key */ struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1); struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1); @@ -226,7 +226,7 @@ static struct sk_buff *capwap_update_header(const struct vport *vport, udph->len = htons(skb->len - skb_transport_offset(skb)); if (unlikely(skb->len - skb_network_offset(skb) > dst_mtu(dst))) { - unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable); + unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(skb); skb = fragment(skb, vport, dst, hlen); } diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index 8fab193..b6a4308 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -45,16 +45,17 @@ struct gre_base_hdr { __be16 protocol; }; -static int gre_hdr_len(const struct tnl_mutable_config *mutable) +static int gre_hdr_len(struct sk_buff *skb) { int len; len = GRE_HEADER_SECTION; - if (mutable->flags & TNL_F_CSUM) + if (OVS_CB(skb)->tun_key->tun_flags & TNL_F_CSUM) len += GRE_HEADER_SECTION; - if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION) + if (OVS_CB(skb)->tun_key->tun_id || + OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) len += GRE_HEADER_SECTION; return len; @@ -70,41 +71,41 @@ static __be32 be64_get_low32(__be64 x) #endif } -static void gre_build_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - void *header) +static void gre_build_header(const struct vport *vport, struct sk_buff *skb) { - struct gre_base_hdr *greh = header; + struct iphdr *iph = (struct iphdr *)skb->data; + struct gre_base_hdr *greh = (struct gre_base_hdr *)(iph + 1); __be32 *options = (__be32 *)(greh + 1); greh->protocol = htons(ETH_P_TEB); greh->flags = 0; - if (mutable->flags & TNL_F_CSUM) { + if (OVS_CB(skb)->tun_key->tun_flags & TNL_F_CSUM) { greh->flags |= GRE_CSUM; *options = 0; options++; } - if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION) + if (OVS_CB(skb)->tun_key->tun_id || + OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) greh->flags |= GRE_KEY; - if (mutable->out_key) - *options = be64_get_low32(mutable->out_key); + if (OVS_CB(skb)->tun_key->tun_id) + *options = be64_get_low32(OVS_CB(skb)->tun_key->tun_id); } static struct sk_buff *gre_update_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - struct dst_entry *dst, + int tun_hlen, struct dst_entry *dst, struct sk_buff *skb) { - __be32 *options = (__be32 *)(skb_network_header(skb) + mutable->tunnel_hlen + __be32 *options = (__be32 *)(skb_network_header(skb) + tun_hlen - GRE_HEADER_SECTION); - if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION) + if (OVS_CB(skb)->tun_key->tun_id || + OVS_CB(skb)->tun_key->tun_flags & TNL_F_OUT_KEY_ACTION) options--; - if (mutable->flags & TNL_F_CSUM) + if (OVS_CB(skb)->tun_key->tun_flags & TNL_F_CSUM) *(__sum16 *)options = csum_fold(skb_checksum(skb, skb_transport_offset(skb), skb->len - skb_transport_offset(skb), -- 1.7.10.2.484.gcd07cc5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev