1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4 #include "fs_core.h"
5 #include "eswitch.h"
6 #include "en_accel/ipsec.h"
7 #include "esw/ipsec_fs.h"
8 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
9 #include "en/tc_priv.h"
10 #endif
11
12 enum {
13 MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL,
14 MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL,
15 MLX5_ESW_IPSEC_RX_POL_FT_LEVEL,
16 };
17
18 enum {
19 MLX5_ESW_IPSEC_TX_POL_FT_LEVEL,
20 MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL,
21 MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL,
22 };
23
mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_rx_create_attr * attr)24 void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
25 struct mlx5e_ipsec_rx_create_attr *attr)
26 {
27 attr->prio = FDB_CRYPTO_INGRESS;
28 attr->pol_level = MLX5_ESW_IPSEC_RX_POL_FT_LEVEL;
29 attr->sa_level = MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL;
30 attr->status_level = MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL;
31 attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
32 }
33
mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec * ipsec,struct mlx5_flow_destination * dest)34 int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
35 struct mlx5_flow_destination *dest)
36 {
37 dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
38 dest->ft = mlx5_chains_get_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
39
40 return 0;
41 }
42
mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry * sa_entry,struct mlx5_flow_act * flow_act)43 int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
44 struct mlx5_flow_act *flow_act)
45 {
46 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
47 struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
48 struct mlx5_core_dev *mdev = ipsec->mdev;
49 struct mlx5_modify_hdr *modify_hdr;
50 u32 mapped_id;
51 int err;
52
53 err = xa_alloc_bh(&ipsec->ipsec_obj_id_map, &mapped_id,
54 xa_mk_value(sa_entry->ipsec_obj_id),
55 XA_LIMIT(1, ESW_IPSEC_RX_MAPPED_ID_MASK), 0);
56 if (err)
57 return err;
58
59 /* reuse tunnel bits for ipsec,
60 * tun_id is always 0 and tun_opts is mapped to ipsec_obj_id.
61 */
62 MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
63 MLX5_SET(set_action_in, action, field,
64 MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
65 MLX5_SET(set_action_in, action, offset, ESW_ZONE_ID_BITS);
66 MLX5_SET(set_action_in, action, length,
67 ESW_TUN_ID_BITS + ESW_TUN_OPTS_BITS);
68 MLX5_SET(set_action_in, action, data, mapped_id);
69
70 modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_FDB,
71 1, action);
72 if (IS_ERR(modify_hdr)) {
73 err = PTR_ERR(modify_hdr);
74 goto err_header_alloc;
75 }
76
77 sa_entry->rx_mapped_id = mapped_id;
78 flow_act->modify_hdr = modify_hdr;
79 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
80
81 return 0;
82
83 err_header_alloc:
84 xa_erase_bh(&ipsec->ipsec_obj_id_map, mapped_id);
85 return err;
86 }
87
mlx5_esw_ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry * sa_entry,struct mlx5_flow_spec * spec)88 void mlx5_esw_ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
89 struct mlx5_flow_spec *spec)
90 {
91 MLX5_SET(fte_match_param, spec->match_criteria,
92 misc_parameters_2.metadata_reg_c_1,
93 ESW_IPSEC_RX_MAPPED_ID_MATCH_MASK);
94 MLX5_SET(fte_match_param, spec->match_value,
95 misc_parameters_2.metadata_reg_c_1,
96 sa_entry->rx_mapped_id << ESW_ZONE_ID_BITS);
97
98 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
99 }
100
mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry * sa_entry)101 void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry)
102 {
103 struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
104
105 if (sa_entry->rx_mapped_id)
106 xa_erase_bh(&ipsec->ipsec_obj_id_map,
107 sa_entry->rx_mapped_id);
108 }
109
mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv * priv,u32 id,u32 * ipsec_obj_id)110 int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
111 u32 *ipsec_obj_id)
112 {
113 struct mlx5e_ipsec *ipsec = priv->ipsec;
114 void *val;
115
116 val = xa_load(&ipsec->ipsec_obj_id_map, id);
117 if (!val)
118 return -ENOENT;
119
120 *ipsec_obj_id = xa_to_value(val);
121
122 return 0;
123 }
124
mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_tx_create_attr * attr)125 void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
126 struct mlx5e_ipsec_tx_create_attr *attr)
127 {
128 attr->prio = FDB_CRYPTO_EGRESS;
129 attr->pol_level = MLX5_ESW_IPSEC_TX_POL_FT_LEVEL;
130 attr->sa_level = MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL;
131 attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL;
132 attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
133 }
134
135 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch * esw,struct mlx5e_tc_flow * flow)136 static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
137 struct mlx5e_tc_flow *flow)
138 {
139 struct mlx5_esw_flow_attr *esw_attr;
140 struct mlx5_flow_attr *attr;
141 int err;
142
143 attr = flow->attr;
144 esw_attr = attr->esw_attr;
145 if (esw_attr->out_count - esw_attr->split_count > 1)
146 return 0;
147
148 err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
149 esw_attr->out_count - 1);
150
151 return err;
152 }
153 #endif
154
mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev * mdev)155 void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
156 {
157 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
158 struct mlx5_eswitch *esw = mdev->priv.eswitch;
159 struct mlx5_eswitch_rep *rep;
160 struct mlx5e_rep_priv *rpriv;
161 struct rhashtable_iter iter;
162 struct mlx5e_tc_flow *flow;
163 unsigned long i;
164 int err;
165
166 mlx5_esw_for_each_rep(esw, i, rep) {
167 if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
168 continue;
169
170 rpriv = rep->rep_data[REP_ETH].priv;
171 rhashtable_walk_enter(&rpriv->tc_ht, &iter);
172 rhashtable_walk_start(&iter);
173 while ((flow = rhashtable_walk_next(&iter)) != NULL) {
174 if (IS_ERR(flow))
175 continue;
176
177 err = mlx5_esw_ipsec_modify_flow_dests(esw, flow);
178 if (err)
179 mlx5_core_warn_once(mdev,
180 "Failed to modify flow dests for IPsec");
181 }
182 rhashtable_walk_stop(&iter);
183 rhashtable_walk_exit(&iter);
184 }
185 #endif
186 }
187