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

net: dsa: tag_8021q: add support for imprecise RX based on the VBID

The sja1105 switch can't populate the PORT field of the tag_8021q header
when sending a frame to the CPU with a non-zero VBID.

Similar to dsa_find_designated_bridge_port_by_vid() which performs
imprecise RX for VLAN-aware bridges, let's introduce a helper in
tag_8021q for performing imprecise RX based on the VLAN that it has
allocated for a VLAN-unaware bridge.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 91495f21
...@@ -41,7 +41,11 @@ void dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, int port, ...@@ -41,7 +41,11 @@ void dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, 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); void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
int *vbid);
struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,
int vbid);
u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num); u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num);
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* VBID - { VID[9], VID[5:4] }: * VBID - { VID[9], VID[5:4] }:
* Virtual bridge ID. If between 1 and 7, packet targets the broadcast * Virtual bridge ID. If between 1 and 7, packet targets the broadcast
* domain of a bridge. If transmitted as zero, packet targets a single * domain of a bridge. If transmitted as zero, packet targets a single
* port. Field only valid on transmit, must be ignored on receive. * port.
* *
* PORT - VID[3:0]: * PORT - VID[3:0]:
* Index of switch port. Must be between 0 and 15. * Index of switch port. Must be between 0 and 15.
...@@ -533,7 +533,37 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, ...@@ -533,7 +533,37 @@ 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) struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,
int vbid)
{
struct dsa_port *cpu_dp = master->dsa_ptr;
struct dsa_switch_tree *dst = cpu_dp->dst;
struct dsa_port *dp;
if (WARN_ON(!vbid))
return NULL;
dsa_tree_for_each_user_port(dp, dst) {
if (!dp->bridge)
continue;
if (dp->stp_state != BR_STATE_LEARNING &&
dp->stp_state != BR_STATE_FORWARDING)
continue;
if (dp->cpu_dp != cpu_dp)
continue;
if (dsa_port_bridge_num_get(dp) == vbid)
return dp->slave;
}
return NULL;
}
EXPORT_SYMBOL_GPL(dsa_tag_8021q_find_port_by_vbid);
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
int *vbid)
{ {
u16 vid, tci; u16 vid, tci;
...@@ -550,6 +580,10 @@ void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id) ...@@ -550,6 +580,10 @@ void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id)
*source_port = dsa_8021q_rx_source_port(vid); *source_port = dsa_8021q_rx_source_port(vid);
*switch_id = dsa_8021q_rx_switch_id(vid); *switch_id = dsa_8021q_rx_switch_id(vid);
if (vbid)
*vbid = dsa_tag_8021q_rx_vbid(vid);
skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
} }
EXPORT_SYMBOL_GPL(dsa_8021q_rcv); EXPORT_SYMBOL_GPL(dsa_8021q_rcv);
...@@ -77,7 +77,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, ...@@ -77,7 +77,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
{ {
int src_port, switch_id; int src_port, switch_id;
dsa_8021q_rcv(skb, &src_port, &switch_id); dsa_8021q_rcv(skb, &src_port, &switch_id, NULL);
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)
......
...@@ -509,7 +509,7 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb) ...@@ -509,7 +509,7 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb)
* packet. * packet.
*/ */
static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port, static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
int *switch_id, u16 *vid) int *switch_id, int *vbid, u16 *vid)
{ {
struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb); struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
u16 vlan_tci; u16 vlan_tci;
...@@ -519,8 +519,8 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port, ...@@ -519,8 +519,8 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
else else
vlan_tci = ntohs(hdr->h_vlan_TCI); vlan_tci = ntohs(hdr->h_vlan_TCI);
if (vid_is_dsa_8021q_rxvlan(vlan_tci & VLAN_VID_MASK)) if (vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK))
return dsa_8021q_rcv(skb, source_port, switch_id); return dsa_8021q_rcv(skb, source_port, switch_id, vbid);
/* Try our best with imprecise RX */ /* Try our best with imprecise RX */
*vid = vlan_tci & VLAN_VID_MASK; *vid = vlan_tci & VLAN_VID_MASK;
...@@ -529,7 +529,7 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port, ...@@ -529,7 +529,7 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
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)
{ {
int source_port = -1, switch_id = -1; int source_port = -1, switch_id = -1, vbid = -1;
struct sja1105_meta meta = {0}; struct sja1105_meta meta = {0};
struct ethhdr *hdr; struct ethhdr *hdr;
bool is_link_local; bool is_link_local;
...@@ -542,7 +542,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, ...@@ -542,7 +542,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
if (sja1105_skb_has_tag_8021q(skb)) { if (sja1105_skb_has_tag_8021q(skb)) {
/* Normal traffic path. */ /* Normal traffic path. */
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid); sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &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
...@@ -561,7 +561,9 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, ...@@ -561,7 +561,9 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
return NULL; return NULL;
} }
if (source_port == -1 || switch_id == -1) if (vbid >= 1)
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
else if (source_port == -1 || switch_id == -1)
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid); skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
else else
skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
...@@ -686,7 +688,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb, ...@@ -686,7 +688,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
static struct sk_buff *sja1110_rcv(struct sk_buff *skb, static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
int source_port = -1, switch_id = -1; int source_port = -1, switch_id = -1, vbid = -1;
bool host_only = false; bool host_only = false;
u16 vid = 0; u16 vid = 0;
...@@ -700,9 +702,11 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb, ...@@ -700,9 +702,11 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
/* Packets with in-band control extensions might still have RX VLANs */ /* Packets with in-band control extensions might still have RX VLANs */
if (likely(sja1105_skb_has_tag_8021q(skb))) if (likely(sja1105_skb_has_tag_8021q(skb)))
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid); sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid);
if (source_port == -1 || switch_id == -1) if (vbid >= 1)
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
else if (source_port == -1 || switch_id == -1)
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid); skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
else else
skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
......
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