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 */
|
||||
if (fs->location == RX_CLS_LOC_ANY)
|
||||
rule_index = find_first_zero_bit(priv->cfp.used,
|
||||
bcm_sf2_cfp_rule_size(priv));
|
||||
priv->num_cfp_rules);
|
||||
else
|
||||
rule_index = fs->location;
|
||||
|
||||
if (rule_index > bcm_sf2_cfp_rule_size(priv))
|
||||
return -ENOSPC;
|
||||
|
||||
layout = &udf_tcpip4_layout;
|
||||
/* We only use one UDF slice for now */
|
||||
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.
|
||||
*/
|
||||
if (fs->location == RX_CLS_LOC_ANY)
|
||||
rule_index[0] = find_first_zero_bit(priv->cfp.used,
|
||||
bcm_sf2_cfp_rule_size(priv));
|
||||
rule_index[1] = find_first_zero_bit(priv->cfp.used,
|
||||
priv->num_cfp_rules);
|
||||
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
|
||||
* 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,
|
||||
bcm_sf2_cfp_rule_size(priv));
|
||||
if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) {
|
||||
rule_index[0] = find_first_zero_bit(priv->cfp.used,
|
||||
priv->num_cfp_rules);
|
||||
if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
|
||||
ret = -ENOSPC;
|
||||
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
|
||||
* 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);
|
||||
fs->location = rule_index[1];
|
||||
|
||||
return ret;
|
||||
|
||||
out_err:
|
||||
clear_bit(rule_index[0], priv->cfp.used);
|
||||
clear_bit(rule_index[1], priv->cfp.used);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
|
|||
int ret;
|
||||
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 */
|
||||
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;
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue