Skip to content

Commit

Permalink
Merge branch 'dsa-tagger-helpers'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
DSA tagger helpers

The goal of this series is to minimize the use of memmove and skb->data
in the DSA tagging protocol drivers. Unfiltered access to this level of
information is not very friendly to drive-by contributors, and sometimes
is also not the easiest to review.

For starters, I have converted the most common form of DSA tagging
protocols: the DSA headers which are placed where the EtherType is.

The helper functions introduced by this series are:
- dsa_alloc_etype_header
- dsa_strip_etype_header
- dsa_etype_header_pos_rx
- dsa_etype_header_pos_tx

This series is just a resend as non-RFC of v1.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 11, 2021
2 parents 1a8e628 + a72808b commit 88be326
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 81 deletions.
78 changes: 78 additions & 0 deletions net/dsa/dsa_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,84 @@ static inline void dsa_default_offload_fwd_mark(struct sk_buff *skb)
skb->offload_fwd_mark = !!(dp->bridge_dev);
}

/* Helper for removing DSA header tags from packets in the RX path.
* Must not be called before skb_pull(len).
* skb->data
* |
* v
* | | | | | | | | | | | | | | | | | | |
* +-----------------------+-----------------------+---------------+-------+
* | Destination MAC | Source MAC | DSA header | EType |
* +-----------------------+-----------------------+---------------+-------+
* | |
* <----- len -----> <----- len ----->
* |
* >>>>>>> v
* >>>>>>> | | | | | | | | | | | | | | |
* >>>>>>> +-----------------------+-----------------------+-------+
* >>>>>>> | Destination MAC | Source MAC | EType |
* +-----------------------+-----------------------+-------+
* ^
* |
* skb->data
*/
static inline void dsa_strip_etype_header(struct sk_buff *skb, int len)
{
memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - len, 2 * ETH_ALEN);
}

/* Helper for creating space for DSA header tags in TX path packets.
* Must not be called before skb_push(len).
*
* Before:
*
* <<<<<<< | | | | | | | | | | | | | | |
* ^ <<<<<<< +-----------------------+-----------------------+-------+
* | <<<<<<< | Destination MAC | Source MAC | EType |
* | +-----------------------+-----------------------+-------+
* <----- len ----->
* |
* |
* skb->data
*
* After:
*
* | | | | | | | | | | | | | | | | | | |
* +-----------------------+-----------------------+---------------+-------+
* | Destination MAC | Source MAC | DSA header | EType |
* +-----------------------+-----------------------+---------------+-------+
* ^ | |
* | <----- len ----->
* skb->data
*/
static inline void dsa_alloc_etype_header(struct sk_buff *skb, int len)
{
memmove(skb->data, skb->data + len, 2 * ETH_ALEN);
}

/* On RX, eth_type_trans() on the DSA master pulls ETH_HLEN bytes starting from
* skb_mac_header(skb), which leaves skb->data pointing at the first byte after
* what the DSA master perceives as the EtherType (the beginning of the L3
* protocol). Since DSA EtherType header taggers treat the EtherType as part of
* the DSA tag itself, and the EtherType is 2 bytes in length, the DSA header
* is located 2 bytes behind skb->data. Note that EtherType in this context
* means the first 2 bytes of the DSA header, not the encapsulated EtherType
* that will become visible after the DSA header is stripped.
*/
static inline void *dsa_etype_header_pos_rx(struct sk_buff *skb)
{
return skb->data - 2;
}

/* On TX, skb->data points to skb_mac_header(skb), which means that EtherType
* header taggers start exactly where the EtherType is (the EtherType is
* treated as part of the DSA header).
*/
static inline void *dsa_etype_header_pos_tx(struct sk_buff *skb)
{
return skb->data + 2 * ETH_ALEN;
}

/* switch.c */
int dsa_switch_register_notifier(struct dsa_switch *ds);
void dsa_switch_unregister_notifier(struct dsa_switch *ds);
Expand Down
16 changes: 5 additions & 11 deletions net/dsa/tag_brcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
skb_push(skb, BRCM_TAG_LEN);

if (offset)
memmove(skb->data, skb->data + BRCM_TAG_LEN, offset);
dsa_alloc_etype_header(skb, BRCM_TAG_LEN);

brcm_tag = skb->data + offset;

