Merge tag 'seccomp-v6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[linux.git] / drivers / net / dsa / microchip / ksz9477_tc_flower.c
blobca7830ab168ac291575bdd18f15a04ac2a7caaf7
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
4 #include "ksz9477.h"
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
11 /**
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.
15 * @port: Port number.
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;
35 int required_entries;
36 u8 *src_mac = NULL;
37 u8 *dst_mac = NULL;
38 u16 ethtype = 0;
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");
49 return -EINVAL;
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;
74 acles = &acl->acles;
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");
81 return -EOPNOTSUPP;
84 ksz9477_acl_match_process_l2(dev, port, ethtype, src_mac, dst_mac,
85 cookie, prio);
87 return 0;
89 not_full_mask_err:
90 NL_SET_ERR_MSG_MOD(extack, "MAC address mask must be a full mask");
91 return -EOPNOTSUPP;
94 /**
95 * ksz9477_flower_parse_key - Parse flow rule keys for a specified port on a
96 * ksz_device.
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;
116 int ret;
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");
124 return -EOPNOTSUPP;
127 if (flow_rule_match_has_control_flags(rule, extack))
128 return -EOPNOTSUPP;
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,
133 cookie, prio);
134 if (ret)
135 return ret;
138 return 0;
142 * ksz9477_flower_parse_action - Parse flow rule actions for a specified port
143 * on a ksz_device.
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
153 * extended ACK.
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,
160 int entry_idx)
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;
167 u8 prio_val = 0;
168 int i;
170 if (TC_H_MIN(cls->classid)) {
171 NL_SET_ERR_MSG_MOD(extack, "hw_tc is not supported. Use: action skbedit prio");
172 return -EOPNOTSUPP;
175 flow_action_for_each(i, act, &rule->action) {
176 switch (act->id) {
177 case FLOW_ACTION_PRIORITY:
178 if (act->priority > KSZ9477_MAX_TC) {
179 NL_SET_ERR_MSG_MOD(extack, "Priority value is too high");
180 return -EOPNOTSUPP;
182 prio_force = true;
183 prio_val = act->priority;
184 break;
185 default:
186 NL_SET_ERR_MSG_MOD(extack, "action not supported");
187 return -EOPNOTSUPP;
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);
197 return 0;
201 * ksz9477_cls_flower_add - Add a flow classification rule for a specified port
202 * on a ksz_device.
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;
223 int ret;
225 acl = dev->ports[port].acl_priv;
227 if (!acl) {
228 NL_SET_ERR_MSG_MOD(extack, "ACL offloading is not supported");
229 return -EOPNOTSUPP;
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,
238 cls->common.prio);
239 if (ret)
240 return ret;
242 ret = ksz9477_flower_parse_action(dev, port, extack, cls,
243 action_entry_idx);
244 if (ret)
245 return ret;
247 ret = ksz9477_sort_acl_entries(dev, port);
248 if (ret)
249 return ret;
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;
278 if (!acl)
279 return -EOPNOTSUPP;
281 ksz9477_acl_remove_entries(dev, port, &acl->acles, cookie);
283 return ksz9477_acl_write_list(dev, port);