Line data Source code
1 : /* SPDX-License-Identifier: BSD-2-Clause
2 : * Copyright(c) HCL TECHNOLOGIES LTD
3 : * Submitted on behalf of a third-party: Intel Corporation, a
4 : * Delaware corporation, having its principal place of business
5 : * at 2200 Mission College Boulevard,
6 : * Santa Clara, California 95052, USA
7 : */
8 : #include "vr_dpdk_n3k_flow.h"
9 :
10 : #include <rte_eth_bond.h>
11 : #include <rte_hash.h>
12 : #include <rte_log.h>
13 : #include <rte_malloc.h>
14 :
15 : #include "offload_entry/vr_dpdk_n3k_offload_converter.h"
16 : #include "offload_entry/vr_dpdk_n3k_offload_entry.h"
17 : #include "vr_dpdk_n3k_packet_metadata.h"
18 : #include "vr_dpdk_n3k_interface.h"
19 : #include "vr_dpdk_n3k_nexthop.h"
20 : #include "vr_dpdk_n3k_offload_hold.h"
21 : #include "vr_dpdk_n3k_config.h"
22 : #include "vr_dpdk.h"
23 : #include "vr_flow.h"
24 :
25 : static uint32_t flows_count;
26 : static struct vr_n3k_offload_flow **flows = NULL;
27 :
28 : int
29 56 : vr_dpdk_n3k_offload_flow_table_add_unlocked(
30 : struct vr_n3k_offload_flowtable_key *key,
31 : struct vr_n3k_offload_flow *flow)
32 : {
33 56 : if (!flows || key->fe_index >= flows_count)
34 0 : return -EINVAL;
35 :
36 56 : flows[key->fe_index] = flow;
37 56 : return 0;
38 : }
39 :
40 : static int
41 0 : vr_dpdk_n3k_offload_flow_table_del(struct vr_n3k_offload_flowtable_key *key)
42 : {
43 0 : if (!flows || key->fe_index >= flows_count)
44 0 : return -EINVAL;
45 :
46 0 : rte_free(flows[key->fe_index]);
47 0 : flows[key->fe_index] = NULL;
48 0 : return 0;
49 : }
50 :
51 : static inline void
52 : vr_dpdk_n3k_offload_flow_del_internal(struct vr_n3k_offload_flow *fe);
53 :
54 : static inline uint16_t
55 0 : vr_dpdk_n3k_offload_flow_get_underlying_hw_port_id(uint16_t port_id)
56 : {
57 : int ret;
58 :
59 0 : if ((ret = rte_eth_bond_primary_get(port_id)) < 0) {
60 0 : return port_id;
61 : }
62 :
63 0 : return ret;
64 : }
65 :
66 :
67 : static int
68 0 : vr_dpdk_n3k_allocate_flow_handles(const struct vr_nexthop *snh, struct vr_n3k_offload_flow *flow)
69 : {
70 0 : if (snh->nh_type == NH_COMPOSITE) {
71 : /* Note: We assume composite has non-zero components, this is checked
72 : * in vr_dpdk_n3k_offload_nexthop_get */
73 0 : flow->handle_count = snh->nh_component_cnt;
74 : } else {
75 0 : flow->handle_count = 1;
76 : }
77 :
78 0 : flow->handles = rte_zmalloc("n3k_flow_handles",
79 0 : sizeof(*flow->handles) * flow->handle_count, 0);
80 0 : if (!flow->handles) {
81 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to allocate flow handles array\n", __func__);
82 0 : return -ENOMEM;
83 : }
84 :
85 0 : return 0;
86 : }
87 :
88 : static int
89 0 : vr_dpdk_n3k_offload_correct_missing_rfe_index(struct vr_flow_entry *fe,
90 : struct vr_n3k_offload_flow *oflow)
91 : {
92 : int ret;
93 : struct vr_n3k_offload_flow *old_rfe;
94 : struct vr_n3k_offload_flow new_rfe;
95 0 : uint32_t old_rfe_id = oflow->reverse_id;
96 0 : struct vr_n3k_offload_flowtable_key old_key = {
97 0 : .fe_index = oflow->reverse_id
98 : };
99 0 : struct vr_n3k_offload_flowtable_key new_key = {
100 0 : .fe_index = fe->fe_rflow
101 : };
102 :
103 0 : oflow->reverse_id = fe->fe_rflow;
104 :
105 0 : if (old_rfe_id == 0 || old_rfe_id == fe->fe_rflow)
106 0 : return 0;
107 :
108 0 : RTE_LOG(WARNING, VROUTER, "%s(): rfe_index changed from %d to %d\n",
109 : __func__, old_rfe_id, fe->fe_rflow);
110 :
111 0 : old_rfe = vr_dpdk_n3k_offload_flow_get(&old_key);
112 0 : if (!old_rfe) {
113 0 : RTE_LOG(ERR, VROUTER,
114 : "%s(): Failed to get old rfe; fe_index: %d\n", __func__,
115 : old_key.fe_index);
116 0 : return -ENOENT;
117 : }
118 :
119 0 : memcpy(&new_rfe, old_rfe, sizeof(struct vr_n3k_offload_flow));
120 0 : new_rfe.id = new_key.fe_index;
121 :
122 : /* Updating flow table */
123 0 : ret = vr_dpdk_n3k_offload_flow_table_del(&old_key);
124 0 : if (ret < 0) {
125 0 : RTE_LOG(ERR, VROUTER,
126 : "%s(): Failed to remove old flow; fe_index: %d\n", __func__,
127 : old_key.fe_index);
128 0 : return ret;
129 : }
130 :
131 0 : struct vr_n3k_offload_flow *flow = vr_dpdk_n3k_offload_flow_get(&new_key);
132 0 : if (flow == NULL) {
133 0 : flow = rte_zmalloc("n3k_flow", sizeof(*flow), 0);
134 0 : if (flow == NULL) {
135 0 : RTE_LOG(ERR, VROUTER,
136 : "%s(): Insufficient memory for flow allocation.\n", __func__);
137 0 : ret = -ENOMEM;
138 0 : goto flow_del;
139 : }
140 : }
141 :
142 0 : memcpy(flow, &new_rfe, sizeof(struct vr_n3k_offload_flow));
143 :
144 0 : ret = vr_dpdk_n3k_offload_flow_table_add_unlocked(&new_key, flow);
145 0 : if (ret < 0) {
146 0 : RTE_LOG(ERR, VROUTER,
147 : "%s(): vr_dpdk_n3k_offload_flow_table_add failed: ret = %d;\n",
148 : __func__, ret);
149 0 : rte_free(flow);
150 0 : goto flow_del;
151 : }
152 0 : return 0;
153 :
154 0 : flow_del:
155 0 : vr_dpdk_n3k_offload_flow_del_internal(&new_rfe);
156 0 : return ret;
157 : }
158 :
159 : static inline void
160 0 : vr_dpdk_n3k_offload_flow_construct(
161 : struct vr_flow_entry *fe,
162 : struct vr_flow_entry *rfe,
163 : struct vr_n3k_offload_flow *oflow)
164 : {
165 0 : oflow->id = fe->fe_hentry.hentry_index;
166 0 : oflow->action = fe->fe_action;
167 0 : oflow->flags = fe->fe_flags;
168 0 : oflow->tcp_flags = fe->fe_tcp_flags;
169 :
170 0 : memset(&oflow->ip, 0, sizeof(oflow->ip));
171 :
172 0 : if (fe->fe_key.flow_key_len == VR_FLOW_IPV4_HASH_SIZE) {
173 0 : oflow->ip.type = VR_N3K_IP_TYPE_IPV4;
174 0 : oflow->ip.src.ipv4 = fe->fe_key.flow4_sip;
175 0 : oflow->ip.dst.ipv4 = fe->fe_key.flow4_dip;
176 : } else {
177 0 : oflow->ip.type = VR_N3K_IP_TYPE_IPV6;
178 0 : memcpy(oflow->ip.src.ipv6, fe->fe_key.flow6_sip,
179 : VR_IP6_ADDRESS_LEN);
180 0 : memcpy(oflow->ip.dst.ipv6, fe->fe_key.flow6_dip,
181 : VR_IP6_ADDRESS_LEN);
182 : }
183 :
184 0 : oflow->proto = fe->fe_key.flow4_proto;
185 0 : oflow->src_port = fe->fe_key.flow4_sport;
186 0 : oflow->dst_port = fe->fe_key.flow4_dport;
187 0 : oflow->tunnel_udp_src_port = RTE_BE16(fe->fe_udp_src_port);
188 0 : oflow->nh_id = fe->fe_key.flow_nh_id;
189 0 : oflow->src_vrf_id = fe->fe_vrf;
190 0 : oflow->ecmp_nh_idx = fe->fe_ecmp_nh_index;
191 0 : oflow->underlay_ecmp_index = fe->fe_underlay_ecmp_index;
192 :
193 : // There is a flag in vr_flow_entry to determine if mirroring is enabled.
194 : // At the same time VR_MAX_MIRROR_INDICES is an invalid value that
195 : // fits into uint8_t, so the flag seems to be redundant.
196 : // VR_MAX_MIRROR_INDICES is used in vrouter to initialize mirroring id
197 : // when mirroring is disabled.
198 : // To keep consistency with vouter code, the flag is checked here;
199 : // further in the processing VR_MAX_MIRROR_INDICES is used
200 : // to mark that mirroring is disabled.
201 : // Only one vif is currently supported in offloading procedure, so
202 : // secondary mirroring id (present in vr_flow_entry) is currently ignored.
203 : // TODO: decide if fe_sec_mirror_id requires further attention.
204 0 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
205 0 : oflow->mirror_id = fe->fe_mirror_id;
206 : } else {
207 0 : oflow->mirror_id = VR_MAX_MIRROR_INDICES;
208 : }
209 :
210 0 : if (rfe != NULL)
211 0 : oflow->reverse_id = rfe->fe_hentry.hentry_index;
212 0 : }
213 :
214 : static inline struct vr_n3k_offload_flowtable_key
215 0 : vr_dpdk_n3k_offload_flow_key_construct(struct vr_flow_entry *fe)
216 : {
217 0 : struct vr_n3k_offload_flowtable_key key = {
218 0 : .fe_index = fe->fe_hentry.hentry_index
219 : };
220 :
221 0 : return key;
222 : }
223 :
224 : static void
225 28 : vr_dpdk_n3k_flow_discard_all_flows(void)
226 : {
227 28 : uint32_t i = 0;
228 :
229 2828 : for (i = 0; i < flows_count; ++i) {
230 2800 : rte_free(flows[i]);
231 2800 : flows[i] = NULL;
232 : }
233 28 : }
234 :
235 : struct vr_n3k_offload_flow *
236 28 : vr_dpdk_n3k_offload_flow_get(struct vr_n3k_offload_flowtable_key *key)
237 : {
238 28 : if (!flows || key->fe_index >= flows_count)
239 0 : return NULL;
240 :
241 28 : return flows[key->fe_index];
242 : }
243 :
244 : int
245 28 : vr_dpdk_n3k_offload_flow_init(size_t flowtable_sz)
246 : {
247 28 : if (flows) {
248 0 : vr_dpdk_n3k_flow_discard_all_flows();
249 0 : rte_free(flows);
250 0 : flows = NULL;
251 : }
252 :
253 28 : flows = rte_zmalloc("n3k_offload_flow", flowtable_sz * sizeof(*flows), 0);
254 28 : if (flows == NULL)
255 0 : return -ENOMEM;
256 :
257 28 : flows_count = flowtable_sz;
258 :
259 28 : return 0;
260 : }
261 :
262 : void
263 28 : vr_dpdk_n3k_offload_flow_exit(void)
264 : {
265 28 : vr_dpdk_n3k_flow_discard_all_flows();
266 28 : rte_free(flows);
267 28 : flows = NULL;
268 28 : }
269 :
270 : static struct vr_n3k_offload_flow *
271 0 : vr_dpdk_n3k_offload_flow_save_copy(
272 : struct vr_flow_entry *fe, struct vr_flow_entry *rfe)
273 : {
274 : struct vr_n3k_offload_flowtable_key key =
275 0 : vr_dpdk_n3k_offload_flow_key_construct(fe);
276 :
277 0 : struct vr_n3k_offload_flow *oflow = vr_dpdk_n3k_offload_flow_get(&key);
278 0 : if (oflow == NULL) {
279 0 : oflow = rte_zmalloc("n3k_flow", sizeof(*oflow), 0);
280 0 : if (oflow == NULL) {
281 0 : RTE_LOG(ERR, VROUTER,
282 : "%s(): Insufficient memory for flow allocation.\n", __func__);
283 0 : return NULL;
284 : }
285 : }
286 :
287 0 : vr_dpdk_n3k_offload_flow_construct(fe, rfe, oflow);
288 :
289 0 : if (vr_dpdk_n3k_offload_flow_table_add_unlocked(&key, oflow)) {
290 0 : rte_free(oflow);
291 0 : return NULL;
292 : }
293 :
294 0 : return oflow;
295 : }
296 :
297 : static inline void
298 0 : log_flow_details(struct vr_flow_entry *fe, const char *prefix)
299 : {
300 : char saddr[40], daddr[40];
301 0 : struct vr_n3k_ips ip = { };
302 :
303 0 : if (fe->fe_key.flow_key_len == VR_FLOW_IPV4_HASH_SIZE) {
304 0 : ip.type = VR_N3K_IP_TYPE_IPV4;
305 0 : ip.src.ipv4 = fe->fe_key.flow4_sip;
306 0 : ip.dst.ipv4 = fe->fe_key.flow4_dip;
307 : } else {
308 0 : ip.type = VR_N3K_IP_TYPE_IPV6;
309 0 : memcpy(ip.src.ipv6, fe->fe_key.flow6_sip,
310 : VR_IP6_ADDRESS_LEN);
311 0 : memcpy(ip.dst.ipv6, fe->fe_key.flow6_dip,
312 : VR_IP6_ADDRESS_LEN);
313 : }
314 :
315 0 : RTE_LOG(DEBUG, VROUTER,
316 : "%10s: id=%d; action=%d; flags=%#x; nh=%d; vrf=%d; rflow=%d;\n",
317 : prefix, fe->fe_hentry.hentry_index, fe->fe_action, fe->fe_flags,
318 : fe->fe_key.flow_nh_id, fe->fe_vrf, fe->fe_rflow
319 : );
320 :
321 0 : RTE_LOG(DEBUG, VROUTER,
322 : " sip=%s; dip=%s; "
323 : "proto=%d; sport=%d; dport=%d;\n",
324 : vr_dpdk_n3k_convert_ip_to_str(saddr, &ip.src, ip.type),
325 : vr_dpdk_n3k_convert_ip_to_str(daddr, &ip.dst, ip.type),
326 : fe->fe_key.flow4_proto,
327 : rte_be_to_cpu_16(fe->fe_key.flow4_sport),
328 : rte_be_to_cpu_16(fe->fe_key.flow4_dport)
329 : );
330 0 : }
331 :
332 : static int
333 0 : vr_dpdk_n3k_offload_destroy_hw_flow(
334 : struct rte_flow *handle, uint16_t port_id, uint32_t flow_idx)
335 : {
336 0 : struct rte_flow_error error = { 0 };
337 0 : int ret = rte_flow_destroy(port_id, handle, &error);
338 0 : if (ret) {
339 0 : RTE_LOG(ERR, VROUTER,
340 : "%s(): Failed to destroy hardware flow %d: ret = %d; [%d]: %s\n",
341 : __func__, flow_idx, ret, error.type, error.message ?
342 : error.message : "No error message");
343 : }
344 :
345 0 : return ret;
346 : }
347 :
348 : static void
349 0 : vr_dpdk_n3k_offload_destroy_hw_flows(
350 : struct vr_n3k_offload_flow *flow)
351 : {
352 : size_t i;
353 0 : if (flow->handles != NULL) {
354 0 : for (i = 0; i < flow->handle_count; ++i) {
355 0 : if (!flow->handles[i])
356 0 : continue;
357 :
358 0 : vr_dpdk_n3k_offload_destroy_hw_flow(
359 0 : flow->handles[i], flow->hw_port_id, flow->id);
360 0 : flow->handles[i] = NULL;
361 : }
362 0 : rte_free(flow->handles);
363 0 : flow->handles = NULL;
364 : }
365 0 : }
366 :
367 : static inline void
368 0 : vr_dpdk_n3k_offload_flow_del_internal(struct vr_n3k_offload_flow *fe) {
369 0 : vr_dpdk_n3k_offload_destroy_hw_flows(fe);
370 0 : vr_dpdk_n3k_packet_metadata_schedule_delete(fe);
371 0 : }
372 :
373 : static inline bool
374 0 : vr_dpdk_n3k_offload_flow_is_tcp_not_established(const struct vr_n3k_offload_flow *flow)
375 : {
376 0 : if (flow->proto != VR_IP_PROTO_TCP)
377 0 : return false;
378 :
379 0 : if (flow->tcp_flags & VR_FLOW_TCP_ESTABLISHED)
380 0 : return false;
381 :
382 0 : if (flow->tcp_flags & VR_FLOW_TCP_ESTABLISHED_R)
383 0 : return false;
384 :
385 0 : return true;
386 : }
387 :
388 : static inline bool
389 0 : vr_dpdk_n3k_offload_flow_is_offloadable_proto(const struct vr_n3k_offload_flow *flow)
390 : {
391 0 : if (flow->proto == VR_IP_PROTO_TCP) {
392 0 : if (flow->action == VR_FLOW_ACTION_DROP)
393 0 : return true;
394 :
395 0 : return !vr_dpdk_n3k_offload_flow_is_tcp_not_established(flow);
396 0 : } else if (flow->proto== VR_IP_PROTO_UDP) {
397 0 : return true;
398 : } else {
399 0 : return false;
400 : }
401 : }
402 :
403 : static int
404 0 : vr_dpdk_n3k_offload_flow_set_internal(
405 : struct vr_n3k_offload_flow *flow,
406 : uint32_t fe_index,
407 : struct vr_n3k_offload_flow *reverse_flow)
408 : {
409 : size_t i;
410 0 : vr_dpdk_n3k_offload_destroy_hw_flows(flow);
411 :
412 0 : int ret = vr_dpdk_n3k_packet_metadata_ensure_entry_for_flow_exists(
413 : flow, reverse_flow);
414 0 : if (ret) {
415 0 : RTE_LOG(ERR, VROUTER,
416 : "%s(): Cannot rebuild packet metadata for flow %d: %d\n",
417 : __func__, flow->id, ret);
418 0 : return ret;
419 : }
420 :
421 0 : if (!vr_dpdk_n3k_config_is_drop_offload_enabled() && flow->action == VR_FLOW_ACTION_DROP) {
422 0 : RTE_LOG(DEBUG, VROUTER,
423 : "%s(): Skipping offload: DROP packets go to slowpath\n", __func__);
424 0 : return 0;
425 : }
426 :
427 0 : if (!vr_dpdk_n3k_offload_flow_is_offloadable_proto(flow)) {
428 : /* We do not offload tcp handshakes, only data. Skip. */
429 0 : RTE_LOG(DEBUG, VROUTER,
430 : "%s(): Skipping offload: proto not offloadable\n", __func__);
431 0 : return 0;
432 : }
433 :
434 : struct vr_n3k_offload_entry pre_offload_entry;
435 0 : ret = vr_dpdk_n3k_fill_offload_entry_partial_start(flow, &pre_offload_entry);
436 0 : if (ret) {
437 0 : RTE_LOG(ERR, VROUTER, "%s(): vr_dpdk_n3k_fill_offload_entry_partial_start failed: %d\n",
438 : __func__, ret);
439 0 : return ret;
440 : }
441 :
442 0 : const struct vr_nexthop *snh = pre_offload_entry.src_nh;
443 0 : ret = vr_dpdk_n3k_allocate_flow_handles(snh, flow);
444 0 : if (ret) {
445 0 : RTE_LOG(ERR, VROUTER, "%s(): vr_dpdk_n3k_allocate_flow_handles failed: %d\n",
446 : __func__, ret);
447 0 : return ret;
448 : }
449 :
450 0 : for (i = 0; i < flow->handle_count; ++i) {
451 0 : struct vr_n3k_offload_entry offload_entry = pre_offload_entry;
452 :
453 0 : if (snh->nh_type == NH_COMPOSITE) {
454 : uint32_t component_nh_idx;
455 : /* We've checked all the preconditions already so
456 : * vr_dpdk_n3k_offload_nexthop_get_cnh_idx can either succeed or
457 : * return -ENOENT */
458 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_idx(snh, i, &component_nh_idx);
459 0 : if (ret == -ENOENT) {
460 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%zu], nh is NULL\n",
461 : __func__, i);
462 0 : continue;
463 : }
464 0 : offload_entry.src_nh = vr_dpdk_n3k_offload_nexthop_get(component_nh_idx);
465 0 : if (offload_entry.src_nh == NULL) {
466 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%zu], nh_idx=%d\n",
467 : __func__, i, component_nh_idx);
468 0 : continue;
469 : }
470 :
471 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_label(snh, i, &offload_entry.tunnel_label);
472 0 : if (ret) {
473 0 : RTE_LOG(ERR, VROUTER, "%s(): getting composite nexthop's label failed: %d\n",
474 : __func__, ret);
475 0 : return ret;
476 : }
477 : }
478 :
479 0 : ret = vr_dpdk_n3k_fill_offload_entry_vifs(&offload_entry);
480 0 : if (ret) {
481 0 : RTE_LOG(ERR, VROUTER, "%s(): filling offload entry vifs failed: %d\n",
482 : __func__, ret);
483 0 : return ret;
484 : }
485 :
486 0 : ret = vr_dpdk_n3k_fill_offload_entry_partial_end(flow, &offload_entry);
487 0 : if (ret) {
488 0 : RTE_LOG(ERR, VROUTER, "%s(): filling offload entry failed: %d\n",
489 : __func__, ret);
490 0 : return ret;
491 : }
492 :
493 : struct vr_n3k_rte_flow_package flow_package =
494 0 : vr_dpdk_n3k_offload_entry_to_rte_flow(&offload_entry);
495 0 : if (flow_package.error) {
496 0 : RTE_LOG(ERR, VROUTER,
497 : "%s(): vr_dpdk_n3k_offload_entry_to_rte_flow failed: %d\n",
498 : __func__, flow_package.error);
499 0 : return flow_package.error;
500 : }
501 :
502 0 : flow->hw_port_id = vr_dpdk_n3k_offload_flow_get_underlying_hw_port_id(
503 0 : vif_port_id(offload_entry.src_vif));
504 :
505 : struct rte_flow_error error;
506 : static struct rte_flow_attr attr = {
507 : .ingress = 1,
508 : };
509 :
510 0 : flow->handles[i] = rte_flow_create(
511 0 : flow->hw_port_id,
512 : &attr,
513 0 : flow_package.pattern,
514 0 : flow_package.actions,
515 : &error
516 : );
517 :
518 0 : if (flow->handles[i] == NULL) {
519 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to create flow %d: [%d]: %s\n",
520 : __func__, fe_index, error.type, error.message ?
521 : error.message : "No error message");
522 0 : return -EINVAL;
523 : }
524 : }
525 :
526 0 : vr_dpdk_n3k_packet_metadata_mark_used(flow);
527 :
528 0 : return 0;
529 : }
530 :
531 : int
532 0 : vr_dpdk_n3k_offload_flow_set_unlocked(struct vr_flow_entry *fe, uint32_t fe_index,
533 : struct vr_flow_entry *rfe)
534 : {
535 : int ret;
536 0 : RTE_LOG(DEBUG, VROUTER, "%s() called; fe=%p; fe_index=%u; rfe=%p\n",
537 : __func__, fe, fe_index, rfe);
538 0 : log_flow_details(fe, "fe");
539 0 : if (rfe != NULL)
540 0 : log_flow_details(rfe, "rfe");
541 :
542 0 : struct vr_n3k_offload_flow *reverse_flow = NULL;
543 : struct vr_n3k_offload_flow *flow =
544 0 : vr_dpdk_n3k_offload_flow_save_copy(fe, rfe);
545 0 : if (flow == NULL)
546 0 : return -ENOMEM;
547 :
548 0 : if (rfe != NULL)
549 0 : reverse_flow = vr_dpdk_n3k_offload_flow_save_copy(rfe, fe);
550 : else {
551 0 : ret = vr_dpdk_n3k_offload_correct_missing_rfe_index(fe, flow);
552 0 : if (ret < 0)
553 0 : RTE_LOG(ERR, VROUTER,
554 : "%s() vr_dpdk_n3k_offload_correct_missing_rfe_index failed "
555 : "with error ret=%d; fe=%p; fe_index=%u; rfe=%p\n",
556 : __func__, ret, fe, fe_index, rfe);
557 : }
558 :
559 0 : bool hold_entry_exist = vr_dpdk_n3k_offload_hold_entry_exist(flow);
560 0 : if (!hold_entry_exist && vr_dpdk_n3k_offload_hold_should_wait(flow, reverse_flow)) {
561 0 : ret = vr_dpdk_n3k_offload_hold_save_flow(flow);
562 0 : if (ret < 0) {
563 0 : RTE_LOG(ERR, VROUTER,
564 : "%s() vr_dpdk_n3k_offload_hold_save_flow failed for fe_index=%d; ret=%d\n",
565 : __func__,
566 : flow->reverse_id, ret);
567 : }
568 0 : return 0;
569 : }
570 0 : else if(hold_entry_exist && vr_dpdk_n3k_offload_hold_get_held(flow, &reverse_flow)) {
571 0 : RTE_LOG(WARNING, VROUTER,
572 : "%s() Offloading held flows fe_index=%d; rfe_index=%d\n",
573 : __func__, flow->reverse_id, flow->id);
574 :
575 0 : ret = vr_dpdk_n3k_offload_flow_set_internal(reverse_flow, flow->reverse_id, flow);
576 0 : if (ret < 0) {
577 0 : RTE_LOG(ERR,
578 : VROUTER,
579 : "%s() vr_dpdk_n3k_offload_flow_set_internal(fe=%d, "
580 : "rfe=%d) failed with ret=%d\n",
581 : __func__,
582 : reverse_flow->id, flow->id, ret);
583 0 : return ret;
584 : }
585 : }
586 :
587 0 : return vr_dpdk_n3k_offload_flow_set_internal(flow, fe_index, reverse_flow);
588 : }
589 :
590 : int
591 0 : vr_dpdk_n3k_offload_flow_del_unlocked(struct vr_flow_entry *fe)
592 : {
593 : struct vr_n3k_offload_flowtable_key ftable_key;
594 : struct vr_n3k_offload_flow* flow;
595 :
596 0 : RTE_LOG(DEBUG, VROUTER, "%s() called; fe=%p\n", __func__, fe);
597 0 : log_flow_details(fe, "fe");
598 :
599 0 : ftable_key = vr_dpdk_n3k_offload_flow_key_construct(fe);
600 0 : flow = vr_dpdk_n3k_offload_flow_get(&ftable_key);
601 0 : if (flow == NULL)
602 0 : return -ENOENT;
603 :
604 0 : vr_dpdk_n3k_offload_hold_del_flow(flow);
605 :
606 0 : vr_dpdk_n3k_offload_flow_del_internal(flow);
607 :
608 0 : vr_dpdk_n3k_offload_flow_table_del(&ftable_key);
609 :
610 0 : return 0;
611 : }
612 :
613 : int
614 0 : vr_dpdk_n3k_offload_flow_stats_update_unlocked(struct vr_flow_entry *fe)
615 : {
616 : struct vr_n3k_offload_flowtable_key ftable_key;
617 : struct vr_n3k_offload_flow* flow;
618 : size_t i;
619 :
620 0 : ftable_key = vr_dpdk_n3k_offload_flow_key_construct(fe);
621 0 : flow = vr_dpdk_n3k_offload_flow_get(&ftable_key);
622 :
623 0 : if (flow == NULL || flow->handles == NULL)
624 0 : return -ENOENT;
625 :
626 0 : struct rte_flow_query_count query = {0};
627 0 : query.hits_set = 1;
628 0 : query.bytes_set = 1;
629 :
630 0 : struct rte_flow_error error = {0};
631 0 : struct rte_flow_action actions[] = {
632 : [0] = {
633 : .type = RTE_FLOW_ACTION_TYPE_COUNT,
634 : .conf = NULL,
635 : },
636 : [1] = {
637 : .type = RTE_FLOW_ACTION_TYPE_END,
638 : .conf = NULL,
639 : },
640 : };
641 :
642 0 : uint64_t hits = 0;
643 0 : uint64_t bytes = 0;
644 0 : for (i = 0; i < flow->handle_count; ++i) {
645 0 : if (!flow->handles[i])
646 0 : continue;
647 :
648 0 : int ret = rte_flow_query(flow->hw_port_id, flow->handles[i],
649 : actions, &query, &error);
650 :
651 0 : if (ret != 0) {
652 0 : RTE_LOG(ERR, VROUTER,
653 : "Failed to get statistics for flow id %u - %s\n",
654 : flow->id,
655 : error.message ? error.message : "no error message");
656 0 : return ret;
657 : }
658 :
659 0 : bytes += query.bytes;
660 0 : hits += query.hits;
661 : }
662 :
663 0 : int stats_bytes_bits_nb = sizeof(fe->fe_stats.flow_bytes) * 8;
664 0 : int stats_packets_bits_nb = sizeof(fe->fe_stats.flow_packets) * 8;
665 :
666 0 : uint64_t delta_dev_stats_bytes = bytes - flow->stats.bytes;
667 0 : uint64_t delta_dev_stats_packets = hits - flow->stats.packets;
668 :
669 0 : uint64_t new_flow_bytes = delta_dev_stats_bytes + fe->fe_stats.flow_bytes;
670 0 : uint64_t new_flow_packets = delta_dev_stats_packets + fe->fe_stats.flow_packets;
671 :
672 0 : fe->fe_stats.flow_bytes = new_flow_bytes;
673 0 : fe->fe_stats.flow_bytes_oflow += new_flow_bytes >> stats_bytes_bits_nb;
674 0 : fe->fe_stats.flow_packets = new_flow_packets;
675 0 : fe->fe_stats.flow_packets_oflow += new_flow_packets >> stats_packets_bits_nb;
676 :
677 0 : flow->stats.bytes = bytes;
678 0 : flow->stats.packets = hits;
679 :
680 0 : return 0;
681 : }
682 :
683 : static int
684 0 : vr_dpdk_n3k_offload_flow_iter(struct vr_n3k_offload_flow **flow, uint32_t *next)
685 : {
686 0 : if (!flows)
687 0 : return -EINVAL;
688 :
689 0 : while (*next < flows_count && flows[*next] == NULL)
690 0 : (*next)++;
691 :
692 0 : if (*next >= flows_count)
693 0 : return -ENOENT;
694 :
695 0 : *flow = flows[*next];
696 0 : (*next)++;
697 0 : return 0;
698 : }
699 :
700 : static int
701 0 : vr_dpdk_n3k_offload_flow_update_with_offload_entry(
702 : struct vr_n3k_offload_flow *flow,
703 : struct vr_n3k_offload_entry *offload_entry,
704 : size_t flow_handle_id)
705 : {
706 : struct vr_n3k_rte_flow_package flow_package =
707 0 : vr_dpdk_n3k_offload_entry_to_rte_flow(offload_entry);
708 0 : if (flow_package.error) {
709 0 : RTE_LOG(ERR, VROUTER,
710 : "%s(): vr_dpdk_n3k_offload_entry_to_rte_flow "
711 : "failed: %d\n",
712 : __func__, flow_package.error);
713 0 : return -1;
714 : }
715 :
716 0 : if (!flow->handles) {
717 0 : RTE_LOG(ERR, VROUTER,
718 : "%s(): flow->handles is NULL\n",
719 : __func__);
720 0 : return -ENOENT;
721 : }
722 :
723 0 : if (flow->handles[flow_handle_id]) {
724 0 : vr_dpdk_n3k_offload_destroy_hw_flow(
725 0 : flow->handles[flow_handle_id], flow->hw_port_id, flow->id);
726 0 : flow->handles[flow_handle_id] = NULL;
727 : }
728 :
729 : /* Offload updated flow */
730 : struct rte_flow_error error;
731 : static struct rte_flow_attr attr = {
732 : .ingress = 1,
733 : };
734 :
735 0 : flow->hw_port_id = vr_dpdk_n3k_offload_flow_get_underlying_hw_port_id(
736 0 : vif_port_id(offload_entry->src_vif));
737 :
738 0 : flow->handles[flow_handle_id] = rte_flow_create(flow->hw_port_id, &attr,
739 0 : flow_package.pattern,
740 0 : flow_package.actions, &error);
741 :
742 0 : if (flow->handles[flow_handle_id] == NULL) {
743 0 : RTE_LOG(ERR, VROUTER,
744 : "%s(): Failed to create flow %d: [%d]: %s\n",
745 : __func__, flow->id, error.type,
746 : error.message ? error.message
747 : : "No error message");
748 0 : return -1;
749 : }
750 :
751 0 : vr_dpdk_n3k_packet_metadata_mark_used(flow);
752 :
753 0 : return 0;
754 : }
755 :
756 : int
757 0 : vr_dpdk_n3k_offload_flow_update_unlocked(
758 : struct vr_n3k_offload_flow *flow)
759 : {
760 0 : size_t i = 0;
761 : int ret;
762 : struct vr_n3k_offload_entry pre_offload_entry;
763 0 : ret = vr_dpdk_n3k_fill_offload_entry_partial_start(flow, &pre_offload_entry);
764 0 : if (ret)
765 0 : return ret;
766 :
767 0 : const struct vr_nexthop *snh = pre_offload_entry.src_nh;
768 :
769 0 : if (snh->nh_type == NH_COMPOSITE && snh->nh_component_cnt != flow->handle_count) {
770 0 : RTE_LOG(WARNING, VROUTER, "%s(): Source nexthop %d changed # of components, cannot update\n",
771 : __func__, snh->nh_id);
772 : /* TODO in this we should just reallocate flow->handles array. This
773 : * array most likely contains just NULL handles (it was initialized in
774 : * the original flow_set, but actual flow handle creation failed
775 : * because of missing mirror) */
776 0 : return -EINVAL;
777 : }
778 :
779 0 : for (i = 0; i < flow->handle_count; ++i) {
780 0 : struct vr_n3k_offload_entry offload_entry = pre_offload_entry;
781 :
782 0 : if (snh->nh_type == NH_COMPOSITE) {
783 : uint32_t component_nh_idx;
784 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_idx(snh, i, &component_nh_idx);
785 0 : if (ret == -ENOENT) {
786 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%zu], nh is NULL\n",
787 : __func__, i);
788 0 : continue;
789 : }
790 0 : offload_entry.src_nh = vr_dpdk_n3k_offload_nexthop_get(component_nh_idx);
791 0 : if (offload_entry.src_nh == NULL) {
792 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%zu], nh_idx=%d\n",
793 : __func__, i, component_nh_idx);
794 0 : continue;
795 : }
796 :
797 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_label(snh, i, &offload_entry.tunnel_label);
798 0 : if (ret) {
799 0 : RTE_LOG(ERR, VROUTER, "%s(): getting composite nexthop's label failed: %d\n",
800 : __func__, ret);
801 0 : return ret;
802 : }
803 : }
804 :
805 0 : if (vr_dpdk_n3k_fill_offload_entry_vifs(&offload_entry) != 0)
806 0 : continue;
807 :
808 0 : if (vr_dpdk_n3k_fill_offload_entry_partial_end(flow, &offload_entry) != 0)
809 0 : continue;
810 :
811 0 : vr_dpdk_n3k_offload_flow_update_with_offload_entry(flow, &offload_entry, i);
812 :
813 : }
814 0 : return 0;
815 : }
816 :
817 : int
818 0 : vr_dpdk_n3k_offload_flow_vif_update_unlocked(const struct vr_interface *vif)
819 : {
820 0 : struct vr_n3k_offload_flow *flow = NULL;
821 0 : uint32_t i = 0;
822 0 : size_t j = 0;
823 0 : int ret = -1;
824 :
825 0 : while (vr_dpdk_n3k_offload_flow_iter(&flow, &i) >= 0) {
826 : struct vr_n3k_offload_entry pre_offload_entry;
827 0 : if (vr_dpdk_n3k_fill_offload_entry_partial_start(flow, &pre_offload_entry) != 0)
828 0 : continue;
829 :
830 0 : const struct vr_nexthop *snh = pre_offload_entry.src_nh;
831 :
832 0 : if (snh->nh_type == NH_COMPOSITE && snh->nh_component_cnt != flow->handle_count) {
833 0 : RTE_LOG(WARNING, VROUTER, "%s(): Source nexthop %d changed # of components, cannot update\n",
834 : __func__, snh->nh_id);
835 0 : continue;
836 : }
837 :
838 0 : for (j = 0; j < flow->handle_count; ++j) {
839 0 : struct vr_n3k_offload_entry offload_entry = pre_offload_entry;
840 :
841 0 : if (snh->nh_type == NH_COMPOSITE) {
842 : uint32_t component_nh_idx;
843 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_idx(snh, i, &component_nh_idx);
844 0 : if (ret == -ENOENT) {
845 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%u], nh is NULL\n",
846 : __func__, i);
847 0 : continue;
848 : }
849 0 : offload_entry.src_nh = vr_dpdk_n3k_offload_nexthop_get(component_nh_idx);
850 0 : if (offload_entry.src_nh == NULL) {
851 0 : RTE_LOG(ERR, VROUTER, "%s(): Failed to get component_nh[%u], nh_idx=%d\n",
852 : __func__, i, component_nh_idx);
853 0 : continue;
854 : }
855 :
856 0 : ret = vr_dpdk_n3k_offload_nexthop_get_cnh_label(snh, i, &offload_entry.tunnel_label);
857 0 : if (ret) {
858 0 : RTE_LOG(ERR, VROUTER, "%s(): getting composite nexthop's label failed: %d\n",
859 : __func__, ret);
860 0 : return ret;
861 : }
862 : }
863 :
864 0 : if (vr_dpdk_n3k_fill_offload_entry_vifs(&offload_entry) != 0)
865 0 : continue;
866 :
867 0 : if (offload_entry.src_vif != vif &&
868 0 : offload_entry.dst_vif != vif)
869 0 : continue;
870 :
871 0 : if (vr_dpdk_n3k_fill_offload_entry_partial_end(flow, &offload_entry) != 0)
872 0 : continue;
873 :
874 0 : ret = vr_dpdk_n3k_offload_flow_update_with_offload_entry(flow, &offload_entry, j);
875 0 : if (ret) {
876 0 : RTE_LOG(ERR, VROUTER,
877 : "%s(): Failed to update flow %d\n",
878 : __func__, flow->id);
879 0 : return ret;
880 : }
881 : }
882 : }
883 :
884 0 : return 0;
885 : }
886 :
887 : void
888 0 : vr_dpdk_n3k_offload_flow_reset_unlocked()
889 : {
890 0 : RTE_LOG(DEBUG, VROUTER, "%s() called\n", __func__);
891 : int i;
892 : struct vr_n3k_offload_flow* flow;
893 0 : for (i = 0; i < flows_count; ++i) {
894 0 : flow = flows[i];
895 0 : if (flow == NULL)
896 0 : continue;
897 :
898 0 : vr_dpdk_n3k_offload_hold_del_flow(flow);
899 0 : vr_dpdk_n3k_offload_flow_del_internal(flow);
900 :
901 0 : rte_free(flows[i]);
902 0 : flows[i] = NULL;
903 : }
904 0 : }
|