Expand Down Expand Up @@ -190,10 +190,7 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (!nskb)
return nskb;

/* Move the Ethernet DA and SA */
memmove(nskb->data - ETH_HLEN,
nskb->data - ETH_HLEN - BRCM_TAG_LEN,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, BRCM_TAG_LEN);

return nskb;
}
Expand Down Expand Up @@ -231,7 +228,7 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,

skb_push(skb, BRCM_LEG_TAG_LEN);

memmove(skb->data, skb->data + BRCM_LEG_TAG_LEN, 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);

brcm_tag = skb->data + 2 * ETH_ALEN;

Expand All @@ -257,7 +254,7 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, BRCM_LEG_PORT_ID)))
return NULL;

brcm_tag = skb->data - 2;
brcm_tag = dsa_etype_header_pos_rx(skb);

source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;

Expand All @@ -270,10 +267,7 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,

dsa_default_offload_fwd_mark(skb);

/* Move the Ethernet DA and SA */
memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - BRCM_LEG_TAG_LEN,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, BRCM_LEG_TAG_LEN);

return skb;
}
Expand Down
20 changes: 8 additions & 12 deletions net/dsa/tag_dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
if (skb->protocol == htons(ETH_P_8021Q)) {
if (extra) {
skb_push(skb, extra);
memmove(skb->data, skb->data + extra, 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, extra);
}

/* Construct tagged DSA tag from 802.1Q tag. */
dsa_header = skb->data + 2 * ETH_ALEN + extra;
dsa_header = dsa_etype_header_pos_tx(skb) + extra;
dsa_header[0] = (cmd << 6) | 0x20 | tag_dev;
dsa_header[1] = tag_port << 3;

Expand All @@ -181,10 +181,10 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
}
} else {
skb_push(skb, DSA_HLEN + extra);
memmove(skb->data, skb->data + DSA_HLEN + extra, 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, DSA_HLEN + extra);

/* Construct untagged DSA tag. */
dsa_header = skb->data + 2 * ETH_ALEN + extra;
dsa_header = dsa_etype_header_pos_tx(skb) + extra;

dsa_header[0] = (cmd << 6) | tag_dev;
dsa_header[1] = tag_port << 3;
Expand All @@ -205,7 +205,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
u8 *dsa_header;

/* The ethertype field is part of the DSA header. */
dsa_header = skb->data - 2;
dsa_header = dsa_etype_header_pos_rx(skb);

cmd = dsa_header[0] >> 6;
switch (cmd) {
Expand Down Expand Up @@ -312,14 +312,10 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
memcpy(dsa_header, new_header, DSA_HLEN);

if (extra)
memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - extra,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, extra);
} else {
skb_pull_rcsum(skb, DSA_HLEN);
memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - DSA_HLEN - extra,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, DSA_HLEN + extra);
}

return skb;
Expand Down Expand Up @@ -364,7 +360,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb)
return NULL;

edsa_header = skb->data + 2 * ETH_ALEN;
edsa_header = dsa_etype_header_pos_tx(skb);
edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
edsa_header[1] = ETH_P_EDSA & 0xff;
edsa_header[2] = 0x00;
Expand Down
18 changes: 7 additions & 11 deletions net/dsa/tag_lan9303.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
skb_push(skb, LAN9303_TAG_LEN);

/* make room between MACs and Ether-Type */
memmove(skb->data, skb->data + LAN9303_TAG_LEN, 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, LAN9303_TAG_LEN);

lan9303_tag = dsa_etype_header_pos_tx(skb);

lan9303_tag = (__be16 *)(skb->data + 2 * ETH_ALEN);
tag = lan9303_xmit_use_arl(dp, skb->data) ?
LAN9303_TAG_TX_USE_ALR :
dp->index | LAN9303_TAG_TX_STP_OVERRIDE;
Expand All @@ -86,13 +87,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
return NULL;
}

/* '->data' points into the middle of our special VLAN tag information:
*
* ~ MAC src | 0x81 | 0x00 | 0xyy | 0xzz | ether type
* ^
* ->data
*/
lan9303_tag = (__be16 *)(skb->data - 2);
lan9303_tag = dsa_etype_header_pos_rx(skb);

