From d0802dc411f469569a537283b6f3833af47aece9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:46 -0700 Subject: net: dsa: bcm_sf2: Fix overflow checks Commit f949a12fd697 ("net: dsa: bcm_sf2: fix buffer overflow doing set_rxnfc") tried to fix the some user controlled buffer overflows in bcm_sf2_cfp_rule_set() and bcm_sf2_cfp_rule_del() but the fix was using CFP_NUM_RULES, which while it is correct not to overflow the bitmaps, is not representative of what the device actually supports. Correct that by using bcm_sf2_cfp_rule_size() instead. The latter subtracts the number of rules by 1, so change the checks from greater than or equal to greater than accordingly. Fixes: f949a12fd697 ("net: dsa: bcm_sf2: fix buffer overflow doing set_rxnfc") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2_cfp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 1962c8330daa..f9785027c096 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -882,17 +882,14 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, fs->m_ext.data[1])) return -EINVAL; - if (fs->location != RX_CLS_LOC_ANY && fs->location >= CFP_NUM_RULES) + if (fs->location != RX_CLS_LOC_ANY && + fs->location > bcm_sf2_cfp_rule_size(priv)) return -EINVAL; if (fs->location != RX_CLS_LOC_ANY && test_bit(fs->location, priv->cfp.used)) return -EBUSY; - if (fs->location != RX_CLS_LOC_ANY && - fs->location > bcm_sf2_cfp_rule_size(priv)) - return -EINVAL; - ret = bcm_sf2_cfp_rule_cmp(priv, port, fs); if (ret == 0) return -EEXIST; @@ -973,7 +970,7 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, u32 loc) struct cfp_rule *rule; int ret; - if (loc >= CFP_NUM_RULES) + if (loc > bcm_sf2_cfp_rule_size(priv)) return -EINVAL; /* Refuse deleting unused rules, and those that are not unique since -- cgit v1.2.3 From d7a0b1f7652f9f6b7ba0c9d8ad8edd6b8c0c1511 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:47 -0700 Subject: net: dsa: b53: Restore VLAN entries upon (re)configuration The first time b53_configure_vlan() is called we have not configured any VLAN entries yet, since that happens later when interfaces get brought up. When b53_configure_vlan() is called again from suspend/resume we need to restore all VLAN entries though. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 39ae4ed87d1d..5cb678e8b9cd 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -681,7 +681,9 @@ int b53_configure_vlan(struct dsa_switch *ds) { struct b53_device *dev = ds->priv; struct b53_vlan vl = { 0 }; + struct b53_vlan *v; int i, def_vid; + u16 vid; def_vid = b53_default_pvid(dev); @@ -699,6 +701,19 @@ int b53_configure_vlan(struct dsa_switch *ds) b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(i), def_vid); + /* Upon initial call we have not set-up any VLANs, but upon + * system resume, we need to restore all VLAN entries. + */ + for (vid = def_vid; vid < dev->num_vlans; vid++) { + v = &dev->vlans[vid]; + + if (!v->members) + continue; + + b53_set_vlan_entry(dev, vid, v); + b53_fast_age_vlan(dev, vid); + } + return 0; } EXPORT_SYMBOL(b53_configure_vlan); -- cgit v1.2.3 From 88631864da093377ce6d5e60b5639328622a8e5c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:48 -0700 Subject: net: dsa: b53: Prevent tagged VLAN on port 7 for 7278 On 7278, port 7 of the switch connects to the ASP UniMAC which is not capable of processing VLAN tagged frames. We can still allow the port to be part of a VLAN entry, and we may want it to be untagged on egress on that VLAN because of that limitation. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 5cb678e8b9cd..42c41b091682 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1355,6 +1355,14 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port, if ((is5325(dev) || is5365(dev)) && vlan->vid_begin == 0) return -EOPNOTSUPP; + /* Port 7 on 7278 connects to the ASP's UniMAC which is not capable of + * receiving VLAN tagged frames at all, we can still allow the port to + * be configured for egress untagged. + */ + if (dev->chip_id == BCM7278_DEVICE_ID && port == 7 && + !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED)) + return -EINVAL; + if (vlan->vid_end > dev->num_vlans) return -ERANGE; -- cgit v1.2.3 From 31bfc2d42cae6e8b1440fc5db3f0aba6c5d7e602 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:49 -0700 Subject: net: dsa: b53: Deny enslaving port 7 for 7278 into a bridge On 7278, port 7 connects to the ASP which should only receive frames through the use of CFP rules, it is not desirable to have it be part of a bridge at all since that would make it pick up unwanted traffic that it may not even be able to filter or sustain. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 42c41b091682..68e2381694b9 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1728,6 +1728,12 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) u16 pvlan, reg; unsigned int i; + /* On 7278, port 7 which connects to the ASP should only receive + * traffic from matching CFP rules. + */ + if (dev->chip_id == BCM7278_DEVICE_ID && port == 7) + return -EINVAL; + /* Make this port leave the all VLANs join since we will have proper * VLAN entries from now on */ -- cgit v1.2.3 From 8b6b208b69917d88bb3e087f8c9e61c6b05ed571 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:50 -0700 Subject: net: dsa: bcm_sf2: Disable learning for ASP port We don't want to enable learning for the ASP port since it only receives directed traffic, this allows us to bypass ARL-driven forwarding rules which could conflict with Broadcom tags and/or CFP forwarding. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 368ead87e07a..affa5c6e135c 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -178,9 +178,17 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, core_writel(priv, reg, CORE_DIS_LEARN); /* Enable Broadcom tags for that port if requested */ - if (priv->brcm_tag_mask & BIT(port)) + if (priv->brcm_tag_mask & BIT(port)) { b53_brcm_hdr_setup(ds, port); + /* Disable learning on ASP port */ + if (port == 7) { + reg = core_readl(priv, CORE_DIS_LEARN); + reg |= BIT(port); + core_writel(priv, reg, CORE_DIS_LEARN); + } + } + /* Configure Traffic Class to QoS mapping, allow each priority to map * to a different queue number */ -- cgit v1.2.3 From 5ae8c0d51ace3bdbfb89c27e7661f081cc9287de Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:51 -0700 Subject: net: dsa: bcm_sf2: Check earlier for FLOW_EXT and FLOW_MAC_EXT We do not currently support matching on FLOW_EXT or FLOW_MAC_EXT, but we were not checking for those bits being set in the flow specification. The check for FLOW_EXT and FLOW_MAC_EXT are separated out because a subsequent commit will add support for matching VLAN TCI which are covered by FLOW_EXT. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2_cfp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index f9785027c096..40ea88c304de 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -878,8 +878,9 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, int ret = -EINVAL; /* Check for unsupported extensions */ - if ((fs->flow_type & FLOW_EXT) && (fs->m_ext.vlan_etype || - fs->m_ext.data[1])) + if ((fs->flow_type & FLOW_EXT) || + (fs->flow_type & FLOW_MAC_EXT) || + fs->m_ext.data[1]) return -EINVAL; if (fs->location != RX_CLS_LOC_ANY && -- cgit v1.2.3 From c2d639d118d27d6419f5848675ed5c112a86910f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:52 -0700 Subject: net: dsa: bcm_sf2: Move writing of CFP_DATA(5) into slicing functions In preparation for matching VLANs, move the writing of CFP_DATA(5) into the IPv4 and IPv6 slicing logic since they are part of the per-flow configuration. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2_cfp.c | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 40ea88c304de..a6cc076f1a67 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -261,11 +261,20 @@ static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv, static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv, struct flow_dissector_key_ipv4_addrs *addrs, struct flow_dissector_key_ports *ports, - unsigned int slice_num, + unsigned int slice_num, u8 num_udf, bool mask) { u32 reg, offset; + /* UDF_Valid[7:0] [31:24] + * S-Tag [23:8] + * C-Tag [7:0] + */ + if (mask) + core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5)); + else + core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5)); + /* C-Tag [31:24] * UDF_n_A8 [23:8] * UDF_n_A7 [7:0] @@ -421,18 +430,11 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, core_writel(priv, layout->udfs[slice_num].mask_value | udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6)); - /* UDF_Valid[7:0] [31:24] - * S-Tag [23:8] - * C-Tag [7:0] - */ - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5)); - - /* Mask all but valid UDFs */ - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5)); - /* Program the match and the mask */ - bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, slice_num, false); - bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, SLICE_NUM_MASK, true); + bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, slice_num, + num_udf, false); + bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, SLICE_NUM_MASK, + num_udf, true); /* Insert into TCAM now */ bcm_sf2_cfp_rule_addr_set(priv, rule_index); @@ -468,11 +470,20 @@ out_err_flow_rule: static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, const __be32 *ip6_addr, const __be16 port, - unsigned int slice_num, + unsigned int slice_num, u32 udf_bits, bool mask) { u32 reg, tmp, val, offset; + /* UDF_Valid[7:0] [31:24] + * S-Tag [23:8] + * C-Tag [7:0] + */ + if (mask) + core_writel(priv, udf_bits << 24, CORE_CFP_MASK_PORT(5)); + else + core_writel(priv, udf_bits << 24, CORE_CFP_DATA_PORT(5)); + /* C-Tag [31:24] * UDF_n_B8 [23:8] (port) * UDF_n_B7 (upper) [7:0] (addr[15:8]) @@ -704,20 +715,13 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, reg = layout->udfs[slice_num].mask_value | udf_upper_bits(num_udf); core_writel(priv, reg, CORE_CFP_MASK_PORT(6)); - /* UDF_Valid[7:0] [31:24] - * S-Tag [23:8] - * C-Tag [7:0] - */ - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5)); - - /* Mask all but valid UDFs */ - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5)); - /* Slice the IPv6 source address and port */ bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->src.in6_u.u6_addr32, - ports.key->src, slice_num, false); + ports.key->src, slice_num, + udf_lower_bits(num_udf), false); bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->src.in6_u.u6_addr32, - ports.mask->src, SLICE_NUM_MASK, true); + ports.mask->src, SLICE_NUM_MASK, + udf_lower_bits(num_udf), true); /* Insert into TCAM now because we need to insert a second rule */ bcm_sf2_cfp_rule_addr_set(priv, rule_index[0]); @@ -768,16 +772,12 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, udf_lower_bits(num_udf) << 8; core_writel(priv, reg, CORE_CFP_MASK_PORT(6)); - /* Don't care */ - core_writel(priv, 0, CORE_CFP_DATA_PORT(5)); - - /* Mask all */ - core_writel(priv, 0, CORE_CFP_MASK_PORT(5)); - bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->dst.in6_u.u6_addr32, - ports.key->dst, slice_num, false); + ports.key->dst, slice_num, + 0, false); bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->dst.in6_u.u6_addr32, - ports.key->dst, SLICE_NUM_MASK, true); + ports.key->dst, SLICE_NUM_MASK, + 0, true); /* Insert into TCAM now */ bcm_sf2_cfp_rule_addr_set(priv, rule_index[1]); -- cgit v1.2.3 From 7555020c44db75a0d934dffc0aa6c678b52b2a13 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:53 -0700 Subject: net: dsa: bcm_sf2: Add support for matching VLAN TCI Update relevant code paths to support the programming and matching of VLAN TCI, this is the only member of the ethtool_flow_ext that we can match, the switch does not permit matching the VLAN Ethernet Type field. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2_cfp.c | 53 +++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index a6cc076f1a67..7b10a9f31538 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -261,6 +261,7 @@ static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv, static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv, struct flow_dissector_key_ipv4_addrs *addrs, struct flow_dissector_key_ports *ports, + const __be16 vlan_tci, unsigned int slice_num, u8 num_udf, bool mask) { @@ -270,16 +271,17 @@ static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv, * S-Tag [23:8] * C-Tag [7:0] */ + reg = udf_lower_bits(num_udf) << 24 | be16_to_cpu(vlan_tci) >> 8; if (mask) - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5)); + core_writel(priv, reg, CORE_CFP_MASK_PORT(5)); else - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5)); + core_writel(priv, reg, CORE_CFP_DATA_PORT(5)); /* C-Tag [31:24] * UDF_n_A8 [23:8] * UDF_n_A7 [7:0] */ - reg = 0; + reg = (u32)(be16_to_cpu(vlan_tci) & 0xff) << 24; if (mask) offset = CORE_CFP_MASK_PORT(4); else @@ -345,6 +347,7 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, struct ethtool_rx_flow_spec *fs) { struct ethtool_rx_flow_spec_input input = {}; + __be16 vlan_tci = 0 , vlan_m_tci = 0xffff; const struct cfp_udf_layout *layout; unsigned int slice_num, rule_index; struct ethtool_rx_flow_rule *flow; @@ -369,6 +372,12 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1); + /* Extract VLAN TCI */ + if (fs->flow_type & FLOW_EXT) { + vlan_tci = fs->h_ext.vlan_tci; + vlan_m_tci = fs->m_ext.vlan_tci; + } + /* Locate the first rule available */ if (fs->location == RX_CLS_LOC_ANY) rule_index = find_first_zero_bit(priv->cfp.used, @@ -431,10 +440,10 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6)); /* Program the match and the mask */ - bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, slice_num, - num_udf, false); - bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, SLICE_NUM_MASK, - num_udf, true); + bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, vlan_tci, + slice_num, num_udf, false); + bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, vlan_m_tci, + SLICE_NUM_MASK, num_udf, true); /* Insert into TCAM now */ bcm_sf2_cfp_rule_addr_set(priv, rule_index); @@ -470,6 +479,7 @@ out_err_flow_rule: static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, const __be32 *ip6_addr, const __be16 port, + const __be16 vlan_tci, unsigned int slice_num, u32 udf_bits, bool mask) { @@ -479,10 +489,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, * S-Tag [23:8] * C-Tag [7:0] */ + reg = udf_bits << 24 | be16_to_cpu(vlan_tci) >> 8; if (mask) - core_writel(priv, udf_bits << 24, CORE_CFP_MASK_PORT(5)); + core_writel(priv, reg, CORE_CFP_MASK_PORT(5)); else - core_writel(priv, udf_bits << 24, CORE_CFP_DATA_PORT(5)); + core_writel(priv, reg, CORE_CFP_DATA_PORT(5)); /* C-Tag [31:24] * UDF_n_B8 [23:8] (port) @@ -490,6 +501,7 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, */ reg = be32_to_cpu(ip6_addr[3]); val = (u32)be16_to_cpu(port) << 8 | ((reg >> 8) & 0xff); + val |= (u32)(be16_to_cpu(vlan_tci) & 0xff) << 24; if (mask) offset = CORE_CFP_MASK_PORT(4); else @@ -598,6 +610,11 @@ static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port, ret = memcmp(&rule->fs.h_u, &fs->h_u, fs_size); ret |= memcmp(&rule->fs.m_u, &fs->m_u, fs_size); + /* Compare VLAN TCI values as well */ + if (rule->fs.flow_type & FLOW_EXT) { + ret |= rule->fs.h_ext.vlan_tci != fs->h_ext.vlan_tci; + ret |= rule->fs.m_ext.vlan_tci != fs->m_ext.vlan_tci; + } if (ret == 0) break; } @@ -611,6 +628,7 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, struct ethtool_rx_flow_spec *fs) { struct ethtool_rx_flow_spec_input input = {}; + __be16 vlan_tci = 0, vlan_m_tci = 0xffff; unsigned int slice_num, rule_index[2]; const struct cfp_udf_layout *layout; struct ethtool_rx_flow_rule *flow; @@ -634,6 +652,12 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1); + /* Extract VLAN TCI */ + if (fs->flow_type & FLOW_EXT) { + vlan_tci = fs->h_ext.vlan_tci; + vlan_m_tci = fs->m_ext.vlan_tci; + } + layout = &udf_tcpip6_layout; slice_num = bcm_sf2_get_slice_number(layout, 0); if (slice_num == UDF_NUM_SLICES) @@ -717,10 +741,10 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, /* Slice the IPv6 source address and port */ bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->src.in6_u.u6_addr32, - ports.key->src, slice_num, + ports.key->src, vlan_tci, slice_num, udf_lower_bits(num_udf), false); bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->src.in6_u.u6_addr32, - ports.mask->src, SLICE_NUM_MASK, + ports.mask->src, vlan_m_tci, SLICE_NUM_MASK, udf_lower_bits(num_udf), true); /* Insert into TCAM now because we need to insert a second rule */ @@ -773,10 +797,10 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, core_writel(priv, reg, CORE_CFP_MASK_PORT(6)); bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->dst.in6_u.u6_addr32, - ports.key->dst, slice_num, + ports.key->dst, 0, slice_num, 0, false); bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->dst.in6_u.u6_addr32, - ports.key->dst, SLICE_NUM_MASK, + ports.key->dst, 0, SLICE_NUM_MASK, 0, true); /* Insert into TCAM now */ @@ -878,8 +902,7 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, int ret = -EINVAL; /* Check for unsupported extensions */ - if ((fs->flow_type & FLOW_EXT) || - (fs->flow_type & FLOW_MAC_EXT) || + if ((fs->flow_type & FLOW_MAC_EXT) || fs->m_ext.data[1]) return -EINVAL; -- cgit v1.2.3 From 8b3abe304c5f1057b7bac70fd5576dfa67e3e2b3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Mar 2020 14:38:54 -0700 Subject: net: dsa: bcm_sf2: Support specifying VLAN tag egress rule The port to which the ASP is connected on 7278 is not capable of processing VLAN tags as part of the Ethernet frame, so allow an user to configure the egress VLAN policy they want to see applied by purposing the h_ext.data[1] field. Bit 0 is used to indicate that 0=tagged, 1=untagged. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2_cfp.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 7b10a9f31538..f707edc641cf 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "bcm_sf2.h" #include "bcm_sf2_regs.h" @@ -847,7 +849,9 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port, struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; __u64 ring_cookie = fs->ring_cookie; + struct switchdev_obj_port_vlan vlan; unsigned int queue_num, port_num; + u16 vid; int ret; /* This rule is a Wake-on-LAN filter and we must specifically @@ -867,6 +871,34 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port, dsa_is_cpu_port(ds, port_num)) || port_num >= priv->hw_params.num_ports) return -EINVAL; + + /* If the rule is matching a particular VLAN, make sure that we honor + * the matching and have it tagged or untagged on the destination port, + * we do this on egress with a VLAN entry. The egress tagging attribute + * is expected to be provided in h_ext.data[1] bit 0. A 1 means untagged, + * a 0 means tagged. + */ + if (fs->flow_type & FLOW_EXT) { + /* We cannot support matching multiple VLAN IDs yet */ + if ((be16_to_cpu(fs->m_ext.vlan_tci) & VLAN_VID_MASK) != + VLAN_VID_MASK) + return -EINVAL; + + vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; + vlan.vid_begin = vid; + vlan.vid_end = vid; + if (cpu_to_be32(fs->h_ext.data[1]) & 1) + vlan.flags = BRIDGE_VLAN_INFO_UNTAGGED; + else + vlan.flags = 0; + + ret = ds->ops->port_vlan_prepare(ds, port_num, &vlan); + if (ret) + return ret; + + ds->ops->port_vlan_add(ds, port_num, &vlan); + } + /* * We have a small oddity where Port 6 just does not have a * valid bit here (so we substract by one). @@ -902,14 +934,18 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, int ret = -EINVAL; /* Check for unsupported extensions */ - if ((fs->flow_type & FLOW_MAC_EXT) || - fs->m_ext.data[1]) + if (fs->flow_type & FLOW_MAC_EXT) return -EINVAL; if (fs->location != RX_CLS_LOC_ANY && fs->location > bcm_sf2_cfp_rule_size(priv)) return -EINVAL; + if ((fs->flow_type & FLOW_EXT) && + !(ds->ops->port_vlan_prepare || ds->ops->port_vlan_add || + ds->ops->port_vlan_del)) + return -EOPNOTSUPP; + if (fs->location != RX_CLS_LOC_ANY && test_bit(fs->location, priv->cfp.used)) return -EBUSY; -- cgit v1.2.3