Skip to content

Commit e80f40c

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: tag_8021q: replace dsa_8021q_remove_header with __skb_vlan_pop
Not only did this wheel did not need reinventing, but there is also an issue with it: It doesn't remove the VLAN header in a way that preserves the L2 payload checksum when that is being provided by the DSA master hw. It should recalculate checksum both for the push, before removing the header, and for the pull afterwards. But the current implementation is quite dizzying, with pulls followed immediately afterwards by pushes, the memmove is done before the push, etc. This makes a DSA master with RX checksumming offload to print stack traces with the infamous 'hw csum failure' message. So remove the dsa_8021q_remove_header function and replace it with something that actually works with inet checksumming. Fixes: d461933 ("net: dsa: tag_8021q: Create helper function for removing VLAN header") Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 961d0e5 commit e80f40c

File tree

3 files changed

+9
-60
lines changed

3 files changed

+9
-60
lines changed

include/linux/dsa/8021q.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ int dsa_8021q_rx_switch_id(u16 vid);
2828

2929
int dsa_8021q_rx_source_port(u16 vid);
3030

31-
struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb);
32-
3331
#else
3432

3533
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
@@ -64,11 +62,6 @@ int dsa_8021q_rx_source_port(u16 vid)
6462
return 0;
6563
}
6664

67-
struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb)
68-
{
69-
return NULL;
70-
}
71-
7265
#endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) */
7366

7467
#endif /* _NET_DSA_8021Q_H */

net/dsa/tag_8021q.c

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -298,47 +298,4 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
298298
}
299299
EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
300300

301-
/* In the DSA packet_type handler, skb->data points in the middle of the VLAN
302-
* tag, after tpid and before tci. This is because so far, ETH_HLEN
303-
* (DMAC, SMAC, EtherType) bytes were pulled.
304-
* There are 2 bytes of VLAN tag left in skb->data, and upper
305-
* layers expect the 'real' EtherType to be consumed as well.
306-
* Coincidentally, a VLAN header is also of the same size as
307-
* the number of bytes that need to be pulled.
308-
*
309-
* skb_mac_header skb->data
310-
* | |
311-
* v v
312-
* | | | | | | | | | | | | | | | | | | |
313-
* +-----------------------+-----------------------+-------+-------+-------+
314-
* | Destination MAC | Source MAC | TPID | TCI | EType |
315-
* +-----------------------+-----------------------+-------+-------+-------+
316-
* ^ | |
317-
* |<--VLAN_HLEN-->to <---VLAN_HLEN--->
318-
* from |
319-
* >>>>>>> v
320-
* >>>>>>> | | | | | | | | | | | | | | |
321-
* >>>>>>> +-----------------------+-----------------------+-------+
322-
* >>>>>>> | Destination MAC | Source MAC | EType |
323-
* +-----------------------+-----------------------+-------+
324-
* ^ ^
325-
* (now part of | |
326-
* skb->head) skb_mac_header skb->data
327-
*/
328-
struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb)
329-
{
330-
u8 *from = skb_mac_header(skb);
331-
u8 *dest = from + VLAN_HLEN;
332-
333-
memmove(dest, from, ETH_HLEN - VLAN_HLEN);
334-
skb_pull(skb, VLAN_HLEN);
335-
skb_push(skb, ETH_HLEN);
336-
skb_reset_mac_header(skb);
337-
skb_reset_mac_len(skb);
338-
skb_pull_rcsum(skb, ETH_HLEN);
339-
340-
return skb;
341-
}
342-
EXPORT_SYMBOL_GPL(dsa_8021q_remove_header);
343-
344301
MODULE_LICENSE("GPL v2");

net/dsa/tag_sja1105.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,14 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
250250
{
251251
struct sja1105_meta meta = {0};
252252
int source_port, switch_id;
253-
struct vlan_ethhdr *hdr;
253+
struct ethhdr *hdr;
254254
u16 tpid, vid, tci;
255255
bool is_link_local;
256256
bool is_tagged;
257257
bool is_meta;
258258

259-
hdr = vlan_eth_hdr(skb);
260-
tpid = ntohs(hdr->h_vlan_proto);
259+
hdr = eth_hdr(skb);
260+
tpid = ntohs(hdr->h_proto);
261261
is_tagged = (tpid == ETH_P_SJA1105);
262262
is_link_local = sja1105_is_link_local(skb);
263263
is_meta = sja1105_is_meta_frame(skb);
@@ -266,7 +266,12 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
266266

267267
if (is_tagged) {
268268
/* Normal traffic path. */
269-
tci = ntohs(hdr->h_vlan_TCI);
269+
skb_push_rcsum(skb, ETH_HLEN);
270+
__skb_vlan_pop(skb, &tci);
271+
skb_pull_rcsum(skb, ETH_HLEN);
272+
skb_reset_network_header(skb);
273+
skb_reset_transport_header(skb);
274+
270275
vid = tci & VLAN_VID_MASK;
271276
source_port = dsa_8021q_rx_source_port(vid);
272277
switch_id = dsa_8021q_rx_switch_id(vid);
@@ -295,12 +300,6 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
295300
return NULL;
296301
}
297302

298-
/* Delete/overwrite fake VLAN header, DSA expects to not find
299-
* it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN).
300-
*/
301-
if (is_tagged)
302-
skb = dsa_8021q_remove_header(skb);
303-
304303
return sja1105_rcv_meta_state_machine(skb, &meta, is_link_local,
305304
is_meta);
306305
}

0 commit comments

Comments
 (0)