NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_gtp_sample.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 <string.h>
27 #include <unistd.h>
28 
29 #include <rte_byteorder.h>
30 
31 #include <doca_log.h>
32 #include <doca_flow.h>
33 
34 #include "flow_common.h"
35 static struct doca_flow_port *ports[2];
36 static int nb_ports = 2;
37 
39 
40 #define CHECK_DOCA_SUCCESS(op, msg) \
41  do { \
42  result = (op); \
43  if (result != DOCA_SUCCESS) { \
44  DOCA_LOG_ERR("Failed to " msg ": %s", doca_error_get_descr(result)); \
45  stop_doca_flow_ports(nb_ports, ports); \
46  doca_flow_destroy(); \
47  return result; \
48  } \
49  } while (0)
50 
51 /*
52  * Create DOCA Flow pipe with changeable match and modify gtp_ext_psc_qfi field
53  *
54  * @port [in]: port of the pipe
55  * @port_id [in]: port ID of the pipe
56  * @pipe [out]: created pipe pointer
57  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
58  */
59 int create_modify_gtp_psc_header_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
60 {
61  struct doca_flow_match match = {0};
62  struct doca_flow_match match_mask = {0};
63  struct doca_flow_actions actions = {0};
64  struct doca_flow_actions *actions_arr[NB_ACTIONS_ARR];
65  struct doca_flow_fwd fwd_hit = {0};
66  struct doca_flow_fwd fwd_miss = {0};
67  struct doca_flow_pipe_cfg *pipe_cfg;
69 
70  /* Set changeable match and match_mask on gtp header */
71  match.tun.type = DOCA_FLOW_TUN_GTPU;
72  match.tun.gtp_next_ext_hdr_type = UINT8_MAX;
73  match.tun.gtp_ext_psc_qfi = UINT8_MAX;
76  match_mask.tun.gtp_ext_psc_qfi = UINT8_MAX;
77 
78  /* Prepare for modifying QFI value */
79  actions_arr[0] = &actions;
81  actions.tun.gtp_ext_psc_qfi = UINT8_MAX;
82 
83  /* Forwarding traffic to other port */
84  fwd_hit.type = DOCA_FLOW_FWD_PORT;
85  fwd_hit.port_id = port_id ^ 1;
87 
88  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
89  if (result != DOCA_SUCCESS) {
90  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
91  return result;
92  }
93  result = set_flow_pipe_cfg(pipe_cfg, "MATCH_PIPE", DOCA_FLOW_PIPE_BASIC, false);
94  if (result != DOCA_SUCCESS) {
95  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
96  goto destroy_pipe_cfg;
97  }
98  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, &match_mask);
99  if (result != DOCA_SUCCESS) {
100  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
101  goto destroy_pipe_cfg;
102  }
103  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ACTIONS_ARR);
104  if (result != DOCA_SUCCESS) {
105  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
106  goto destroy_pipe_cfg;
107  }
108 
109  result = doca_flow_pipe_create(pipe_cfg, &fwd_hit, &fwd_miss, pipe);
111  doca_flow_pipe_cfg_destroy(pipe_cfg);
112  return result;
113 }
114 
115 /*
116  * Add DOCA Flow pipe entry that match and modify gtp_ext_psc_qfi field
117  *
118  * @pipe [in]: pipe of the entry
119  * @status [in]: user context for adding entry
120  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
121  */
122 int add_modify_gtp_psc_header_entry(struct doca_flow_pipe *pipe, struct entries_status *status)
123 {
124  struct doca_flow_match match;
125  struct doca_flow_actions actions;
126  struct doca_flow_pipe_entry *entry;
128 
129  match.tun.type = DOCA_FLOW_TUN_GTPU;
130  match.tun.gtp_next_ext_hdr_type = 0x85;
131  match.tun.gtp_ext_psc_qfi = 0x01;
132 
134  actions.tun.gtp_ext_psc_qfi = 0x3a;
135 
136  result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, DOCA_FLOW_NO_WAIT, status, &entry);
137  if (result != DOCA_SUCCESS)
138  return result;
139 
140  return DOCA_SUCCESS;
141 }
142 
143 /*
144  * Create DOCA Flow pipe with specific match that a gtp header is gtp psc type and add entry
145  *
146  * @port [in]: port of the pipe
147  * @modify_qfi_pipe [in]: pipe to forward the matched packets
148  * @status [in]: user context for adding entry
149  * @pipe [out]: created pipe pointer
150  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
151  */
152 static doca_error_t create_match_gtp_pipe_and_add_entry(struct doca_flow_port *port,
153  struct doca_flow_pipe *modify_qfi_pipe,
154  struct entries_status *status,
155  struct doca_flow_pipe **pipe)
156 {
157  struct doca_flow_pipe_cfg *pipe_cfg;
158  struct doca_flow_pipe_entry *entry;
159  struct doca_flow_match match = {0};
160  struct doca_flow_fwd fwd_hit = {0};
161  struct doca_flow_fwd fwd_miss = {0};
163 
164  /* Set specific match on gtp header */
165  match.tun.type = DOCA_FLOW_TUN_GTPU;
166  match.tun.gtp_next_ext_hdr_type = 0x85;
167 
168  /* Forwarding traffic to other port or drop */
169  fwd_hit.type = DOCA_FLOW_FWD_PIPE;
170  fwd_hit.next_pipe = modify_qfi_pipe;
172 
173  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
174  if (result != DOCA_SUCCESS) {
175  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
176  return result;
177  }
178  result = set_flow_pipe_cfg(pipe_cfg, "MATCH_PIPE", DOCA_FLOW_PIPE_BASIC, true);
179  if (result != DOCA_SUCCESS) {
180  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
181  goto destroy_pipe_cfg;
182  }
183  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
184  if (result != DOCA_SUCCESS) {
185  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
186  goto destroy_pipe_cfg;
187  }
188  result = doca_flow_pipe_create(pipe_cfg, &fwd_hit, &fwd_miss, pipe);
189  if (result != DOCA_SUCCESS) {
190  DOCA_LOG_ERR("Failed to create match gtp psc type pipe: %s", doca_error_get_descr(result));
191  goto destroy_pipe_cfg;
192  }
193 
195 
197  doca_flow_pipe_cfg_destroy(pipe_cfg);
198  return result;
199 }
200 
201 /*
202  * Run flow_gtp sample
203  * This sample has two pipes and two entries for each. The first pipe forwards the second pipe only the gtp psc packet
204  * and drops the others. The second pipe modifies all packets with QFI equals 0x1 to 0x3a and hairpinned those packets.
205  * All other packets are dropped. Eventually, only gtp psc packets with QFI equal to 0x1 will arrive at the other port
206  * with QFI equal to 0x3a, and all the other packets are dropped.
207  *
208  * @nb_queues [in]: number of queues the sample will use
209  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
210  */
211 doca_error_t flow_gtp(int nb_queues)
212 {
213  struct flow_resources resource = {0};
214  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
215  struct doca_dev *dev_arr[nb_ports];
216  uint32_t actions_mem_size[nb_ports];
217  struct doca_flow_pipe *modify_qfi_pipe, *gtp_pipe;
218  struct entries_status status = {0};
219  int num_of_entries = 2;
221  int port_id;
222 
223  result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
224  if (result != DOCA_SUCCESS) {
225  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
226  return result;
227  }
228 
229  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
230  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_queues, num_of_entries));
232  if (result != DOCA_SUCCESS) {
233  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
235  return result;
236  }
237 
238  for (port_id = 0; port_id < nb_ports; port_id++) {
239  memset(&status, 0, sizeof(status));
240  CHECK_DOCA_SUCCESS(create_modify_gtp_psc_header_pipe(ports[port_id], port_id, &modify_qfi_pipe),
241  "create modify GTP PSC header pipe");
242 
243  CHECK_DOCA_SUCCESS(add_modify_gtp_psc_header_entry(modify_qfi_pipe, &status),
244  "add GTP PSC header entry");
245 
247  create_match_gtp_pipe_and_add_entry(ports[port_id], modify_qfi_pipe, &status, &gtp_pipe),
248  "create match gtp pipe");
249 
250  CHECK_DOCA_SUCCESS(flow_process_entries(ports[port_id], &status, num_of_entries), "process entries");
251  }
252 
253  DOCA_LOG_INFO("Wait few seconds for packets to arrive");
254  sleep(5);
255 
258  return result;
259 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
struct doca_flow_port * init_doca_flow(uint16_t port_id, uint8_t rxq_num)
Definition: flow.c:37
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
doca_error_t flow_gtp(int nb_queues)
DOCA_LOG_REGISTER(FLOW_GTP)
static int nb_ports
static doca_error_t create_match_gtp_pipe_and_add_entry(struct doca_flow_port *port, struct doca_flow_pipe *modify_qfi_pipe, struct entries_status *status, struct doca_flow_pipe **pipe)
int create_modify_gtp_psc_header_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
static struct doca_flow_port * ports[2]
#define CHECK_DOCA_SUCCESS(op, msg)
int add_modify_gtp_psc_header_entry(struct doca_flow_pipe *pipe, struct entries_status *status)
static struct doca_flow_fwd fwd_miss
Definition: flow_parser.c:110
static struct doca_flow_actions actions
Definition: flow_parser.c:107
static struct doca_flow_match match_mask
Definition: flow_parser.c:106
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
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_SUCCESS
Definition: doca_error.h:38
@ DOCA_FLOW_TUN_GTPU
DOCA_STABLE doca_error_t doca_flow_pipe_cfg_destroy(struct doca_flow_pipe_cfg *cfg)
Destroy DOCA Flow pipe configuration struct.
DOCA_STABLE doca_error_t doca_flow_pipe_cfg_create(struct doca_flow_pipe_cfg **cfg, struct doca_flow_port *port)
Create DOCA Flow pipe configuration struct.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_cfg_set_match(struct doca_flow_pipe_cfg *cfg, const struct doca_flow_match *match, const struct doca_flow_match *match_mask)
Set pipe's match and match mask.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_create(const struct doca_flow_pipe_cfg *cfg, const struct doca_flow_fwd *fwd, const struct doca_flow_fwd *fwd_miss, struct doca_flow_pipe **pipe)
Create one new pipe.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_cfg_set_actions(struct doca_flow_pipe_cfg *cfg, struct doca_flow_actions *const *actions, struct doca_flow_actions *const *actions_masks, struct doca_flow_action_descs *const *action_descs, size_t nr_actions)
Set pipe's actions, actions mask and actions descriptor.
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 void doca_flow_destroy(void)
Destroy the doca flow.
@ DOCA_FLOW_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_NO_WAIT
Definition: doca_flow.h:115
@ DOCA_FLOW_FWD_PORT
Definition: doca_flow.h:744
@ DOCA_FLOW_FWD_PIPE
Definition: doca_flow.h:746
@ DOCA_FLOW_FWD_DROP
Definition: doca_flow.h:748
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
doca_error_t flow_process_entries(struct doca_flow_port *port, struct entries_status *status, uint32_t nr_entries)
Definition: flow_common.c:338
doca_error_t stop_doca_flow_ports(int nb_ports, struct doca_flow_port *ports[])
Definition: flow_common.c:240
doca_error_t init_doca_flow_ports(int nb_ports, struct doca_flow_port *ports[], bool is_hairpin, struct doca_dev *dev_arr[], uint32_t actions_mem_size[])
Definition: flow_common.c:296
doca_error_t set_flow_pipe_cfg(struct doca_flow_pipe_cfg *cfg, const char *name, enum doca_flow_pipe_type type, bool is_root)
Definition: flow_common.c:305
#define NB_ACTIONS_ARR
Definition: flow_common.h:58
#define SHARED_RESOURCE_NUM_VALUES
Definition: flow_common.h:59
#define ACTIONS_MEM_SIZE(nr_queues, entries)
Definition: flow_common.h:66
#define ARRAY_INIT(array, val)
Definition: flow_common.h:71
doca flow actions information
Definition: doca_flow.h:684
struct doca_flow_tun tun
Definition: doca_flow.h:705
forwarding configuration
Definition: doca_flow.h:779
struct doca_flow_pipe * next_pipe
Definition: doca_flow.h:800
struct doca_flow_pipe * pipe
Definition: doca_flow.h:806
uint16_t port_id
Definition: doca_flow.h:795
enum doca_flow_fwd_type type
Definition: doca_flow.h:780
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_tun tun
Definition: doca_flow.h:500
enum doca_flow_tun_type type
uint8_t gtp_ext_psc_qfi
uint8_t gtp_next_ext_hdr_type
user context struct that will be used in entries process callback
Definition: flow_common.h:78
static uint32_t actions_mem_size[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:43