|
@@ -1328,6 +1328,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
|
|
|
|
|
|
for (p = *head; p; p = p->next) {
|
|
|
struct iphdr *iph2;
|
|
|
+ u16 flush_id;
|
|
|
|
|
|
if (!NAPI_GRO_CB(p)->same_flow)
|
|
|
continue;
|
|
@@ -1351,16 +1352,36 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
|
|
|
(iph->tos ^ iph2->tos) |
|
|
|
((iph->frag_off ^ iph2->frag_off) & htons(IP_DF));
|
|
|
|
|
|
- /* Save the IP ID check to be included later when we get to
|
|
|
- * the transport layer so only the inner most IP ID is checked.
|
|
|
- * This is because some GSO/TSO implementations do not
|
|
|
- * correctly increment the IP ID for the outer hdrs.
|
|
|
- */
|
|
|
- NAPI_GRO_CB(p)->flush_id =
|
|
|
- ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
|
|
|
NAPI_GRO_CB(p)->flush |= flush;
|
|
|
+
|
|
|
+ /* We need to store of the IP ID check to be included later
|
|
|
+ * when we can verify that this packet does in fact belong
|
|
|
+ * to a given flow.
|
|
|
+ */
|
|
|
+ flush_id = (u16)(id - ntohs(iph2->id));
|
|
|
+
|
|
|
+ /* This bit of code makes it much easier for us to identify
|
|
|
+ * the cases where we are doing atomic vs non-atomic IP ID
|
|
|
+ * checks. Specifically an atomic check can return IP ID
|
|
|
+ * values 0 - 0xFFFF, while a non-atomic check can only
|
|
|
+ * return 0 or 0xFFFF.
|
|
|
+ */
|
|
|
+ if (!NAPI_GRO_CB(p)->is_atomic ||
|
|
|
+ !(iph->frag_off & htons(IP_DF))) {
|
|
|
+ flush_id ^= NAPI_GRO_CB(p)->count;
|
|
|
+ flush_id = flush_id ? 0xFFFF : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If the previous IP ID value was based on an atomic
|
|
|
+ * datagram we can overwrite the value and ignore it.
|
|
|
+ */
|
|
|
+ if (NAPI_GRO_CB(skb)->is_atomic)
|
|
|
+ NAPI_GRO_CB(p)->flush_id = flush_id;
|
|
|
+ else
|
|
|
+ NAPI_GRO_CB(p)->flush_id |= flush_id;
|
|
|
}
|
|
|
|
|
|
+ NAPI_GRO_CB(skb)->is_atomic = !!(iph->frag_off & htons(IP_DF));
|
|
|
NAPI_GRO_CB(skb)->flush |= flush;
|
|
|
skb_set_network_header(skb, off);
|
|
|
/* The above will be needed by the transport layer if there is one
|