OSDN Git Service

qede: Add support for handling IP fragmented packets.
authorManish Chopra <manish.chopra@qlogic.com>
Thu, 30 Jun 2016 06:35:18 +0000 (02:35 -0400)
committerDavid S. Miller <davem@davemloft.net>
Fri, 1 Jul 2016 09:40:53 +0000 (05:40 -0400)
When handling IP fragmented packets with csum in their
transport header, the csum isn't changed as part of the
fragmentation. As a result, the packet containing the
transport headers would have the correct csum of the original
packet, but one that mismatches the actual packet that
passes on the wire. As a result, on receive path HW would
give an indication that the packet has incorrect csum,
which would cause qede to discard the incoming packet.

Since HW also delivers a notification of IP fragments,
change driver behavior to pass such incoming packets
to stack and let it make the decision whether it needs
to be dropped.

Signed-off-by: Manish <manish.chopra@qlogic.com>
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c

index 1441c8f..677213e 100644 (file)
@@ -235,6 +235,7 @@ struct qede_rx_queue {
 
        u64                     rx_hw_errors;
        u64                     rx_alloc_errors;
+       u64                     rx_ip_frags;
 };
 
 union db_prod {
index c5c658a..85633cf 100644 (file)
@@ -37,6 +37,7 @@ static const struct {
 } qede_rqstats_arr[] = {
        QEDE_RQSTAT(rx_hw_errors),
        QEDE_RQSTAT(rx_alloc_errors),
+       QEDE_RQSTAT(rx_ip_frags),
 };
 
 #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr)
index 19bc631..ae4c53b 100644 (file)
@@ -1348,6 +1348,20 @@ static u8 qede_check_csum(u16 flag)
                return qede_check_tunn_csum(flag);
 }
 
+static bool qede_pkt_is_ip_fragmented(struct eth_fast_path_rx_reg_cqe *cqe,
+                                     u16 flag)
+{
+       u8 tun_pars_flg = cqe->tunnel_pars_flags.flags;
+
+       if ((tun_pars_flg & (ETH_TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_MASK <<
+                            ETH_TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_SHIFT)) ||
+           (flag & (PARSING_AND_ERR_FLAGS_IPV4FRAG_MASK <<
+                    PARSING_AND_ERR_FLAGS_IPV4FRAG_SHIFT)))
+               return true;
+
+       return false;
+}
+
 static int qede_rx_int(struct qede_fastpath *fp, int budget)
 {
        struct qede_dev *edev = fp->edev;
@@ -1426,6 +1440,12 @@ static int qede_rx_int(struct qede_fastpath *fp, int budget)
 
                csum_flag = qede_check_csum(parse_flag);
                if (unlikely(csum_flag == QEDE_CSUM_ERROR)) {
+                       if (qede_pkt_is_ip_fragmented(&cqe->fast_path_regular,
+                                                     parse_flag)) {
+                               rxq->rx_ip_frags++;
+                               goto alloc_skb;
+                       }
+
                        DP_NOTICE(edev,
                                  "CQE in CONS = %u has error, flags = %x, dropping incoming packet\n",
                                  sw_comp_cons, parse_flag);
@@ -1434,6 +1454,7 @@ static int qede_rx_int(struct qede_fastpath *fp, int budget)
                        goto next_cqe;
                }
 
+alloc_skb:
                skb = netdev_alloc_skb(edev->ndev, QEDE_RX_HDR_SIZE);
                if (unlikely(!skb)) {
                        DP_NOTICE(edev,