]> git.droids-corp.org - dpdk.git/commitdiff
net/enic: fix memory leak with oversized Tx packets
authorJohn Daley <johndale@cisco.com>
Fri, 3 Feb 2017 01:18:40 +0000 (17:18 -0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 10 Feb 2017 11:25:49 +0000 (12:25 +0100)
If a packet send is attempted with a packet larger than the NIC
is capable of processing (9208) it will be dropped with no
completion descriptor returned or completion index update, which
will lead to an mbuf leak and eventual hang.

Drop and count oversized Tx packets in the Tx burst function and
dereference/free the mbuf without sending it to the NIC.

Since the maximum Rx and Tx packet sizes are different on enic
and are now both being used, make the define ENIC_DEFAULT_MAX_PKT_SIZE
be 2 defines, one for Rx and one for Tx.

Fixes: fefed3d1e62c ("enic: new driver")
Cc: stable@dpdk.org
Signed-off-by: John Daley <johndale@cisco.com>
drivers/net/enic/enic.h
drivers/net/enic/enic_main.c
drivers/net/enic/enic_res.c
drivers/net/enic/enic_res.h
drivers/net/enic/enic_rxtx.c

index a4540178ef5599ebb7257dc3e8c5348944d87bf4..e921de4055959254175afb953ccf898365344d2b 100644 (file)
@@ -103,6 +103,7 @@ struct enic_fdir {
 struct enic_soft_stats {
        rte_atomic64_t rx_nombuf;
        rte_atomic64_t rx_packet_errors;
+       rte_atomic64_t tx_oversized;
 };
 
 struct enic_memzone_entry {
index 21e8edeb08339afea93b4b456f9971c9041a2102..570b7b69a162e8a96036034b1f1e437af72ff87e 100644 (file)
@@ -137,6 +137,7 @@ static void enic_clear_soft_stats(struct enic *enic)
        struct enic_soft_stats *soft_stats = &enic->soft_stats;
        rte_atomic64_clear(&soft_stats->rx_nombuf);
        rte_atomic64_clear(&soft_stats->rx_packet_errors);
+       rte_atomic64_clear(&soft_stats->tx_oversized);
 }
 
 static void enic_init_soft_stats(struct enic *enic)
@@ -144,6 +145,7 @@ static void enic_init_soft_stats(struct enic *enic)
        struct enic_soft_stats *soft_stats = &enic->soft_stats;
        rte_atomic64_init(&soft_stats->rx_nombuf);
        rte_atomic64_init(&soft_stats->rx_packet_errors);
+       rte_atomic64_init(&soft_stats->tx_oversized);
        enic_clear_soft_stats(enic);
 }
 
@@ -183,7 +185,8 @@ void enic_dev_stats_get(struct enic *enic, struct rte_eth_stats *r_stats)
        r_stats->obytes = stats->tx.tx_bytes_ok;
 
        r_stats->ierrors = stats->rx.rx_errors + stats->rx.rx_drop;
-       r_stats->oerrors = stats->tx.tx_errors;
+       r_stats->oerrors = stats->tx.tx_errors
+                          + rte_atomic64_read(&soft_stats->tx_oversized);
 
        r_stats->imissed = stats->rx.rx_no_bufs + rx_truncated;
 
index 8a230a1664c8217888831ae073bd8b95aa4e94f2..867bd25c48ac3706e5b13613f50f199e9b589526 100644 (file)
@@ -89,10 +89,11 @@ int enic_get_vnic_config(struct enic *enic)
        /* max packet size is only defined in newer VIC firmware
         * and will be 0 for legacy firmware and VICs
         */
-       if (c->max_pkt_size > ENIC_DEFAULT_MAX_PKT_SIZE)
+       if (c->max_pkt_size > ENIC_DEFAULT_RX_MAX_PKT_SIZE)
                enic->max_mtu = c->max_pkt_size - (ETHER_HDR_LEN + 4);
        else
-               enic->max_mtu = ENIC_DEFAULT_MAX_PKT_SIZE - (ETHER_HDR_LEN + 4);
+               enic->max_mtu = ENIC_DEFAULT_RX_MAX_PKT_SIZE
+                               - (ETHER_HDR_LEN + 4);
        if (c->mtu == 0)
                c->mtu = 1500;
 
index 303530efbc9aa495717838be709d235715edaf20..1135d2e1d6eba247c238b69e55ae339d7c37177b 100644 (file)
 #define ENIC_MIN_MTU                   68
 
 /* Does not include (possible) inserted VLAN tag and FCS */
-#define ENIC_DEFAULT_MAX_PKT_SIZE      9022
+#define ENIC_DEFAULT_RX_MAX_PKT_SIZE   9022
+
+/* Does not include (possible) inserted VLAN tag and FCS */
+#define ENIC_TX_MAX_PKT_SIZE           9208
 
 #define ENIC_MULTICAST_PERFECT_FILTERS 32
 #define ENIC_UNICAST_PERFECT_FILTERS   32
index 26b83ae9b25b376aaf72ba1115a773a368368292..343dabc644e6b5365b0d75d5ba3a7fcb9f73c4a3 100644 (file)
@@ -546,16 +546,23 @@ uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
        for (index = 0; index < nb_pkts; index++) {
                tx_pkt = *tx_pkts++;
+               pkt_len = tx_pkt->pkt_len;
+               data_len = tx_pkt->data_len;
+               ol_flags = tx_pkt->ol_flags;
                nb_segs = tx_pkt->nb_segs;
+
+               if (pkt_len > ENIC_TX_MAX_PKT_SIZE) {
+                       rte_pktmbuf_free(tx_pkt);
+                       rte_atomic64_inc(&enic->soft_stats.tx_oversized);
+                       continue;
+               }
+
                if (nb_segs > wq_desc_avail) {
                        if (index > 0)
                                goto post;
                        goto done;
                }
 
-               pkt_len = tx_pkt->pkt_len;
-               data_len = tx_pkt->data_len;
-               ol_flags = tx_pkt->ol_flags;
                mss = 0;
                vlan_id = 0;
                vlan_tag_insert = 0;