aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/sch_generic.h
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-06-12 02:03:51 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-12 18:29:21 -0400
commit5ee31c6898ea5537fcea160999d60dc63bc0c305 (patch)
tree84d7ce7e966ae47282ab902f19f73b8233ebc1f2 /include/net/sch_generic.h
parent8a93664df90db983cfede122f9b4ddb3a8284e52 (diff)
bonding: Fix corrupted queue_mapping
In the transmit path of the bonding driver, skb->cb is used to stash the skb->queue_mapping so that the bonding device can set its own queue mapping. This value becomes corrupted since the skb->cb is also used in __dev_xmit_skb. When transmitting through bonding driver, bond_select_queue is called from dev_queue_xmit. In bond_select_queue the original skb->queue_mapping is copied into skb->cb (via bond_queue_mapping) and skb->queue_mapping is overwritten with the bond driver queue. Subsequently in dev_queue_xmit, __dev_xmit_skb is called which writes the packet length into skb->cb, thereby overwriting the stashed queue mappping. In bond_dev_queue_xmit (called from hard_start_xmit), the queue mapping for the skb is set to the stashed value which is now the skb length and hence is an invalid queue for the slave device. If we want to save skb->queue_mapping into skb->cb[], best place is to add a field in struct qdisc_skb_cb, to make sure it wont conflict with other layers (eg : Qdiscc, Infiniband...) This patchs also makes sure (struct qdisc_skb_cb)->data is aligned on 8 bytes : netem qdisc for example assumes it can store an u64 in it, without misalignment penalty. Note : we only have 20 bytes left in (struct qdisc_skb_cb)->data[]. The largest user is CHOKe and it fills it. Based on a previous patch from Tom Herbert. Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Tom Herbert <therbert@google.com> Cc: John Fastabend <john.r.fastabend@intel.com> Cc: Roland Dreier <roland@kernel.org> Acked-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/sch_generic.h')
-rw-r--r--include/net/sch_generic.h7
1 files changed, 5 insertions, 2 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 55ce96b53b09..9d7d54a00e63 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -220,13 +220,16 @@ struct tcf_proto {
220 220
221struct qdisc_skb_cb { 221struct qdisc_skb_cb {
222 unsigned int pkt_len; 222 unsigned int pkt_len;
223 unsigned char data[24]; 223 u16 bond_queue_mapping;
224 u16 _pad;
225 unsigned char data[20];
224}; 226};
225 227
226static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) 228static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
227{ 229{
228 struct qdisc_skb_cb *qcb; 230 struct qdisc_skb_cb *qcb;
229 BUILD_BUG_ON(sizeof(skb->cb) < sizeof(unsigned int) + sz); 231
232 BUILD_BUG_ON(sizeof(skb->cb) < offsetof(struct qdisc_skb_cb, data) + sz);
230 BUILD_BUG_ON(sizeof(qcb->data) < sz); 233 BUILD_BUG_ON(sizeof(qcb->data) < sz);
231} 234}
232 235