1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include "lan966x_main.h"
4 #include "vcap_api.h"
5 #include "vcap_api_client.h"
6 #include "vcap_tc.h"
7 
8 static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st,
9 				      u16 etype)
10 {
11 	switch (st->admin->vtype) {
12 	case VCAP_TYPE_IS1:
13 		switch (etype) {
14 		case ETH_P_ALL:
15 		case ETH_P_ARP:
16 		case ETH_P_IP:
17 		case ETH_P_IPV6:
18 			return true;
19 		}
20 		break;
21 	case VCAP_TYPE_IS2:
22 		switch (etype) {
23 		case ETH_P_ALL:
24 		case ETH_P_ARP:
25 		case ETH_P_IP:
26 		case ETH_P_IPV6:
27 		case ETH_P_SNAP:
28 		case ETH_P_802_2:
29 			return true;
30 		}
31 		break;
32 	default:
33 		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
34 				   "VCAP type not supported");
35 		return false;
36 	}
37 
38 	return false;
39 }
40 
41 static int
42 lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
43 {
44 	struct flow_match_control match;
45 	int err = 0;
46 
47 	flow_rule_match_control(st->frule, &match);
48 	if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) {
49 		if (match.key->flags & FLOW_DIS_IS_FRAGMENT)
50 			err = vcap_rule_add_key_bit(st->vrule,
51 						    VCAP_KF_L3_FRAGMENT,
52 						    VCAP_BIT_1);
53 		else
54 			err = vcap_rule_add_key_bit(st->vrule,
55 						    VCAP_KF_L3_FRAGMENT,
56 						    VCAP_BIT_0);
57 		if (err)
58 			goto out;
59 	}
60 
61 	if (match.mask->flags & FLOW_DIS_FIRST_FRAG) {
62 		if (match.key->flags & FLOW_DIS_FIRST_FRAG)
63 			err = vcap_rule_add_key_bit(st->vrule,
64 						    VCAP_KF_L3_FRAG_OFS_GT0,
65 						    VCAP_BIT_0);
66 		else
67 			err = vcap_rule_add_key_bit(st->vrule,
68 						    VCAP_KF_L3_FRAG_OFS_GT0,
69 						    VCAP_BIT_1);
70 		if (err)
71 			goto out;
72 	}
73 
74 	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
75 
76 	return err;
77 
78 out:
79 	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
80 	return err;
81 }
82 
83 static int
84 lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
85 {
86 	struct flow_match_basic match;
87 	int err = 0;
88 
89 	flow_rule_match_basic(st->frule, &match);
90 	if (match.mask->n_proto) {
91 		st->l3_proto = be16_to_cpu(match.key->n_proto);
92 		if (!lan966x_tc_is_known_etype(st, st->l3_proto)) {
93 			err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
94 						    st->l3_proto, ~0);
95 			if (err)
96 				goto out;
97 		} else if (st->l3_proto == ETH_P_IP) {
98 			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
99 						    VCAP_BIT_1);
100 			if (err)
101 				goto out;
102 		} else if (st->l3_proto == ETH_P_IPV6 &&
103 			   st->admin->vtype == VCAP_TYPE_IS1) {
104 			/* Don't set any keys in this case */
105 		} else if (st->l3_proto == ETH_P_SNAP &&
106 			   st->admin->vtype == VCAP_TYPE_IS1) {
107 			err = vcap_rule_add_key_bit(st->vrule,
108 						    VCAP_KF_ETYPE_LEN_IS,
109 						    VCAP_BIT_0);
110 			if (err)
111 				goto out;
112 
113 			err = vcap_rule_add_key_bit(st->vrule,
114 						    VCAP_KF_IP_SNAP_IS,
115 						    VCAP_BIT_1);
116 			if (err)
117 				goto out;
118 		} else if (st->admin->vtype == VCAP_TYPE_IS1) {
119 			err = vcap_rule_add_key_bit(st->vrule,
120 						    VCAP_KF_ETYPE_LEN_IS,
121 						    VCAP_BIT_1);
122 			if (err)
123 				goto out;
124 
125 			err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
126 						    st->l3_proto, ~0);
127 			if (err)
128 				goto out;
129 		}
130 	}
131 	if (match.mask->ip_proto) {
132 		st->l4_proto = match.key->ip_proto;
133 
134 		if (st->l4_proto == IPPROTO_TCP) {
135 			if (st->admin->vtype == VCAP_TYPE_IS1) {
136 				err = vcap_rule_add_key_bit(st->vrule,
137 							    VCAP_KF_TCP_UDP_IS,
138 							    VCAP_BIT_1);
139 				if (err)
140 					goto out;
141 			}
142 
143 			err = vcap_rule_add_key_bit(st->vrule,
144 						    VCAP_KF_TCP_IS,
145 						    VCAP_BIT_1);
146 			if (err)
147 				goto out;
148 		} else if (st->l4_proto == IPPROTO_UDP) {
149 			if (st->admin->vtype == VCAP_TYPE_IS1) {
150 				err = vcap_rule_add_key_bit(st->vrule,
151 							    VCAP_KF_TCP_UDP_IS,
152 							    VCAP_BIT_1);
153 				if (err)
154 					goto out;
155 			}
156 
157 			err = vcap_rule_add_key_bit(st->vrule,
158 						    VCAP_KF_TCP_IS,
159 						    VCAP_BIT_0);
160 			if (err)
161 				goto out;
162 		} else {
163 			err = vcap_rule_add_key_u32(st->vrule,
164 						    VCAP_KF_L3_IP_PROTO,
165 						    st->l4_proto, ~0);
166 			if (err)
167 				goto out;
168 		}
169 	}
170 
171 	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
172 	return err;
173 out:
174 	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
175 	return err;
176 }
177 
178 static int
179 lan966x_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
180 {
181 	if (st->admin->vtype != VCAP_TYPE_IS1) {
182 		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
183 				   "cvlan not supported in this VCAP");
184 		return -EINVAL;
185 	}
186 
187 	return vcap_tc_flower_handler_cvlan_usage(st);
188 }
189 
190 static int
191 lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
192 {
193 	enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
194 	enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
195 
196 	if (st->admin->vtype == VCAP_TYPE_IS1) {
197 		vid_key = VCAP_KF_8021Q_VID0;
198 		pcp_key = VCAP_KF_8021Q_PCP0;
199 	}
200 
201 	return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
202 }
203 
204 static int
205 (*lan966x_tc_flower_handlers_usage[])(struct vcap_tc_flower_parse_usage *st) = {
206 	[FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
207 	[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
208 	[FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
209 	[FLOW_DISSECTOR_KEY_CONTROL] = lan966x_tc_flower_handler_control_usage,
210 	[FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
211 	[FLOW_DISSECTOR_KEY_BASIC] = lan966x_tc_flower_handler_basic_usage,
212 	[FLOW_DISSECTOR_KEY_CVLAN] = lan966x_tc_flower_handler_cvlan_usage,
213 	[FLOW_DISSECTOR_KEY_VLAN] = lan966x_tc_flower_handler_vlan_usage,
214 	[FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
215 	[FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
216 	[FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
217 };
218 
219 static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
220 					    struct vcap_admin *admin,
221 					    struct vcap_rule *vrule,
222 					    u16 *l3_proto)
223 {
224 	struct vcap_tc_flower_parse_usage state = {
225 		.fco = f,
226 		.vrule = vrule,
227 		.l3_proto = ETH_P_ALL,
228 		.admin = admin,
229 	};
230 	int err = 0;
231 
232 	state.frule = flow_cls_offload_flow_rule(f);
233 	for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) {
234 		if (!flow_rule_match_key(state.frule, i) ||
235 		    !lan966x_tc_flower_handlers_usage[i])
236 			continue;
237 
238 		err = lan966x_tc_flower_handlers_usage[i](&state);
239 		if (err)
240 			return err;
241 	}
242 
243 	if (l3_proto)
244 		*l3_proto = state.l3_proto;
245 
246 	return err;
247 }
248 
249 static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
250 					  struct net_device *dev,
251 					  struct flow_cls_offload *fco,
252 					  bool ingress)
253 {
254 	struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
255 	struct flow_action_entry *actent, *last_actent = NULL;
256 	struct flow_action *act = &rule->action;
257 	u64 action_mask = 0;
258 	int idx;
259 
260 	if (!flow_action_has_entries(act)) {
261 		NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
262 		return -EINVAL;
263 	}
264 
265 	if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
266 		return -EOPNOTSUPP;
267 
268 	flow_action_for_each(idx, actent, act) {
269 		if (action_mask & BIT(actent->id)) {
270 			NL_SET_ERR_MSG_MOD(fco->common.extack,
271 					   "More actions of the same type");
272 			return -EINVAL;
273 		}
274 		action_mask |= BIT(actent->id);
275 		last_actent = actent; /* Save last action for later check */
276 	}
277 
278 	/* Check that last action is a goto
279 	 * The last chain/lookup does not need to have goto action
280 	 */
281 	if (last_actent->id == FLOW_ACTION_GOTO) {
282 		/* Check if the destination chain is in one of the VCAPs */
283 		if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
284 					 last_actent->chain_index)) {
285 			NL_SET_ERR_MSG_MOD(fco->common.extack,
286 					   "Invalid goto chain");
287 			return -EINVAL;
288 		}
289 	} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
290 				       ingress)) {
291 		NL_SET_ERR_MSG_MOD(fco->common.extack,
292 				   "Last action must be 'goto'");
293 		return -EINVAL;
294 	}
295 
296 	/* Catch unsupported combinations of actions */
297 	if (action_mask & BIT(FLOW_ACTION_TRAP) &&
298 	    action_mask & BIT(FLOW_ACTION_ACCEPT)) {
299 		NL_SET_ERR_MSG_MOD(fco->common.extack,
300 				   "Cannot combine pass and trap action");
301 		return -EOPNOTSUPP;
302 	}
303 
304 	return 0;
305 }
306 
307 /* Add the actionset that is the default for the VCAP type */
308 static int lan966x_tc_set_actionset(struct vcap_admin *admin,
309 				    struct vcap_rule *vrule)
310 {
311 	enum vcap_actionfield_set aset;
312 	int err = 0;
313 
314 	switch (admin->vtype) {
315 	case VCAP_TYPE_IS1:
316 		aset = VCAP_AFS_S1;
317 		break;
318 	case VCAP_TYPE_IS2:
319 		aset = VCAP_AFS_BASE_TYPE;
320 		break;
321 	default:
322 		return -EINVAL;
323 	}
324 
325 	/* Do not overwrite any current actionset */
326 	if (vrule->actionset == VCAP_AFS_NO_VALUE)
327 		err = vcap_set_rule_set_actionset(vrule, aset);
328 
329 	return err;
330 }
331 
332 static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin,
333 					   struct vcap_rule *vrule,
334 					   int target_cid)
335 {
336 	int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
337 	int err;
338 
339 	if (!link_val)
340 		return 0;
341 
342 	switch (admin->vtype) {
343 	case VCAP_TYPE_IS1:
344 		/* Choose IS1 specific NXT_IDX key (for chaining rules from IS1) */
345 		err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
346 					    1, ~0);
347 		if (err)
348 			return err;
349 
350 		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
351 					     link_val, ~0);
352 	case VCAP_TYPE_IS2:
353 		/* Add IS2 specific PAG key (for chaining rules from IS1) */
354 		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
355 					     link_val, ~0);
356 	default:
357 		break;
358 	}
359 	return 0;
360 }
361 
362 static int lan966x_tc_add_rule_link(struct vcap_control *vctrl,
363 				    struct vcap_admin *admin,
364 				    struct vcap_rule *vrule,
365 				    struct flow_cls_offload *f,
366 				    int to_cid)
367 {
368 	struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
369 	int diff, err = 0;
370 
371 	if (!to_admin) {
372 		NL_SET_ERR_MSG_MOD(f->common.extack,
373 				   "Unknown destination chain");
374 		return -EINVAL;
375 	}
376 
377 	diff = vcap_chain_offset(vctrl, f->common.chain_index, to_cid);
378 	if (!diff)
379 		return 0;
380 
381 	/* Between IS1 and IS2 the PAG value is used */
382 	if (admin->vtype == VCAP_TYPE_IS1 && to_admin->vtype == VCAP_TYPE_IS2) {
383 		/* This works for IS1->IS2 */
384 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
385 		if (err)
386 			return err;
387 
388 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_OVERRIDE_MASK,
389 					       0xff);
390 		if (err)
391 			return err;
392 	} else {
393 		NL_SET_ERR_MSG_MOD(f->common.extack,
394 				   "Unsupported chain destination");
395 		return -EOPNOTSUPP;
396 	}
397 
398 	return err;
399 }
400 
401 static int lan966x_tc_flower_add(struct lan966x_port *port,
402 				 struct flow_cls_offload *f,
403 				 struct vcap_admin *admin,
404 				 bool ingress)
405 {
406 	struct flow_action_entry *act;
407 	u16 l3_proto = ETH_P_ALL;
408 	struct flow_rule *frule;
409 	struct vcap_rule *vrule;
410 	int err, idx;
411 
412 	err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl,
413 					     port->dev, f, ingress);
414 	if (err)
415 		return err;
416 
417 	vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev,
418 				f->common.chain_index, VCAP_USER_TC,
419 				f->common.prio, 0);
420 	if (IS_ERR(vrule))
421 		return PTR_ERR(vrule);
422 
423 	vrule->cookie = f->cookie;
424 	err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto);
425 	if (err)
426 		goto out;
427 
428 	err = lan966x_tc_add_rule_link_target(admin, vrule,
429 					      f->common.chain_index);
430 	if (err)
431 		goto out;
432 
433 	frule = flow_cls_offload_flow_rule(f);
434 
435 	flow_action_for_each(idx, act, &frule->action) {
436 		switch (act->id) {
437 		case FLOW_ACTION_TRAP:
438 			if (admin->vtype != VCAP_TYPE_IS2) {
439 				NL_SET_ERR_MSG_MOD(f->common.extack,
440 						   "Trap action not supported in this VCAP");
441 				err = -EOPNOTSUPP;
442 				goto out;
443 			}
444 
445 			err = vcap_rule_add_action_bit(vrule,
446 						       VCAP_AF_CPU_COPY_ENA,
447 						       VCAP_BIT_1);
448 			err |= vcap_rule_add_action_u32(vrule,
449 							VCAP_AF_CPU_QUEUE_NUM,
450 							0);
451 			err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
452 							LAN966X_PMM_REPLACE);
453 			if (err)
454 				goto out;
455 
456 			break;
457 		case FLOW_ACTION_GOTO:
458 			err = lan966x_tc_set_actionset(admin, vrule);
459 			if (err)
460 				goto out;
461 
462 			err = lan966x_tc_add_rule_link(port->lan966x->vcap_ctrl,
463 						       admin, vrule,
464 						       f, act->chain_index);
465 			if (err)
466 				goto out;
467 
468 			break;
469 		default:
470 			NL_SET_ERR_MSG_MOD(f->common.extack,
471 					   "Unsupported TC action");
472 			err = -EOPNOTSUPP;
473 			goto out;
474 		}
475 	}
476 
477 	err = vcap_val_rule(vrule, l3_proto);
478 	if (err) {
479 		vcap_set_tc_exterr(f, vrule);
480 		goto out;
481 	}
482 
483 	err = vcap_add_rule(vrule);
484 	if (err)
485 		NL_SET_ERR_MSG_MOD(f->common.extack,
486 				   "Could not add the filter");
487 out:
488 	vcap_free_rule(vrule);
489 	return err;
490 }
491 
492 static int lan966x_tc_flower_del(struct lan966x_port *port,
493 				 struct flow_cls_offload *f,
494 				 struct vcap_admin *admin)
495 {
496 	struct vcap_control *vctrl;
497 	int err = -ENOENT, rule_id;
498 
499 	vctrl = port->lan966x->vcap_ctrl;
500 	while (true) {
501 		rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie);
502 		if (rule_id <= 0)
503 			break;
504 
505 		err = vcap_del_rule(vctrl, port->dev, rule_id);
506 		if (err) {
507 			NL_SET_ERR_MSG_MOD(f->common.extack,
508 					   "Cannot delete rule");
509 			break;
510 		}
511 	}
512 
513 	return err;
514 }
515 
516 static int lan966x_tc_flower_stats(struct lan966x_port *port,
517 				   struct flow_cls_offload *f,
518 				   struct vcap_admin *admin)
519 {
520 	struct vcap_counter count = {};
521 	int err;
522 
523 	err = vcap_get_rule_count_by_cookie(port->lan966x->vcap_ctrl,
524 					    &count, f->cookie);
525 	if (err)
526 		return err;
527 
528 	flow_stats_update(&f->stats, 0x0, count.value, 0, 0,
529 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
530 
531 	return err;
532 }
533 
534 int lan966x_tc_flower(struct lan966x_port *port,
535 		      struct flow_cls_offload *f,
536 		      bool ingress)
537 {
538 	struct vcap_admin *admin;
539 
540 	admin = vcap_find_admin(port->lan966x->vcap_ctrl,
541 				f->common.chain_index);
542 	if (!admin) {
543 		NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain");
544 		return -EINVAL;
545 	}
546 
547 	switch (f->command) {
548 	case FLOW_CLS_REPLACE:
549 		return lan966x_tc_flower_add(port, f, admin, ingress);
550 	case FLOW_CLS_DESTROY:
551 		return lan966x_tc_flower_del(port, f, admin);
552 	case FLOW_CLS_STATS:
553 		return lan966x_tc_flower_stats(port, f, admin);
554 	default:
555 		return -EOPNOTSUPP;
556 	}
557 
558 	return 0;
559 }
560