NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
upf_accel_flow_processing.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2025 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 
26 #include <rte_cycles.h>
27 #include <rte_ethdev.h>
28 #include <rte_ether.h>
29 #include <rte_gtp.h>
30 #include <rte_ip.h>
31 #include <rte_mbuf.h>
32 #include <rte_tcp.h>
33 #include <rte_udp.h>
34 
35 #include <doca_bitfield.h>
36 #include <doca_flow_net.h>
37 #include <doca_log.h>
38 
39 #include "upf_accel.h"
41 
42 #define UPF_ACCEL_MAX_PKT_BURST 32
43 /* Maximum DOCA Flow entries to age in an aging function call */
44 #define UPF_ACCEL_MAX_NUM_AGING (UPF_ACCEL_MAX_PKT_BURST * 2)
45 /* Maximum timeout for DOCA Flow handling and processing functions. 0 for no limit */
46 #define UPF_ACCEL_DOCA_FLOW_MAX_TIMEOUT_US (0)
47 
49  struct rte_mbuf *rx_pkts[UPF_ACCEL_MAX_PKT_BURST]; /* Rx packet burst */
50  struct rte_mbuf *tx_pkts[UPF_ACCEL_MAX_PKT_BURST]; /* Tx packet burst */
51  struct upf_accel_match_8t *matches[UPF_ACCEL_MAX_PKT_BURST]; /* Packet n-tuple matches */
52  struct upf_accel_entry_ctx *conns[UPF_ACCEL_MAX_PKT_BURST]; /* Connections matched to packet n-tuples */
53  struct tun_parser_ctx parse_ctxs[UPF_ACCEL_MAX_PKT_BURST]; /* Packet n-tuple parser contexts */
54  enum parser_pkt_type pkts_type[UPF_ACCEL_MAX_PKT_BURST]; /* Packet type (plain or tunneled) */
55  uint16_t rx_pkts_cnt; /* Rx packet burst count */
56  uint16_t tx_pkts_cnt; /* Tx packet burst count */
57  bool pkts_drop[UPF_ACCEL_MAX_PKT_BURST]; /* Packet processing drop indicator */
58 } __rte_aligned(RTE_CACHE_LINE_SIZE);
59 
60 static_assert(UPF_ACCEL_MAX_PKT_BURST <= RTE_HASH_LOOKUP_BULK_MAX,
61  "Can't process a burst larger than RTE bulk size limit");
62 
63 DOCA_LOG_REGISTER(UPF_ACCEL::FLOW_PROCESSING);
64 
65 /*
66  * Get the opposite packet type
67  *
68  * @pkt_type [in]: packet type
69  * @return: the opposite type of packet
70  */
72 {
74 }
75 
76 /*
77  * Delete flow
78  *
79  * Assign its status to NONE, and delete its context from the ht if the flow
80  * in the second type is also NONE (or in error status)
81  *
82  * @fp_data [in]: flow processing data
83  * @dyn_ctx [in]: dynamic entry context
84  * @pkt_type [in]: packet type
85  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise
86  */
89  enum parser_pkt_type pkt_type)
90 {
91  enum parser_pkt_type opposite_dir_type = upf_accel_fp_get_opposite_pkt_type(pkt_type);
92  bool last_entry = dyn_ctx->flow_status[opposite_dir_type] == UPF_ACCEL_FLOW_STATUS_NONE ||
93  (dyn_ctx->flow_status[opposite_dir_type] == UPF_ACCEL_FLOW_STATUS_ACCELERATED &&
94  dyn_ctx->entries[opposite_dir_type].status == DOCA_FLOW_ENTRY_STATUS_ERROR);
95 
97 
98  if (!last_entry)
99  return DOCA_SUCCESS;
100 
101  if (rte_hash_del_key_with_hash(fp_data->dyn_tbl, &dyn_ctx->match.inner, dyn_ctx->hash) < 0) {
102  DOCA_LOG_WARN("Failed entry aging - hash free failed");
104  }
105 
106  DOCA_LOG_DBG("Entry removed from hash table");
107  return DOCA_SUCCESS;
108 }
109 
110 /*
111  * Dynamic entry processing handler
112  *
113  * @dyn_ctx [in]: dynamic entry context
114  * @entry [in]: DOCA Flow entry pointer
115  * @pipe_queue [in]: queue identifier
116  * @status [in]: DOCA Flow entry status
117  * @op [in]: DOCA Flow entry operation
118  */
120  struct doca_flow_pipe_entry *entry,
121  uint16_t pipe_queue,
122  enum doca_flow_entry_status status,
123  enum doca_flow_entry_op op)
124 {
126  struct upf_accel_fp_data *fp_data = dyn_ctx->fp_data;
127  enum doca_flow_entry_status *entry_status;
128  enum parser_pkt_type pkt_type;
129  doca_error_t ret;
130 
132  pkt_type = PARSER_PKT_TYPE_TUNNELED;
133  } else if (entry == dyn_ctx->entries[PARSER_PKT_TYPE_PLAIN].entry) {
134  pkt_type = PARSER_PKT_TYPE_PLAIN;
135  } else {
136  DOCA_LOG_ERR("Unexpected entry");
137  return;
138  }
139  accel_counters = &fp_data->accel_counters[pkt_type];
140  entry_status = &dyn_ctx->entries[pkt_type].status;
141 
142  switch (op) {
144  if (status != DOCA_FLOW_ENTRY_STATUS_SUCCESS) {
145  DOCA_LOG_ERR("Aging status failed");
147  }
148 
150  if (ret != DOCA_SUCCESS) {
151  DOCA_LOG_ERR("Aging remove entry failed");
153  } else {
154  DOCA_LOG_DBG("Entry aged out of pipe");
155  }
156 
157  break;
159  if (status == DOCA_FLOW_ENTRY_STATUS_SUCCESS) {
162  } else {
163  DOCA_LOG_ERR("Failed to process dynamic entry add");
165  }
166  *entry_status = status;
167  break;
169  if (status == DOCA_FLOW_ENTRY_STATUS_SUCCESS) {
170  ret = upf_accel_fp_delete_flow(fp_data, dyn_ctx, pkt_type);
171  if (ret != DOCA_SUCCESS) {
172  DOCA_LOG_ERR("Failed to delete accelerated flow");
174  }
175 
177  } else {
178  DOCA_LOG_ERR("Failed to process dynamic entry del");
180  }
181  break;
182  default:
183  DOCA_LOG_WARN("UPF accel dynamic entry cb - bad op %u", op);
184  return;
185  }
186 }
187 
188 /*
189  * Static entry processing handler
190  *
191  * @static_ctx [in]: static entry context
192  * @status [in]: DOCA Flow entry status
193  * @op [in]: DOCA Flow entry operation
194  */
196  enum doca_flow_entry_status status,
197  enum doca_flow_entry_op op)
198 {
200 
201  switch (op) {
204  if (status != DOCA_FLOW_ENTRY_STATUS_SUCCESS)
205  entries_status->failure = true; /* set failure to true if processing failed */
207  break;
208  default:
209  DOCA_LOG_ERR("UPF accel static entry cb - bad op %u", op);
210  return;
211  }
212 }
213 
214 void upf_accel_check_for_valid_entry_aging(struct doca_flow_pipe_entry *entry,
215  uint16_t pipe_queue,
216  enum doca_flow_entry_status status,
217  enum doca_flow_entry_op op,
218  void *user_ctx)
219 {
220  struct upf_accel_entry_ctx *entry_ctx = (struct upf_accel_entry_ctx *)user_ctx;
221 
222  if (entry_ctx == NULL)
223  return;
224 
226  upf_accel_dyn_entry_cb(&entry_ctx->dyn_ctx, entry, pipe_queue, status, op);
227  else
228  upf_accel_static_entry_cb(&entry_ctx->static_ctx, status, op);
229 }
230 
232 {
233  struct upf_accel_sw_aging_ll *ll = &fp_data->sw_aging_ll[pkt_type];
234 
237 }
238 
239 /*
240  * Init a SW Aging doubly linked list node
241  *
242  * @conn [in]: connection descriptor
243  * @pkt_type [in]: packet type
244  */
246 {
247  struct upf_accel_sw_aging_ll_node *node = &conn->dyn_ctx.entries[pkt_type].sw_aging_node;
248 
251 }
252 
253 /*
254  * Check if a SW aging linked list node is valid
255  *
256  * @node_idx [in]: Node index
257  * @return: true if is valid, false otherwise
258  */
259 static bool upf_accel_sw_aging_ll_node_is_valid(int32_t node_idx)
260 {
261  return (node_idx != UPF_ACCEL_SW_AGING_LL_INVALID_NODE);
262 }
263 
264 /*
265  * Check if a flow exists as a node in the SW Aging linked list
266  *
267  * @fp_data [in]: flow processing data
268  * @conn [in]: connection descriptor
269  * @pkt_type [in]: packet type
270  * @return: true if the node exist, false otherwise
271  */
273  struct upf_accel_entry_ctx *conn,
274  enum parser_pkt_type pkt_type)
275 {
276  struct upf_accel_sw_aging_ll_node *node = &conn->dyn_ctx.entries[pkt_type].sw_aging_node;
277  int32_t conn_idx = conn->dyn_ctx.conn_idx;
278 
280  conn_idx == fp_data->sw_aging_ll[pkt_type].head || conn_idx == fp_data->sw_aging_ll[pkt_type].tail;
281 }
282 
283 /*
284  * Remove node from the SW Aging linked list
285  *
286  * @fp_data [in]: flow processing data
287  * @conn [in]: connection descriptor
288  * @pkt_type [in]: packet type
289  * @return: true if the node existed, false otherwise
290  */
292  struct upf_accel_entry_ctx *conn,
293  enum parser_pkt_type pkt_type)
294 {
295  int32_t prev = conn->dyn_ctx.entries[pkt_type].sw_aging_node.prev;
296  int32_t next = conn->dyn_ctx.entries[pkt_type].sw_aging_node.next;
297  int32_t conn_idx = conn->dyn_ctx.conn_idx;
298  struct upf_accel_entry_ctx *tmp_conn;
299 
300  if (!upf_accel_sw_aging_ll_node_exist(fp_data, conn, pkt_type))
301  return false;
302 
304  tmp_conn = &fp_data->dyn_tbl_data[prev];
305  tmp_conn->dyn_ctx.entries[pkt_type].sw_aging_node.next = next;
306  }
308  tmp_conn = &fp_data->dyn_tbl_data[next];
309  tmp_conn->dyn_ctx.entries[pkt_type].sw_aging_node.prev = prev;
310  }
311  if (fp_data->sw_aging_ll[pkt_type].tail == conn_idx)
312  fp_data->sw_aging_ll[pkt_type].tail = prev;
313  if (fp_data->sw_aging_ll[pkt_type].head == conn_idx)
314  fp_data->sw_aging_ll[pkt_type].head = next;
315 
316  fp_data->unaccel_counters[pkt_type].current--;
317  return true;
318 }
319 
320 /*
321  * Insert node to the head of the SW Aging linked list and update its timestamp
322  *
323  * @fp_data [in]: flow processing data
324  * @conn [in]: connection descriptor
325  * @pkt_type [in]: packet type
326  */
328  struct upf_accel_entry_ctx *conn,
329  enum parser_pkt_type pkt_type)
330 {
331  struct upf_accel_sw_aging_ll_node *node = &conn->dyn_ctx.entries[pkt_type].sw_aging_node;
332  int32_t old_head = fp_data->sw_aging_ll[pkt_type].head;
333  int32_t conn_idx = conn->dyn_ctx.conn_idx;
334  struct upf_accel_entry_ctx *tmp_conn;
335 
336  if (upf_accel_sw_aging_ll_node_is_valid(old_head)) {
337  tmp_conn = &fp_data->dyn_tbl_data[old_head];
338  tmp_conn->dyn_ctx.entries[pkt_type].sw_aging_node.prev = conn_idx;
339  }
340 
342  node->next = old_head;
343  node->timestamp = rte_rdtsc();
344 
345  fp_data->sw_aging_ll[pkt_type].head = conn_idx;
346  if (!upf_accel_sw_aging_ll_node_is_valid(fp_data->sw_aging_ll[pkt_type].tail))
347  fp_data->sw_aging_ll[pkt_type].tail = conn_idx;
348 
349  fp_data->unaccel_counters[pkt_type].current++;
350 }
351 
352 /*
353  * Move node to the head of the SW Aging linked list
354  *
355  * First, remove it from its current position (if exist)
356  * and then insert it to the head.
357  * If the node was not yet in the list, the 'total' counter is increased.
358  *
359  * @fp_data [in]: flow processing data
360  * @conn [in]: connection descriptor
361  * @pkt_type [in]: packet type
362  */
364  struct upf_accel_entry_ctx *conn,
365  enum parser_pkt_type pkt_type)
366 {
367  if (!upf_accel_sw_aging_ll_node_remove(fp_data, conn, pkt_type))
368  fp_data->unaccel_counters[pkt_type].total++;
369 
370  upf_accel_sw_aging_ll_node_insert(fp_data, conn, pkt_type);
371 }
372 
373 /*
374  * Scans all the flows in the list, starting from the oldest (tail), and ages out
375  * all those that have exceeded the aging period until it encounters a flow that
376  * has not yet aged.
377  *
378  * @fp_data [in]: flow processing data
379  * @pkt_type [in]: packet type
380  */
381 static void upf_accel_sw_aging_ll_scan(struct upf_accel_fp_data *fp_data, enum parser_pkt_type pkt_type)
382 {
383  uint64_t aging_period_tsc = fp_data->ctx->upf_accel_cfg->sw_aging_time_sec * rte_get_tsc_hz();
384  int32_t curr = fp_data->sw_aging_ll[pkt_type].tail;
385  struct upf_accel_sw_aging_ll_node *node;
386  uint64_t tsc = rte_rdtsc();
387  struct upf_accel_entry_ctx *conn;
388  doca_error_t ret;
389 
391  conn = &fp_data->dyn_tbl_data[curr];
392  node = &conn->dyn_ctx.entries[pkt_type].sw_aging_node;
393 
394  if (tsc - node->timestamp < aging_period_tsc)
395  break;
396 
397  ret = upf_accel_fp_delete_flow(fp_data, &conn->dyn_ctx, pkt_type);
398  if (ret != DOCA_SUCCESS) {
399  fp_data->unaccel_counters[pkt_type].aging_errors++;
400  DOCA_LOG_ERR("Failed to delete unaccelerated flow");
401  }
402 
403  fp_data->unaccel_counters[pkt_type].current--;
404  curr = node->prev;
405  }
406 
407  fp_data->sw_aging_ll[pkt_type].tail = curr;
408 }
409 
410 /*
411  * Indicate a flow exists
412  *
413  * @flow_status [in]: Status of the connection
414  * @return: true if the connection was initialized, false otherwise
415  */
416 static inline bool upf_accel_flow_is_alive(enum upf_accel_flow_status flow_status)
417 {
418  return flow_status != UPF_ACCEL_FLOW_STATUS_NONE;
419 }
420 
421 /*
422  * Returns a mask with `mask` number of set MSBs
423  *
424  * @mask [in]: number of MSbits to set.
425  * @return: netmask
426  */
427 static inline uint32_t ipv4_netmask_get(uint8_t mask)
428 {
429  return ~((1ul << (32 - mask)) - 1);
430 }
431 
432 /*
433  * Check if masked IPV4 address is matching
434  *
435  * @masked [in]: struct of a masked IPV4 address.
436  * @ipv4 [in]: ipv4 address to match
437  * @return: true if the address matches, otherwise false.
438  */
439 static inline bool ipv4_masked_is_matching(const struct upf_accel_ip_addr *masked, uint32_t ipv4)
440 {
441  return masked->v4 == (ipv4 & ipv4_netmask_get(masked->netmask));
442 }
443 
444 /*
445  * Parse 5 tuple data from a raw packet, without ethernet header.
446  *
447  * @parse_ctx [in]: pointer to the parser context
448  * @src_ip [out]: pointer to store the source IP
449  * @dst_ip [out]: pointer to store the destination IP
450  * @src_port [out]: pointer to store the source port
451  * @dst_port [out]: pointer to store the destination port
452  * @ip_proto [out]: pointer to store the IP protocol
453  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
454  */
456  uint32_t *src_ip,
457  uint32_t *dst_ip,
458  uint16_t *src_port,
459  uint16_t *dst_port,
460  uint8_t *ip_proto)
461 {
462  switch (parse_ctx->transport_ctx.proto) {
463  case DOCA_FLOW_PROTO_TCP: {
464  *src_port = rte_be_to_cpu_16(parse_ctx->transport_ctx.tcp_hdr->src_port);
465  *dst_port = rte_be_to_cpu_16(parse_ctx->transport_ctx.tcp_hdr->dst_port);
466  break;
467  }
468  case DOCA_FLOW_PROTO_UDP: {
469  *src_port = rte_be_to_cpu_16(parse_ctx->transport_ctx.udp_hdr->src_port);
470  *dst_port = rte_be_to_cpu_16(parse_ctx->transport_ctx.udp_hdr->dst_port);
471  break;
472  }
473  default:
474  DOCA_LOG_WARN("Unsupported L4 %d", parse_ctx->transport_ctx.proto);
476  }
477 
478  *src_ip = rte_be_to_cpu_32(parse_ctx->network_ctx.ipv4_hdr->src_addr);
479  *dst_ip = rte_be_to_cpu_32(parse_ctx->network_ctx.ipv4_hdr->dst_addr);
480  *ip_proto = parse_ctx->transport_ctx.proto;
481 
482  return DOCA_SUCCESS;
483 }
484 
485 /*
486  * Create a GTPU match from a raw packet
487  *
488  * @tun_parse_ctx [in]: pointer to the parser context
489  * @match [out]: pointer to store the result at
490  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
491  */
492 static doca_error_t upf_accel_gtpu_match(struct tun_parser_ctx *tun_parse_ctx, struct upf_accel_match_8t *match)
493 {
494  doca_error_t ret;
495 
496  if (tun_parse_ctx->link_ctx.next_proto != RTE_ETHER_TYPE_IPV4 ||
497  tun_parse_ctx->network_ctx.next_proto != DOCA_FLOW_PROTO_UDP ||
498  tun_parse_ctx->transport_ctx.proto != DOCA_FLOW_PROTO_UDP ||
499  rte_be_to_cpu_16(tun_parse_ctx->transport_ctx.udp_hdr->dst_port) != DOCA_FLOW_GTPU_DEFAULT_PORT) {
500  DOCA_LOG_DBG("Only support GTPU encapsulation with UDP over IPv4 and GTPU-reserved destination port");
502  }
503 
504  ret = upf_accel_5t_match(&tun_parse_ctx->inner,
505  &match->inner.ue_ip,
506  &match->inner.extern_ip,
507  &match->inner.ue_port,
508  &match->inner.extern_port,
509  &match->inner.ip_proto);
510  if (ret != DOCA_SUCCESS) {
511  DOCA_LOG_ERR("Failed parsing GTPU PDU");
512  return ret;
513  }
514 
515  match->outer.te_ip = rte_be_to_cpu_32(tun_parse_ctx->network_ctx.ipv4_hdr->src_addr);
516  match->outer.te_id = rte_be_to_cpu_32(tun_parse_ctx->gtp_ctx.gtp_hdr->teid);
517  if (tun_parse_ctx->gtp_ctx.ext_hdr)
518  match->outer.qfi = tun_parse_ctx->gtp_ctx.ext_hdr->qfi;
519  return DOCA_SUCCESS;
520 }
521 
522 /*
523  * Create a match from a raw packet, coming from the RAN side.
524  *
525  * @data [in]: pointer to the start of the data
526  * @data_end [in]: pointer to the end of the data
527  * @parse_ctx [out]: pointer to the parser context
528  * @match [out]: pointer to store the result at
529  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
530  */
531 static doca_error_t upf_accel_ran_match(uint8_t *data,
532  uint8_t *data_end,
533  struct tun_parser_ctx *parse_ctx,
534  struct upf_accel_match_8t *match)
535 {
536  doca_error_t ret;
537 
538  ret = tunnel_parse(data, data_end, parse_ctx);
539  if (ret != DOCA_SUCCESS)
540  return ret;
541 
542  return upf_accel_gtpu_match(parse_ctx, match);
543 }
544 
545 /*
546  * Create a match from a raw packet, coming from the WAN side.
547  *
548  * @data [in]: pointer to the start of the data
549  * @data_end [in]: pointer to the end of the data
550  * @parse_ctx [out]: pointer to the parser context
551  * @match [out]: pointer to store the result at
552  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
553  */
554 static doca_error_t upf_accel_wan_match(uint8_t *data,
555  uint8_t *data_end,
556  struct conn_parser_ctx *parse_ctx,
557  struct upf_accel_match_5t *match)
558 {
559  doca_error_t ret;
560 
561  ret = plain_parse(data, data_end, parse_ctx);
562  if (ret != DOCA_SUCCESS)
563  return ret;
564 
565  return upf_accel_5t_match(parse_ctx,
566  &match->extern_ip,
567  &match->ue_ip,
568  &match->extern_port,
569  &match->ue_port,
570  &match->ip_proto);
571 }
572 
573 /*
574  * Check if a given tunnel header matches the PDR properties.
575  *
576  * @pdr [in]: the PDR describing the match criteria
577  * @match [in]: header to check
578  * @return: true if the header matches, otherwise false.
579  */
580 static bool upf_accel_pdr_tunnel_is_matching(const struct upf_accel_pdr *pdr, const struct upf_accel_match_tun *match)
581 {
582  if (match->te_id < pdr->pdi_local_teid_start || match->te_id > pdr->pdi_local_teid_end)
583  return false;
584 
585  if ((match->qfi || pdr->pdi_qfi) && pdr->pdi_qfi != match->qfi)
586  return false;
587 
588  return ipv4_masked_is_matching(&pdr->pdi_local_teid_ip, match->te_ip);
589 }
590 
591 /*
592  * Check if a given 5 tuple header matches the PDR properties.
593  *
594  * @pdr [in]: the PDR describing the match criteria
595  * @match [in]: header to check
596  * @return: true if the header matches, otherwise false.
597  */
598 static bool upf_accel_pdr_tuple_is_matching(const struct upf_accel_pdr *pdr, const struct upf_accel_match_5t *match)
599 {
600  if (pdr->pdi_sdf_proto && match->ip_proto != pdr->pdi_sdf_proto)
601  return false;
602 
603  if (match->ue_port < pdr->pdi_sdf_from_port_range.from || match->ue_port > pdr->pdi_sdf_from_port_range.to)
604  return false;
605 
606  if (match->extern_port < pdr->pdi_sdf_to_port_range.from || match->extern_port > pdr->pdi_sdf_to_port_range.to)
607  return false;
608 
609  if (pdr->pdi_sdf_from_ip.v4 && !ipv4_masked_is_matching(&pdr->pdi_sdf_from_ip, match->ue_ip))
610  return false;
611 
612  if (pdr->pdi_sdf_to_ip.v4 && !ipv4_masked_is_matching(&pdr->pdi_sdf_to_ip, match->extern_ip))
613  return false;
614 
615  return ipv4_masked_is_matching(&pdr->pdi_ueip, match->ue_ip);
616 }
617 
618 /*
619  * Lookup a PDR that matches a given 8 tuple, from RAN side
620  *
621  * @pdrs [in]: list of PDRs
622  * @match [in]: header to check
623  * @return: pointer to a matching PDR, or NULL if non found
624  */
625 static const struct upf_accel_pdr *upf_accel_ran_pdr_lookup(const struct upf_accel_pdrs *pdrs,
626  const struct upf_accel_match_8t *match)
627 {
628  const struct upf_accel_pdr *pdr;
629  size_t i;
630 
631  for (i = 0; i < pdrs->num_pdrs; i++) {
632  pdr = &pdrs->arr_pdrs[i];
633  if (pdr->pdi_si != UPF_ACCEL_PDR_PDI_SI_UL)
634  continue;
635 
636  if (!upf_accel_pdr_tunnel_is_matching(pdr, &match->outer))
637  continue;
638  if (!upf_accel_pdr_tuple_is_matching(pdr, &match->inner))
639  continue;
640 
641  return pdr;
642  }
643 
644  return NULL;
645 }
646 
647 /*
648  * Decap GTPU header of a packet inplace
649  *
650  * @pkt [in]: pointer to the pkt
651  * @parse_ctx [in]: pointer to the parser context
652  */
653 static void upf_accel_decap(struct rte_mbuf *pkt, struct tun_parser_ctx *parse_ctx)
654 {
655  const uint8_t src_mac[] = UPF_ACCEL_SRC_MAC;
656  const uint8_t dst_mac[] = UPF_ACCEL_DST_MAC;
657  struct rte_ether_hdr *eth = NULL;
658 
659  rte_pktmbuf_adj(pkt, parse_ctx->len - parse_ctx->inner.len - sizeof(*eth));
660 
661  eth = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
662  eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
663  SET_MAC_ADDR(eth->src_addr.addr_bytes, src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]);
664  SET_MAC_ADDR(eth->dst_addr.addr_bytes, dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);
665 }
666 
667 /*
668  * Lookup a PDR that matches a given 5 tuple, from WAN side
669  *
670  * @pdrs [in]: list of PDRs
671  * @match [in]: header to check
672  * @return: pointer to a matching PDR, or NULL if non found
673  */
674 static const struct upf_accel_pdr *upf_accel_wan_pdr_lookup(const struct upf_accel_pdrs *pdrs,
675  const struct upf_accel_match_5t *match)
676 {
677  const struct upf_accel_pdr *pdr;
678  size_t i;
679 
680  for (i = 0; i < pdrs->num_pdrs; i++) {
681  pdr = &pdrs->arr_pdrs[i];
682  if (pdr->pdi_si != UPF_ACCEL_PDR_PDI_SI_DL)
683  continue;
684 
685  if (!upf_accel_pdr_tuple_is_matching(pdr, match))
686  continue;
687 
688  return pdr;
689  }
690 
691  return NULL;
692 }
693 
694 /*
695  * Accelerating 8T flow to the applicable DOCA flow pipe.
696  *
697  * @ctx [in]: UPF Acceleration context.
698  * @port_id [in]: port id to accelerate the flow on
699  * @queue_id [in]: queue ID
700  * @match [in]: software flow match
701  * @pdr_id [in]: matching PDR id
702  * @entry_ctx [in]: resulting DOCA flow entry accelerate context
703  * @entry [out]: resulting DOCA flow entry
704  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
705  */
707  enum upf_accel_port port_id,
708  uint16_t queue_id,
709  struct upf_accel_match_8t *match,
710  uint32_t pdr_id,
712  struct doca_flow_pipe_entry **entry)
713 {
714  struct doca_flow_match hw_match = {0};
715  struct doca_flow_actions actions = {
716  .action_idx = 0,
717  .meta.pkt_meta = DOCA_HTOBE32(pdr_id),
718  };
719  struct doca_flow_pipe *pipe;
720  doca_error_t res;
721 
722  hw_match.outer.ip4.src_ip = rte_cpu_to_be_32(match->outer.te_ip);
723 
724  hw_match.tun.gtp_teid = rte_cpu_to_be_32(match->outer.te_id);
725  hw_match.tun.gtp_ext_psc_qfi = match->outer.qfi & 0x3f;
726  pipe = match->outer.qfi ? ctx->pipes[port_id][UPF_ACCEL_PIPE_8T] : ctx->pipes[port_id][UPF_ACCEL_PIPE_7T];
727 
728  hw_match.inner.ip4.dst_ip = rte_cpu_to_be_32(match->inner.extern_ip);
729  hw_match.inner.ip4.src_ip = rte_cpu_to_be_32(match->inner.ue_ip);
730  hw_match.inner.ip4.next_proto = match->inner.ip_proto;
731  switch (match->inner.ip_proto) {
732  case DOCA_FLOW_PROTO_TCP:
733  hw_match.inner.tcp.l4_port.dst_port = rte_cpu_to_be_16(match->inner.extern_port);
734  hw_match.inner.tcp.l4_port.src_port = rte_cpu_to_be_16(match->inner.ue_port);
735  break;
736  case DOCA_FLOW_PROTO_UDP:
737  hw_match.inner.udp.l4_port.dst_port = rte_cpu_to_be_16(match->inner.extern_port);
738  hw_match.inner.udp.l4_port.src_port = rte_cpu_to_be_16(match->inner.ue_port);
739  break;
740  default:
741  assert(0);
742  }
743 
745  pipe,
746  &hw_match,
747  &actions,
748  NULL,
749  NULL,
751  entry_ctx,
752  entry);
753  if (res != DOCA_SUCCESS) {
754  DOCA_LOG_WARN("Failed to add dynamic 8T entry: %s", doca_error_get_descr(res));
755  return res;
756  }
757 
758  return res;
759 }
760 
761 /*
762  * Accelerating 5T flow to the applicable DOCA flow pipe.
763  *
764  * @ctx [in]: UPF Acceleration context.
765  * @port_id [in]: port id to accelerate the flow on
766  * @queue_id [in]: queue ID
767  * @match [in]: software flow match
768  * @pdr_id [in]: matching PDR id
769  * @entry_ctx [in]: resulting DOCA flow entry accelerate context
770  * @entry [out]: resulting DOCA flow entry
771  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
772  */
774  enum upf_accel_port port_id,
775  uint16_t queue_id,
776  struct upf_accel_match_5t *match,
777  uint32_t pdr_id,
779  struct doca_flow_pipe_entry **entry)
780 {
781  struct doca_flow_pipe *pipe = ctx->pipes[port_id][UPF_ACCEL_PIPE_5T];
782  struct doca_flow_match hw_match = {0};
783  struct doca_flow_actions actions = {
784  .action_idx = 0,
785  .meta.pkt_meta = DOCA_HTOBE32(pdr_id),
786  };
787  doca_error_t res;
788 
789  hw_match.outer.ip4.dst_ip = rte_cpu_to_be_32(match->ue_ip);
790  hw_match.outer.ip4.src_ip = rte_cpu_to_be_32(match->extern_ip);
791  hw_match.outer.ip4.next_proto = match->ip_proto;
792  switch (match->ip_proto) {
793  case DOCA_FLOW_PROTO_TCP:
794  hw_match.outer.tcp.l4_port.dst_port = rte_cpu_to_be_16(match->ue_port);
795  hw_match.outer.tcp.l4_port.src_port = rte_cpu_to_be_16(match->extern_port);
796  break;
797  case DOCA_FLOW_PROTO_UDP:
798  hw_match.outer.udp.l4_port.dst_port = rte_cpu_to_be_16(match->ue_port);
799  hw_match.outer.udp.l4_port.src_port = rte_cpu_to_be_16(match->extern_port);
800  break;
801  default:
802  assert(0);
803  }
804 
805  res = doca_flow_pipe_add_entry(queue_id, pipe, &hw_match, &actions, NULL, NULL, 0, entry_ctx, entry);
806  if (res != DOCA_SUCCESS) {
807  DOCA_LOG_WARN("Failed to add dynamic 5T entry: %s", doca_error_get_descr(res));
808  return res;
809  }
810 
811  return res;
812 }
813 
814 /*
815  * Parse the packet and fill in the match structure.
816  *
817  * @pkt_type [in]: packet type
818  * @pkt [in]: pointer to the pkt
819  * @match [in]: software flow match
820  * @parse_ctx [out]: pointer to the parser context
821  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
822  */
824  struct rte_mbuf *pkt,
825  struct upf_accel_match_8t *match,
826  struct tun_parser_ctx *parse_ctx)
827 {
828  uint8_t *data_beg = rte_pktmbuf_mtod(pkt, uint8_t *);
829  uint8_t *data_end = data_beg + rte_pktmbuf_data_len(pkt);
830  doca_error_t ret;
831 
832  memset(match, 0, sizeof(*match));
833 
834  if (pkt_type == PARSER_PKT_TYPE_TUNNELED) {
835  ret = upf_accel_ran_match(data_beg, data_end, parse_ctx, match);
836  if (ret != DOCA_SUCCESS) {
837  DOCA_LOG_DBG("Failed to parse RAN packet status %u", ret);
838  return ret;
839  }
840  } else {
841  ret = upf_accel_wan_match(data_beg, data_end, &parse_ctx->inner, &match->inner);
842  if (ret != DOCA_SUCCESS) {
843  DOCA_LOG_DBG("Failed to parse WAN packet status %u", ret);
844  return ret;
845  }
846  }
847 
848  return DOCA_SUCCESS;
849 }
850 
851 /*
852  * Fetch packet type from metadata.
853  *
854  * @pkt [in]: pointer to the pkt
855  * @return: packet type (ran / wan)
856  */
857 static enum parser_pkt_type upf_accel_fp_fetch_pkt_type(const struct rte_mbuf *pkt)
858 {
859  const uint32_t md = *RTE_FLOW_DYNF_METADATA(pkt);
860  const uint32_t dir = md & UPF_ACCEL_META_PKT_DIR_MASK;
861 
862  assert(dir == UPF_ACCEL_META_PKT_DIR_UL || dir == UPF_ACCEL_META_PKT_DIR_DL);
863 
865 }
866 
867 /*
868  * Parse the packet burst and fill in the match structures.
869  *
870  * @burst_ctx [in]: packet burst context
871  * @match_mem [in]: array of match structure used to init burst_ctx->matches
872  */
873 static void upf_accel_fp_pkts_match(struct upf_accel_fp_burst_ctx *burst_ctx, struct upf_accel_match_8t match_mem[])
874 {
875  doca_error_t ret;
876  uint16_t i;
877 
878  for (i = 0; i < burst_ctx->rx_pkts_cnt; i++) {
879  burst_ctx->pkts_type[i] = upf_accel_fp_fetch_pkt_type(burst_ctx->rx_pkts[i]);
880  burst_ctx->matches[i] = &match_mem[i];
881 
882  ret = upf_accel_fp_pkt_match(burst_ctx->pkts_type[i],
883  burst_ctx->rx_pkts[i],
884  burst_ctx->matches[i],
885  &burst_ctx->parse_ctxs[i]);
886  if (ret != DOCA_SUCCESS)
887  burst_ctx->pkts_drop[i] = true;
888  }
889 }
890 
891 /*
892  * Compare outer headers (the part of 8/7tuple that is not included in 5tuple)
893  *
894  * @tunnel1 [in]: first tunnel match
895  * @tunnel2 [in]: second tunnel match
896  * @return: true if tunnels are equal, false otherwise
897  */
898 static bool upf_accel_fp_tunnel_eq(struct upf_accel_match_tun *tunnel1, struct upf_accel_match_tun *tunnel2)
899 {
900  return tunnel1->te_ip == tunnel2->te_ip && tunnel1->te_id == tunnel2->te_id && tunnel1->qfi == tunnel2->qfi;
901 }
902 
903 /*
904  * PDR lookup according to 5T match
905  *
906  * @fp_data [in]: flow processing data
907  * @pkt_type [in]: packet type
908  * @match [in]: software flow match
909  * @pdr_out [out]: pdr
910  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
911  */
913  enum parser_pkt_type pkt_type,
914  struct upf_accel_match_8t *match,
915  const struct upf_accel_pdr **pdr_out)
916 {
917  const struct upf_accel_pdr *pdr;
918 
919  pdr = pkt_type == PARSER_PKT_TYPE_TUNNELED ?
920  upf_accel_ran_pdr_lookup(fp_data->ctx->upf_accel_cfg->pdrs, match) :
921  upf_accel_wan_pdr_lookup(fp_data->ctx->upf_accel_cfg->pdrs, &match->inner);
922  if (!pdr) {
923  DOCA_LOG_DBG("Failed to lookup PDR for packet type %u", pkt_type);
924  return DOCA_ERROR_NOT_FOUND;
925  }
926  *pdr_out = pdr;
927 
928  return DOCA_SUCCESS;
929 }
930 
931 /*
932  * Get existing or initialize a new instance of dynamic connection.
933  *
934  * @fp_data [in]: flow processing data
935  * @pkt_type [in]: packet type
936  * @match [in]: software flow match
937  * @conn_idx [in]: existing connection position in dynamic table or a negative value
938  * @conn_out [out]: resulting connection descriptor
939  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
940  */
942  enum parser_pkt_type pkt_type,
943  struct upf_accel_match_8t *match,
944  int32_t conn_idx,
945  struct upf_accel_entry_ctx **conn_out)
946 {
947  struct upf_accel_entry_ctx *conn;
948  const struct upf_accel_pdr *pdr;
950  hash_sig_t hash;
951 
952  if (conn_idx < 0) {
953  result = upf_accel_fp_pdr_lookup(fp_data, pkt_type, match, &pdr);
954  if (result != DOCA_SUCCESS)
955  return result;
956 
957  hash = rte_hash_hash(fp_data->dyn_tbl, &match->inner);
958  conn_idx = rte_hash_add_key_with_hash(fp_data->dyn_tbl, &match->inner, hash);
959  if (conn_idx < 0) {
960  fp_data->accel_failed_counters[pkt_type].errors++;
961  DOCA_LOG_DBG("Couldn't create flow, No space available in the ht, err %d", conn_idx);
962  return DOCA_ERROR_FULL;
963  }
964 
965  conn = &fp_data->dyn_tbl_data[conn_idx];
966  memset(conn, 0, sizeof(*conn));
967  conn->dyn_ctx.match = *match;
968  conn->dyn_ctx.hash = hash;
969  conn->dyn_ctx.pdr_id[pkt_type] = pdr->id;
970  conn->dyn_ctx.fp_data = fp_data;
971  conn->dyn_ctx.conn_idx = conn_idx;
973 
974  upf_accel_sw_aging_ll_node_init(conn, pkt_type);
975  } else {
976  conn = &fp_data->dyn_tbl_data[conn_idx];
977 
978  if (pkt_type == PARSER_PKT_TYPE_TUNNELED) {
979  if (upf_accel_flow_is_alive(conn->dyn_ctx.flow_status[pkt_type]) &&
980  !upf_accel_fp_tunnel_eq(&match->outer, &conn->dyn_ctx.match.outer)) {
981  DOCA_LOG_DBG("Detected packet with same 5tuple as connection with different tunnel");
983  }
984  conn->dyn_ctx.match.outer = match->outer;
985  }
986 
987  /*
988  * The connection was already initialized by a packet arriving
989  * from the opposite type; now, we need to complete the
990  * initialization for the other type.
991  */
992  if (conn->dyn_ctx.flow_status[pkt_type] == UPF_ACCEL_FLOW_STATUS_NONE) {
993  result = upf_accel_fp_pdr_lookup(fp_data, pkt_type, match, &pdr);
994  if (result != DOCA_SUCCESS)
995  return result;
996 
998  conn->dyn_ctx.pdr_id[pkt_type] = pdr->id;
999  upf_accel_sw_aging_ll_node_init(conn, pkt_type);
1000  }
1001  }
1002 
1003  *conn_out = conn;
1004  return DOCA_SUCCESS;
1005 }
1006 
1007 /*
1008  * Get existing or initialize a new instance of dynamic connection for every packet in the burst.
1009  *
1010  * @fp_data [in]: flow processing data
1011  * @burst_ctx [in]: packet burst context
1012  */
1013 static void upf_accel_fp_conns_lookup(struct upf_accel_fp_data *fp_data, struct upf_accel_fp_burst_ctx *burst_ctx)
1014 {
1015  int32_t conn_idxs[RTE_HASH_LOOKUP_BULK_MAX];
1016  doca_error_t ret;
1017  uint16_t i;
1018  int err;
1019 
1020  if (!burst_ctx->rx_pkts_cnt)
1021  return;
1022 
1023  err = rte_hash_lookup_bulk(fp_data->dyn_tbl,
1024  (const void **)burst_ctx->matches,
1025  burst_ctx->rx_pkts_cnt,
1026  conn_idxs);
1027  assert(!err);
1028  UNUSED(err);
1029 
1030  for (i = 0; i < burst_ctx->rx_pkts_cnt; i++) {
1031  if (burst_ctx->pkts_drop[i])
1032  continue;
1033 
1034  ret = upf_accel_fp_conn_lookup(fp_data,
1035  burst_ctx->pkts_type[i],
1036  burst_ctx->matches[i],
1037  conn_idxs[i],
1038  &burst_ctx->conns[i]);
1039  if (ret != DOCA_SUCCESS)
1040  burst_ctx->pkts_drop[i] = true;
1041  }
1042 }
1043 
1044 /*
1045  * Accelerate a unidirectional flow on a connection
1046  *
1047  * @fp_data [in]: flow processing data
1048  * @port_id [in]: port id
1049  * @pkt_type [in]: packet type
1050  * @match [in]: software flow match
1051  * @conn [in]: connection descriptor
1052  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1053  */
1055  enum upf_accel_port port_id,
1056  enum parser_pkt_type pkt_type,
1057  struct upf_accel_match_8t *match,
1058  struct upf_accel_entry_ctx *conn)
1059 {
1060  doca_error_t ret;
1061 
1062  if (conn->dyn_ctx.flow_status[pkt_type] == UPF_ACCEL_FLOW_STATUS_ACCELERATED)
1063  return DOCA_ERROR_ALREADY_EXIST;
1065  return DOCA_SUCCESS;
1066 
1067  if (upf_accel_flow_is_alive(conn->dyn_ctx.flow_status[pkt_type]) &&
1068  (conn->dyn_ctx.cnt_pkts[pkt_type] + 1) < fp_data->ctx->upf_accel_cfg->dpi_threshold) {
1070  return DOCA_SUCCESS;
1071  }
1072 
1073  ret = pkt_type == PARSER_PKT_TYPE_TUNNELED ? upf_accel_pipe_8t_accel(fp_data->ctx,
1074  port_id,
1075  fp_data->queue_id,
1076  match,
1077  conn->dyn_ctx.pdr_id[pkt_type],
1078  conn,
1079  &conn->dyn_ctx.entries[pkt_type].entry) :
1080  upf_accel_pipe_5t_accel(fp_data->ctx,
1081  port_id,
1082  fp_data->queue_id,
1083  &match->inner,
1084  conn->dyn_ctx.pdr_id[pkt_type],
1085  conn,
1086  &conn->dyn_ctx.entries[pkt_type].entry);
1087  switch (ret) {
1088  case DOCA_SUCCESS:
1090  upf_accel_sw_aging_ll_node_remove(fp_data, conn, pkt_type);
1091  break;
1092  default:
1094  fp_data->accel_failed_counters[pkt_type].current++;
1095  fp_data->accel_failed_counters[pkt_type].total++;
1096  DOCA_LOG_DBG("Failed to accelerate connection on port %u, type %u.", port_id, pkt_type);
1097  }
1098 
1099  return DOCA_SUCCESS;
1100 }
1101 
1102 /*
1103  * Increase packet counter (bytes and number).
1104  *
1105  * @ctr [in]: counter to increase.
1106  * @pkt [in]: pointer to the pkt mbuf.
1107  */
1108 static inline void upf_accel_packet_byte_counter_inc(struct upf_accel_packet_byte_counter *ctr, struct rte_mbuf *pkt)
1109 {
1110  ctr->pkts++;
1111  ctr->bytes += rte_pktmbuf_pkt_len(pkt);
1112 }
1113 
1114 /*
1115  * Accelerate a unidirectional flow on every connection in the burst.
1116  *
1117  * @fp_data [in]: flow processing data
1118  * @rx_port_id [in]: incoming packet port id
1119  * @burst_ctx [in]: packet burst context
1120  */
1121 static void upf_accel_fp_flows_accel(struct upf_accel_fp_data *fp_data,
1122  enum upf_accel_port rx_port_id,
1123  struct upf_accel_fp_burst_ctx *burst_ctx)
1124 {
1125  enum parser_pkt_type pkt_type;
1126  struct upf_accel_entry_ctx *conn;
1127  struct rte_mbuf *pkt;
1128  doca_error_t ret;
1129  uint16_t i;
1130 
1131  for (i = 0; i < burst_ctx->rx_pkts_cnt; i++) {
1132  if (burst_ctx->pkts_drop[i])
1133  continue;
1134 
1135  conn = burst_ctx->conns[i];
1136  pkt = burst_ctx->rx_pkts[i];
1137  pkt_type = burst_ctx->pkts_type[i];
1138 
1139  ret = upf_accel_fp_flow_accel(fp_data, rx_port_id, pkt_type, burst_ctx->matches[i], conn);
1140  if (ret == DOCA_ERROR_ALREADY_EXIST)
1141  DOCA_LOG_DBG("Got a sneaker packet on core %u, port %u, type %u.",
1142  fp_data->queue_id,
1143  rx_port_id,
1144  pkt_type);
1145 
1146  if (conn->dyn_ctx.cnt_pkts[pkt_type])
1148  else
1150 
1151  conn->dyn_ctx.cnt_pkts[pkt_type]++;
1152  conn->dyn_ctx.cnt_bytes[pkt_type] += rte_pktmbuf_pkt_len(pkt);
1153  }
1154 }
1155 
1156 /*
1157  * Drop the packet and increase error counters.
1158  *
1159  * @fp_data [in]: flow processing data
1160  * @pkt [in]: packet to drop
1161  */
1162 static void upf_accel_fp_pkt_err_drop(struct upf_accel_fp_data *fp_data, struct rte_mbuf *pkt)
1163 {
1165  rte_pktmbuf_free(pkt);
1166 }
1167 
1168 /*
1169  * Set metadata to a packet, in place
1170  *
1171  * @pkt [in]: pointer to the pkt
1172  * @md [in]: metadata to set
1173  */
1174 static void upf_accel_md_set(struct rte_mbuf *pkt, uint32_t md)
1175 {
1176  assert(md < UPF_ACCEL_MAX_NUM_PDR);
1177  *RTE_FLOW_DYNF_METADATA(pkt) = md;
1178  pkt->ol_flags |= RTE_MBUF_DYNFLAG_TX_METADATA;
1179 }
1180 
1181 /*
1182  * Check if the flow is not in an accelerated status
1183  *
1184  * @pkt_type [in]: packet type
1185  * @conn [in]: connection descriptor
1186  * @return: true if it`s unaccelerated, false otherwise
1187  */
1188 static bool is_flow_unaccelerated(enum parser_pkt_type pkt_type, struct upf_accel_entry_ctx *conn)
1189 {
1190  return (conn->dyn_ctx.flow_status[pkt_type] == UPF_ACCEL_FLOW_STATUS_FAILED_ACCELERATION) ||
1192 }
1193 
1194 /*
1195  * Perform miscellaneous post processing operations on the burst. (packet metadata, decap, send)
1196  *
1197  * @fp_data [in]: flow processing data
1198  * @burst_ctx [in]: packet burst context
1199  */
1200 static void upf_accel_fp_burst_postprocess(struct upf_accel_fp_data *fp_data, struct upf_accel_fp_burst_ctx *burst_ctx)
1201 {
1202  enum parser_pkt_type pkt_type;
1203  struct upf_accel_entry_ctx *conn;
1204  struct upf_accel_match_8t *match;
1205  struct rte_mbuf *pkt;
1206  uint16_t i;
1207 
1208  for (i = 0; i < burst_ctx->rx_pkts_cnt; i++) {
1209  pkt = burst_ctx->rx_pkts[i];
1210  conn = burst_ctx->conns[i];
1211  match = burst_ctx->matches[i];
1212  pkt_type = burst_ctx->pkts_type[i];
1213 
1214  if (burst_ctx->pkts_drop[i]) {
1215  upf_accel_fp_pkt_err_drop(fp_data, pkt);
1216  continue;
1217  }
1218 
1219  DOCA_LOG_DBG(
1220  "Core %u, type %u parsed 8t tun_ip=%x teid=%u qfi=%hhu ue_ip=%x extern_ip=%x ue_port=%hu extern_port=%hu ip_proto=%hhu pdr=%u ran_pkts=%lu ran_bytes=%lu, wan_pkts=%lu, wan_bytes=%lu",
1221  rte_lcore_id(),
1222  pkt_type,
1223  match->outer.te_ip,
1224  match->outer.te_id,
1225  match->outer.qfi,
1226  match->inner.ue_ip,
1227  match->inner.extern_ip,
1228  match->inner.ue_port,
1229  match->inner.extern_port,
1230  match->inner.ip_proto,
1231  conn->dyn_ctx.pdr_id[pkt_type],
1236 
1237  if (pkt_type == PARSER_PKT_TYPE_TUNNELED)
1238  upf_accel_decap(pkt, &burst_ctx->parse_ctxs[i]);
1239 
1240  if (is_flow_unaccelerated(pkt_type, conn))
1241  upf_accel_sw_aging_ll_node_move_to_head(fp_data, conn, pkt_type);
1242 
1243  upf_accel_md_set(pkt, conn->dyn_ctx.pdr_id[pkt_type]);
1244  burst_ctx->tx_pkts[burst_ctx->tx_pkts_cnt++] = burst_ctx->rx_pkts[i];
1245  }
1246 }
1247 
1248 /*
1249  * Initialize aging infrastructure.
1250  *
1251  * @fp_data [in]: flow processing data
1252  */
1253 static void upf_accel_aging_init(struct upf_accel_fp_data *fp_data)
1254 {
1255  enum upf_accel_port port_id;
1256 
1257  for (port_id = 0; port_id < fp_data->ctx->num_ports; port_id++)
1258  fp_data->last_hw_aging_tsc[port_id] = rte_rdtsc();
1259 }
1260 
1261 /*
1262  * If aging is in progress or the aging period timeout has expired, poll for up to UPF_ACCEL_MAX_NUM_AGING entries. Note
1263  * that this function doesn't process any potential resulting flow removals and relies on the caller to do it
1264  * afterwards, potentially combining it with entry additions/removal scheduled by other sources.
1265  *
1266  * @fp_data [in]: flow processing data
1267  * @port_id [in]: port_id of the port to remove the aged flows from
1268  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
1269  */
1271 {
1272  uint64_t aging_interval_tsc = UPF_ACCEL_HW_AGING_POLL_INTERVAL_SEC * rte_get_tsc_hz();
1273  struct upf_accel_ctx *ctx = fp_data->ctx;
1274  int num_aged_entries;
1275 
1276  if (rte_rdtsc() - fp_data->last_hw_aging_tsc[port_id] >= aging_interval_tsc) {
1277  if (fp_data->hw_aging_in_progress[port_id])
1278  DOCA_LOG_ERR("In core %d port %d: couldn't finish HW aging, continuing...",
1279  fp_data->queue_id,
1280  port_id);
1281  fp_data->hw_aging_in_progress[port_id] = true;
1282  fp_data->last_hw_aging_tsc[port_id] = rte_rdtsc();
1283  }
1284  if (!fp_data->hw_aging_in_progress[port_id])
1285  return DOCA_SUCCESS;
1286 
1287  num_aged_entries = doca_flow_aging_handle(ctx->ports[port_id],
1288  fp_data->queue_id,
1291  if (num_aged_entries == -1)
1292  fp_data->hw_aging_in_progress[port_id] = false;
1293  else
1294  DOCA_LOG_DBG("In core %d port %d: num of aged entries: %d",
1295  fp_data->queue_id,
1296  port_id,
1297  num_aged_entries);
1298 
1299  return DOCA_SUCCESS;
1300 }
1301 
1302 /*
1303  * Run one iteration of flow processing for specific port
1304  *
1305  * Receive burst of packets on rx port, process them accelerating any rules, if
1306  * necessary, and send the packets out to tx port.
1307  *
1308  * @fp_data [in]: flow processing data
1309  * @rx_port_id [in]: receive port id
1310  * @tx_port_id [in]: send port id
1311  */
1312 static void upf_accel_fp_run_port(struct upf_accel_fp_data *fp_data,
1313  enum upf_accel_port rx_port_id,
1314  enum upf_accel_port tx_port_id)
1315 {
1316  struct upf_accel_match_8t match_mem[UPF_ACCEL_MAX_PKT_BURST];
1317  struct upf_accel_fp_burst_ctx burst_ctx = {
1318  .pkts_drop = {0},
1319  };
1320  doca_error_t ret;
1321  uint16_t sent;
1322 
1323  burst_ctx.rx_pkts_cnt =
1324  rte_eth_rx_burst(rx_port_id, fp_data->queue_id, burst_ctx.rx_pkts, UPF_ACCEL_MAX_PKT_BURST);
1325 
1326  upf_accel_fp_pkts_match(&burst_ctx, match_mem);
1327  upf_accel_fp_conns_lookup(fp_data, &burst_ctx);
1328  upf_accel_fp_flows_accel(fp_data, rx_port_id, &burst_ctx);
1329  upf_accel_fp_burst_postprocess(fp_data, &burst_ctx);
1330 
1331  ret = upf_accel_hw_aging_poll(fp_data, rx_port_id);
1332  if (ret != DOCA_SUCCESS)
1333  DOCA_LOG_ERR("Failed to execute HW aging poll on port %hu: %s", rx_port_id, doca_error_get_descr(ret));
1334 
1335  ret = doca_flow_entries_process(fp_data->ctx->ports[rx_port_id],
1336  fp_data->queue_id,
1338  0);
1339  if (ret != DOCA_SUCCESS)
1340  DOCA_LOG_ERR("Failed to process flow entries on port %hu: %s", rx_port_id, doca_error_get_descr(ret));
1341 
1342  sent = rte_eth_tx_burst(tx_port_id, fp_data->queue_id, burst_ctx.tx_pkts, burst_ctx.tx_pkts_cnt);
1343  if (unlikely(sent < burst_ctx.tx_pkts_cnt)) {
1344  DOCA_LOG_WARN("Failed to send packets to port id %hu queue %hu", tx_port_id, fp_data->queue_id);
1345 
1346  do {
1347  upf_accel_fp_pkt_err_drop(fp_data, burst_ctx.tx_pkts[sent]);
1348  } while (++sent < burst_ctx.tx_pkts_cnt);
1349  }
1350 }
1351 
1352 /*
1353  * Run one iteration of flow processing.
1354  *
1355  * @fp_data [in]: flow processing data
1356  */
1357 static void upf_accel_fp_run(struct upf_accel_fp_data *fp_data)
1358 {
1359  enum upf_accel_port port_id;
1360 
1361  for (port_id = 0; port_id < fp_data->ctx->num_ports; port_id++)
1362  upf_accel_fp_run_port(fp_data, port_id, fp_data->ctx->get_fwd_port(port_id));
1363 }
1364 
1365 /*
1366  * Check and handles (if exceeds) a quota for pdr
1367  *
1368  * @ctx [in]: UPF Acceleration context
1369  * @pdr_id [in]: pdr ID
1370  * @query [in]: quota counter query
1371  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1372  */
1374  uint16_t pdr_id,
1375  struct doca_flow_resource_query *query)
1376 {
1377  struct upf_accel_pdr *pdr = &ctx->upf_accel_cfg->pdrs->arr_pdrs[pdr_id];
1378  struct upf_accel_urr *urr;
1379  uint32_t i;
1380 
1381  for (i = 0; i < pdr->urrids_num; ++i) {
1382  urr = &ctx->upf_accel_cfg->urrs->arr_urrs[pdr->urrids[i]];
1383  if (query->counter.total_bytes >= urr->volume_quota_total_volume) {
1384  /*
1385  * Quota exceeded.
1386  * This code part should be implemented once a definition
1387  * of how to react is complete.
1388  */
1389  }
1390  }
1391 
1392  return DOCA_SUCCESS;
1393 }
1394 
1395 /*
1396  * Iterates through all quota counters and handles if exceeds
1397  *
1398  * @fp_data [in]: flow processing data
1399  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1400  */
1402 {
1403  struct app_shared_counter_ids *shared_counter_ids = &fp_data->quota_cntrs;
1404  struct doca_flow_resource_query query_results_array[UPF_ACCEL_MAX_NUM_PDR];
1405  size_t cntrs_num = shared_counter_ids->cntrs_num;
1406  enum upf_accel_port port_id;
1408  uint16_t pdr_id;
1409  uint32_t i;
1410 
1411  if (!cntrs_num)
1412  return DOCA_SUCCESS;
1413 
1414  for (port_id = 0; port_id < fp_data->ctx->num_ports; ++port_id) {
1416  shared_counter_ids->ids[port_id],
1417  query_results_array,
1418  cntrs_num);
1419  if (result != DOCA_SUCCESS) {
1420  DOCA_LOG_ERR("Failed to query entries: %s", doca_error_get_descr(result));
1421  return result;
1422  }
1423 
1424  for (i = 0; i < cntrs_num; ++i) {
1425  pdr_id = shared_counter_ids->cntr_0 + i;
1426 
1427  result = handle_exceeds_quota_for_pdr(fp_data->ctx, pdr_id, &query_results_array[i]);
1428  if (result != DOCA_SUCCESS) {
1429  DOCA_LOG_ERR("Failed to handle quota for pdr %d: %s",
1430  pdr_id,
1432  return result;
1433  }
1434  }
1435  }
1436 
1437  return DOCA_SUCCESS;
1438 }
1439 
1441 {
1443 
1444  upf_accel_aging_init(fp_data);
1445 
1446  while (!force_quit) {
1447  upf_accel_fp_run(fp_data);
1448 
1451 
1452  result = handle_exceeds_quotas(fp_data);
1453  if (result != DOCA_SUCCESS) {
1454  DOCA_LOG_ERR("Failed to handle expired quotas: %s", doca_error_get_descr(result));
1455  return;
1456  }
1457  }
1458 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
#define SET_MAC_ADDR(addr, a, b, c, d, e, f)
Definition: flow_common.h:60
#define likely(x)
Definition: utils.h:38
#define unlikely(x)
Definition: utils.h:42
static struct doca_flow_actions actions
Definition: flow_parser.c:107
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
static volatile bool force_quit
Definition: flow_skeleton.c:49
#define DOCA_HTOBE32(_x)
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_descr(doca_error_t error)
Returns the description string of an error code.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_ERROR_NOT_FOUND
Definition: doca_error.h:54
@ DOCA_ERROR_NOT_SUPPORTED
Definition: doca_error.h:42
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_FULL
Definition: doca_error.h:62
@ DOCA_ERROR_ALREADY_EXIST
Definition: doca_error.h:61
#define DOCA_FLOW_PROTO_UDP
Definition: doca_flow_net.h:42
#define DOCA_FLOW_PROTO_TCP
Definition: doca_flow_net.h:41
#define DOCA_FLOW_GTPU_DEFAULT_PORT
Definition: doca_flow_net.h:48
DOCA_STABLE doca_error_t doca_flow_entries_process(struct doca_flow_port *port, uint16_t pipe_queue, uint64_t timeout, uint32_t max_processed_entries)
Process entries in queue.
doca_flow_entry_op
doca flow entry operation
Definition: doca_flow.h:146
DOCA_STABLE int doca_flow_aging_handle(struct doca_flow_port *port, uint16_t queue, uint64_t quota, uint64_t max_entries)
Handle aging of entries.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_add_entry(uint16_t pipe_queue, struct doca_flow_pipe *pipe, const struct doca_flow_match *match, const struct doca_flow_actions *actions, const struct doca_flow_monitor *monitor, const struct doca_flow_fwd *fwd, uint32_t flags, void *usr_ctx, struct doca_flow_pipe_entry **entry)
Add one new entry to a pipe.
DOCA_STABLE doca_error_t doca_flow_pipe_remove_entry(uint16_t pipe_queue, uint32_t flags, struct doca_flow_pipe_entry *entry)
Free one pipe entry.
doca_flow_entry_status
doca flow entry status
Definition: doca_flow.h:160
DOCA_EXPERIMENTAL doca_error_t doca_flow_shared_resources_query(enum doca_flow_shared_resource_type type, uint32_t *res_array, struct doca_flow_resource_query *query_results_array, uint32_t array_len)
Extract information about shared counter.
@ DOCA_FLOW_SHARED_RESOURCE_COUNTER
Definition: doca_flow.h:95
@ DOCA_FLOW_ENTRY_OP_ADD
Definition: doca_flow.h:147
@ DOCA_FLOW_ENTRY_OP_AGED
Definition: doca_flow.h:153
@ DOCA_FLOW_ENTRY_OP_DEL
Definition: doca_flow.h:149
@ DOCA_FLOW_WAIT_FOR_BATCH
Definition: doca_flow.h:117
@ DOCA_FLOW_ENTRY_STATUS_SUCCESS
Definition: doca_flow.h:163
@ DOCA_FLOW_ENTRY_STATUS_ERROR
Definition: doca_flow.h:165
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
uint16_t queue_id
Definition: ip_frag_dp.c:1
#define UNUSED(x)
Definition: ip_frag_dp.h:35
doca_error_t tunnel_parse(uint8_t *data, uint8_t *data_end, struct tun_parser_ctx *ctx)
doca_error_t plain_parse(uint8_t *data, uint8_t *data_end, struct conn_parser_ctx *ctx)
parser_pkt_type
Definition: packet_parser.h:35
@ PARSER_PKT_TYPE_PLAIN
Definition: packet_parser.h:37
@ PARSER_PKT_TYPE_TUNNELED
Definition: packet_parser.h:36
uint16_t src_port
Definition: packets.h:0
uint16_t dst_port
Definition: packets.h:1
rte_ether_hdr eth
Definition: psp_gw_flows.cpp:1
uint32_t * ids[UPF_ACCEL_PORTS_MAX]
Definition: upf_accel.h:171
struct network_parser_ctx network_ctx
Definition: packet_parser.h:81
struct transport_parser_ctx transport_ctx
Definition: packet_parser.h:82
doca flow actions information
Definition: doca_flow.h:684
uint8_t action_idx
Definition: doca_flow.h:685
struct doca_flow_header_ip4 ip4
Definition: doca_flow.h:449
struct doca_flow_header_udp udp
Definition: doca_flow.h:459
struct doca_flow_header_tcp tcp
Definition: doca_flow.h:461
struct doca_flow_header_l4_port l4_port
struct doca_flow_header_l4_port l4_port
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_header_format inner
Definition: doca_flow.h:502
struct doca_flow_header_format outer
Definition: doca_flow.h:498
struct doca_flow_tun tun
Definition: doca_flow.h:500
flow resource query
Definition: doca_flow.h:1101
struct doca_flow_resource_query::@115::@117 counter
uint8_t gtp_ext_psc_qfi
doca_be32_t gtp_teid
user context struct that will be used in entries process callback
Definition: flow_common.h:78
struct rte_gtp_psc_type0_hdr * ext_hdr
Definition: packet_parser.h:75
struct rte_gtp_hdr * gtp_hdr
Definition: packet_parser.h:73
struct rte_ipv4_hdr * ipv4_hdr
Definition: packet_parser.h:54
struct rte_udp_hdr * udp_hdr
Definition: packet_parser.h:66
struct rte_tcp_hdr * tcp_hdr
Definition: packet_parser.h:67
struct link_parser_ctx link_ctx
Definition: packet_parser.h:87
struct transport_parser_ctx transport_ctx
Definition: packet_parser.h:89
struct conn_parser_ctx inner
Definition: packet_parser.h:91
struct network_parser_ctx network_ctx
Definition: packet_parser.h:88
struct gtp_parser_ctx gtp_ctx
Definition: packet_parser.h:90
struct upf_accel_pdrs * pdrs
Definition: upf_accel.h:260
uint32_t sw_aging_time_sec
Definition: upf_accel.h:267
struct upf_accel_urrs * urrs
Definition: upf_accel.h:262
uint32_t dpi_threshold
Definition: upf_accel.h:268
upf_accel_get_forwarding_port get_fwd_port
Definition: upf_accel.h:351
struct doca_flow_pipe * pipes[UPF_ACCEL_PORTS_MAX][UPF_ACCEL_PIPE_NUM]
Definition: upf_accel.h:343
struct doca_flow_port * ports[UPF_ACCEL_PORTS_MAX]
Definition: upf_accel.h:344
uint16_t num_ports
Definition: upf_accel.h:338
const struct upf_accel_config * upf_accel_cfg
Definition: upf_accel.h:342
Definition: upf_accel.h:305
uint64_t cnt_pkts[PARSER_PKT_TYPE_NUM]
Definition: upf_accel.h:307
struct upf_accel_match_8t match
Definition: upf_accel.h:306
uint32_t pdr_id[PARSER_PKT_TYPE_NUM]
Definition: upf_accel.h:319
struct doca_flow_pipe_entry * entry
Definition: upf_accel.h:313
hash_sig_t hash
Definition: upf_accel.h:321
struct upf_accel_fp_data * fp_data
Definition: upf_accel.h:318
uint64_t cnt_bytes[PARSER_PKT_TYPE_NUM]
Definition: upf_accel.h:308
union upf_accel_dyn_entry_ctx::@47 entries[PARSER_PKT_TYPE_NUM]
enum doca_flow_entry_status status
Definition: upf_accel.h:312
struct upf_accel_sw_aging_ll_node sw_aging_node
Definition: upf_accel.h:316
int32_t conn_idx
Definition: upf_accel.h:320
enum upf_accel_flow_status flow_status[PARSER_PKT_TYPE_NUM]
Definition: upf_accel.h:322
Definition: upf_accel.h:329
struct upf_accel_dyn_entry_ctx dyn_ctx
Definition: upf_accel.h:332
enum parser_pkt_type pkts_type[UPF_ACCEL_MAX_PKT_BURST]
struct tun_parser_ctx parse_ctxs[UPF_ACCEL_MAX_PKT_BURST]
struct rte_mbuf * tx_pkts[UPF_ACCEL_MAX_PKT_BURST]
bool pkts_drop[UPF_ACCEL_MAX_PKT_BURST]
struct rte_mbuf * rx_pkts[UPF_ACCEL_MAX_PKT_BURST]
struct upf_accel_entry_ctx * conns[UPF_ACCEL_MAX_PKT_BURST]
struct upf_accel_match_8t * matches[UPF_ACCEL_MAX_PKT_BURST]
struct upf_accel_fp_accel_counters accel_failed_counters[PARSER_PKT_TYPE_NUM]
bool hw_aging_in_progress[UPF_ACCEL_PORTS_MAX]
struct upf_accel_entry_ctx * dyn_tbl_data
struct upf_accel_ctx * ctx
struct app_shared_counter_ids quota_cntrs
struct upf_accel_fp_sw_counters sw_counters
uint64_t last_hw_aging_tsc[UPF_ACCEL_PORTS_MAX]
struct upf_accel_sw_aging_ll sw_aging_ll[PARSER_PKT_TYPE_NUM]
struct upf_accel_fp_accel_counters accel_counters[PARSER_PKT_TYPE_NUM]
struct upf_accel_fp_accel_counters unaccel_counters[PARSER_PKT_TYPE_NUM]
struct upf_accel_packet_byte_counter new_conn
struct upf_accel_packet_byte_counter err
struct upf_accel_packet_byte_counter ex_conn
uint16_t ue_port
Definition: upf_accel.h:282
uint16_t extern_port
Definition: upf_accel.h:283
uint32_t extern_ip
Definition: upf_accel.h:281
struct upf_accel_match_5t inner
Definition: upf_accel.h:289
struct upf_accel_match_tun outer
Definition: upf_accel.h:290
struct upf_accel_ip_addr pdi_sdf_to_ip
Definition: upf_accel.h:205
uint32_t urrids_num
Definition: upf_accel.h:192
uint8_t pdi_qfi
Definition: upf_accel.h:202
uint16_t pdi_sdf_proto
Definition: upf_accel.h:201
struct upf_accel_ip_addr pdi_local_teid_ip
Definition: upf_accel.h:199
struct upf_accel_ip_addr pdi_sdf_from_ip
Definition: upf_accel.h:203
uint32_t pdi_local_teid_start
Definition: upf_accel.h:197
uint32_t pdi_local_teid_end
Definition: upf_accel.h:198
struct upf_accel_ip_addr pdi_ueip
Definition: upf_accel.h:200
uint32_t urrids[UPF_ACCEL_PDR_URRIDS_LEN]
Definition: upf_accel.h:193
struct upf_accel_ip_port_range pdi_sdf_from_port_range
Definition: upf_accel.h:204
enum upf_accel_pdr_pdi_si pdi_si
Definition: upf_accel.h:196
struct upf_accel_ip_port_range pdi_sdf_to_port_range
Definition: upf_accel.h:206
uint32_t id
Definition: upf_accel.h:190
struct upf_accel_pdr arr_pdrs[]
Definition: upf_accel.h:211
size_t num_pdrs
Definition: upf_accel.h:210
Definition: upf_accel.h:325
struct entries_status ctrl_status
Definition: upf_accel.h:326
uint64_t volume_quota_total_volume
Definition: upf_accel.h:227
struct upf_accel_urr arr_urrs[]
Definition: upf_accel.h:232
upf_accel_flow_status
Definition: upf_accel.h:162
@ UPF_ACCEL_FLOW_STATUS_UNACCELERATED
Definition: upf_accel.h:165
@ UPF_ACCEL_FLOW_STATUS_FAILED_ACCELERATION
Definition: upf_accel.h:167
@ UPF_ACCEL_FLOW_STATUS_ACCELERATED
Definition: upf_accel.h:166
@ UPF_ACCEL_FLOW_STATUS_PENDING
Definition: upf_accel.h:164
@ UPF_ACCEL_FLOW_STATUS_NONE
Definition: upf_accel.h:163
#define UPF_ACCEL_SRC_MAC
Definition: upf_accel.h:58
#define UPF_ACCEL_HW_AGING_POLL_INTERVAL_SEC
Definition: upf_accel.h:78
#define UPF_ACCEL_META_PKT_DIR_UL
Definition: upf_accel.h:74
upf_accel_port
Definition: upf_accel.h:40
struct upf_accel_dyn_entry_ctx dyn_ctx
Definition: upf_accel.h:2
#define UPF_ACCEL_DST_MAC
Definition: upf_accel.h:62
#define UPF_ACCEL_MAX_NUM_PDR
Definition: upf_accel.h:54
#define UPF_ACCEL_META_PKT_DIR_DL
Definition: upf_accel.h:75
@ UPF_ACCEL_RULE_DYNAMIC
Definition: upf_accel.h:158
@ UPF_ACCEL_PIPE_8T
Definition: upf_accel.h:142
@ UPF_ACCEL_PIPE_5T
Definition: upf_accel.h:144
@ UPF_ACCEL_PIPE_7T
Definition: upf_accel.h:143
#define UPF_ACCEL_META_PKT_DIR_MASK
Definition: upf_accel.h:76
struct upf_accel_static_entry_ctx static_ctx
Definition: upf_accel.h:3
@ UPF_ACCEL_PDR_PDI_SI_DL
Definition: upf_accel.h:104
@ UPF_ACCEL_PDR_PDI_SI_UL
Definition: upf_accel.h:103
void upf_accel_sw_aging_ll_init(struct upf_accel_fp_data *fp_data, enum parser_pkt_type pkt_type)
static bool upf_accel_fp_tunnel_eq(struct upf_accel_match_tun *tunnel1, struct upf_accel_match_tun *tunnel2)
static doca_error_t handle_exceeds_quotas(struct upf_accel_fp_data *fp_data)
DOCA_LOG_REGISTER(UPF_ACCEL::FLOW_PROCESSING)
static void upf_accel_sw_aging_ll_node_insert(struct upf_accel_fp_data *fp_data, struct upf_accel_entry_ctx *conn, enum parser_pkt_type pkt_type)
static const struct upf_accel_pdr * upf_accel_wan_pdr_lookup(const struct upf_accel_pdrs *pdrs, const struct upf_accel_match_5t *match)
static void upf_accel_static_entry_cb(struct upf_accel_static_entry_ctx *static_ctx, enum doca_flow_entry_status status, enum doca_flow_entry_op op)
static void upf_accel_decap(struct rte_mbuf *pkt, struct tun_parser_ctx *parse_ctx)
static bool ipv4_masked_is_matching(const struct upf_accel_ip_addr *masked, uint32_t ipv4)
static doca_error_t upf_accel_fp_flow_accel(struct upf_accel_fp_data *fp_data, enum upf_accel_port port_id, enum parser_pkt_type pkt_type, struct upf_accel_match_8t *match, struct upf_accel_entry_ctx *conn)
static doca_error_t upf_accel_fp_pkt_match(enum parser_pkt_type pkt_type, struct rte_mbuf *pkt, struct upf_accel_match_8t *match, struct tun_parser_ctx *parse_ctx)
static const struct upf_accel_pdr * upf_accel_ran_pdr_lookup(const struct upf_accel_pdrs *pdrs, const struct upf_accel_match_8t *match)
static enum parser_pkt_type upf_accel_fp_fetch_pkt_type(const struct rte_mbuf *pkt)
static doca_error_t upf_accel_fp_delete_flow(struct upf_accel_fp_data *fp_data, struct upf_accel_dyn_entry_ctx *dyn_ctx, enum parser_pkt_type pkt_type)
static bool upf_accel_pdr_tunnel_is_matching(const struct upf_accel_pdr *pdr, const struct upf_accel_match_tun *match)
static void upf_accel_packet_byte_counter_inc(struct upf_accel_packet_byte_counter *ctr, struct rte_mbuf *pkt)
static void upf_accel_fp_pkt_err_drop(struct upf_accel_fp_data *fp_data, struct rte_mbuf *pkt)
static doca_error_t upf_accel_fp_conn_lookup(struct upf_accel_fp_data *fp_data, enum parser_pkt_type pkt_type, struct upf_accel_match_8t *match, int32_t conn_idx, struct upf_accel_entry_ctx **conn_out)
static void upf_accel_fp_conns_lookup(struct upf_accel_fp_data *fp_data, struct upf_accel_fp_burst_ctx *burst_ctx)
static void upf_accel_sw_aging_ll_scan(struct upf_accel_fp_data *fp_data, enum parser_pkt_type pkt_type)
struct upf_accel_fp_burst_ctx __rte_aligned(RTE_CACHE_LINE_SIZE)
static doca_error_t handle_exceeds_quota_for_pdr(struct upf_accel_ctx *ctx, uint16_t pdr_id, struct doca_flow_resource_query *query)
static void upf_accel_dyn_entry_cb(struct upf_accel_dyn_entry_ctx *dyn_ctx, struct doca_flow_pipe_entry *entry, uint16_t pipe_queue, enum doca_flow_entry_status status, enum doca_flow_entry_op op)
static bool upf_accel_pdr_tuple_is_matching(const struct upf_accel_pdr *pdr, const struct upf_accel_match_5t *match)
static bool upf_accel_sw_aging_ll_node_remove(struct upf_accel_fp_data *fp_data, struct upf_accel_entry_ctx *conn, enum parser_pkt_type pkt_type)
#define UPF_ACCEL_MAX_NUM_AGING
void upf_accel_check_for_valid_entry_aging(struct doca_flow_pipe_entry *entry, uint16_t pipe_queue, enum doca_flow_entry_status status, enum doca_flow_entry_op op, void *user_ctx)
static uint32_t ipv4_netmask_get(uint8_t mask)
static bool upf_accel_sw_aging_ll_node_is_valid(int32_t node_idx)
static bool upf_accel_sw_aging_ll_node_exist(struct upf_accel_fp_data *fp_data, struct upf_accel_entry_ctx *conn, enum parser_pkt_type pkt_type)
static void upf_accel_fp_run_port(struct upf_accel_fp_data *fp_data, enum upf_accel_port rx_port_id, enum upf_accel_port tx_port_id)
static doca_error_t upf_accel_pipe_8t_accel(struct upf_accel_ctx *ctx, enum upf_accel_port port_id, uint16_t queue_id, struct upf_accel_match_8t *match, uint32_t pdr_id, struct upf_accel_entry_ctx *entry_ctx, struct doca_flow_pipe_entry **entry)
#define UPF_ACCEL_MAX_PKT_BURST
static void upf_accel_fp_pkts_match(struct upf_accel_fp_burst_ctx *burst_ctx, struct upf_accel_match_8t match_mem[])
static doca_error_t upf_accel_ran_match(uint8_t *data, uint8_t *data_end, struct tun_parser_ctx *parse_ctx, struct upf_accel_match_8t *match)
void upf_accel_fp_loop(struct upf_accel_fp_data *fp_data)
static void upf_accel_fp_run(struct upf_accel_fp_data *fp_data)
static void upf_accel_fp_flows_accel(struct upf_accel_fp_data *fp_data, enum upf_accel_port rx_port_id, struct upf_accel_fp_burst_ctx *burst_ctx)
static void upf_accel_sw_aging_ll_node_move_to_head(struct upf_accel_fp_data *fp_data, struct upf_accel_entry_ctx *conn, enum parser_pkt_type pkt_type)
static void upf_accel_sw_aging_ll_node_init(struct upf_accel_entry_ctx *conn, enum parser_pkt_type pkt_type)
static doca_error_t upf_accel_wan_match(uint8_t *data, uint8_t *data_end, struct conn_parser_ctx *parse_ctx, struct upf_accel_match_5t *match)
static doca_error_t upf_accel_hw_aging_poll(struct upf_accel_fp_data *fp_data, enum upf_accel_port port_id)
static doca_error_t upf_accel_fp_pdr_lookup(struct upf_accel_fp_data *fp_data, enum parser_pkt_type pkt_type, struct upf_accel_match_8t *match, const struct upf_accel_pdr **pdr_out)
static doca_error_t upf_accel_5t_match(struct conn_parser_ctx *parse_ctx, uint32_t *src_ip, uint32_t *dst_ip, uint16_t *src_port, uint16_t *dst_port, uint8_t *ip_proto)
static bool upf_accel_flow_is_alive(enum upf_accel_flow_status flow_status)
static void upf_accel_aging_init(struct upf_accel_fp_data *fp_data)
static doca_error_t upf_accel_gtpu_match(struct tun_parser_ctx *tun_parse_ctx, struct upf_accel_match_8t *match)
static bool is_flow_unaccelerated(enum parser_pkt_type pkt_type, struct upf_accel_entry_ctx *conn)
static enum parser_pkt_type upf_accel_fp_get_opposite_pkt_type(enum parser_pkt_type pkt_type)
static doca_error_t upf_accel_pipe_5t_accel(struct upf_accel_ctx *ctx, enum upf_accel_port port_id, uint16_t queue_id, struct upf_accel_match_5t *match, uint32_t pdr_id, struct upf_accel_entry_ctx *entry_ctx, struct doca_flow_pipe_entry **entry)
static void upf_accel_fp_burst_postprocess(struct upf_accel_fp_data *fp_data, struct upf_accel_fp_burst_ctx *burst_ctx)
static void upf_accel_md_set(struct rte_mbuf *pkt, uint32_t md)
#define UPF_ACCEL_DOCA_FLOW_MAX_TIMEOUT_US
struct upf_accel_ctx * ctx
#define UPF_ACCEL_SW_AGING_LL_INVALID_NODE
struct upf_accel_fp_accel_counters accel_counters[PARSER_PKT_TYPE_NUM]