Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
233697b3 ab6a303c

+39 -38
+3
include/linux/dsa/8021q.h
··· 50 50 struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, 51 51 u16 tpid, u16 tci); 52 52 53 + void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id, 54 + int *subvlan); 55 + 53 56 u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port); 54 57 55 58 u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port);
+23
net/dsa/tag_8021q.c
··· 471 471 } 472 472 EXPORT_SYMBOL_GPL(dsa_8021q_xmit); 473 473 474 + void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id, 475 + int *subvlan) 476 + { 477 + u16 vid, tci; 478 + 479 + skb_push_rcsum(skb, ETH_HLEN); 480 + if (skb_vlan_tag_present(skb)) { 481 + tci = skb_vlan_tag_get(skb); 482 + __vlan_hwaccel_clear_tag(skb); 483 + } else { 484 + __skb_vlan_pop(skb, &tci); 485 + } 486 + skb_pull_rcsum(skb, ETH_HLEN); 487 + 488 + vid = tci & VLAN_VID_MASK; 489 + 490 + *source_port = dsa_8021q_rx_source_port(vid); 491 + *switch_id = dsa_8021q_rx_switch_id(vid); 492 + *subvlan = dsa_8021q_rx_subvlan(vid); 493 + skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 494 + } 495 + EXPORT_SYMBOL_GPL(dsa_8021q_rcv); 496 + 474 497 MODULE_LICENSE("GPL v2");
+2 -16
net/dsa/tag_ocelot_8021q.c
··· 41 41 struct net_device *netdev, 42 42 struct packet_type *pt) 43 43 { 44 - int src_port, switch_id, qos_class; 45 - u16 vid, tci; 44 + int src_port, switch_id, subvlan; 46 45 47 - skb_push_rcsum(skb, ETH_HLEN); 48 - if (skb_vlan_tag_present(skb)) { 49 - tci = skb_vlan_tag_get(skb); 50 - __vlan_hwaccel_clear_tag(skb); 51 - } else { 52 - __skb_vlan_pop(skb, &tci); 53 - } 54 - skb_pull_rcsum(skb, ETH_HLEN); 55 - 56 - vid = tci & VLAN_VID_MASK; 57 - src_port = dsa_8021q_rx_source_port(vid); 58 - switch_id = dsa_8021q_rx_switch_id(vid); 59 - qos_class = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 46 + dsa_8021q_rcv(skb, &src_port, &switch_id, &subvlan); 60 47 61 48 skb->dev = dsa_master_find_slave(netdev, switch_id, src_port); 62 49 if (!skb->dev) 63 50 return NULL; 64 51 65 52 skb->offload_fwd_mark = 1; 66 - skb->priority = qos_class; 67 53 68 54 return skb; 69 55 }
+11 -22
net/dsa/tag_sja1105.c
··· 275 275 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); 276 276 } 277 277 278 + static bool sja1105_skb_has_tag_8021q(const struct sk_buff *skb) 279 + { 280 + u16 tpid = ntohs(eth_hdr(skb)->h_proto); 281 + 282 + return tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q || 283 + skb_vlan_tag_present(skb); 284 + } 285 + 278 286 static struct sk_buff *sja1105_rcv(struct sk_buff *skb, 279 287 struct net_device *netdev, 280 288 struct packet_type *pt) 281 289 { 290 + int source_port, switch_id, subvlan = 0; 282 291 struct sja1105_meta meta = {0}; 283 - int source_port, switch_id; 284 292 struct ethhdr *hdr; 285 - u16 tpid, vid, tci; 286 293 bool is_link_local; 287 - u16 subvlan = 0; 288 - bool is_tagged; 289 294 bool is_meta; 290 295 291 296 hdr = eth_hdr(skb); 292 - tpid = ntohs(hdr->h_proto); 293 - is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q || 294 - skb_vlan_tag_present(skb)); 295 297 is_link_local = sja1105_is_link_local(skb); 296 298 is_meta = sja1105_is_meta_frame(skb); 297 299 298 300 skb->offload_fwd_mark = 1; 299 301 300 - if (is_tagged) { 302 + if (sja1105_skb_has_tag_8021q(skb)) { 301 303 /* Normal traffic path. */ 302 - skb_push_rcsum(skb, ETH_HLEN); 303 - if (skb_vlan_tag_present(skb)) { 304 - tci = skb_vlan_tag_get(skb); 305 - __vlan_hwaccel_clear_tag(skb); 306 - } else { 307 - __skb_vlan_pop(skb, &tci); 308 - } 309 - skb_pull_rcsum(skb, ETH_HLEN); 310 - 311 - vid = tci & VLAN_VID_MASK; 312 - source_port = dsa_8021q_rx_source_port(vid); 313 - switch_id = dsa_8021q_rx_switch_id(vid); 314 - skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 315 - subvlan = dsa_8021q_rx_subvlan(vid); 304 + dsa_8021q_rcv(skb, &source_port, &switch_id, &subvlan); 316 305 } else if (is_link_local) { 317 306 /* Management traffic path. Switch embeds the switch ID and 318 307 * port ID into bytes of the destination MAC, courtesy of