Skip to content

Commit d7f9787

Browse files
vladimirolteandavem330
authored andcommitted
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: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 91495f2 commit d7f9787

File tree

4 files changed

+55
-13
lines changed

4 files changed

+55
-13
lines changed

include/linux/dsa/8021q.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ void dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, int port,
4141
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
4242
u16 tpid, u16 tci);
4343

44-
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id);
44+
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
45+
int *vbid);
46+
47+
struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,
48+
int vbid);
4549

4650
u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num);
4751

net/dsa/tag_8021q.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* VBID - { VID[9], VID[5:4] }:
3333
* Virtual bridge ID. If between 1 and 7, packet targets the broadcast
3434
* domain of a bridge. If transmitted as zero, packet targets a single
35-
* port. Field only valid on transmit, must be ignored on receive.
35+
* port.
3636
*
3737
* PORT - VID[3:0]:
3838
* 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,
533533
}
534534
EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
535535

536-
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id)
536+
struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,
537+
int vbid)
538+
{
539+
struct dsa_port *cpu_dp = master->dsa_ptr;
540+
struct dsa_switch_tree *dst = cpu_dp->dst;
541+
struct dsa_port *dp;
542+
543+
if (WARN_ON(!vbid))
544+
return NULL;
545+
546+
dsa_tree_for_each_user_port(dp, dst) {
547+
if (!dp->bridge)
548+
continue;
549+
550+
if (dp->stp_state != BR_STATE_LEARNING &&
551+
dp->stp_state != BR_STATE_FORWARDING)
552+
continue;
553+
554+
if (dp->cpu_dp != cpu_dp)
555+
continue;
556+
557+
if (dsa_port_bridge_num_get(dp) == vbid)
558+
return dp->slave;
559+
}
560+
561+
return NULL;
562+
}
563+
EXPORT_SYMBOL_GPL(dsa_tag_8021q_find_port_by_vbid);
564+
565+
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
566+
int *vbid)
537567
{
538568
u16 vid, tci;
539569

@@ -550,6 +580,10 @@ void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id)
550580

551581
*source_port = dsa_8021q_rx_source_port(vid);
552582
*switch_id = dsa_8021q_rx_switch_id(vid);
583+
584+
if (vbid)
585+
*vbid = dsa_tag_8021q_rx_vbid(vid);
586+
553587
skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
554588
}
555589
EXPORT_SYMBOL_GPL(dsa_8021q_rcv);

net/dsa/tag_ocelot_8021q.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
7777
{
7878
int src_port, switch_id;
7979

80-
dsa_8021q_rcv(skb, &src_port, &switch_id);
80+
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL);
8181

8282
skb->dev = dsa_master_find_slave(netdev, switch_id, src_port);
8383
if (!skb->dev)

net/dsa/tag_sja1105.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb)
509509
* packet.
510510
*/
511511
static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
512-
int *switch_id, u16 *vid)
512+
int *switch_id, int *vbid, u16 *vid)
513513
{
514514
struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
515515
u16 vlan_tci;
@@ -519,8 +519,8 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
519519
else
520520
vlan_tci = ntohs(hdr->h_vlan_TCI);
521521

522-
if (vid_is_dsa_8021q_rxvlan(vlan_tci & VLAN_VID_MASK))
523-
return dsa_8021q_rcv(skb, source_port, switch_id);
522+
if (vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK))
523+
return dsa_8021q_rcv(skb, source_port, switch_id, vbid);
524524

525525
/* Try our best with imprecise RX */
526526
*vid = vlan_tci & VLAN_VID_MASK;
@@ -529,7 +529,7 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
529529
static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
530530
struct net_device *netdev)
531531
{
532-
int source_port = -1, switch_id = -1;
532+
int source_port = -1, switch_id = -1, vbid = -1;
533533
struct sja1105_meta meta = {0};
534534
struct ethhdr *hdr;
535535
bool is_link_local;
@@ -542,7 +542,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
542542

543543
if (sja1105_skb_has_tag_8021q(skb)) {
544544
/* Normal traffic path. */
545-
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
545+
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid);
546546
} else if (is_link_local) {
547547
/* Management traffic path. Switch embeds the switch ID and
548548
* port ID into bytes of the destination MAC, courtesy of
@@ -561,7 +561,9 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
561561
return NULL;
562562
}
563563

564-
if (source_port == -1 || switch_id == -1)
564+
if (vbid >= 1)
565+
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
566+
else if (source_port == -1 || switch_id == -1)
565567
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
566568
else
567569
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,
686688
static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
687689
struct net_device *netdev)
688690
{
689-
int source_port = -1, switch_id = -1;
691+
int source_port = -1, switch_id = -1, vbid = -1;
690692
bool host_only = false;
691693
u16 vid = 0;
692694

@@ -700,9 +702,11 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
700702

701703
/* Packets with in-band control extensions might still have RX VLANs */
702704
if (likely(sja1105_skb_has_tag_8021q(skb)))
703-
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
705+
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid);
704706

705-
if (source_port == -1 || switch_id == -1)
707+
if (vbid >= 1)
708+
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
709+
else if (source_port == -1 || switch_id == -1)
706710
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
707711
else
708712
skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);

0 commit comments

Comments
 (0)