if (lan9303_tag[0] != htons(ETH_P_8021Q)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid VLAN marker\n");
Expand All @@ -112,8 +107,9 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
* and the current ethertype field.
*/
skb_pull_rcsum(skb, 2 + 2);
memmove(skb->data - ETH_HLEN, skb->data - (ETH_HLEN + LAN9303_TAG_LEN),
2 * ETH_ALEN);

dsa_strip_etype_header(skb, LAN9303_TAG_LEN);

if (!(lan9303_tag1 & LAN9303_TAG_RX_TRAPPED_TO_CPU))
dsa_default_offload_fwd_mark(skb);

Expand Down
14 changes: 4 additions & 10 deletions net/dsa/tag_mtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
default:
xmit_tpid = MTK_HDR_XMIT_UNTAGGED;
skb_push(skb, MTK_HDR_LEN);
memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, MTK_HDR_LEN);
}

mtk_tag = skb->data + 2 * ETH_ALEN;
mtk_tag = dsa_etype_header_pos_tx(skb);

/* Mark tag attribute on special tag insertion to notify hardware
* whether that's a combined special tag with 802.1Q header.
Expand All @@ -70,19 +70,13 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
return NULL;

/* The MTK header is added by the switch between src addr
* and ethertype at this point, skb->data points to 2 bytes
* after src addr so header should be 2 bytes right before.
*/
phdr = (__be16 *)(skb->data - 2);
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);

/* Remove MTK tag and recalculate checksum. */
skb_pull_rcsum(skb, MTK_HDR_LEN);

memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - MTK_HDR_LEN,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, MTK_HDR_LEN);

/* Get source port information */
port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
Expand Down
13 changes: 4 additions & 9 deletions net/dsa/tag_qca.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)

skb_push(skb, QCA_HDR_LEN);

memmove(skb->data, skb->data + QCA_HDR_LEN, 2 * ETH_ALEN);
phdr = (__be16 *)(skb->data + 2 * ETH_ALEN);
dsa_alloc_etype_header(skb, QCA_HDR_LEN);
phdr = dsa_etype_header_pos_tx(skb);

/* Set the version field, and set destination port information */
hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S |
Expand All @@ -58,11 +58,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
return NULL;

/* The QCA header is added by the switch between src addr and Ethertype
* At this point, skb->data points to ethertype so header should be
* right before
*/
phdr = (__be16 *)(skb->data - 2);
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);

/* Make sure the version is correct */
Expand All @@ -72,8 +68,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)

/* Remove QCA tag and recalculate checksum */
skb_pull_rcsum(skb, QCA_HDR_LEN);
memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - QCA_HDR_LEN,
ETH_HLEN - QCA_HDR_LEN);
dsa_strip_etype_header(skb, QCA_HDR_LEN);

/* Get source port information */
port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK);
Expand Down
16 changes: 4 additions & 12 deletions net/dsa/tag_rtl4_a.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
dp->index);
skb_push(skb, RTL4_A_HDR_LEN);

memmove(skb->data, skb->data + RTL4_A_HDR_LEN, 2 * ETH_ALEN);
tag = skb->data + 2 * ETH_ALEN;
dsa_alloc_etype_header(skb, RTL4_A_HDR_LEN);
tag = dsa_etype_header_pos_tx(skb);

/* Set Ethertype */
p = (__be16 *)tag;
Expand Down Expand Up @@ -76,12 +76,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
return NULL;

/* The RTL4 header has its own custom Ethertype 0x8899 and that
* starts right at the beginning of the packet, after the src
* ethernet addr. Apparently skb->data always points 2 bytes in,
* behind the Ethertype.
*/
tag = skb->data - 2;
tag = dsa_etype_header_pos_rx(skb);
p = (__be16 *)tag;
etype = ntohs(*p);
if (etype != RTL4_A_ETHERTYPE) {
Expand All @@ -108,10 +103,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
/* Remove RTL4 tag and recalculate checksum */
skb_pull_rcsum(skb, RTL4_A_HDR_LEN);

/* Move ethernet DA and SA in front of the data */
memmove(skb->data - ETH_HLEN,
skb->data - ETH_HLEN - RTL4_A_HDR_LEN,
2 * ETH_ALEN);
dsa_strip_etype_header(skb, RTL4_A_HDR_LEN);

dsa_default_offload_fwd_mark(skb);

Expand Down
Loading

0 comments on commit 88be326

Please sign in to comment.