net: dsa: sja1105: make room for virtual link parsing in flower offload

Virtual links are a sja1105 hardware concept of executing various flow
actions based on a key extracted from the frame's DMAC, VID and PCP.

Currently the tc-flower offload code supports only parsing the DMAC if
that is the broadcast MAC address, and the VLAN PCP. Extract the key
parsing logic from the L2 policers functionality and move it into its
own function, after adding extra logic for matching on any DMAC and VID.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vladimir Oltean 2020-05-05 22:20:54 +03:00 committed by David S. Miller
parent 94f94d4acf
commit b70bb8d4ab
2 changed files with 112 additions and 27 deletions

View File

@ -97,6 +97,32 @@ struct sja1105_info {
const char *name;
};
enum sja1105_key_type {
SJA1105_KEY_BCAST,
SJA1105_KEY_TC,
SJA1105_KEY_VLAN_UNAWARE_VL,
SJA1105_KEY_VLAN_AWARE_VL,
};
struct sja1105_key {
enum sja1105_key_type type;
union {
/* SJA1105_KEY_TC */
struct {
int pcp;
} tc;
/* SJA1105_KEY_VLAN_UNAWARE_VL */
/* SJA1105_KEY_VLAN_AWARE_VL */
struct {
u64 dmac;
u16 vid;
u16 pcp;
} vl;
};
};
enum sja1105_rule_type {
SJA1105_RULE_BCAST_POLICER,
SJA1105_RULE_TC_POLICER,
@ -106,6 +132,7 @@ struct sja1105_rule {
struct list_head list;
unsigned long cookie;
unsigned long port_mask;
struct sja1105_key key;
enum sja1105_rule_type type;
union {
@ -117,7 +144,6 @@ struct sja1105_rule {
/* SJA1105_RULE_TC_POLICER */
struct {
int sharindx;
int tc;
} tc_pol;
};
};

View File

@ -46,6 +46,7 @@ static int sja1105_setup_bcast_policer(struct sja1105_private *priv,
rule->cookie = cookie;
rule->type = SJA1105_RULE_BCAST_POLICER;
rule->bcast_pol.sharindx = sja1105_find_free_l2_policer(priv);
rule->key.type = SJA1105_KEY_BCAST;
new_rule = true;
}
@ -117,7 +118,8 @@ static int sja1105_setup_tc_policer(struct sja1105_private *priv,
rule->cookie = cookie;
rule->type = SJA1105_RULE_TC_POLICER;
rule->tc_pol.sharindx = sja1105_find_free_l2_policer(priv);
rule->tc_pol.tc = tc;
rule->key.type = SJA1105_KEY_TC;
rule->key.tc.pcp = tc;
new_rule = true;
}
@ -169,14 +171,37 @@ out:
return rc;
}
static int sja1105_flower_parse_policer(struct sja1105_private *priv, int port,
struct netlink_ext_ack *extack,
struct flow_cls_offload *cls,
u64 rate_bytes_per_sec,
s64 burst)
static int sja1105_flower_policer(struct sja1105_private *priv, int port,
struct netlink_ext_ack *extack,
unsigned long cookie, struct sja1105_key *key,
u64 rate_bytes_per_sec,
s64 burst)
{
switch (key->type) {
case SJA1105_KEY_BCAST:
return sja1105_setup_bcast_policer(priv, extack, cookie, port,
rate_bytes_per_sec, burst);
case SJA1105_KEY_TC:
return sja1105_setup_tc_policer(priv, extack, cookie, port,
key->tc.pcp, rate_bytes_per_sec,
burst);
default:
NL_SET_ERR_MSG_MOD(extack, "Unknown keys for policing");
return -EOPNOTSUPP;
}
}
static int sja1105_flower_parse_key(struct sja1105_private *priv,
struct netlink_ext_ack *extack,
struct flow_cls_offload *cls,
struct sja1105_key *key)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
struct flow_dissector *dissector = rule->match.dissector;
bool is_bcast_dmac = false;
u64 dmac = U64_MAX;
u16 vid = U16_MAX;
u16 pcp = U16_MAX;
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
@ -213,16 +238,14 @@ static int sja1105_flower_parse_policer(struct sja1105_private *priv, int port,
return -EOPNOTSUPP;
}
if (!ether_addr_equal_masked(match.key->dst, bcast,
match.mask->dst)) {
if (!ether_addr_equal(match.mask->dst, bcast)) {
NL_SET_ERR_MSG_MOD(extack,
"Only matching on broadcast DMAC is supported");
"Masked matching on MAC not supported");
return -EOPNOTSUPP;
}
return sja1105_setup_bcast_policer(priv, extack, cls->cookie,
port, rate_bytes_per_sec,
burst);
dmac = ether_addr_to_u64(match.key->dst);
is_bcast_dmac = ether_addr_equal(match.key->dst, bcast);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
@ -230,22 +253,46 @@ static int sja1105_flower_parse_policer(struct sja1105_private *priv, int port,
flow_rule_match_vlan(rule, &match);
if (match.key->vlan_id & match.mask->vlan_id) {
if (match.mask->vlan_id &&
match.mask->vlan_id != VLAN_VID_MASK) {
NL_SET_ERR_MSG_MOD(extack,
"Matching on VID is not supported");
"Masked matching on VID is not supported");
return -EOPNOTSUPP;
}
if (match.mask->vlan_priority != 0x7) {
if (match.mask->vlan_priority &&
match.mask->vlan_priority != 0x7) {
NL_SET_ERR_MSG_MOD(extack,
"Masked matching on PCP is not supported");
return -EOPNOTSUPP;
}
return sja1105_setup_tc_policer(priv, extack, cls->cookie, port,
match.key->vlan_priority,
rate_bytes_per_sec,
burst);
if (match.mask->vlan_id)
vid = match.key->vlan_id;
if (match.mask->vlan_priority)
pcp = match.key->vlan_priority;
}
if (is_bcast_dmac && vid == U16_MAX && pcp == U16_MAX) {
key->type = SJA1105_KEY_BCAST;
return 0;
}
if (dmac == U64_MAX && vid == U16_MAX && pcp != U16_MAX) {
key->type = SJA1105_KEY_TC;
key->tc.pcp = pcp;
return 0;
}
if (dmac != U64_MAX && vid != U16_MAX && pcp != U16_MAX) {
key->type = SJA1105_KEY_VLAN_AWARE_VL;
key->vl.dmac = dmac;
key->vl.vid = vid;
key->vl.pcp = pcp;
return 0;
}
if (dmac != U64_MAX) {
key->type = SJA1105_KEY_VLAN_UNAWARE_VL;
key->vl.dmac = dmac;
return 0;
}
NL_SET_ERR_MSG_MOD(extack, "Not matching on any known key");
@ -259,22 +306,34 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack = cls->common.extack;
struct sja1105_private *priv = ds->priv;
const struct flow_action_entry *act;
int rc = -EOPNOTSUPP, i;
unsigned long cookie = cls->cookie;
struct sja1105_key key;
int rc, i;
rc = sja1105_flower_parse_key(priv, extack, cls, &key);
if (rc)
return rc;
rc = -EOPNOTSUPP;
flow_action_for_each(i, act, &rule->action) {
switch (act->id) {
case FLOW_ACTION_POLICE:
rc = sja1105_flower_parse_policer(priv, port, extack, cls,
act->police.rate_bytes_ps,
act->police.burst);
rc = sja1105_flower_policer(priv, port,
extack, cookie, &key,
act->police.rate_bytes_ps,
act->police.burst);
if (rc)
goto out;
break;
default:
NL_SET_ERR_MSG_MOD(extack,
"Action not supported");
break;
rc = -EOPNOTSUPP;
goto out;
}
}
out:
return rc;
}
@ -297,7 +356,7 @@ int sja1105_cls_flower_del(struct dsa_switch *ds, int port,
old_sharindx = policing[bcast].sharindx;
policing[bcast].sharindx = port;
} else if (rule->type == SJA1105_RULE_TC_POLICER) {
int index = (port * SJA1105_NUM_TC) + rule->tc_pol.tc;
int index = (port * SJA1105_NUM_TC) + rule->key.tc.pcp;
old_sharindx = policing[index].sharindx;
policing[index].sharindx = port;