Merge branch 'dsa-bcm_sf2-CFP-fixes'
Florian Fainelli says: ==================== net: dsa: bcm_sf2: CFP fixes This patch series fixes a number of usability issues with the SF2 Compact Field Processor code: - we would not be properly bound checking the location when we let the kernel automatically place rules with RX_CLS_LOC_ANY - when using IPv6 rules and user space specifies a location identifier we would be off by one in what the chain ID (within the Broadcom tag) indicates - it would be possible to delete one of the two slices of an IPv6 while leaving the other one programming leading to various problems ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ac22bfb15c
|
@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
|
||||||
/* Locate the first rule available */
|
/* Locate the first rule available */
|
||||||
if (fs->location == RX_CLS_LOC_ANY)
|
if (fs->location == RX_CLS_LOC_ANY)
|
||||||
rule_index = find_first_zero_bit(priv->cfp.used,
|
rule_index = find_first_zero_bit(priv->cfp.used,
|
||||||
bcm_sf2_cfp_rule_size(priv));
|
priv->num_cfp_rules);
|
||||||
else
|
else
|
||||||
rule_index = fs->location;
|
rule_index = fs->location;
|
||||||
|
|
||||||
|
if (rule_index > bcm_sf2_cfp_rule_size(priv))
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
layout = &udf_tcpip4_layout;
|
layout = &udf_tcpip4_layout;
|
||||||
/* We only use one UDF slice for now */
|
/* We only use one UDF slice for now */
|
||||||
slice_num = bcm_sf2_get_slice_number(layout, 0);
|
slice_num = bcm_sf2_get_slice_number(layout, 0);
|
||||||
|
@ -562,19 +565,21 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
|
||||||
* first half because the HW search is by incrementing addresses.
|
* first half because the HW search is by incrementing addresses.
|
||||||
*/
|
*/
|
||||||
if (fs->location == RX_CLS_LOC_ANY)
|
if (fs->location == RX_CLS_LOC_ANY)
|
||||||
rule_index[0] = find_first_zero_bit(priv->cfp.used,
|
rule_index[1] = find_first_zero_bit(priv->cfp.used,
|
||||||
bcm_sf2_cfp_rule_size(priv));
|
priv->num_cfp_rules);
|
||||||
else
|
else
|
||||||
rule_index[0] = fs->location;
|
rule_index[1] = fs->location;
|
||||||
|
if (rule_index[1] > bcm_sf2_cfp_rule_size(priv))
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
/* Flag it as used (cleared on error path) such that we can immediately
|
/* Flag it as used (cleared on error path) such that we can immediately
|
||||||
* obtain a second one to chain from.
|
* obtain a second one to chain from.
|
||||||
*/
|
*/
|
||||||
set_bit(rule_index[0], priv->cfp.used);
|
set_bit(rule_index[1], priv->cfp.used);
|
||||||
|
|
||||||
rule_index[1] = find_first_zero_bit(priv->cfp.used,
|
rule_index[0] = find_first_zero_bit(priv->cfp.used,
|
||||||
bcm_sf2_cfp_rule_size(priv));
|
priv->num_cfp_rules);
|
||||||
if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) {
|
if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
|
||||||
/* Flag the second half rule as being used now, return it as the
|
/* Flag the second half rule as being used now, return it as the
|
||||||
* location, and flag it as unique while dumping rules
|
* location, and flag it as unique while dumping rules
|
||||||
*/
|
*/
|
||||||
set_bit(rule_index[1], priv->cfp.used);
|
set_bit(rule_index[0], priv->cfp.used);
|
||||||
set_bit(rule_index[1], priv->cfp.unique);
|
set_bit(rule_index[1], priv->cfp.unique);
|
||||||
fs->location = rule_index[1];
|
fs->location = rule_index[1];
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
clear_bit(rule_index[0], priv->cfp.used);
|
clear_bit(rule_index[1], priv->cfp.used);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
|
||||||
int ret;
|
int ret;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
/* Refuse deletion of unused rules, and the default reserved rule */
|
|
||||||
if (!test_bit(loc, priv->cfp.used) || loc == 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Indicate which rule we want to read */
|
/* Indicate which rule we want to read */
|
||||||
bcm_sf2_cfp_rule_addr_set(priv, loc);
|
bcm_sf2_cfp_rule_addr_set(priv, loc);
|
||||||
|
|
||||||
|
@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
|
||||||
u32 next_loc = 0;
|
u32 next_loc = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Refuse deleting unused rules, and those that are not unique since
|
||||||
|
* that could leave IPv6 rules with one of the chained rule in the
|
||||||
|
* table.
|
||||||
|
*/
|
||||||
|
if (!test_bit(loc, priv->cfp.unique) || loc == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
|
ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue