]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/core/dev.c
net: fix problem in reading sock TX queue
[net-next-2.6.git] / net / core / dev.c
index 1845b08c624e1fa4c9dd398f4b61c2963dbfc1f2..0ea10f849be862fff3219bc69ed4c5db0cbd9253 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)
 {
@@ -1893,8 +1911,16 @@ static int dev_gso_segment(struct sk_buff *skb)
  */
 static inline void skb_orphan_try(struct sk_buff *skb)
 {
-       if (!skb_tx(skb)->flags)
+       struct sock *sk = skb->sk;
+
+       if (sk && !skb_tx(skb)->flags) {
+               /* skb_tx_hash() wont be able to get sk.
+                * We copy sk_hash into skb->rxhash
+                */
+               if (!skb->rxhash)
+                       skb->rxhash = sk->sk_hash;
                skb_orphan(skb);
+       }
 }
 
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
@@ -1980,8 +2006,7 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
        if (skb->sk && skb->sk->sk_hash)
                hash = skb->sk->sk_hash;
        else
-               hash = (__force u16) skb->protocol;
-
+               hash = (__force u16) skb->protocol ^ skb->rxhash;
        hash = jhash_1word(hash, hashrnd);
 
        return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
@@ -2004,12 +2029,11 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
 static struct netdev_queue *dev_pick_tx(struct net_device *dev,
                                        struct sk_buff *skb)
 {
-       u16 queue_index;
+       int queue_index;
        struct sock *sk = skb->sk;
 
-       if (sk_tx_queue_recorded(sk)) {
-               queue_index = sk_tx_queue_get(sk);
-       } else {
+       queue_index = sk_tx_queue_get(sk);
+       if (queue_index < 0) {
                const struct net_device_ops *ops = dev->netdev_ops;
 
                if (ops->ndo_select_queue) {
@@ -2253,11 +2277,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;
@@ -2795,7 +2817,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
        struct net_device *orig_dev;
        struct net_device *master;
        struct net_device *null_or_orig;
-       struct net_device *null_or_bond;
+       struct net_device *orig_or_bond;
        int ret = NET_RX_DROP;
        __be16 type;
 
@@ -2812,13 +2834,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;
        }
 
@@ -2868,10 +2901,10 @@ ncls:
         * device that may have registered for a specific ptype.  The
         * handler may have to adjust skb->dev and orig_dev.
         */
-       null_or_bond = NULL;
+       orig_or_bond = orig_dev;
        if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
            (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
-               null_or_bond = vlan_dev_real_dev(skb->dev);
+               orig_or_bond = vlan_dev_real_dev(skb->dev);
        }
 
        type = skb->protocol;
@@ -2879,7 +2912,7 @@ ncls:
                        &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
                if (ptype->type == type && (ptype->dev == null_or_orig ||
                     ptype->dev == skb->dev || ptype->dev == orig_dev ||
-                    ptype->dev == null_or_bond)) {
+                    ptype->dev == orig_or_bond)) {
                        if (pt_prev)
                                ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = ptype;