|
@@ -1193,10 +1193,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
|
|
|
u32 rx_error,
|
|
|
u16 rx_ptype)
|
|
|
{
|
|
|
+ struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
|
|
|
+ bool ipv4 = false, ipv6 = false;
|
|
|
bool ipv4_tunnel, ipv6_tunnel;
|
|
|
__wsum rx_udp_csum;
|
|
|
- __sum16 csum;
|
|
|
struct iphdr *iph;
|
|
|
+ __sum16 csum;
|
|
|
|
|
|
ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
|
|
|
(rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
|
|
@@ -1207,29 +1209,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
|
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
|
|
|
|
/* Rx csum enabled and ip headers found? */
|
|
|
- if (!(vsi->netdev->features & NETIF_F_RXCSUM &&
|
|
|
- rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
|
|
|
+ if (!(vsi->netdev->features & NETIF_F_RXCSUM))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* did the hardware decode the packet and checksum? */
|
|
|
+ if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* both known and outer_ip must be set for the below code to work */
|
|
|
+ if (!(decoded.known && decoded.outer_ip))
|
|
|
return;
|
|
|
|
|
|
+ if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
|
|
|
+ decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
|
|
|
+ ipv4 = true;
|
|
|
+ else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
|
|
|
+ decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
|
|
|
+ ipv6 = true;
|
|
|
+
|
|
|
+ if (ipv4 &&
|
|
|
+ (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
|
|
|
+ (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))))
|
|
|
+ goto checksum_fail;
|
|
|
+
|
|
|
/* likely incorrect csum if alternate IP extension headers found */
|
|
|
- if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
|
|
|
+ if (ipv6 &&
|
|
|
+ decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP &&
|
|
|
+ rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) &&
|
|
|
+ rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
|
|
|
+ /* don't increment checksum err here, non-fatal err */
|
|
|
return;
|
|
|
|
|
|
- /* IP or L4 or outmost IP checksum error */
|
|
|
- if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
|
|
|
- (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) |
|
|
|
- (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) {
|
|
|
- vsi->back->hw_csum_rx_error++;
|
|
|
+ /* there was some L4 error, count error and punt packet to the stack */
|
|
|
+ if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))
|
|
|
+ goto checksum_fail;
|
|
|
+
|
|
|
+ /* handle packets that were not able to be checksummed due
|
|
|
+ * to arrival speed, in this case the stack can compute
|
|
|
+ * the csum.
|
|
|
+ */
|
|
|
+ if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT))
|
|
|
return;
|
|
|
- }
|
|
|
|
|
|
+ /* If VXLAN traffic has an outer UDPv4 checksum we need to check
|
|
|
+ * it in the driver, hardware does not do it for us.
|
|
|
+ * Since L3L4P bit was set we assume a valid IHL value (>=5)
|
|
|
+ * so the total length of IPv4 header is IHL*4 bytes
|
|
|
+ * The UDP_0 bit *may* bet set if the *inner* header is UDP
|
|
|
+ */
|
|
|
if (ipv4_tunnel &&
|
|
|
+ (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) &&
|
|
|
!(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) {
|
|
|
- /* If VXLAN traffic has an outer UDPv4 checksum we need to check
|
|
|
- * it in the driver, hardware does not do it for us.
|
|
|
- * Since L3L4P bit was set we assume a valid IHL value (>=5)
|
|
|
- * so the total length of IPv4 header is IHL*4 bytes
|
|
|
- */
|
|
|
skb->transport_header = skb->mac_header +
|
|
|
sizeof(struct ethhdr) +
|
|
|
(ip_hdr(skb)->ihl * 4);
|
|
@@ -1246,13 +1276,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
|
|
|
(skb->len - skb_transport_offset(skb)),
|
|
|
IPPROTO_UDP, rx_udp_csum);
|
|
|
|
|
|
- if (udp_hdr(skb)->check != csum) {
|
|
|
- vsi->back->hw_csum_rx_error++;
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (udp_hdr(skb)->check != csum)
|
|
|
+ goto checksum_fail;
|
|
|
}
|
|
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+checksum_fail:
|
|
|
+ vsi->back->hw_csum_rx_error++;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1429,6 +1462,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
|
|
|
/* ERR_MASK will only have valid bits if EOP set */
|
|
|
if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
|
|
|
dev_kfree_skb_any(skb);
|
|
|
+ /* TODO: shouldn't we increment a counter indicating the
|
|
|
+ * drop?
|
|
|
+ */
|
|
|
goto next_desc;
|
|
|
}
|
|
|
|