1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */
4 #include <linux/netdevice.h>
10 #define NUM_IPSEC_FTE BIT(15)
12 struct mlx5e_ipsec_rx_err {
13 struct mlx5_flow_table *ft;
14 struct mlx5_flow_handle *rule;
15 struct mlx5_modify_hdr *copy_modify_hdr;
18 struct mlx5e_ipsec_ft {
19 struct mutex mutex; /* Protect changes to this struct */
20 struct mlx5_flow_table *sa;
24 struct mlx5e_ipsec_rx {
25 struct mlx5e_ipsec_ft ft;
26 struct mlx5_flow_group *miss_group;
27 struct mlx5_flow_handle *miss_rule;
28 struct mlx5_flow_destination default_dest;
29 struct mlx5e_ipsec_rx_err rx_err;
32 struct mlx5e_ipsec_tx {
33 struct mlx5e_ipsec_ft ft;
34 struct mlx5_flow_namespace *ns;
37 /* IPsec RX flow steering */
38 static enum mlx5_traffic_types family2tt(u32 family)
40 if (family == AF_INET)
41 return MLX5_TT_IPV4_IPSEC_ESP;
42 return MLX5_TT_IPV6_IPSEC_ESP;
45 static struct mlx5_flow_table *ipsec_ft_create(struct mlx5_flow_namespace *ns,
49 struct mlx5_flow_table_attr ft_attr = {};
51 ft_attr.autogroup.num_reserved_entries = 1;
52 ft_attr.autogroup.max_num_groups = max_num_groups;
53 ft_attr.max_fte = NUM_IPSEC_FTE;
54 ft_attr.level = level;
57 return mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
60 static int rx_err_add_rule(struct mlx5_core_dev *mdev,
61 struct mlx5e_ipsec_rx *rx,
62 struct mlx5e_ipsec_rx_err *rx_err)
64 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
65 struct mlx5_flow_act flow_act = {};
66 struct mlx5_modify_hdr *modify_hdr;
67 struct mlx5_flow_handle *fte;
68 struct mlx5_flow_spec *spec;
71 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
75 /* Action to copy 7 bit ipsec_syndrome to regB[24:30] */
76 MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
77 MLX5_SET(copy_action_in, action, src_field, MLX5_ACTION_IN_FIELD_IPSEC_SYNDROME);
78 MLX5_SET(copy_action_in, action, src_offset, 0);
79 MLX5_SET(copy_action_in, action, length, 7);
80 MLX5_SET(copy_action_in, action, dst_field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
81 MLX5_SET(copy_action_in, action, dst_offset, 24);
83 modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
86 if (IS_ERR(modify_hdr)) {
87 err = PTR_ERR(modify_hdr);
89 "fail to alloc ipsec copy modify_header_id err=%d\n", err);
94 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
95 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
96 flow_act.modify_hdr = modify_hdr;
97 fte = mlx5_add_flow_rules(rx_err->ft, spec, &flow_act,
98 &rx->default_dest, 1);
101 mlx5_core_err(mdev, "fail to add ipsec rx err copy rule err=%d\n", err);
107 rx_err->copy_modify_hdr = modify_hdr;
111 mlx5_modify_header_dealloc(mdev, modify_hdr);
117 static int rx_fs_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_rx *rx)
119 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
120 struct mlx5_flow_table *ft = rx->ft.sa;
121 struct mlx5_flow_group *miss_group;
122 struct mlx5_flow_handle *miss_rule;
123 MLX5_DECLARE_FLOW_ACT(flow_act);
124 struct mlx5_flow_spec *spec;
128 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
129 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
130 if (!flow_group_in || !spec) {
135 /* Create miss_group */
136 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
137 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
138 miss_group = mlx5_create_flow_group(ft, flow_group_in);
139 if (IS_ERR(miss_group)) {
140 err = PTR_ERR(miss_group);
141 mlx5_core_err(mdev, "fail to create ipsec rx miss_group err=%d\n", err);
144 rx->miss_group = miss_group;
146 /* Create miss rule */
148 mlx5_add_flow_rules(ft, spec, &flow_act, &rx->default_dest, 1);
149 if (IS_ERR(miss_rule)) {
150 mlx5_destroy_flow_group(rx->miss_group);
151 err = PTR_ERR(miss_rule);
152 mlx5_core_err(mdev, "fail to create ipsec rx miss_rule err=%d\n", err);
155 rx->miss_rule = miss_rule;
157 kvfree(flow_group_in);
162 static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_rx *rx)
164 mlx5_del_flow_rules(rx->miss_rule);
165 mlx5_destroy_flow_group(rx->miss_group);
166 mlx5_destroy_flow_table(rx->ft.sa);
168 mlx5_del_flow_rules(rx->rx_err.rule);
169 mlx5_modify_header_dealloc(mdev, rx->rx_err.copy_modify_hdr);
170 mlx5_destroy_flow_table(rx->rx_err.ft);
173 static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
174 struct mlx5e_ipsec_rx *rx, u32 family)
176 struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(ipsec->fs, false);
177 struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
178 struct mlx5_flow_table *ft;
181 rx->default_dest = mlx5_ttc_get_default_dest(ttc, family2tt(family));
183 ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL,
189 err = rx_err_add_rule(mdev, rx, &rx->rx_err);
194 ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_LEVEL, MLX5E_NIC_PRIO,
202 err = rx_fs_create(mdev, rx);
209 mlx5_destroy_flow_table(rx->ft.sa);
211 mlx5_del_flow_rules(rx->rx_err.rule);
212 mlx5_modify_header_dealloc(mdev, rx->rx_err.copy_modify_hdr);
214 mlx5_destroy_flow_table(rx->rx_err.ft);
218 static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
219 struct mlx5e_ipsec *ipsec, u32 family)
221 struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
222 struct mlx5_flow_destination dest = {};
223 struct mlx5e_ipsec_rx *rx;
226 if (family == AF_INET)
231 mutex_lock(&rx->ft.mutex);
236 err = rx_create(mdev, ipsec, rx, family);
241 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
243 mlx5_ttc_fwd_dest(ttc, family2tt(family), &dest);
248 mutex_unlock(&rx->ft.mutex);
254 static void rx_ft_put(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
257 struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
258 struct mlx5e_ipsec_rx *rx;
260 if (family == AF_INET)
265 mutex_lock(&rx->ft.mutex);
271 mlx5_ttc_fwd_default_dest(ttc, family2tt(family));
274 rx_destroy(mdev, rx);
277 mutex_unlock(&rx->ft.mutex);
280 /* IPsec TX flow steering */
281 static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx)
283 struct mlx5_flow_table *ft;
285 ft = ipsec_ft_create(tx->ns, 0, 0, 1);
293 static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
294 struct mlx5e_ipsec *ipsec)
296 struct mlx5e_ipsec_tx *tx = ipsec->tx;
299 mutex_lock(&tx->ft.mutex);
303 err = tx_create(mdev, tx);
309 mutex_unlock(&tx->ft.mutex);
315 static void tx_ft_put(struct mlx5e_ipsec *ipsec)
317 struct mlx5e_ipsec_tx *tx = ipsec->tx;
319 mutex_lock(&tx->ft.mutex);
324 mlx5_destroy_flow_table(tx->ft.sa);
326 mutex_unlock(&tx->ft.mutex);
329 static void setup_fte_addr4(struct mlx5_flow_spec *spec, __be32 *saddr,
332 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
334 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
335 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 4);
337 memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
338 outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), saddr, 4);
339 memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
340 outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), daddr, 4);
341 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
342 outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
343 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
344 outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
347 static void setup_fte_addr6(struct mlx5_flow_spec *spec, __be32 *saddr,
350 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
352 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
353 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 6);
355 memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
356 outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), saddr, 16);
357 memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
358 outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), daddr, 16);
359 memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
360 outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 0xff, 16);
361 memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
362 outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 0xff, 16);
365 static void setup_fte_esp(struct mlx5_flow_spec *spec)
368 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
370 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
371 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_ESP);
374 static void setup_fte_spi(struct mlx5_flow_spec *spec, u32 spi)
377 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
379 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.outer_esp_spi);
380 MLX5_SET(fte_match_param, spec->match_value, misc_parameters.outer_esp_spi, spi);
383 static void setup_fte_no_frags(struct mlx5_flow_spec *spec)
386 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
388 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.frag);
389 MLX5_SET(fte_match_param, spec->match_value, outer_headers.frag, 0);
392 static void setup_fte_reg_a(struct mlx5_flow_spec *spec)
394 /* Add IPsec indicator in metadata_reg_a */
395 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
397 MLX5_SET(fte_match_param, spec->match_criteria,
398 misc_parameters_2.metadata_reg_a, MLX5_ETH_WQE_FT_META_IPSEC);
399 MLX5_SET(fte_match_param, spec->match_value,
400 misc_parameters_2.metadata_reg_a, MLX5_ETH_WQE_FT_META_IPSEC);
403 static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
405 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
406 struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
407 struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
408 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
409 struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
410 struct mlx5_modify_hdr *modify_hdr = NULL;
411 struct mlx5_flow_destination dest = {};
412 struct mlx5_flow_act flow_act = {};
413 struct mlx5_flow_handle *rule;
414 struct mlx5_flow_spec *spec;
415 struct mlx5e_ipsec_rx *rx;
418 rx = rx_ft_get(mdev, ipsec, attrs->family);
422 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
428 if (attrs->family == AF_INET)
429 setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
431 setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
433 setup_fte_spi(spec, attrs->spi);
435 setup_fte_no_frags(spec);
437 /* Set bit[31] ipsec marker */
438 /* Set bit[23-0] ipsec_obj_id */
439 MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
440 MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
441 MLX5_SET(set_action_in, action, data,
442 (sa_entry->ipsec_obj_id | BIT(31)));
443 MLX5_SET(set_action_in, action, offset, 0);
444 MLX5_SET(set_action_in, action, length, 32);
446 modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
448 if (IS_ERR(modify_hdr)) {
449 err = PTR_ERR(modify_hdr);
451 "fail to alloc ipsec set modify_header_id err=%d\n", err);
456 flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_IPSEC;
457 flow_act.crypto.obj_id = sa_entry->ipsec_obj_id;
458 flow_act.flags |= FLOW_ACT_NO_APPEND;
459 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
460 MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
461 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
462 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
463 flow_act.modify_hdr = modify_hdr;
464 dest.ft = rx->rx_err.ft;
465 rule = mlx5_add_flow_rules(rx->ft.sa, spec, &flow_act, &dest, 1);
468 mlx5_core_err(mdev, "fail to add RX ipsec rule err=%d\n", err);
472 ipsec_rule->rule = rule;
473 ipsec_rule->set_modify_hdr = modify_hdr;
478 mlx5_modify_header_dealloc(mdev, modify_hdr);
479 rx_ft_put(mdev, ipsec, attrs->family);
486 static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
488 struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
489 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
490 struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
491 struct mlx5_flow_act flow_act = {};
492 struct mlx5_flow_handle *rule;
493 struct mlx5_flow_spec *spec;
494 struct mlx5e_ipsec_tx *tx;
497 tx = tx_ft_get(mdev, ipsec);
501 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
507 if (attrs->family == AF_INET)
508 setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
510 setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
512 setup_fte_spi(spec, attrs->spi);
514 setup_fte_no_frags(spec);
515 setup_fte_reg_a(spec);
517 flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_IPSEC;
518 flow_act.crypto.obj_id = sa_entry->ipsec_obj_id;
519 flow_act.flags |= FLOW_ACT_NO_APPEND;
520 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW |
521 MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT;
522 rule = mlx5_add_flow_rules(tx->ft.sa, spec, &flow_act, NULL, 0);
525 mlx5_core_err(mdev, "fail to add TX ipsec rule err=%d\n", err);
529 sa_entry->ipsec_rule.rule = rule;
538 int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
540 if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
541 return tx_add_rule(sa_entry);
543 return rx_add_rule(sa_entry);
546 void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
548 struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
549 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
551 mlx5_del_flow_rules(ipsec_rule->rule);
553 if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) {
554 tx_ft_put(sa_entry->ipsec);
558 mlx5_modify_header_dealloc(mdev, ipsec_rule->set_modify_hdr);
559 rx_ft_put(mdev, sa_entry->ipsec, sa_entry->attrs.family);
562 void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
567 mutex_destroy(&ipsec->tx->ft.mutex);
568 WARN_ON(ipsec->tx->ft.refcnt);
571 mutex_destroy(&ipsec->rx_ipv4->ft.mutex);
572 WARN_ON(ipsec->rx_ipv4->ft.refcnt);
573 kfree(ipsec->rx_ipv4);
575 mutex_destroy(&ipsec->rx_ipv6->ft.mutex);
576 WARN_ON(ipsec->rx_ipv6->ft.refcnt);
577 kfree(ipsec->rx_ipv6);
580 int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
582 struct mlx5_flow_namespace *ns;
585 ns = mlx5_get_flow_namespace(ipsec->mdev,
586 MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
590 ipsec->tx = kzalloc(sizeof(*ipsec->tx), GFP_KERNEL);
594 ipsec->rx_ipv4 = kzalloc(sizeof(*ipsec->rx_ipv4), GFP_KERNEL);
598 ipsec->rx_ipv6 = kzalloc(sizeof(*ipsec->rx_ipv6), GFP_KERNEL);
602 mutex_init(&ipsec->tx->ft.mutex);
603 mutex_init(&ipsec->rx_ipv4->ft.mutex);
604 mutex_init(&ipsec->rx_ipv6->ft.mutex);
610 kfree(ipsec->rx_ipv4);