mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									91495f21fc
								
							
						
					
					
						commit
						d7f9787a76
					
				
					 4 changed files with 55 additions and 13 deletions
				
			
		| 
						 | 
					@ -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 @@
 | 
				
			||||||
 * 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,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*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,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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)
 | 
				
			||||||
 * 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,
 | 
				
			||||||
	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,
 | 
				
			||||||
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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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,
 | 
				
			||||||
		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,
 | 
				
			||||||
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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue