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