Commit 233697b3 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: tag_8021q: refactor RX VLAN parsing into a dedicated function

The added value of this function is that it can deal with both the case
where the VLAN header is in the skb head, as well as in the offload field.
This is something I was not able to do using other functions in the
network stack.

Since both ocelot-8021q and sja1105 need to do the same stuff, let's
make it a common service provided by tag_8021q.

This is done as refactoring for the new SJA1110 tagger, which partly
uses tag_8021q as well (just like SJA1105), and will be the third caller.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab6a303c
...@@ -50,6 +50,9 @@ int dsa_8021q_crosschip_bridge_leave(struct dsa_8021q_context *ctx, int port, ...@@ -50,6 +50,9 @@ int dsa_8021q_crosschip_bridge_leave(struct dsa_8021q_context *ctx, int port,
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
u16 tpid, u16 tci); u16 tpid, u16 tci);
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
int *subvlan);
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port); u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port);
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port); u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port);
......
...@@ -471,4 +471,27 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, ...@@ -471,4 +471,27 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
} }
EXPORT_SYMBOL_GPL(dsa_8021q_xmit); EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
int *subvlan)
{
u16 vid, tci;
skb_push_rcsum(skb, ETH_HLEN);
if (skb_vlan_tag_present(skb)) {
tci = skb_vlan_tag_get(skb);
__vlan_hwaccel_clear_tag(skb);
} else {
__skb_vlan_pop(skb, &tci);
}
skb_pull_rcsum(skb, ETH_HLEN);
vid = tci & VLAN_VID_MASK;
*source_port = dsa_8021q_rx_source_port(vid);
*switch_id = dsa_8021q_rx_switch_id(vid);
*subvlan = dsa_8021q_rx_subvlan(vid);
skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
}
EXPORT_SYMBOL_GPL(dsa_8021q_rcv);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -41,29 +41,15 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, ...@@ -41,29 +41,15 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
struct net_device *netdev, struct net_device *netdev,
struct packet_type *pt) struct packet_type *pt)
{ {
int src_port, switch_id, qos_class; int src_port, switch_id, subvlan;
u16 vid, tci;
skb_push_rcsum(skb, ETH_HLEN); dsa_8021q_rcv(skb, &src_port, &switch_id, &subvlan);
if (skb_vlan_tag_present(skb)) {
tci = skb_vlan_tag_get(skb);
__vlan_hwaccel_clear_tag(skb);
} else {
__skb_vlan_pop(skb, &tci);
}
skb_pull_rcsum(skb, ETH_HLEN);
vid = tci & VLAN_VID_MASK;
src_port = dsa_8021q_rx_source_port(vid);
switch_id = dsa_8021q_rx_switch_id(vid);
qos_class = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
skb->dev = dsa_master_find_slave(netdev, switch_id, src_port); skb->dev = dsa_master_find_slave(netdev, switch_id, src_port);
if (!skb->dev) if (!skb->dev)
return NULL; return NULL;
skb->offload_fwd_mark = 1; skb->offload_fwd_mark = 1;
skb->priority = qos_class;
return skb; return skb;
} }
......
...@@ -275,44 +275,33 @@ static void sja1105_decode_subvlan(struct sk_buff *skb, u16 subvlan) ...@@ -275,44 +275,33 @@ static void sja1105_decode_subvlan(struct sk_buff *skb, u16 subvlan)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
} }
static bool sja1105_skb_has_tag_8021q(const struct sk_buff *skb)
{
u16 tpid = ntohs(eth_hdr(skb)->h_proto);
return tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q ||
skb_vlan_tag_present(skb);
}
static struct sk_buff *sja1105_rcv(struct sk_buff *skb, static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
struct net_device *netdev, struct net_device *netdev,
struct packet_type *pt) struct packet_type *pt)
{ {
int source_port, switch_id, subvlan = 0;
struct sja1105_meta meta = {0}; struct sja1105_meta meta = {0};
int source_port, switch_id;
struct ethhdr *hdr; struct ethhdr *hdr;
u16 tpid, vid, tci;
bool is_link_local; bool is_link_local;
u16 subvlan = 0;
bool is_tagged;
bool is_meta; bool is_meta;
hdr = eth_hdr(skb); hdr = eth_hdr(skb);
tpid = ntohs(hdr->h_proto);
is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q ||
skb_vlan_tag_present(skb));
is_link_local = sja1105_is_link_local(skb); is_link_local = sja1105_is_link_local(skb);
is_meta = sja1105_is_meta_frame(skb); is_meta = sja1105_is_meta_frame(skb);
skb->offload_fwd_mark = 1; skb->offload_fwd_mark = 1;
if (is_tagged) { if (sja1105_skb_has_tag_8021q(skb)) {
/* Normal traffic path. */ /* Normal traffic path. */
skb_push_rcsum(skb, ETH_HLEN); dsa_8021q_rcv(skb, &source_port, &switch_id, &subvlan);
if (skb_vlan_tag_present(skb)) {
tci = skb_vlan_tag_get(skb);
__vlan_hwaccel_clear_tag(skb);
} else {
__skb_vlan_pop(skb, &tci);
}
skb_pull_rcsum(skb, ETH_HLEN);
vid = tci & VLAN_VID_MASK;
source_port = dsa_8021q_rx_source_port(vid);
switch_id = dsa_8021q_rx_switch_id(vid);
skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
subvlan = dsa_8021q_rx_subvlan(vid);
} else if (is_link_local) { } else if (is_link_local) {
/* Management traffic path. Switch embeds the switch ID and /* Management traffic path. Switch embeds the switch ID and
* port ID into bytes of the destination MAC, courtesy of * port ID into bytes of the destination MAC, courtesy of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment