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

net: dsa: tag_sja1105: absorb entire sja1105_vlan_rcv() into dsa_8021q_rcv()

tag_sja1105 has a wrapper over dsa_8021q_rcv(): sja1105_vlan_rcv(),
which determines whether the packet came from a bridge with
vlan_filtering=1 (the case resolved via
dsa_find_designated_bridge_port_by_vid()), or if it contains a tag_8021q
header.

Looking at a new tagger implementation for vsc73xx, based also on
tag_8021q, it is becoming clear that the logic is needed there as well.
So instead of forcing each tagger to wrap around dsa_8021q_rcv(), let's
merge the logic into the core.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Tested-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
Link: https://patch.msgid.link/20240713211620.1125910-5-paweldembicki@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vladimir Oltean and committed by
Jakub Kicinski
0064b863 dcfe7673

+34 -36
+28 -6
net/dsa/tag_8021q.c
··· 507 507 * @vbid: pointer to storage for imprecise bridge ID. Must be pre-initialized 508 508 * with -1. If a positive value is returned, the source_port and switch_id 509 509 * are invalid. 510 + * @vid: pointer to storage for original VID, in case tag_8021q decoding failed. 511 + * 512 + * If the packet has a tag_8021q header, decode it and set @source_port, 513 + * @switch_id and @vbid, and strip the header. Otherwise set @vid and keep the 514 + * header in the hwaccel area of the packet. 510 515 */ 511 516 void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id, 512 - int *vbid) 517 + int *vbid, int *vid) 513 518 { 514 519 int tmp_source_port, tmp_switch_id, tmp_vbid; 515 - u16 vid, tci; 520 + __be16 vlan_proto; 521 + u16 tmp_vid, tci; 516 522 517 523 if (skb_vlan_tag_present(skb)) { 524 + vlan_proto = skb->vlan_proto; 518 525 tci = skb_vlan_tag_get(skb); 519 526 __vlan_hwaccel_clear_tag(skb); 520 527 } else { 528 + struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); 529 + 530 + vlan_proto = hdr->h_vlan_proto; 521 531 skb_push_rcsum(skb, ETH_HLEN); 522 532 __skb_vlan_pop(skb, &tci); 523 533 skb_pull_rcsum(skb, ETH_HLEN); 524 534 } 525 535 526 - vid = tci & VLAN_VID_MASK; 536 + tmp_vid = tci & VLAN_VID_MASK; 537 + if (!vid_is_dsa_8021q(tmp_vid)) { 538 + /* Not a tag_8021q frame, so return the VID to the 539 + * caller for further processing, and put the tag back 540 + */ 541 + if (vid) 542 + *vid = tmp_vid; 527 543 528 - tmp_source_port = dsa_8021q_rx_source_port(vid); 529 - tmp_switch_id = dsa_8021q_rx_switch_id(vid); 530 - tmp_vbid = dsa_tag_8021q_rx_vbid(vid); 544 + __vlan_hwaccel_put_tag(skb, vlan_proto, tci); 545 + 546 + return; 547 + } 548 + 549 + tmp_source_port = dsa_8021q_rx_source_port(tmp_vid); 550 + tmp_switch_id = dsa_8021q_rx_switch_id(tmp_vid); 551 + tmp_vbid = dsa_tag_8021q_rx_vbid(tmp_vid); 531 552 532 553 /* Precise source port information is unknown when receiving from a 533 554 * VLAN-unaware bridging domain, and tmp_source_port and tmp_switch_id ··· 567 546 *vbid = tmp_vbid; 568 547 569 548 skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 549 + return; 570 550 } 571 551 EXPORT_SYMBOL_GPL(dsa_8021q_rcv);
+1 -1
net/dsa/tag_8021q.h
··· 14 14 u16 tpid, u16 tci); 15 15 16 16 void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id, 17 - int *vbid); 17 + int *vbid, int *vid); 18 18 19 19 struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *conduit, 20 20 int vbid);
+1 -1
net/dsa/tag_ocelot_8021q.c
··· 81 81 { 82 82 int src_port, switch_id; 83 83 84 - dsa_8021q_rcv(skb, &src_port, &switch_id, NULL); 84 + dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL); 85 85 86 86 skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port); 87 87 if (!skb->dev)
+4 -28
net/dsa/tag_sja1105.c
··· 472 472 return ntohs(eth_hdr(skb)->h_proto) == ETH_P_SJA1110; 473 473 } 474 474 475 - /* If the VLAN in the packet is a tag_8021q one, set @source_port and 476 - * @switch_id and strip the header. Otherwise set @vid and keep it in the 477 - * packet. 478 - */ 479 - static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port, 480 - int *switch_id, int *vbid, u16 *vid) 481 - { 482 - struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); 483 - u16 vlan_tci; 484 - 485 - if (skb_vlan_tag_present(skb)) 486 - vlan_tci = skb_vlan_tag_get(skb); 487 - else 488 - vlan_tci = ntohs(hdr->h_vlan_TCI); 489 - 490 - if (vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK)) 491 - return dsa_8021q_rcv(skb, source_port, switch_id, vbid); 492 - 493 - /* Try our best with imprecise RX */ 494 - *vid = vlan_tci & VLAN_VID_MASK; 495 - } 496 - 497 475 static struct sk_buff *sja1105_rcv(struct sk_buff *skb, 498 476 struct net_device *netdev) 499 477 { 500 - int source_port = -1, switch_id = -1, vbid = -1; 478 + int source_port = -1, switch_id = -1, vbid = -1, vid = -1; 501 479 struct sja1105_meta meta = {0}; 502 480 struct ethhdr *hdr; 503 481 bool is_link_local; 504 482 bool is_meta; 505 - u16 vid; 506 483 507 484 hdr = eth_hdr(skb); 508 485 is_link_local = sja1105_is_link_local(skb); ··· 502 525 * a tag_8021q VLAN which we have to strip 503 526 */ 504 527 if (sja1105_skb_has_tag_8021q(skb)) 505 - sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid); 528 + dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid); 506 529 else if (source_port == -1 && switch_id == -1) 507 530 /* Packets with no source information have no chance of 508 531 * getting accepted, drop them straight away. ··· 637 660 static struct sk_buff *sja1110_rcv(struct sk_buff *skb, 638 661 struct net_device *netdev) 639 662 { 640 - int source_port = -1, switch_id = -1, vbid = -1; 663 + int source_port = -1, switch_id = -1, vbid = -1, vid = -1; 641 664 bool host_only = false; 642 - u16 vid = 0; 643 665 644 666 if (sja1110_skb_has_inband_control_extension(skb)) { 645 667 skb = sja1110_rcv_inband_control_extension(skb, &source_port, ··· 650 674 651 675 /* Packets with in-band control extensions might still have RX VLANs */ 652 676 if (likely(sja1105_skb_has_tag_8021q(skb))) 653 - sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid); 677 + dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid); 654 678 655 679 if (vbid >= 1) 656 680 skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);