1
2
3
4#include "conntrack.h"
5
6const struct rhashtable_params nfp_tc_ct_merge_params = {
7 .head_offset = offsetof(struct nfp_fl_ct_tc_merge,
8 hash_node),
9 .key_len = sizeof(unsigned long) * 2,
10 .key_offset = offsetof(struct nfp_fl_ct_tc_merge, cookie),
11 .automatic_shrinking = true,
12};
13
14const struct rhashtable_params nfp_nft_ct_merge_params = {
15 .head_offset = offsetof(struct nfp_fl_nft_tc_merge,
16 hash_node),
17 .key_len = sizeof(unsigned long) * 3,
18 .key_offset = offsetof(struct nfp_fl_nft_tc_merge, cookie),
19 .automatic_shrinking = true,
20};
21
22static struct flow_action_entry *get_flow_act(struct flow_rule *rule,
23 enum flow_action_id act_id);
24
25
26
27
28
29
30
31
32
33
34
35static void *get_hashentry(struct rhashtable *ht, void *key,
36 const struct rhashtable_params params, size_t size)
37{
38 void *result;
39
40 result = rhashtable_lookup_fast(ht, key, params);
41
42 if (result)
43 return result;
44
45 result = kzalloc(size, GFP_KERNEL);
46 if (!result)
47 return ERR_PTR(-ENOMEM);
48
49 return result;
50}
51
52bool is_pre_ct_flow(struct flow_cls_offload *flow)
53{
54 struct flow_action_entry *act;
55 int i;
56
57 flow_action_for_each(i, act, &flow->rule->action) {
58 if (act->id == FLOW_ACTION_CT && !act->ct.action)
59 return true;
60 }
61 return false;
62}
63
64bool is_post_ct_flow(struct flow_cls_offload *flow)
65{
66 struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
67 struct flow_dissector *dissector = rule->match.dissector;
68 struct flow_match_ct ct;
69
70 if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT)) {
71 flow_rule_match_ct(rule, &ct);
72 if (ct.key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED)
73 return true;
74 }
75 return false;
76}
77
78static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
79 struct nfp_fl_ct_flow_entry *entry2)
80{
81 unsigned int ovlp_keys = entry1->rule->match.dissector->used_keys &
82 entry2->rule->match.dissector->used_keys;
83 bool out;
84
85
86
87
88 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) {
89 struct flow_match_control match1, match2;
90
91 flow_rule_match_control(entry1->rule, &match1);
92 flow_rule_match_control(entry2->rule, &match2);
93 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
94 if (out)
95 goto check_failed;
96 }
97
98 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) {
99 struct flow_match_basic match1, match2;
100
101 flow_rule_match_basic(entry1->rule, &match1);
102 flow_rule_match_basic(entry2->rule, &match2);
103 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
104 if (out)
105 goto check_failed;
106 }
107
108 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
109 struct flow_match_ipv4_addrs match1, match2;
110
111 flow_rule_match_ipv4_addrs(entry1->rule, &match1);
112 flow_rule_match_ipv4_addrs(entry2->rule, &match2);
113 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
114 if (out)
115 goto check_failed;
116 }
117
118 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
119 struct flow_match_ipv6_addrs match1, match2;
120
121 flow_rule_match_ipv6_addrs(entry1->rule, &match1);
122 flow_rule_match_ipv6_addrs(entry2->rule, &match2);
123 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
124 if (out)
125 goto check_failed;
126 }
127
128 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_PORTS)) {
129 struct flow_match_ports match1, match2;
130
131 flow_rule_match_ports(entry1->rule, &match1);
132 flow_rule_match_ports(entry2->rule, &match2);
133 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
134 if (out)
135 goto check_failed;
136 }
137
138 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
139 struct flow_match_eth_addrs match1, match2;
140
141 flow_rule_match_eth_addrs(entry1->rule, &match1);
142 flow_rule_match_eth_addrs(entry2->rule, &match2);
143 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
144 if (out)
145 goto check_failed;
146 }
147
148 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_VLAN)) {
149 struct flow_match_vlan match1, match2;
150
151 flow_rule_match_vlan(entry1->rule, &match1);
152 flow_rule_match_vlan(entry2->rule, &match2);
153 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
154 if (out)
155 goto check_failed;
156 }
157
158 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_MPLS)) {
159 struct flow_match_mpls match1, match2;
160
161 flow_rule_match_mpls(entry1->rule, &match1);
162 flow_rule_match_mpls(entry2->rule, &match2);
163 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
164 if (out)
165 goto check_failed;
166 }
167
168 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_TCP)) {
169 struct flow_match_tcp match1, match2;
170
171 flow_rule_match_tcp(entry1->rule, &match1);
172 flow_rule_match_tcp(entry2->rule, &match2);
173 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
174 if (out)
175 goto check_failed;
176 }
177
178 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IP)) {
179 struct flow_match_ip match1, match2;
180
181 flow_rule_match_ip(entry1->rule, &match1);
182 flow_rule_match_ip(entry2->rule, &match2);
183 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
184 if (out)
185 goto check_failed;
186 }
187
188 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_KEYID)) {
189 struct flow_match_enc_keyid match1, match2;
190
191 flow_rule_match_enc_keyid(entry1->rule, &match1);
192 flow_rule_match_enc_keyid(entry2->rule, &match2);
193 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
194 if (out)
195 goto check_failed;
196 }
197
198 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
199 struct flow_match_ipv4_addrs match1, match2;
200
201 flow_rule_match_enc_ipv4_addrs(entry1->rule, &match1);
202 flow_rule_match_enc_ipv4_addrs(entry2->rule, &match2);
203 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
204 if (out)
205 goto check_failed;
206 }
207
208 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
209 struct flow_match_ipv6_addrs match1, match2;
210
211 flow_rule_match_enc_ipv6_addrs(entry1->rule, &match1);
212 flow_rule_match_enc_ipv6_addrs(entry2->rule, &match2);
213 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
214 if (out)
215 goto check_failed;
216 }
217
218 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
219 struct flow_match_control match1, match2;
220
221 flow_rule_match_enc_control(entry1->rule, &match1);
222 flow_rule_match_enc_control(entry2->rule, &match2);
223 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
224 if (out)
225 goto check_failed;
226 }
227
228 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IP)) {
229 struct flow_match_ip match1, match2;
230
231 flow_rule_match_enc_ip(entry1->rule, &match1);
232 flow_rule_match_enc_ip(entry2->rule, &match2);
233 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
234 if (out)
235 goto check_failed;
236 }
237
238 if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_OPTS)) {
239 struct flow_match_enc_opts match1, match2;
240
241 flow_rule_match_enc_opts(entry1->rule, &match1);
242 flow_rule_match_enc_opts(entry2->rule, &match2);
243 COMPARE_UNMASKED_FIELDS(match1, match2, &out);
244 if (out)
245 goto check_failed;
246 }
247
248 return 0;
249
250check_failed:
251 return -EINVAL;
252}
253
254static int nfp_ct_check_mangle_merge(struct flow_action_entry *a_in,
255 struct flow_rule *rule)
256{
257 enum flow_action_mangle_base htype = a_in->mangle.htype;
258 u32 offset = a_in->mangle.offset;
259
260 switch (htype) {
261 case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
262 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS))
263 return -EOPNOTSUPP;
264 break;
265 case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
266 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
267 struct flow_match_ip match;
268
269 flow_rule_match_ip(rule, &match);
270 if (offset == offsetof(struct iphdr, ttl) &&
271 match.mask->ttl)
272 return -EOPNOTSUPP;
273 if (offset == round_down(offsetof(struct iphdr, tos), 4) &&
274 match.mask->tos)
275 return -EOPNOTSUPP;
276 }
277 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
278 struct flow_match_ipv4_addrs match;
279
280 flow_rule_match_ipv4_addrs(rule, &match);
281 if (offset == offsetof(struct iphdr, saddr) &&
282 match.mask->src)
283 return -EOPNOTSUPP;
284 if (offset == offsetof(struct iphdr, daddr) &&
285 match.mask->dst)
286 return -EOPNOTSUPP;
287 }
288 break;
289 case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
290 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
291 struct flow_match_ip match;
292
293 flow_rule_match_ip(rule, &match);
294 if (offset == round_down(offsetof(struct ipv6hdr, hop_limit), 4) &&
295 match.mask->ttl)
296 return -EOPNOTSUPP;
297
298 if (offset == round_down(offsetof(struct ipv6hdr, flow_lbl), 4) &&
299 match.mask->tos)
300 return -EOPNOTSUPP;
301 }
302 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
303 struct flow_match_ipv6_addrs match;
304
305 flow_rule_match_ipv6_addrs(rule, &match);
306 if (offset >= offsetof(struct ipv6hdr, saddr) &&
307 offset < offsetof(struct ipv6hdr, daddr) &&
308 memchr_inv(&match.mask->src, 0, sizeof(match.mask->src)))
309 return -EOPNOTSUPP;
310 if (offset >= offsetof(struct ipv6hdr, daddr) &&
311 offset < sizeof(struct ipv6hdr) &&
312 memchr_inv(&match.mask->dst, 0, sizeof(match.mask->dst)))
313 return -EOPNOTSUPP;
314 }
315 break;
316 case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
317 case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
318
319 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS))
320 return -EOPNOTSUPP;
321 break;
322 default:
323 break;
324 }
325 return 0;
326}
327
328static int nfp_ct_merge_act_check(struct nfp_fl_ct_flow_entry *pre_ct_entry,
329 struct nfp_fl_ct_flow_entry *post_ct_entry,
330 struct nfp_fl_ct_flow_entry *nft_entry)
331{
332 struct flow_action_entry *act;
333 int err, i;
334
335
336 flow_action_for_each(i, act, &pre_ct_entry->rule->action) {
337 switch (act->id) {
338 case FLOW_ACTION_MANGLE:
339 err = nfp_ct_check_mangle_merge(act, nft_entry->rule);
340 if (err)
341 return err;
342 err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule);
343 if (err)
344 return err;
345 break;
346 case FLOW_ACTION_VLAN_PUSH:
347 case FLOW_ACTION_VLAN_POP:
348 case FLOW_ACTION_VLAN_MANGLE:
349 case FLOW_ACTION_MPLS_PUSH:
350 case FLOW_ACTION_MPLS_POP:
351 case FLOW_ACTION_MPLS_MANGLE:
352 return -EOPNOTSUPP;
353 default:
354 break;
355 }
356 }
357
358
359 flow_action_for_each(i, act, &nft_entry->rule->action) {
360 switch (act->id) {
361 case FLOW_ACTION_MANGLE:
362 err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule);
363 if (err)
364 return err;
365 break;
366 case FLOW_ACTION_VLAN_PUSH:
367 case FLOW_ACTION_VLAN_POP:
368 case FLOW_ACTION_VLAN_MANGLE:
369 case FLOW_ACTION_MPLS_PUSH:
370 case FLOW_ACTION_MPLS_POP:
371 case FLOW_ACTION_MPLS_MANGLE:
372 return -EOPNOTSUPP;
373 default:
374 break;
375 }
376 }
377 return 0;
378}
379
380static int nfp_ct_check_meta(struct nfp_fl_ct_flow_entry *post_ct_entry,
381 struct nfp_fl_ct_flow_entry *nft_entry)
382{
383 struct flow_dissector *dissector = post_ct_entry->rule->match.dissector;
384 struct flow_action_entry *ct_met;
385 struct flow_match_ct ct;
386 int i;
387
388 ct_met = get_flow_act(nft_entry->rule, FLOW_ACTION_CT_METADATA);
389 if (ct_met && (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT))) {
390 u32 *act_lbl;
391
392 act_lbl = ct_met->ct_metadata.labels;
393 flow_rule_match_ct(post_ct_entry->rule, &ct);
394 for (i = 0; i < 4; i++) {
395 if ((ct.key->ct_labels[i] & ct.mask->ct_labels[i]) ^
396 (act_lbl[i] & ct.mask->ct_labels[i]))
397 return -EINVAL;
398 }
399
400 if ((ct.key->ct_mark & ct.mask->ct_mark) ^
401 (ct_met->ct_metadata.mark & ct.mask->ct_mark))
402 return -EINVAL;
403
404 return 0;
405 }
406
407 return -EINVAL;
408}
409
410static int nfp_fl_ct_add_offload(struct nfp_fl_nft_tc_merge *m_entry)
411{
412 return 0;
413}
414
415static int nfp_fl_ct_del_offload(struct nfp_app *app, unsigned long cookie,
416 struct net_device *netdev)
417{
418 return 0;
419}
420
421static int nfp_ct_do_nft_merge(struct nfp_fl_ct_zone_entry *zt,
422 struct nfp_fl_ct_flow_entry *nft_entry,
423 struct nfp_fl_ct_tc_merge *tc_m_entry)
424{
425 struct nfp_fl_ct_flow_entry *post_ct_entry, *pre_ct_entry;
426 struct nfp_fl_nft_tc_merge *nft_m_entry;
427 unsigned long new_cookie[3];
428 int err;
429
430 pre_ct_entry = tc_m_entry->pre_ct_parent;
431 post_ct_entry = tc_m_entry->post_ct_parent;
432
433 err = nfp_ct_merge_act_check(pre_ct_entry, post_ct_entry, nft_entry);
434 if (err)
435 return err;
436
437
438
439
440
441
442
443 err = nfp_ct_merge_check(pre_ct_entry, nft_entry);
444 if (err)
445 return err;
446 err = nfp_ct_merge_check(post_ct_entry, nft_entry);
447 if (err)
448 return err;
449 err = nfp_ct_check_meta(post_ct_entry, nft_entry);
450 if (err)
451 return err;
452
453
454 new_cookie[0] = tc_m_entry->cookie[0];
455 new_cookie[1] = tc_m_entry->cookie[1];
456 new_cookie[2] = nft_entry->cookie;
457 nft_m_entry = get_hashentry(&zt->nft_merge_tb,
458 &new_cookie,
459 nfp_nft_ct_merge_params,
460 sizeof(*nft_m_entry));
461
462 if (IS_ERR(nft_m_entry))
463 return PTR_ERR(nft_m_entry);
464
465
466 if (!memcmp(&new_cookie, nft_m_entry->cookie, sizeof(new_cookie)))
467 return 0;
468
469 memcpy(&nft_m_entry->cookie, &new_cookie, sizeof(new_cookie));
470 nft_m_entry->zt = zt;
471 nft_m_entry->tc_m_parent = tc_m_entry;
472 nft_m_entry->nft_parent = nft_entry;
473 nft_m_entry->tc_flower_cookie = 0;
474
475
476
477 nft_m_entry->netdev = pre_ct_entry->netdev;
478
479
480 list_add(&nft_m_entry->tc_merge_list, &tc_m_entry->children);
481 list_add(&nft_m_entry->nft_flow_list, &nft_entry->children);
482
483
484 err = nfp_fl_ct_add_offload(nft_m_entry);
485 if (err)
486 goto err_nft_ct_offload;
487
488 err = rhashtable_insert_fast(&zt->nft_merge_tb, &nft_m_entry->hash_node,
489 nfp_nft_ct_merge_params);
490 if (err)
491 goto err_nft_ct_merge_insert;
492
493 zt->nft_merge_count++;
494
495 return err;
496
497err_nft_ct_merge_insert:
498 nfp_fl_ct_del_offload(zt->priv->app, nft_m_entry->tc_flower_cookie,
499 nft_m_entry->netdev);
500err_nft_ct_offload:
501 list_del(&nft_m_entry->tc_merge_list);
502 list_del(&nft_m_entry->nft_flow_list);
503 kfree(nft_m_entry);
504 return err;
505}
506
507static int nfp_ct_do_tc_merge(struct nfp_fl_ct_zone_entry *zt,
508 struct nfp_fl_ct_flow_entry *ct_entry1,
509 struct nfp_fl_ct_flow_entry *ct_entry2)
510{
511 struct nfp_fl_ct_flow_entry *post_ct_entry, *pre_ct_entry;
512 struct nfp_fl_ct_flow_entry *nft_entry, *nft_tmp;
513 struct nfp_fl_ct_tc_merge *m_entry;
514 unsigned long new_cookie[2];
515 int err;
516
517 if (ct_entry1->type == CT_TYPE_PRE_CT) {
518 pre_ct_entry = ct_entry1;
519 post_ct_entry = ct_entry2;
520 } else {
521 post_ct_entry = ct_entry1;
522 pre_ct_entry = ct_entry2;
523 }
524
525 if (post_ct_entry->netdev != pre_ct_entry->netdev)
526 return -EINVAL;
527
528
529
530 if (post_ct_entry->chain_index != pre_ct_entry->chain_index)
531 return -EINVAL;
532
533 err = nfp_ct_merge_check(post_ct_entry, pre_ct_entry);
534 if (err)
535 return err;
536
537 new_cookie[0] = pre_ct_entry->cookie;
538 new_cookie[1] = post_ct_entry->cookie;
539 m_entry = get_hashentry(&zt->tc_merge_tb, &new_cookie,
540 nfp_tc_ct_merge_params, sizeof(*m_entry));
541 if (IS_ERR(m_entry))
542 return PTR_ERR(m_entry);
543
544
545 if (!memcmp(&new_cookie, m_entry->cookie, sizeof(new_cookie)))
546 return 0;
547
548 memcpy(&m_entry->cookie, &new_cookie, sizeof(new_cookie));
549 m_entry->zt = zt;
550 m_entry->post_ct_parent = post_ct_entry;
551 m_entry->pre_ct_parent = pre_ct_entry;
552
553
554 list_add(&m_entry->post_ct_list, &post_ct_entry->children);
555 list_add(&m_entry->pre_ct_list, &pre_ct_entry->children);
556 INIT_LIST_HEAD(&m_entry->children);
557
558 err = rhashtable_insert_fast(&zt->tc_merge_tb, &m_entry->hash_node,
559 nfp_tc_ct_merge_params);
560 if (err)
561 goto err_ct_tc_merge_insert;
562 zt->tc_merge_count++;
563
564
565 list_for_each_entry_safe(nft_entry, nft_tmp, &zt->nft_flows_list,
566 list_node) {
567 nfp_ct_do_nft_merge(zt, nft_entry, m_entry);
568 }
569
570 return 0;
571
572err_ct_tc_merge_insert:
573 list_del(&m_entry->post_ct_list);
574 list_del(&m_entry->pre_ct_list);
575 kfree(m_entry);
576 return err;
577}
578
579static struct
580nfp_fl_ct_zone_entry *get_nfp_zone_entry(struct nfp_flower_priv *priv,
581 u16 zone, bool wildcarded)
582{
583 struct nfp_fl_ct_zone_entry *zt;
584 int err;
585
586 if (wildcarded && priv->ct_zone_wc)
587 return priv->ct_zone_wc;
588
589 if (!wildcarded) {
590 zt = get_hashentry(&priv->ct_zone_table, &zone,
591 nfp_zone_table_params, sizeof(*zt));
592
593
594 if (IS_ERR(zt) || zt->priv)
595 return zt;
596 } else {
597 zt = kzalloc(sizeof(*zt), GFP_KERNEL);
598 if (!zt)
599 return ERR_PTR(-ENOMEM);
600 }
601
602 zt->zone = zone;
603 zt->priv = priv;
604 zt->nft = NULL;
605
606
607 INIT_LIST_HEAD(&zt->pre_ct_list);
608 INIT_LIST_HEAD(&zt->post_ct_list);
609 INIT_LIST_HEAD(&zt->nft_flows_list);
610
611 err = rhashtable_init(&zt->tc_merge_tb, &nfp_tc_ct_merge_params);
612 if (err)
613 goto err_tc_merge_tb_init;
614
615 err = rhashtable_init(&zt->nft_merge_tb, &nfp_nft_ct_merge_params);
616 if (err)
617 goto err_nft_merge_tb_init;
618
619 if (wildcarded) {
620 priv->ct_zone_wc = zt;
621 } else {
622 err = rhashtable_insert_fast(&priv->ct_zone_table,
623 &zt->hash_node,
624 nfp_zone_table_params);
625 if (err)
626 goto err_zone_insert;
627 }
628
629 return zt;
630
631err_zone_insert:
632 rhashtable_destroy(&zt->nft_merge_tb);
633err_nft_merge_tb_init:
634 rhashtable_destroy(&zt->tc_merge_tb);
635err_tc_merge_tb_init:
636 kfree(zt);
637 return ERR_PTR(err);
638}
639
640static struct
641nfp_fl_ct_flow_entry *nfp_fl_ct_add_flow(struct nfp_fl_ct_zone_entry *zt,
642 struct net_device *netdev,
643 struct flow_cls_offload *flow,
644 bool is_nft, struct netlink_ext_ack *extack)
645{
646 struct nf_flow_match *nft_match = NULL;
647 struct nfp_fl_ct_flow_entry *entry;
648 struct nfp_fl_ct_map_entry *map;
649 struct flow_action_entry *act;
650 int err, i;
651
652 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
653 if (!entry)
654 return ERR_PTR(-ENOMEM);
655
656 entry->rule = flow_rule_alloc(flow->rule->action.num_entries);
657 if (!entry->rule) {
658 err = -ENOMEM;
659 goto err_pre_ct_rule;
660 }
661
662
663
664
665 if (is_nft) {
666 nft_match = kzalloc(sizeof(*nft_match), GFP_KERNEL);
667 if (!nft_match) {
668 err = -ENOMEM;
669 goto err_pre_ct_act;
670 }
671 memcpy(&nft_match->dissector, flow->rule->match.dissector,
672 sizeof(nft_match->dissector));
673 memcpy(&nft_match->mask, flow->rule->match.mask,
674 sizeof(nft_match->mask));
675 memcpy(&nft_match->key, flow->rule->match.key,
676 sizeof(nft_match->key));
677 entry->rule->match.dissector = &nft_match->dissector;
678 entry->rule->match.mask = &nft_match->mask;
679 entry->rule->match.key = &nft_match->key;
680 } else {
681 entry->rule->match.dissector = flow->rule->match.dissector;
682 entry->rule->match.mask = flow->rule->match.mask;
683 entry->rule->match.key = flow->rule->match.key;
684 }
685
686 entry->zt = zt;
687 entry->netdev = netdev;
688 entry->cookie = flow->cookie;
689 entry->chain_index = flow->common.chain_index;
690 entry->tun_offset = NFP_FL_CT_NO_TUN;
691
692
693
694
695
696
697 entry->rule->action.num_entries = flow->rule->action.num_entries;
698 flow_action_for_each(i, act, &flow->rule->action) {
699 struct flow_action_entry *new_act;
700
701 new_act = &entry->rule->action.entries[i];
702 memcpy(new_act, act, sizeof(struct flow_action_entry));
703
704
705
706 if (act->id == FLOW_ACTION_TUNNEL_ENCAP) {
707 struct ip_tunnel_info *tun = act->tunnel;
708 size_t tun_size = sizeof(*tun) + tun->options_len;
709
710 new_act->tunnel = kmemdup(tun, tun_size, GFP_ATOMIC);
711 if (!new_act->tunnel) {
712 err = -ENOMEM;
713 goto err_pre_ct_tun_cp;
714 }
715 entry->tun_offset = i;
716 }
717 }
718
719 INIT_LIST_HEAD(&entry->children);
720
721
722 map = get_hashentry(&zt->priv->ct_map_table, &flow->cookie,
723 nfp_ct_map_params, sizeof(*map));
724 if (IS_ERR(map)) {
725 NL_SET_ERR_MSG_MOD(extack,
726 "offload error: ct map entry creation failed");
727 err = -ENOMEM;
728 goto err_ct_flow_insert;
729 }
730 map->cookie = flow->cookie;
731 map->ct_entry = entry;
732 err = rhashtable_insert_fast(&zt->priv->ct_map_table,
733 &map->hash_node,
734 nfp_ct_map_params);
735 if (err) {
736 NL_SET_ERR_MSG_MOD(extack,
737 "offload error: ct map entry table add failed");
738 goto err_map_insert;
739 }
740
741 return entry;
742
743err_map_insert:
744 kfree(map);
745err_ct_flow_insert:
746 if (entry->tun_offset != NFP_FL_CT_NO_TUN)
747 kfree(entry->rule->action.entries[entry->tun_offset].tunnel);
748err_pre_ct_tun_cp:
749 kfree(nft_match);
750err_pre_ct_act:
751 kfree(entry->rule);
752err_pre_ct_rule:
753 kfree(entry);
754 return ERR_PTR(err);
755}
756
757static void cleanup_nft_merge_entry(struct nfp_fl_nft_tc_merge *m_entry)
758{
759 struct nfp_fl_ct_zone_entry *zt;
760 int err;
761
762 zt = m_entry->zt;
763
764
765 if (m_entry->tc_flower_cookie) {
766 err = nfp_fl_ct_del_offload(zt->priv->app, m_entry->tc_flower_cookie,
767 m_entry->netdev);
768 if (err)
769 return;
770 }
771
772 WARN_ON_ONCE(rhashtable_remove_fast(&zt->nft_merge_tb,
773 &m_entry->hash_node,
774 nfp_nft_ct_merge_params));
775 zt->nft_merge_count--;
776 list_del(&m_entry->tc_merge_list);
777 list_del(&m_entry->nft_flow_list);
778
779 kfree(m_entry);
780}
781
782static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow)
783{
784 struct nfp_fl_nft_tc_merge *m_entry, *tmp;
785
786
787
788
789
790
791 if (is_nft_flow) {
792
793 struct nfp_fl_ct_flow_entry *ct_entry = entry;
794
795 list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
796 nft_flow_list) {
797 cleanup_nft_merge_entry(m_entry);
798 }
799 } else {
800
801 struct nfp_fl_ct_tc_merge *ct_entry = entry;
802
803 list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
804 tc_merge_list) {
805 cleanup_nft_merge_entry(m_entry);
806 }
807 }
808}
809
810static void nfp_del_tc_merge_entry(struct nfp_fl_ct_tc_merge *m_ent)
811{
812 struct nfp_fl_ct_zone_entry *zt;
813 int err;
814
815 zt = m_ent->zt;
816 err = rhashtable_remove_fast(&zt->tc_merge_tb,
817 &m_ent->hash_node,
818 nfp_tc_ct_merge_params);
819 if (err)
820 pr_warn("WARNING: could not remove merge_entry from hashtable\n");
821 zt->tc_merge_count--;
822 list_del(&m_ent->post_ct_list);
823 list_del(&m_ent->pre_ct_list);
824
825 if (!list_empty(&m_ent->children))
826 nfp_free_nft_merge_children(m_ent, false);
827 kfree(m_ent);
828}
829
830static void nfp_free_tc_merge_children(struct nfp_fl_ct_flow_entry *entry)
831{
832 struct nfp_fl_ct_tc_merge *m_ent, *tmp;
833
834 switch (entry->type) {
835 case CT_TYPE_PRE_CT:
836 list_for_each_entry_safe(m_ent, tmp, &entry->children, pre_ct_list) {
837 nfp_del_tc_merge_entry(m_ent);
838 }
839 break;
840 case CT_TYPE_POST_CT:
841 list_for_each_entry_safe(m_ent, tmp, &entry->children, post_ct_list) {
842 nfp_del_tc_merge_entry(m_ent);
843 }
844 break;
845 default:
846 break;
847 }
848}
849
850void nfp_fl_ct_clean_flow_entry(struct nfp_fl_ct_flow_entry *entry)
851{
852 list_del(&entry->list_node);
853
854 if (!list_empty(&entry->children)) {
855 if (entry->type == CT_TYPE_NFT)
856 nfp_free_nft_merge_children(entry, true);
857 else
858 nfp_free_tc_merge_children(entry);
859 }
860
861 if (entry->tun_offset != NFP_FL_CT_NO_TUN)
862 kfree(entry->rule->action.entries[entry->tun_offset].tunnel);
863
864 if (entry->type == CT_TYPE_NFT) {
865 struct nf_flow_match *nft_match;
866
867 nft_match = container_of(entry->rule->match.dissector,
868 struct nf_flow_match, dissector);
869 kfree(nft_match);
870 }
871
872 kfree(entry->rule);
873 kfree(entry);
874}
875
876static struct flow_action_entry *get_flow_act(struct flow_rule *rule,
877 enum flow_action_id act_id)
878{
879 struct flow_action_entry *act = NULL;
880 int i;
881
882 flow_action_for_each(i, act, &rule->action) {
883 if (act->id == act_id)
884 return act;
885 }
886 return NULL;
887}
888
889static void
890nfp_ct_merge_tc_entries(struct nfp_fl_ct_flow_entry *ct_entry1,
891 struct nfp_fl_ct_zone_entry *zt_src,
892 struct nfp_fl_ct_zone_entry *zt_dst)
893{
894 struct nfp_fl_ct_flow_entry *ct_entry2, *ct_tmp;
895 struct list_head *ct_list;
896
897 if (ct_entry1->type == CT_TYPE_PRE_CT)
898 ct_list = &zt_src->post_ct_list;
899 else if (ct_entry1->type == CT_TYPE_POST_CT)
900 ct_list = &zt_src->pre_ct_list;
901 else
902 return;
903
904 list_for_each_entry_safe(ct_entry2, ct_tmp, ct_list,
905 list_node) {
906 nfp_ct_do_tc_merge(zt_dst, ct_entry2, ct_entry1);
907 }
908}
909
910static void
911nfp_ct_merge_nft_with_tc(struct nfp_fl_ct_flow_entry *nft_entry,
912 struct nfp_fl_ct_zone_entry *zt)
913{
914 struct nfp_fl_ct_tc_merge *tc_merge_entry;
915 struct rhashtable_iter iter;
916
917 rhashtable_walk_enter(&zt->tc_merge_tb, &iter);
918 rhashtable_walk_start(&iter);
919 while ((tc_merge_entry = rhashtable_walk_next(&iter)) != NULL) {
920 if (IS_ERR(tc_merge_entry))
921 continue;
922 rhashtable_walk_stop(&iter);
923 nfp_ct_do_nft_merge(zt, nft_entry, tc_merge_entry);
924 rhashtable_walk_start(&iter);
925 }
926 rhashtable_walk_stop(&iter);
927 rhashtable_walk_exit(&iter);
928}
929
930int nfp_fl_ct_handle_pre_ct(struct nfp_flower_priv *priv,
931 struct net_device *netdev,
932 struct flow_cls_offload *flow,
933 struct netlink_ext_ack *extack)
934{
935 struct flow_action_entry *ct_act, *ct_goto;
936 struct nfp_fl_ct_flow_entry *ct_entry;
937 struct nfp_fl_ct_zone_entry *zt;
938 int err;
939
940 ct_act = get_flow_act(flow->rule, FLOW_ACTION_CT);
941 if (!ct_act) {
942 NL_SET_ERR_MSG_MOD(extack,
943 "unsupported offload: Conntrack action empty in conntrack offload");
944 return -EOPNOTSUPP;
945 }
946
947 ct_goto = get_flow_act(flow->rule, FLOW_ACTION_GOTO);
948 if (!ct_goto) {
949 NL_SET_ERR_MSG_MOD(extack,
950 "unsupported offload: Conntrack requires ACTION_GOTO");
951 return -EOPNOTSUPP;
952 }
953
954 zt = get_nfp_zone_entry(priv, ct_act->ct.zone, false);
955 if (IS_ERR(zt)) {
956 NL_SET_ERR_MSG_MOD(extack,
957 "offload error: Could not create zone table entry");
958 return PTR_ERR(zt);
959 }
960
961 if (!zt->nft) {
962 zt->nft = ct_act->ct.flow_table;
963 err = nf_flow_table_offload_add_cb(zt->nft, nfp_fl_ct_handle_nft_flow, zt);
964 if (err) {
965 NL_SET_ERR_MSG_MOD(extack,
966 "offload error: Could not register nft_callback");
967 return err;
968 }
969 }
970
971
972 ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, false, extack);
973 if (IS_ERR(ct_entry))
974 return PTR_ERR(ct_entry);
975 ct_entry->type = CT_TYPE_PRE_CT;
976 ct_entry->chain_index = ct_goto->chain_index;
977 list_add(&ct_entry->list_node, &zt->pre_ct_list);
978 zt->pre_ct_count++;
979
980 nfp_ct_merge_tc_entries(ct_entry, zt, zt);
981
982
983 if (priv->ct_zone_wc)
984 nfp_ct_merge_tc_entries(ct_entry, priv->ct_zone_wc, zt);
985
986 return 0;
987}
988
989int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
990 struct net_device *netdev,
991 struct flow_cls_offload *flow,
992 struct netlink_ext_ack *extack)
993{
994 struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
995 struct nfp_fl_ct_flow_entry *ct_entry;
996 struct nfp_fl_ct_zone_entry *zt;
997 bool wildcarded = false;
998 struct flow_match_ct ct;
999
1000 flow_rule_match_ct(rule, &ct);
1001 if (!ct.mask->ct_zone) {
1002 wildcarded = true;
1003 } else if (ct.mask->ct_zone != U16_MAX) {
1004 NL_SET_ERR_MSG_MOD(extack,
1005 "unsupported offload: partially wildcarded ct_zone is not supported");
1006 return -EOPNOTSUPP;
1007 }
1008
1009 zt = get_nfp_zone_entry(priv, ct.key->ct_zone, wildcarded);
1010 if (IS_ERR(zt)) {
1011 NL_SET_ERR_MSG_MOD(extack,
1012 "offload error: Could not create zone table entry");
1013 return PTR_ERR(zt);
1014 }
1015
1016
1017 ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, false, extack);
1018 if (IS_ERR(ct_entry))
1019 return PTR_ERR(ct_entry);
1020
1021 ct_entry->type = CT_TYPE_POST_CT;
1022 ct_entry->chain_index = flow->common.chain_index;
1023 list_add(&ct_entry->list_node, &zt->post_ct_list);
1024 zt->post_ct_count++;
1025
1026 if (wildcarded) {
1027
1028
1029
1030 struct rhashtable_iter iter;
1031 struct nfp_fl_ct_zone_entry *zone_table;
1032
1033 rhashtable_walk_enter(&priv->ct_zone_table, &iter);
1034 rhashtable_walk_start(&iter);
1035 while ((zone_table = rhashtable_walk_next(&iter)) != NULL) {
1036 if (IS_ERR(zone_table))
1037 continue;
1038 rhashtable_walk_stop(&iter);
1039 nfp_ct_merge_tc_entries(ct_entry, zone_table, zone_table);
1040 rhashtable_walk_start(&iter);
1041 }
1042 rhashtable_walk_stop(&iter);
1043 rhashtable_walk_exit(&iter);
1044 } else {
1045 nfp_ct_merge_tc_entries(ct_entry, zt, zt);
1046 }
1047
1048 return 0;
1049}
1050
1051static int
1052nfp_fl_ct_offload_nft_flow(struct nfp_fl_ct_zone_entry *zt, struct flow_cls_offload *flow)
1053{
1054 struct nfp_fl_ct_map_entry *ct_map_ent;
1055 struct nfp_fl_ct_flow_entry *ct_entry;
1056 struct netlink_ext_ack *extack = NULL;
1057
1058 ASSERT_RTNL();
1059
1060 extack = flow->common.extack;
1061 switch (flow->command) {
1062 case FLOW_CLS_REPLACE:
1063
1064
1065
1066 ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table, &flow->cookie,
1067 nfp_ct_map_params);
1068 if (!ct_map_ent) {
1069 ct_entry = nfp_fl_ct_add_flow(zt, NULL, flow, true, extack);
1070 if (IS_ERR(ct_entry))
1071 return PTR_ERR(ct_entry);
1072 ct_entry->type = CT_TYPE_NFT;
1073 list_add(&ct_entry->list_node, &zt->nft_flows_list);
1074 zt->nft_flows_count++;
1075 nfp_ct_merge_nft_with_tc(ct_entry, zt);
1076 }
1077 return 0;
1078 case FLOW_CLS_DESTROY:
1079 ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table, &flow->cookie,
1080 nfp_ct_map_params);
1081 return nfp_fl_ct_del_flow(ct_map_ent);
1082 case FLOW_CLS_STATS:
1083 return 0;
1084 default:
1085 break;
1086 }
1087 return -EINVAL;
1088}
1089
1090int nfp_fl_ct_handle_nft_flow(enum tc_setup_type type, void *type_data, void *cb_priv)
1091{
1092 struct flow_cls_offload *flow = type_data;
1093 struct nfp_fl_ct_zone_entry *zt = cb_priv;
1094 int err = -EOPNOTSUPP;
1095
1096 switch (type) {
1097 case TC_SETUP_CLSFLOWER:
1098 rtnl_lock();
1099 err = nfp_fl_ct_offload_nft_flow(zt, flow);
1100 rtnl_unlock();
1101 break;
1102 default:
1103 return -EOPNOTSUPP;
1104 }
1105 return err;
1106}
1107
1108static void
1109nfp_fl_ct_clean_nft_entries(struct nfp_fl_ct_zone_entry *zt)
1110{
1111 struct nfp_fl_ct_flow_entry *nft_entry, *ct_tmp;
1112 struct nfp_fl_ct_map_entry *ct_map_ent;
1113
1114 list_for_each_entry_safe(nft_entry, ct_tmp, &zt->nft_flows_list,
1115 list_node) {
1116 ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table,
1117 &nft_entry->cookie,
1118 nfp_ct_map_params);
1119 nfp_fl_ct_del_flow(ct_map_ent);
1120 }
1121}
1122
1123int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
1124{
1125 struct nfp_fl_ct_flow_entry *ct_entry;
1126 struct nfp_fl_ct_zone_entry *zt;
1127 struct rhashtable *m_table;
1128
1129 if (!ct_map_ent)
1130 return -ENOENT;
1131
1132 zt = ct_map_ent->ct_entry->zt;
1133 ct_entry = ct_map_ent->ct_entry;
1134 m_table = &zt->priv->ct_map_table;
1135
1136 switch (ct_entry->type) {
1137 case CT_TYPE_PRE_CT:
1138 zt->pre_ct_count--;
1139 rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
1140 nfp_ct_map_params);
1141 nfp_fl_ct_clean_flow_entry(ct_entry);
1142 kfree(ct_map_ent);
1143
1144 if (!zt->pre_ct_count) {
1145 zt->nft = NULL;
1146 nfp_fl_ct_clean_nft_entries(zt);
1147 }
1148 break;
1149 case CT_TYPE_POST_CT:
1150 zt->post_ct_count--;
1151 rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
1152 nfp_ct_map_params);
1153 nfp_fl_ct_clean_flow_entry(ct_entry);
1154 kfree(ct_map_ent);
1155 break;
1156 case CT_TYPE_NFT:
1157 zt->nft_flows_count--;
1158 rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
1159 nfp_ct_map_params);
1160 nfp_fl_ct_clean_flow_entry(ct_map_ent->ct_entry);
1161 kfree(ct_map_ent);
1162 break;
1163 default:
1164 break;
1165 }
1166
1167 return 0;
1168}
1169