net: decreasing real_num_tx_queues needs to flush qdisc
[linux-drm-fsl-dcu.git] / net / core / dev.c
index d03470f5260ae530f9945b50a6a1722466d07d60..723a34710ad401ff24afd5b1be1af86505f7da33 100644 (file)
@@ -1553,6 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
        rcu_read_unlock();
 }
 
+/*
+ * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
+ * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
+ */
+void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+       unsigned int real_num = dev->real_num_tx_queues;
+
+       if (unlikely(txq > dev->num_tx_queues))
+               ;
+       else if (txq > real_num)
+               dev->real_num_tx_queues = txq;
+       else if (txq < real_num) {
+               dev->real_num_tx_queues = txq;
+               qdisc_reset_all_tx_gt(dev, txq);
+       }
+}
+EXPORT_SYMBOL(netif_set_real_num_tx_queues);
 
 static inline void __netif_reschedule(struct Qdisc *q)
 {
@@ -2253,11 +2271,9 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        if (skb_rx_queue_recorded(skb)) {
                u16 index = skb_get_rx_queue(skb);
                if (unlikely(index >= dev->num_rx_queues)) {
-                       if (net_ratelimit()) {
-                               pr_warning("%s received packet on queue "
-                                       "%u, but number of RX queues is %u\n",
-                                       dev->name, index, dev->num_rx_queues);
-                       }
+                       WARN_ONCE(dev->num_rx_queues > 1, "%s received packet "
+                               "on queue %u, but number of RX queues is %u\n",
+                               dev->name, index, dev->num_rx_queues);
                        goto done;
                }
                rxqueue = dev->_rx + index;
@@ -2812,13 +2828,24 @@ static int __netif_receive_skb(struct sk_buff *skb)
        if (!skb->skb_iif)
                skb->skb_iif = skb->dev->ifindex;
 
+       /*
+        * bonding note: skbs received on inactive slaves should only
+        * be delivered to pkt handlers that are exact matches.  Also
+        * the deliver_no_wcard flag will be set.  If packet handlers
+        * are sensitive to duplicate packets these skbs will need to
+        * be dropped at the handler.  The vlan accel path may have
+        * already set the deliver_no_wcard flag.
+        */
        null_or_orig = NULL;
        orig_dev = skb->dev;
        master = ACCESS_ONCE(orig_dev->master);
-       if (master) {
-               if (skb_bond_should_drop(skb, master))
+       if (skb->deliver_no_wcard)
+               null_or_orig = orig_dev;
+       else if (master) {
+               if (skb_bond_should_drop(skb, master)) {
+                       skb->deliver_no_wcard = 1;
                        null_or_orig = orig_dev; /* deliver only exact match */
-               else
+               else
                        skb->dev = master;
        }