X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Ftunnel.c;h=a0d9fd959a86ad03375a0b25bbd34388b49ab15a;hb=76f1c218bd84e44666c5a0ae54d543dbce42c376;hp=95492f76f07d7e51f527afe3338d6d51234a97c0;hpb=a992ec0b06bfddc4e8c2a50d79362b3dfb286dd5;p=openvswitch diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 95492f76..a0d9fd95 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -33,6 +33,7 @@ #include "datapath.h" #include "table.h" #include "tunnel.h" +#include "vlan.h" #include "vport.h" #include "vport-generic.h" #include "vport-internal_dev.h" @@ -435,10 +436,12 @@ void tnl_rcv(struct vport *vport, struct sk_buff *skb) skb_dst_drop(skb); nf_reset(skb); + skb_clear_rxhash(skb); secpath_reset(skb); ecn_decapsulate(skb); compute_ip_summed(skb, false); + vlan_set_tci(skb, 0); vport_receive(vport, skb); } @@ -682,7 +685,8 @@ bool tnl_frag_needed(struct vport *vport, const struct tnl_mutable_config *mutab vh->h_vlan_TCI = vlan_eth_hdr(skb)->h_vlan_TCI; vh->h_vlan_encapsulated_proto = skb->protocol; - } + } else + vlan_set_tci(nskb, vlan_get_tci(skb)); skb_reset_mac_header(nskb); /* Protocol */ @@ -720,17 +724,27 @@ static bool check_mtu(struct sk_buff *skb, int mtu = 0; unsigned int packet_length = skb->len - ETH_HLEN; - if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) + /* Allow for one level of tagging in the packet length. */ + if (!vlan_tx_tag_present(skb) && + eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) packet_length -= VLAN_HLEN; if (pmtud) { + int vlan_header = 0; + frag_off = htons(IP_DF); + /* The tag needs to go in packet regardless of where it + * currently is, so subtract it from the MTU. + */ + if (vlan_tx_tag_present(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 - - (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q) ? - VLAN_HLEN : 0); + - vlan_header; } if (skb->protocol == htons(ETH_P_IP)) { @@ -1041,28 +1055,18 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb, goto error_free; min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len - + mutable->tunnel_hlen; + + mutable->tunnel_hlen + + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + skb = check_headroom(skb, min_headroom); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto error; + } if (skb_is_gso(skb)) { struct sk_buff *nskb; - /* - * If we are doing GSO on a pskb it is better to make sure that - * the headroom is correct now. We will only have to copy the - * portion in the linear data area and GSO will preserve - * headroom when it creates the segments. This is particularly - * beneficial on Xen where we get a lot of GSO pskbs. - * Conversely, we avoid copying if it is just to get our own - * writable clone because GSO will do the copy for us. - */ - if (skb_headroom(skb) < min_headroom) { - skb = check_headroom(skb, min_headroom); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - goto error; - } - } - nskb = skb_gso_segment(skb, 0); kfree_skb(skb); if (IS_ERR(nskb)) { @@ -1071,32 +1075,23 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb, } skb = nskb; - } else { - skb = check_headroom(skb, min_headroom); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - goto error; - } - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - /* - * Pages aren't locked and could change at any time. - * If this happens after we compute the checksum, the - * checksum will be wrong. We linearize now to avoid - * this problem. - */ - if (unlikely(need_linearize(skb))) { - err = __skb_linearize(skb); - if (unlikely(err)) - goto error_free; - } - - err = skb_checksum_help(skb); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Pages aren't locked and could change at any time. + * If this happens after we compute the checksum, the + * checksum will be wrong. We linearize now to avoid + * this problem. + */ + if (unlikely(need_linearize(skb))) { + err = __skb_linearize(skb); if (unlikely(err)) goto error_free; - } else if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - } + } + + err = skb_checksum_help(skb); + if (unlikely(err)) + goto error_free; + } else if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->ip_summed = CHECKSUM_NONE; return skb; @@ -1159,7 +1154,8 @@ int tnl_send(struct vport *vport, struct sk_buff *skb) u8 tos; /* Validate the protocol headers before we try to use them. */ - if (skb->protocol == htons(ETH_P_8021Q)) { + if (skb->protocol == htons(ETH_P_8021Q) && + !vlan_tx_tag_present(skb)) { if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) goto error_free; @@ -1208,6 +1204,7 @@ int tnl_send(struct vport *vport, struct sk_buff *skb) nf_reset(skb); secpath_reset(skb); skb_dst_drop(skb); + skb_clear_rxhash(skb); /* Offloading */ skb = handle_offloads(skb, mutable, rt); @@ -1250,6 +1247,9 @@ int tnl_send(struct vport *vport, struct sk_buff *skb) struct sk_buff *next_skb = skb->next; skb->next = NULL; + if (unlikely(vlan_deaccel_tag(skb))) + goto next; + if (likely(cache)) { skb_push(skb, cache->len); memcpy(skb->data, get_cached_header(cache), cache->len);