Merge branch 'dsa-tagger-helpers'
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>
This commit is contained in:
commit
88be326349
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -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;
|
||||
@ -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) {
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
@ -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");
|
||||
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
@ -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);
|
||||
|
@ -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 |
|
||||
@ -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 */
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
@ -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);
|
||||
|
||||
|
@ -188,7 +188,6 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
|
||||
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
|
||||
u16 queue_mapping = skb_get_queue_mapping(skb);
|
||||
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
|
||||
struct ethhdr *eth_hdr;
|
||||
__be32 *tx_trailer;
|
||||
__be16 *tx_header;
|
||||
int trailer_pos;
|
||||
@ -206,28 +205,24 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
|
||||
|
||||
skb_push(skb, SJA1110_HEADER_LEN);
|
||||
|
||||
/* Move Ethernet header to the left, making space for DSA tag */
|
||||
memmove(skb->data, skb->data + SJA1110_HEADER_LEN, 2 * ETH_ALEN);
|
||||
dsa_alloc_etype_header(skb, SJA1110_HEADER_LEN);
|
||||
|
||||
trailer_pos = skb->len;
|
||||
|
||||
/* On TX, skb->data points to skb_mac_header(skb) */
|
||||
eth_hdr = (struct ethhdr *)skb->data;
|
||||
tx_header = (__be16 *)(eth_hdr + 1);
|
||||
tx_header = dsa_etype_header_pos_tx(skb);
|
||||
tx_trailer = skb_put(skb, SJA1110_TX_TRAILER_LEN);
|
||||
|
||||
eth_hdr->h_proto = htons(ETH_P_SJA1110);
|
||||
|
||||
*tx_header = htons(SJA1110_HEADER_HOST_TO_SWITCH |
|
||||
SJA1110_TX_HEADER_HAS_TRAILER |
|
||||
SJA1110_TX_HEADER_TRAILER_POS(trailer_pos));
|
||||
tx_header[0] = htons(ETH_P_SJA1110);
|
||||
tx_header[1] = htons(SJA1110_HEADER_HOST_TO_SWITCH |
|
||||
SJA1110_TX_HEADER_HAS_TRAILER |
|
||||
SJA1110_TX_HEADER_TRAILER_POS(trailer_pos));
|
||||
*tx_trailer = cpu_to_be32(SJA1110_TX_TRAILER_PRIO(pcp) |
|
||||
SJA1110_TX_TRAILER_SWITCHID(dp->ds->index) |
|
||||
SJA1110_TX_TRAILER_DESTPORTS(BIT(dp->index)));
|
||||
if (clone) {
|
||||
u8 ts_id = SJA1105_SKB_CB(clone)->ts_id;
|
||||
|
||||
*tx_header |= htons(SJA1110_TX_HEADER_TAKE_TS);
|
||||
tx_header[1] |= htons(SJA1110_TX_HEADER_TAKE_TS);
|
||||
*tx_trailer |= cpu_to_be32(SJA1110_TX_TRAILER_TSTAMP_ID(ts_id));
|
||||
}
|
||||
|
||||
@ -443,11 +438,11 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
|
||||
|
||||
static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
|
||||
{
|
||||
u8 *buf = dsa_etype_header_pos_rx(skb) + SJA1110_HEADER_LEN;
|
||||
int switch_id = SJA1110_RX_HEADER_SWITCH_ID(rx_header);
|
||||
int n_ts = SJA1110_RX_HEADER_N_TS(rx_header);
|
||||
struct net_device *master = skb->dev;
|
||||
struct dsa_port *cpu_dp;
|
||||
u8 *buf = skb->data + 2;
|
||||
struct dsa_switch *ds;
|
||||
int i;
|
||||
|
||||
@ -532,9 +527,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
|
||||
/* Advance skb->data past the DSA header */
|
||||
skb_pull_rcsum(skb, SJA1110_HEADER_LEN);
|
||||
|
||||
/* Remove the DSA header */
|
||||
memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - SJA1110_HEADER_LEN,
|
||||
2 * ETH_ALEN);
|
||||
dsa_strip_etype_header(skb, SJA1110_HEADER_LEN);
|
||||
|
||||
/* With skb->data in its final place, update the MAC header
|
||||
* so that eth_hdr() continues to works properly.
|
||||
|
Loading…
x
Reference in New Issue
Block a user