1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
3 
4 #include "prestera.h"
5 #include "prestera_acl.h"
6 #include "prestera_flower.h"
7 
8 static int prestera_flower_parse_actions(struct prestera_flow_block *block,
9 					 struct prestera_acl_rule *rule,
10 					 struct flow_action *flow_action,
11 					 struct netlink_ext_ack *extack)
12 {
13 	struct prestera_acl_rule_action_entry a_entry;
14 	const struct flow_action_entry *act;
15 	int err, i;
16 
17 	if (!flow_action_has_entries(flow_action))
18 		return 0;
19 
20 	flow_action_for_each(i, act, flow_action) {
21 		memset(&a_entry, 0, sizeof(a_entry));
22 
23 		switch (act->id) {
24 		case FLOW_ACTION_ACCEPT:
25 			a_entry.id = PRESTERA_ACL_RULE_ACTION_ACCEPT;
26 			break;
27 		case FLOW_ACTION_DROP:
28 			a_entry.id = PRESTERA_ACL_RULE_ACTION_DROP;
29 			break;
30 		case FLOW_ACTION_TRAP:
31 			a_entry.id = PRESTERA_ACL_RULE_ACTION_TRAP;
32 			break;
33 		default:
34 			NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
35 			pr_err("Unsupported action\n");
36 			return -EOPNOTSUPP;
37 		}
38 
39 		err = prestera_acl_rule_action_add(rule, &a_entry);
40 		if (err)
41 			return err;
42 	}
43 
44 	return 0;
45 }
46 
47 static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
48 				      struct flow_cls_offload *f,
49 				      struct prestera_flow_block *block)
50 {
51 	struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
52 	struct prestera_acl_rule_match_entry m_entry = {0};
53 	struct net_device *ingress_dev;
54 	struct flow_match_meta match;
55 	struct prestera_port *port;
56 
57 	flow_rule_match_meta(f_rule, &match);
58 	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
59 		NL_SET_ERR_MSG_MOD(f->common.extack,
60 				   "Unsupported ingress ifindex mask");
61 		return -EINVAL;
62 	}
63 
64 	ingress_dev = __dev_get_by_index(prestera_acl_block_net(block),
65 					 match.key->ingress_ifindex);
66 	if (!ingress_dev) {
67 		NL_SET_ERR_MSG_MOD(f->common.extack,
68 				   "Can't find specified ingress port to match on");
69 		return -EINVAL;
70 	}
71 
72 	if (!prestera_netdev_check(ingress_dev)) {
73 		NL_SET_ERR_MSG_MOD(f->common.extack,
74 				   "Can't match on switchdev ingress port");
75 		return -EINVAL;
76 	}
77 	port = netdev_priv(ingress_dev);
78 
79 	m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT;
80 	m_entry.keymask.u64.key = port->hw_id | ((u64)port->dev_id << 32);
81 	m_entry.keymask.u64.mask = ~(u64)0;
82 
83 	return prestera_acl_rule_match_add(rule, &m_entry);
84 }
85 
86 static int prestera_flower_parse(struct prestera_flow_block *block,
87 				 struct prestera_acl_rule *rule,
88 				 struct flow_cls_offload *f)
89 {
90 	struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
91 	struct flow_dissector *dissector = f_rule->match.dissector;
92 	struct prestera_acl_rule_match_entry m_entry;
93 	u16 n_proto_mask = 0;
94 	u16 n_proto_key = 0;
95 	u16 addr_type = 0;
96 	u8 ip_proto = 0;
97 	int err;
98 
99 	if (dissector->used_keys &
100 	    ~(BIT(FLOW_DISSECTOR_KEY_META) |
101 	      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
102 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
103 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
104 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
105 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
106 	      BIT(FLOW_DISSECTOR_KEY_ICMP) |
107 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
108 	      BIT(FLOW_DISSECTOR_KEY_VLAN))) {
109 		NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
110 		return -EOPNOTSUPP;
111 	}
112 
113 	prestera_acl_rule_priority_set(rule, f->common.prio);
114 
115 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
116 		err = prestera_flower_parse_meta(rule, f, block);
117 		if (err)
118 			return err;
119 	}
120 
121 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
122 		struct flow_match_control match;
123 
124 		flow_rule_match_control(f_rule, &match);
125 		addr_type = match.key->addr_type;
126 	}
127 
128 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
129 		struct flow_match_basic match;
130 
131 		flow_rule_match_basic(f_rule, &match);
132 		n_proto_key = ntohs(match.key->n_proto);
133 		n_proto_mask = ntohs(match.mask->n_proto);
134 
135 		if (n_proto_key == ETH_P_ALL) {
136 			n_proto_key = 0;
137 			n_proto_mask = 0;
138 		}
139 
140 		/* add eth type key,mask */
141 		memset(&m_entry, 0, sizeof(m_entry));
142 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE;
143 		m_entry.keymask.u16.key = n_proto_key;
144 		m_entry.keymask.u16.mask = n_proto_mask;
145 		err = prestera_acl_rule_match_add(rule, &m_entry);
146 		if (err)
147 			return err;
148 
149 		/* add ip proto key,mask */
150 		memset(&m_entry, 0, sizeof(m_entry));
151 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO;
152 		m_entry.keymask.u8.key = match.key->ip_proto;
153 		m_entry.keymask.u8.mask = match.mask->ip_proto;
154 		err = prestera_acl_rule_match_add(rule, &m_entry);
155 		if (err)
156 			return err;
157 
158 		ip_proto = match.key->ip_proto;
159 	}
160 
161 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
162 		struct flow_match_eth_addrs match;
163 
164 		flow_rule_match_eth_addrs(f_rule, &match);
165 
166 		/* add ethernet dst key,mask */
167 		memset(&m_entry, 0, sizeof(m_entry));
168 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC;
169 		memcpy(&m_entry.keymask.mac.key,
170 		       &match.key->dst, sizeof(match.key->dst));
171 		memcpy(&m_entry.keymask.mac.mask,
172 		       &match.mask->dst, sizeof(match.mask->dst));
173 		err = prestera_acl_rule_match_add(rule, &m_entry);
174 		if (err)
175 			return err;
176 
177 		/* add ethernet src key,mask */
178 		memset(&m_entry, 0, sizeof(m_entry));
179 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC;
180 		memcpy(&m_entry.keymask.mac.key,
181 		       &match.key->src, sizeof(match.key->src));
182 		memcpy(&m_entry.keymask.mac.mask,
183 		       &match.mask->src, sizeof(match.mask->src));
184 		err = prestera_acl_rule_match_add(rule, &m_entry);
185 		if (err)
186 			return err;
187 	}
188 
189 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
190 		struct flow_match_ipv4_addrs match;
191 
192 		flow_rule_match_ipv4_addrs(f_rule, &match);
193 
194 		memset(&m_entry, 0, sizeof(m_entry));
195 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC;
196 		memcpy(&m_entry.keymask.u32.key,
197 		       &match.key->src, sizeof(match.key->src));
198 		memcpy(&m_entry.keymask.u32.mask,
199 		       &match.mask->src, sizeof(match.mask->src));
200 		err = prestera_acl_rule_match_add(rule, &m_entry);
201 		if (err)
202 			return err;
203 
204 		memset(&m_entry, 0, sizeof(m_entry));
205 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST;
206 		memcpy(&m_entry.keymask.u32.key,
207 		       &match.key->dst, sizeof(match.key->dst));
208 		memcpy(&m_entry.keymask.u32.mask,
209 		       &match.mask->dst, sizeof(match.mask->dst));
210 		err = prestera_acl_rule_match_add(rule, &m_entry);
211 		if (err)
212 			return err;
213 	}
214 
215 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
216 		struct flow_match_ports match;
217 
218 		if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
219 			NL_SET_ERR_MSG_MOD
220 			    (f->common.extack,
221 			     "Only UDP and TCP keys are supported");
222 			return -EINVAL;
223 		}
224 
225 		flow_rule_match_ports(f_rule, &match);
226 
227 		memset(&m_entry, 0, sizeof(m_entry));
228 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC;
229 		m_entry.keymask.u16.key = ntohs(match.key->src);
230 		m_entry.keymask.u16.mask = ntohs(match.mask->src);
231 		err = prestera_acl_rule_match_add(rule, &m_entry);
232 		if (err)
233 			return err;
234 
235 		memset(&m_entry, 0, sizeof(m_entry));
236 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST;
237 		m_entry.keymask.u16.key = ntohs(match.key->dst);
238 		m_entry.keymask.u16.mask = ntohs(match.mask->dst);
239 		err = prestera_acl_rule_match_add(rule, &m_entry);
240 		if (err)
241 			return err;
242 	}
243 
244 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
245 		struct flow_match_vlan match;
246 
247 		flow_rule_match_vlan(f_rule, &match);
248 
249 		if (match.mask->vlan_id != 0) {
250 			memset(&m_entry, 0, sizeof(m_entry));
251 			m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID;
252 			m_entry.keymask.u16.key = match.key->vlan_id;
253 			m_entry.keymask.u16.mask = match.mask->vlan_id;
254 			err = prestera_acl_rule_match_add(rule, &m_entry);
255 			if (err)
256 				return err;
257 		}
258 
259 		memset(&m_entry, 0, sizeof(m_entry));
260 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID;
261 		m_entry.keymask.u16.key = ntohs(match.key->vlan_tpid);
262 		m_entry.keymask.u16.mask = ntohs(match.mask->vlan_tpid);
263 		err = prestera_acl_rule_match_add(rule, &m_entry);
264 		if (err)
265 			return err;
266 	}
267 
268 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
269 		struct flow_match_icmp match;
270 
271 		flow_rule_match_icmp(f_rule, &match);
272 
273 		memset(&m_entry, 0, sizeof(m_entry));
274 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE;
275 		m_entry.keymask.u8.key = match.key->type;
276 		m_entry.keymask.u8.mask = match.mask->type;
277 		err = prestera_acl_rule_match_add(rule, &m_entry);
278 		if (err)
279 			return err;
280 
281 		memset(&m_entry, 0, sizeof(m_entry));
282 		m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE;
283 		m_entry.keymask.u8.key = match.key->code;
284 		m_entry.keymask.u8.mask = match.mask->code;
285 		err = prestera_acl_rule_match_add(rule, &m_entry);
286 		if (err)
287 			return err;
288 	}
289 
290 	return prestera_flower_parse_actions(block, rule,
291 					     &f->rule->action,
292 					     f->common.extack);
293 }
294 
295 int prestera_flower_replace(struct prestera_flow_block *block,
296 			    struct flow_cls_offload *f)
297 {
298 	struct prestera_switch *sw = prestera_acl_block_sw(block);
299 	struct prestera_acl_rule *rule;
300 	int err;
301 
302 	rule = prestera_acl_rule_create(block, f->cookie);
303 	if (IS_ERR(rule))
304 		return PTR_ERR(rule);
305 
306 	err = prestera_flower_parse(block, rule, f);
307 	if (err)
308 		goto err_flower_parse;
309 
310 	err = prestera_acl_rule_add(sw, rule);
311 	if (err)
312 		goto err_rule_add;
313 
314 	return 0;
315 
316 err_rule_add:
317 err_flower_parse:
318 	prestera_acl_rule_destroy(rule);
319 	return err;
320 }
321 
322 void prestera_flower_destroy(struct prestera_flow_block *block,
323 			     struct flow_cls_offload *f)
324 {
325 	struct prestera_acl_rule *rule;
326 	struct prestera_switch *sw;
327 
328 	rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
329 					f->cookie);
330 	if (rule) {
331 		sw = prestera_acl_block_sw(block);
332 		prestera_acl_rule_del(sw, rule);
333 		prestera_acl_rule_destroy(rule);
334 	}
335 }
336 
337 int prestera_flower_stats(struct prestera_flow_block *block,
338 			  struct flow_cls_offload *f)
339 {
340 	struct prestera_switch *sw = prestera_acl_block_sw(block);
341 	struct prestera_acl_rule *rule;
342 	u64 packets;
343 	u64 lastuse;
344 	u64 bytes;
345 	int err;
346 
347 	rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
348 					f->cookie);
349 	if (!rule)
350 		return -EINVAL;
351 
352 	err = prestera_acl_rule_get_stats(sw, rule, &packets, &bytes, &lastuse);
353 	if (err)
354 		return err;
355 
356 	flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
357 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
358 	return 0;
359 }
360