diff options
| author | David Yang <mmyangfl@gmail.com> | 2026-10-17 10:31:32 +0800 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-10-21 13:36:53 +0200 |
| commit | 279d5c8afcd38bd841832a39bfe1aa4f8518d98e (patch) | |
| tree | 89e047c1c1771283000e533a485345cbf0d6ad8c | |
| parent | 39e24cf5e29a01d28ef53bfa6ea08d0382a05dc2 (diff) | |
net: dsa: motorcomm: Extend ACL with UDF
The native ACL key set cannot express IP TTL or ICMP type/code. Use the
User Defined Filter windows to match them in the tc flower offload.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Link: https://patch.msgid.link/20261017023136.2961543-1-mmyangfl@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
| -rw-r--r-- | drivers/net/dsa/motorcomm/chip.h | 2 | ||||
| -rw-r--r-- | drivers/net/dsa/motorcomm/tc.c | 140 | ||||
| -rw-r--r-- | drivers/net/dsa/motorcomm/tc.h | 12 |
3 files changed, 144 insertions, 10 deletions
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h index 7047ad98f431..fc315f1d8f87 100644 --- a/drivers/net/dsa/motorcomm/chip.h +++ b/drivers/net/dsa/motorcomm/chip.h @@ -440,7 +440,7 @@ enum yt921x_fdb_entry_status { #define YT921X_TAG_LEN 8 #define YT921X_ACL_BLK_NUM 48 -#define YT921X_UDF_NUM 8 +#define YT921X_UDF_NUM 16 #define YT921X_LED_GROUP_NUM 3 #define YT921X_LED_PORT_NUM 10 diff --git a/drivers/net/dsa/motorcomm/tc.c b/drivers/net/dsa/motorcomm/tc.c index 3e0f80500f41..9dbd61e48fee 100644 --- a/drivers/net/dsa/motorcomm/tc.c +++ b/drivers/net/dsa/motorcomm/tc.c @@ -543,6 +543,24 @@ yt921x_acl_rule_set_ports(struct yt921x_acl_rule *aclrule, u16 ord, } } +struct yt921x_udf_entry { + unsigned char type; + unsigned char offset; + u8 key; + u8 mask; +}; + +struct yt921x_udf_map { + unsigned char type; + unsigned char offset; +}; + +/* UDF windows are preselected - that's enough for now. */ +static struct yt921x_udf_map yt921x_udf_maps[] = { + {YT921X_UDF_TYPE_L3, 7}, + {YT921X_UDF_TYPE_L4, 0}, +}; + struct yt921x_acl_rule_ext { struct yt921x_acl_rule r; @@ -556,9 +574,13 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, const struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct yt921x_acl_entry *entries = ruleext->r.entries; struct netlink_ext_ack *extack = cls->common.extack; + struct yt921x_udf_entry udfs[YT921X_UDF_NUM]; const struct flow_dissector *dissector; struct yt921x_acl_entry *entry; + unsigned int udfs_cnt = 0; unsigned int size = 0; + __be16 n_proto = 0; + u8 ip_proto = 0; bool use_dport; bool use_sport; @@ -575,7 +597,8 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, BIT_ULL(FLOW_DISSECTOR_KEY_PORTS_RANGE) | BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) | BIT_ULL(FLOW_DISSECTOR_KEY_IP) | - BIT_ULL(FLOW_DISSECTOR_KEY_TCP))) { + BIT_ULL(FLOW_DISSECTOR_KEY_TCP) | + BIT_ULL(FLOW_DISSECTOR_KEY_ICMP))) { NL_SET_ERR_MSG_MOD(extack, "Unsupported keys used"); return -EOPNOTSUPP; } @@ -741,7 +764,9 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, if (match.mask->n_proto) { enum yt921x_l3_type l3type = YT921X_L3_TYPE_OTHER; - if (match.mask->n_proto == htons(~0)) + if (match.mask->n_proto == htons(~0)) { + n_proto = match.key->n_proto; + switch (match.key->n_proto) { case htons(ETH_P_IP): l3type = YT921X_L3_TYPE_IPV4; @@ -762,6 +787,7 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, l3type = YT921X_L3_TYPE_ERP; break; } + } if (l3type != YT921X_L3_TYPE_OTHER) { size = yt921x_acl_entries_set_l3_type(entries, @@ -783,7 +809,9 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, if (match.mask->ip_proto) { enum yt921x_l4_type l4type = YT921X_L4_TYPE_OTHER; - if (match.mask->ip_proto == (u8)~0) + if (match.mask->ip_proto == (u8)~0) { + ip_proto = match.key->ip_proto; + switch (match.key->ip_proto) { case IPPROTO_TCP: l4type = YT921X_L4_TYPE_TCP; @@ -801,6 +829,7 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, l4type = YT921X_L4_TYPE_IGMP; break; } + } if (l4type != YT921X_L4_TYPE_OTHER) { size = yt921x_acl_entries_set_l4_type(entries, @@ -852,10 +881,25 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, struct flow_match_ip match; flow_rule_match_ip(rule, &match); + if (match.mask->ttl) { - NL_SET_ERR_MSG_MOD(extack, - "Matching on TTL not supported"); - return -EOPNOTSUPP; + if (n_proto != htons(ETH_P_IP) && + n_proto != htons(ETH_P_IPV6)) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on TTL requires protocol ip or ipv6"); + return -EOPNOTSUPP; + } + + if (udfs_cnt >= YT921X_UDF_NUM) + goto err; + + udfs[udfs_cnt] = (struct yt921x_udf_entry){ + .type = YT921X_UDF_TYPE_L3, + .offset = n_proto == htons(ETH_P_IP) ? 8 : 7, + .key = match.key->ttl, + .mask = match.mask->ttl, + }; + udfs_cnt++; } if (match.mask->tos) { @@ -889,6 +933,82 @@ yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, } } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP)) { + struct flow_match_icmp match; + + flow_rule_match_icmp(rule, &match); + + if (match.mask->type || match.mask->code) { + if (ip_proto != IPPROTO_ICMP && + ip_proto != IPPROTO_ICMPV6) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on ICMP type/code requires ip_proto icmp or icmpv6"); + return -EOPNOTSUPP; + } + + if (match.mask->type) { + if (udfs_cnt >= YT921X_UDF_NUM) + goto err; + + udfs[udfs_cnt] = (struct yt921x_udf_entry){ + .type = YT921X_UDF_TYPE_L4, + .offset = 0, + .key = match.key->type, + .mask = match.mask->type, + }; + udfs_cnt++; + } + + if (match.mask->code) { + if (udfs_cnt >= YT921X_UDF_NUM) + goto err; + + udfs[udfs_cnt] = (struct yt921x_udf_entry){ + .type = YT921X_UDF_TYPE_L4, + .offset = 1, + .key = match.key->code, + .mask = match.mask->code, + }; + udfs_cnt++; + } + } + } + + /* Compile UDFs */ + for (unsigned int i = 0; i < udfs_cnt; i++) { + unsigned int o; + u32 mask; + u32 key; + + for (o = 0; o < ARRAY_SIZE(yt921x_udf_maps); o++) + if (udfs[i].type == yt921x_udf_maps[o].type && + (udfs[i].offset == yt921x_udf_maps[o].offset || + udfs[i].offset == yt921x_udf_maps[o].offset + 1)) + break; + + if (WARN_ON(o == ARRAY_SIZE(yt921x_udf_maps))) + return -EOPNOTSUPP; + + entry = yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_UDF0 + o / 2); + if (!entry) + goto err; + + key = udfs[i].key; + mask = udfs[i].mask; + if (udfs[i].offset == yt921x_udf_maps[o].offset) { + key <<= 8; + mask <<= 8; + } + if (!(o % 2)) { + key <<= 16; + mask <<= 16; + } + + entry->key[0] |= key; + entry->mask[0] |= mask; + } + if (!size) { NL_SET_ERR_MSG_MOD(extack, "Empty rule generated, this should not happen"); return -EOPNOTSUPP; @@ -1579,5 +1699,13 @@ int yt921x_chip_setup_acl(struct yt921x_priv *priv) if (res) return res; + for (unsigned int o = 0; o < ARRAY_SIZE(yt921x_udf_maps); o++) { + ctrl = YT921X_UDF_CTRL_UDF_OFFSET(yt921x_udf_maps[o].offset) | + YT921X_UDF_CTRL_UDF_TYPE(yt921x_udf_maps[o].type); + res = yt921x_reg_write(priv, YT921X_UDFn_CTRL(o), ctrl); + if (res) + return res; + } + return 0; } diff --git a/drivers/net/dsa/motorcomm/tc.h b/drivers/net/dsa/motorcomm/tc.h index f11136a1c5e2..cc53f148d690 100644 --- a/drivers/net/dsa/motorcomm/tc.h +++ b/drivers/net/dsa/motorcomm/tc.h @@ -118,6 +118,9 @@ enum yt921x_acl_type { YT921X_ACL_TYPE_IPV6_SA3, YT921X_ACL_TYPE_MISC, YT921X_ACL_TYPE_L4, + /* Each User Defined Filter entry contains 2 UDF windows (UDF_CTRL 2i + * and 2i+1) + */ YT921X_ACL_TYPE_UDF0, YT921X_ACL_TYPE_UDF1, YT921X_ACL_TYPE_UDF2, @@ -255,12 +258,15 @@ enum yt921x_l4_type { #define YT921X_UDFn_CTRL(x) (0x210094 + 4 * (x)) #define YT921X_UDF_CTRL_UDF_TYPE_M GENMASK(8, 7) #define YT921X_UDF_CTRL_UDF_TYPE(x) FIELD_PREP(YT921X_UDF_CTRL_UDF_TYPE_M, (x)) -#define YT921X_UDF_CTRL_UDF_TYPE_ETH YT921X_UDF_CTRL_UDF_TYPE(0) -#define YT921X_UDF_CTRL_UDF_TYPE_L3 YT921X_UDF_CTRL_UDF_TYPE(1) -#define YT921X_UDF_CTRL_UDF_TYPE_L4 YT921X_UDF_CTRL_UDF_TYPE(2) #define YT921X_UDF_CTRL_UDF_OFFSET_M GENMASK(6, 0) #define YT921X_UDF_CTRL_UDF_OFFSET(x) FIELD_PREP(YT921X_UDF_CTRL_UDF_OFFSET_M, (x)) +enum yt921x_udf_type { + YT921X_UDF_TYPE_L2, + YT921X_UDF_TYPE_L3, + YT921X_UDF_TYPE_L4, +}; + #define YT921X_PORTn_RATE(port) (0x220000 + 4 * (port)) #define YT921X_PORT_RATE_GAP_VALUE GENMASK(4, 0) /* default 20 */ #define YT921X_METER_SLOT 0x220104 |
