Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2021 Xilinx, Inc.
4 : : */
5 : :
6 : : #include "efx.h"
7 : : #include "efx_impl.h"
8 : :
9 : : #if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_TUNNEL
10 : :
11 : : /* Match by Ether-type */
12 : : #define EFX_VNIC_ENCAP_RULE_MATCH_ETHER_TYPE \
13 : : (1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_ETHER_TYPE_LBN)
14 : : /* Match by outer VLAN ID */
15 : : #define EFX_VNIC_ENCAP_RULE_MATCH_OUTER_VID \
16 : : (1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_OUTER_VLAN_LBN)
17 : : /* Match by local IP host address */
18 : : #define EFX_VNIC_ENCAP_RULE_MATCH_LOC_HOST \
19 : : (1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_DST_IP_LBN)
20 : : /* Match by IP transport protocol */
21 : : #define EFX_VNIC_ENCAP_RULE_MATCH_IP_PROTO \
22 : : (1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_IP_PROTO_LBN)
23 : : /* Match by local TCP/UDP port */
24 : : #define EFX_VNIC_ENCAP_RULE_MATCH_LOC_PORT \
25 : : (1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_DST_PORT_LBN)
26 : :
27 : : /*
28 : : * Helper structure to pass parameters to MCDI function to add a VNIC
29 : : * encapsulation rule.
30 : : */
31 : : typedef struct efx_vnic_encap_rule_spec_s {
32 : : uint32_t evers_mport_selector; /* Host-endian */
33 : : uint32_t evers_match_flags; /* Host-endian */
34 : : uint16_t evers_ether_type; /* Host-endian */
35 : : uint16_t evers_outer_vid; /* Host-endian */
36 : : efx_oword_t evers_loc_host; /* Big-endian */
37 : : uint8_t evers_ip_proto;
38 : : uint16_t evers_loc_port; /* Host-endian */
39 : : efx_tunnel_protocol_t evers_encap_type;
40 : : } efx_vnic_encap_rule_spec_t;
41 : :
42 : : static uint32_t
43 : : efx_tunnel_protocol2mae_encap_type(
44 : : __in efx_tunnel_protocol_t proto,
45 : : __out uint32_t *typep)
46 : : {
47 : : efx_rc_t rc;
48 : :
49 : : switch (proto) {
50 : : case EFX_TUNNEL_PROTOCOL_NONE:
51 : : *typep = MAE_MCDI_ENCAP_TYPE_NONE;
52 : : break;
53 : : case EFX_TUNNEL_PROTOCOL_VXLAN:
54 : : *typep = MAE_MCDI_ENCAP_TYPE_VXLAN;
55 : : break;
56 : : case EFX_TUNNEL_PROTOCOL_GENEVE:
57 : : *typep = MAE_MCDI_ENCAP_TYPE_GENEVE;
58 : : break;
59 : : case EFX_TUNNEL_PROTOCOL_NVGRE:
60 : : *typep = MAE_MCDI_ENCAP_TYPE_NVGRE;
61 : : break;
62 : 0 : default:
63 : : rc = EINVAL;
64 : 0 : goto fail1;
65 : : }
66 : :
67 : : return (0);
68 : :
69 : : fail1:
70 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
71 : :
72 : 0 : return (rc);
73 : : }
74 : :
75 : : static __checkReturn efx_rc_t
76 : 0 : efx_mcdi_vnic_encap_rule_add(
77 : : __in efx_nic_t *enp,
78 : : __in const efx_vnic_encap_rule_spec_t *spec,
79 : : __out efx_vnic_encap_rule_handle_t *handle)
80 : :
81 : : {
82 : : efx_mcdi_req_t req;
83 : 0 : EFX_MCDI_DECLARE_BUF(payload,
84 : : MC_CMD_VNIC_ENCAP_RULE_ADD_IN_LEN,
85 : : MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN);
86 : : uint32_t encap_type;
87 : : efx_rc_t rc;
88 : :
89 : 0 : req.emr_cmd = MC_CMD_VNIC_ENCAP_RULE_ADD;
90 : 0 : req.emr_in_buf = payload;
91 : 0 : req.emr_in_length = MC_CMD_VNIC_ENCAP_RULE_ADD_IN_LEN;
92 : 0 : req.emr_out_buf = payload;
93 : 0 : req.emr_out_length = MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN;
94 : :
95 : 0 : MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_MPORT_SELECTOR,
96 : : spec->evers_mport_selector);
97 : 0 : MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_MATCH_FLAGS,
98 : : spec->evers_match_flags);
99 : :
100 : 0 : MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_ETHER_TYPE,
101 : : __CPU_TO_BE_16(spec->evers_ether_type));
102 : 0 : MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_OUTER_VLAN_WORD,
103 : : __CPU_TO_BE_16(spec->evers_outer_vid));
104 : :
105 : : /*
106 : : * Address is already in network order as well as the MCDI field,
107 : : * so plain copy is used.
108 : : */
109 : : EFX_STATIC_ASSERT(sizeof (spec->evers_loc_host) ==
110 : : MC_CMD_VNIC_ENCAP_RULE_ADD_IN_DST_IP_LEN);
111 : : memcpy(MCDI_IN2(req, uint8_t, VNIC_ENCAP_RULE_ADD_IN_DST_IP),
112 : 0 : &spec->evers_loc_host.eo_byte[0],
113 : : MC_CMD_VNIC_ENCAP_RULE_ADD_IN_DST_IP_LEN);
114 : :
115 : 0 : MCDI_IN_SET_BYTE(req, VNIC_ENCAP_RULE_ADD_IN_IP_PROTO,
116 : : spec->evers_ip_proto);
117 : 0 : MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_DST_PORT,
118 : : __CPU_TO_BE_16(spec->evers_loc_port));
119 : :
120 [ # # ]: 0 : rc = efx_tunnel_protocol2mae_encap_type(spec->evers_encap_type,
121 : : &encap_type);
122 [ # # ]: 0 : if (rc != 0)
123 : 0 : goto fail1;
124 : :
125 : 0 : MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_ENCAP_TYPE, encap_type);
126 : :
127 : 0 : efx_mcdi_execute(enp, &req);
128 : :
129 [ # # ]: 0 : if (req.emr_rc != 0) {
130 : : rc = req.emr_rc;
131 : 0 : goto fail2;
132 : : }
133 : :
134 [ # # ]: 0 : if (req.emr_out_length_used != MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN) {
135 : : rc = EMSGSIZE;
136 : 0 : goto fail3;
137 : : }
138 : :
139 [ # # ]: 0 : if (handle != NULL)
140 : 0 : *handle = MCDI_OUT_DWORD(req, VNIC_ENCAP_RULE_ADD_OUT_HANDLE);
141 : :
142 : : return (0);
143 : :
144 : : fail3:
145 : : EFSYS_PROBE(fail3);
146 : :
147 : : fail2:
148 : : EFSYS_PROBE(fail2);
149 : :
150 : : fail1:
151 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
152 : :
153 : : return (rc);
154 : : }
155 : :
156 : : static __checkReturn efx_rc_t
157 : 0 : efx_mcdi_vnic_encap_rule_remove(
158 : : __in efx_nic_t *enp,
159 : : __in efx_vnic_encap_rule_handle_t handle)
160 : :
161 : : {
162 : : efx_mcdi_req_t req;
163 : 0 : EFX_MCDI_DECLARE_BUF(payload,
164 : : MC_CMD_VNIC_ENCAP_RULE_REMOVE_IN_LEN,
165 : : MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN);
166 : : efx_rc_t rc;
167 : :
168 : 0 : req.emr_cmd = MC_CMD_VNIC_ENCAP_RULE_REMOVE;
169 : 0 : req.emr_in_buf = payload;
170 : 0 : req.emr_in_length = MC_CMD_VNIC_ENCAP_RULE_REMOVE_IN_LEN;
171 : 0 : req.emr_out_buf = payload;
172 : 0 : req.emr_out_length = MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN;
173 : :
174 : 0 : MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_REMOVE_IN_HANDLE, handle);
175 : :
176 : 0 : efx_mcdi_execute(enp, &req);
177 : :
178 [ # # ]: 0 : if (req.emr_rc != 0) {
179 : : rc = req.emr_rc;
180 : 0 : goto fail1;
181 : : }
182 : :
183 [ # # ]: 0 : if (req.emr_out_length_used != MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN) {
184 : : rc = EMSGSIZE;
185 : 0 : goto fail2;
186 : : }
187 : :
188 : : return (0);
189 : :
190 : : fail2:
191 : : EFSYS_PROBE(fail2);
192 : :
193 : : fail1:
194 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
195 : :
196 : : return (rc);
197 : : }
198 : :
199 : : static void
200 : : rhead_vnic_encap_rule_spec_init(
201 : : __in const efx_tunnel_udp_entry_t *etuep,
202 : : __out efx_vnic_encap_rule_spec_t *spec)
203 : : {
204 : : memset(spec, 0, sizeof (*spec));
205 : :
206 : 0 : spec->evers_mport_selector = MAE_MPORT_SELECTOR_ASSIGNED;
207 : 0 : spec->evers_match_flags = EFX_VNIC_ENCAP_RULE_MATCH_IP_PROTO |
208 : : EFX_VNIC_ENCAP_RULE_MATCH_LOC_PORT;
209 : 0 : spec->evers_ip_proto = EFX_IPPROTO_UDP;
210 : 0 : spec->evers_loc_port = etuep->etue_port;
211 : 0 : spec->evers_encap_type = etuep->etue_protocol;
212 : : }
213 : :
214 : : static __checkReturn efx_rc_t
215 : 0 : rhead_udp_port_tunnel_add(
216 : : __in efx_nic_t *enp,
217 : : __inout efx_tunnel_udp_entry_t *etuep)
218 : : {
219 : : efx_vnic_encap_rule_spec_t spec;
220 : :
221 : : rhead_vnic_encap_rule_spec_init(etuep, &spec);
222 : 0 : return (efx_mcdi_vnic_encap_rule_add(enp, &spec, &etuep->etue_handle));
223 : : }
224 : :
225 : : static __checkReturn efx_rc_t
226 : : rhead_udp_port_tunnel_remove(
227 : : __in efx_nic_t *enp,
228 : : __in efx_tunnel_udp_entry_t *etuep)
229 : : {
230 : 0 : return (efx_mcdi_vnic_encap_rule_remove(enp, etuep->etue_handle));
231 : : }
232 : :
233 : : __checkReturn efx_rc_t
234 : 0 : rhead_tunnel_reconfigure(
235 : : __in efx_nic_t *enp)
236 : : {
237 : 0 : efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
238 : : efx_rc_t rc;
239 : : efsys_lock_state_t state;
240 : : efx_tunnel_cfg_t etc;
241 : : efx_tunnel_cfg_t added;
242 : : unsigned int i;
243 : : unsigned int j;
244 : :
245 : : memset(&added, 0, sizeof(added));
246 : :
247 : : /*
248 : : * Make a local copy of UDP tunnel table to release the lock
249 : : * when executing MCDIs.
250 : : */
251 : 0 : EFSYS_LOCK(enp->en_eslp, state);
252 : : memcpy(&etc, etcp, sizeof (etc));
253 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
254 : :
255 [ # # ]: 0 : for (i = 0; i < etc.etc_udp_entries_num; i++) {
256 : 0 : efx_tunnel_udp_entry_t *etc_entry = &etc.etc_udp_entries[i];
257 : :
258 [ # # ]: 0 : if (etc_entry->etue_busy == B_FALSE)
259 : 0 : continue;
260 : :
261 [ # # # # ]: 0 : switch (etc_entry->etue_state) {
262 : : case EFX_TUNNEL_UDP_ENTRY_APPLIED:
263 : : break;
264 : 0 : case EFX_TUNNEL_UDP_ENTRY_ADDED:
265 : 0 : rc = rhead_udp_port_tunnel_add(enp, etc_entry);
266 [ # # ]: 0 : if (rc != 0)
267 : 0 : goto fail1;
268 : 0 : added.etc_udp_entries[added.etc_udp_entries_num] =
269 : : *etc_entry;
270 : 0 : added.etc_udp_entries_num++;
271 : 0 : break;
272 : : case EFX_TUNNEL_UDP_ENTRY_REMOVED:
273 : : rc = rhead_udp_port_tunnel_remove(enp, etc_entry);
274 [ # # ]: 0 : if (rc != 0)
275 : 0 : goto fail2;
276 : : break;
277 : : default:
278 : 0 : EFSYS_ASSERT(0);
279 : : break;
280 : : }
281 : : }
282 : :
283 : 0 : EFSYS_LOCK(enp->en_eslp, state);
284 : :
285 : : /*
286 : : * Adding or removing non-busy entries does not change the
287 : : * order of busy entries. Therefore one linear search iteration
288 : : * suffices.
289 : : */
290 [ # # ]: 0 : for (i = 0, j = 0; i < etcp->etc_udp_entries_num; i++) {
291 : : efx_tunnel_udp_entry_t *cur_entry = &etcp->etc_udp_entries[i];
292 : : efx_tunnel_udp_entry_t *added_entry = &added.etc_udp_entries[j];
293 : :
294 [ # # ]: 0 : if (cur_entry->etue_state == EFX_TUNNEL_UDP_ENTRY_ADDED &&
295 [ # # ]: 0 : cur_entry->etue_port == added_entry->etue_port) {
296 : 0 : cur_entry->etue_handle = added_entry->etue_handle;
297 : 0 : j++;
298 : : }
299 : : }
300 : :
301 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
302 : :
303 : 0 : return (0);
304 : :
305 : : fail2:
306 : : EFSYS_PROBE(fail2);
307 : :
308 : 0 : fail1:
309 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
310 : :
311 [ # # ]: 0 : while (i-- > 0) {
312 [ # # ]: 0 : if (etc.etc_udp_entries[i].etue_busy == B_FALSE)
313 : 0 : continue;
314 : :
315 [ # # # # ]: 0 : switch (etc.etc_udp_entries[i].etue_state) {
316 : : case EFX_TUNNEL_UDP_ENTRY_APPLIED:
317 : : break;
318 : 0 : case EFX_TUNNEL_UDP_ENTRY_ADDED:
319 : : (void) rhead_udp_port_tunnel_remove(enp,
320 : : &etc.etc_udp_entries[i]);
321 : : break;
322 : 0 : case EFX_TUNNEL_UDP_ENTRY_REMOVED:
323 : 0 : (void) rhead_udp_port_tunnel_add(enp,
324 : : &etc.etc_udp_entries[i]);
325 : 0 : break;
326 : : default:
327 : 0 : EFSYS_ASSERT(0);
328 : : break;
329 : : }
330 : : }
331 : :
332 : : return (rc);
333 : : }
334 : :
335 : : void
336 : 0 : rhead_tunnel_fini(
337 : : __in efx_nic_t *enp)
338 : : {
339 : 0 : (void) efx_tunnel_config_clear(enp);
340 : 0 : (void) efx_tunnel_reconfigure(enp);
341 : 0 : }
342 : :
343 : : #endif /* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_TUNNEL */
|