1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
5 #include "ksz9477_reg.h"
6 #include "ksz_common.h"
8 #define ETHER_TYPE_FULL_MASK cpu_to_be16(~0)
9 #define KSZ9477_MAX_TC 7
12 * ksz9477_flower_parse_key_l2 - Parse Layer 2 key from flow rule and configure
13 * ACL entries accordingly.
14 * @dev: Pointer to the ksz_device.
16 * @extack: Pointer to the netlink_ext_ack.
17 * @rule: Pointer to the flow_rule.
18 * @cookie: The cookie to associate with the entry.
19 * @prio: The priority of the entry.
21 * This function parses the Layer 2 key from the flow rule and configures
22 * the corresponding ACL entries. It checks for unsupported offloads and
23 * available entries before proceeding with the configuration.
25 * Returns: 0 on success or a negative error code on failure.
27 static int ksz9477_flower_parse_key_l2(struct ksz_device
*dev
, int port
,
28 struct netlink_ext_ack
*extack
,
29 struct flow_rule
*rule
,
30 unsigned long cookie
, u32 prio
)
32 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
33 struct flow_match_eth_addrs ematch
;
34 struct ksz9477_acl_entries
*acles
;
40 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_BASIC
)) {
41 struct flow_match_basic match
;
43 flow_rule_match_basic(rule
, &match
);
45 if (match
.key
->n_proto
) {
46 if (match
.mask
->n_proto
!= ETHER_TYPE_FULL_MASK
) {
47 NL_SET_ERR_MSG_MOD(extack
,
48 "ethernet type mask must be a full mask");
52 ethtype
= be16_to_cpu(match
.key
->n_proto
);
56 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_ETH_ADDRS
)) {
57 flow_rule_match_eth_addrs(rule
, &ematch
);
59 if (!is_zero_ether_addr(ematch
.key
->src
)) {
60 if (!is_broadcast_ether_addr(ematch
.mask
->src
))
61 goto not_full_mask_err
;
63 src_mac
= ematch
.key
->src
;
66 if (!is_zero_ether_addr(ematch
.key
->dst
)) {
67 if (!is_broadcast_ether_addr(ematch
.mask
->dst
))
68 goto not_full_mask_err
;
70 dst_mac
= ematch
.key
->dst
;
75 /* ACL supports only one MAC per entry */
76 required_entries
= src_mac
&& dst_mac
? 2 : 1;
78 /* Check if there are enough available entries */
79 if (acles
->entries_count
+ required_entries
> KSZ9477_ACL_MAX_ENTRIES
) {
80 NL_SET_ERR_MSG_MOD(extack
, "ACL entry limit reached");
84 ksz9477_acl_match_process_l2(dev
, port
, ethtype
, src_mac
, dst_mac
,
90 NL_SET_ERR_MSG_MOD(extack
, "MAC address mask must be a full mask");
95 * ksz9477_flower_parse_key - Parse flow rule keys for a specified port on a
97 * @dev: The ksz_device instance.
98 * @port: The port number to parse the flow rule keys for.
99 * @extack: The netlink extended ACK for reporting errors.
100 * @rule: The flow_rule to parse.
101 * @cookie: The cookie to associate with the entry.
102 * @prio: The priority of the entry.
104 * This function checks if the used keys in the flow rule are supported by
105 * the device and parses the L2 keys if they match. If unsupported keys are
106 * used, an error message is set in the extended ACK.
108 * Returns: 0 on success or a negative error code on failure.
110 static int ksz9477_flower_parse_key(struct ksz_device
*dev
, int port
,
111 struct netlink_ext_ack
*extack
,
112 struct flow_rule
*rule
,
113 unsigned long cookie
, u32 prio
)
115 struct flow_dissector
*dissector
= rule
->match
.dissector
;
118 if (dissector
->used_keys
&
119 ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC
) |
120 BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
121 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL
))) {
122 NL_SET_ERR_MSG_MOD(extack
,
123 "Unsupported keys used");
127 if (flow_rule_match_has_control_flags(rule
, extack
))
130 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_BASIC
) ||
131 flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_ETH_ADDRS
)) {
132 ret
= ksz9477_flower_parse_key_l2(dev
, port
, extack
, rule
,
142 * ksz9477_flower_parse_action - Parse flow rule actions for a specified port
144 * @dev: The ksz_device instance.
145 * @port: The port number to parse the flow rule actions for.
146 * @extack: The netlink extended ACK for reporting errors.
147 * @cls: The flow_cls_offload instance containing the flow rule.
148 * @entry_idx: The index of the ACL entry to store the action.
150 * This function checks if the actions in the flow rule are supported by
151 * the device. Currently, only actions that change priorities are supported.
152 * If unsupported actions are encountered, an error message is set in the
155 * Returns: 0 on success or a negative error code on failure.
157 static int ksz9477_flower_parse_action(struct ksz_device
*dev
, int port
,
158 struct netlink_ext_ack
*extack
,
159 struct flow_cls_offload
*cls
,
162 struct flow_rule
*rule
= flow_cls_offload_flow_rule(cls
);
163 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
164 const struct flow_action_entry
*act
;
165 struct ksz9477_acl_entry
*entry
;
166 bool prio_force
= false;
170 if (TC_H_MIN(cls
->classid
)) {
171 NL_SET_ERR_MSG_MOD(extack
, "hw_tc is not supported. Use: action skbedit prio");
175 flow_action_for_each(i
, act
, &rule
->action
) {
177 case FLOW_ACTION_PRIORITY
:
178 if (act
->priority
> KSZ9477_MAX_TC
) {
179 NL_SET_ERR_MSG_MOD(extack
, "Priority value is too high");
183 prio_val
= act
->priority
;
186 NL_SET_ERR_MSG_MOD(extack
, "action not supported");
191 /* pick entry to store action */
192 entry
= &acl
->acles
.entries
[entry_idx
];
194 ksz9477_acl_action_rule_cfg(entry
->entry
, prio_force
, prio_val
);
195 ksz9477_acl_processing_rule_set_action(entry
->entry
, entry_idx
);
201 * ksz9477_cls_flower_add - Add a flow classification rule for a specified port
203 * @ds: The DSA switch instance.
204 * @port: The port number to add the flow classification rule to.
205 * @cls: The flow_cls_offload instance containing the flow rule.
206 * @ingress: A flag indicating if the rule is applied on the ingress path.
208 * This function adds a flow classification rule for a specified port on a
209 * ksz_device. It checks if the ACL offloading is supported and parses the flow
210 * keys and actions. If the ACL is not supported, it returns an error. If there
211 * are unprocessed entries, it parses the action for the rule.
213 * Returns: 0 on success or a negative error code on failure.
215 int ksz9477_cls_flower_add(struct dsa_switch
*ds
, int port
,
216 struct flow_cls_offload
*cls
, bool ingress
)
218 struct flow_rule
*rule
= flow_cls_offload_flow_rule(cls
);
219 struct netlink_ext_ack
*extack
= cls
->common
.extack
;
220 struct ksz_device
*dev
= ds
->priv
;
221 struct ksz9477_acl_priv
*acl
;
222 int action_entry_idx
;
225 acl
= dev
->ports
[port
].acl_priv
;
228 NL_SET_ERR_MSG_MOD(extack
, "ACL offloading is not supported");
232 /* A complex rule set can take multiple entries. Use first entry
233 * to store the action.
235 action_entry_idx
= acl
->acles
.entries_count
;
237 ret
= ksz9477_flower_parse_key(dev
, port
, extack
, rule
, cls
->cookie
,
242 ret
= ksz9477_flower_parse_action(dev
, port
, extack
, cls
,
247 ret
= ksz9477_sort_acl_entries(dev
, port
);
251 return ksz9477_acl_write_list(dev
, port
);
255 * ksz9477_cls_flower_del - Remove a flow classification rule for a specified
256 * port on a ksz_device.
257 * @ds: The DSA switch instance.
258 * @port: The port number to remove the flow classification rule from.
259 * @cls: The flow_cls_offload instance containing the flow rule.
260 * @ingress: A flag indicating if the rule is applied on the ingress path.
262 * This function removes a flow classification rule for a specified port on a
263 * ksz_device. It checks if the ACL is initialized, and if not, returns an
264 * error. If the ACL is initialized, it removes entries with the specified
265 * cookie and rewrites the ACL list.
267 * Returns: 0 on success or a negative error code on failure.
269 int ksz9477_cls_flower_del(struct dsa_switch
*ds
, int port
,
270 struct flow_cls_offload
*cls
, bool ingress
)
272 unsigned long cookie
= cls
->cookie
;
273 struct ksz_device
*dev
= ds
->priv
;
274 struct ksz9477_acl_priv
*acl
;
276 acl
= dev
->ports
[port
].acl_priv
;
281 ksz9477_acl_remove_entries(dev
, port
, &acl
->acles
, cookie
);
283 return ksz9477_acl_write_list(dev
, port
);