NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_gtp_encap_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024 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 <doca_log.h>
30 #include <doca_flow.h>
31 #include <doca_bitfield.h>
32 
33 #include "flow_common.h"
34 
35 DOCA_LOG_REGISTER(FLOW_GTP_ENCAP);
36 
37 /*
38  * Create DOCA Flow pipe with match on header types to filter out non IPV4 packets.
39  *
40  * @port [in]: port of the pipe
41  * @port_id [in]: port ID of the pipe
42  * @status [in]: user context for adding entry
43  * @pipe [out]: created pipe pointer
44  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
45  */
46 static doca_error_t create_classifier_pipe(struct doca_flow_port *port,
47  int port_id,
48  struct entries_status *status,
49  struct doca_flow_pipe **pipe)
50 {
51  struct doca_flow_match match;
52  struct doca_flow_fwd fwd;
53  struct doca_flow_pipe_cfg *pipe_cfg;
54  struct doca_flow_pipe_entry *entry;
56 
57  memset(&match, 0, sizeof(match));
58  memset(&fwd, 0, sizeof(fwd));
59 
61 
62  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
63  if (result != DOCA_SUCCESS) {
64  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
65  return result;
66  }
67 
68  result = set_flow_pipe_cfg(pipe_cfg, "CLASSIFIER_PIPE", DOCA_FLOW_PIPE_BASIC, true);
69  if (result != DOCA_SUCCESS) {
70  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
71  goto destroy_pipe_cfg;
72  }
73  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
74  if (result != DOCA_SUCCESS) {
75  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
76  goto destroy_pipe_cfg;
77  }
78 
79  /* forwarding traffic to other port */
81  fwd.port_id = port_id ^ 1;
82 
83  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
84  if (result != DOCA_SUCCESS) {
85  DOCA_LOG_ERR("Failed to create classifier pipe: %s", doca_error_get_descr(result));
86  goto destroy_pipe_cfg;
87  }
88  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, NULL, 0, status, &entry);
89 
92  return result;
93 }
94 
95 /*
96  * Create DOCA Flow pipe on EGRESS domain with encap action with changeable values
97  *
98  * @port [in]: port of the pipe
99  * @port_id [in]: pipe port ID
100  * @pipe [out]: created pipe pointer
101  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
102  */
103 static doca_error_t create_gtp_encap_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
104 {
105  struct doca_flow_actions actions, *actions_arr[NB_ACTIONS_ARR];
106  struct doca_flow_match match;
107  struct doca_flow_fwd fwd;
108  struct doca_flow_pipe_cfg *pipe_cfg;
110 
111  memset(&match, 0, sizeof(match));
112  memset(&actions, 0, sizeof(actions));
113  memset(&fwd, 0, sizeof(fwd));
114 
115  /* build basic outer GTP encap data*/
117  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.src_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
118  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.dst_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
120  actions.encap_cfg.encap.outer.ip4.src_ip = 0xffffffff;
121  actions.encap_cfg.encap.outer.ip4.dst_ip = 0xffffffff;
127  actions.encap_cfg.encap.tun.gtp_teid = 0xffffffff;
130  actions_arr[0] = &actions;
131 
132  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
133  if (result != DOCA_SUCCESS) {
134  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
135  return result;
136  }
137 
138  result = set_flow_pipe_cfg(pipe_cfg, "GTP_ENCAP_PIPE", DOCA_FLOW_PIPE_BASIC, true);
139  if (result != DOCA_SUCCESS) {
140  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
141  goto destroy_pipe_cfg;
142  }
143 
145  if (result != DOCA_SUCCESS) {
146  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg domain: %s", doca_error_get_descr(result));
147  goto destroy_pipe_cfg;
148  }
149 
150  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
151  if (result != DOCA_SUCCESS) {
152  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
153  goto destroy_pipe_cfg;
154  }
155 
156  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ACTIONS_ARR);
157  if (result != DOCA_SUCCESS) {
158  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
159  goto destroy_pipe_cfg;
160  }
161 
162  /* forwarding traffic to the wire */
164  fwd.port_id = port_id;
165 
166  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
168  doca_flow_pipe_cfg_destroy(pipe_cfg);
169  return result;
170 }
171 
172 /*
173  * Add DOCA Flow pipe entry with example gtp encap values
174  *
175  * @pipe [in]: pipe of the entry
176  * @status [in]: user context for adding entry
177  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
178  */
179 static doca_error_t add_gtp_encap_pipe_entry(struct doca_flow_pipe *pipe, struct entries_status *status)
180 {
181  struct doca_flow_actions actions;
182  struct doca_flow_pipe_entry *entry;
184 
185  doca_be32_t encap_dst_ip_addr = BE_IPV4_ADDR(81, 81, 81, 81);
186  doca_be32_t encap_src_ip_addr = BE_IPV4_ADDR(11, 21, 31, 41);
187  doca_be16_t encap_flags_fragment_offset = DOCA_HTOBE16(DOCA_FLOW_IP4_FLAG_DONT_FRAGMENT);
188  uint8_t encap_ttl = 17;
189  uint8_t src_mac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
190  uint8_t dst_mac[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
191 
193  src_mac[0],
194  src_mac[1],
195  src_mac[2],
196  src_mac[3],
197  src_mac[4],
198  src_mac[5]);
200  dst_mac[0],
201  dst_mac[1],
202  dst_mac[2],
203  dst_mac[3],
204  dst_mac[4],
205  dst_mac[5]);
207  actions.encap_cfg.encap.outer.ip4.src_ip = encap_src_ip_addr;
208  actions.encap_cfg.encap.outer.ip4.dst_ip = encap_dst_ip_addr;
209  actions.encap_cfg.encap.outer.ip4.flags_fragment_offset = encap_flags_fragment_offset;
210  actions.encap_cfg.encap.outer.ip4.ttl = encap_ttl;
215  actions.action_idx = 0;
216 
217  result = doca_flow_pipe_add_entry(0, pipe, NULL, &actions, NULL, NULL, 0, status, &entry);
218  if (result != DOCA_SUCCESS)
219  return result;
220 
221  return DOCA_SUCCESS;
222 }
223 
224 /*
225  * Run flow_gtp_encap sample
226  *
227  * @nb_queues [in]: number of queues the sample will use
228  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
229  */
231 {
232  int nb_ports = 2;
233  struct flow_resources resource = {0};
234  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
235  struct doca_flow_port *ports[nb_ports];
236  struct doca_dev *dev_arr[nb_ports];
237  uint32_t actions_mem_size[nb_ports];
238  struct doca_flow_pipe *pipe;
239  struct doca_flow_pipe *classifier_pipe;
240  struct entries_status status_ingress;
241  int num_of_entries_ingress = 1;
242  struct entries_status status_egress;
243  int num_of_entries_egress = 1;
245  int port_id;
246 
247  result = init_doca_flow(nb_queues, "vnf", &resource, nr_shared_resources);
248  if (result != DOCA_SUCCESS) {
249  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
250  return result;
251  }
252 
253  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
254  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_queues, num_of_entries_ingress + num_of_entries_egress));
256  if (result != DOCA_SUCCESS) {
257  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
259  return result;
260  }
261 
262  for (port_id = 0; port_id < nb_ports; port_id++) {
263  memset(&status_ingress, 0, sizeof(status_ingress));
264  memset(&status_egress, 0, sizeof(status_egress));
265 
266  result = create_classifier_pipe(ports[port_id], port_id, &status_ingress, &classifier_pipe);
267  if (result != DOCA_SUCCESS) {
268  DOCA_LOG_ERR("Failed to create match pipe: %s", doca_error_get_descr(result));
269  goto err;
270  }
271 
272  result = create_gtp_encap_pipe(ports[port_id ^ 1], port_id ^ 1, &pipe);
273  if (result != DOCA_SUCCESS) {
274  DOCA_LOG_ERR("Failed to create gtp encap pipe: %s", doca_error_get_descr(result));
275  goto err;
276  }
277 
278  result = add_gtp_encap_pipe_entry(pipe, &status_egress);
279  if (result != DOCA_SUCCESS) {
280  DOCA_LOG_ERR("Failed to add entry to gtp encap pipe: %s", doca_error_get_descr(result));
281  goto err;
282  }
283 
284  result = flow_process_entries(ports[port_id], &status_ingress, num_of_entries_ingress);
285  if (result != DOCA_SUCCESS) {
286  DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
287  goto err;
288  }
289 
290  result = flow_process_entries(ports[port_id ^ 1], &status_egress, num_of_entries_egress);
291  if (result != DOCA_SUCCESS) {
292  DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
293  goto err;
294  }
295  }
296 
297  DOCA_LOG_INFO("Wait few seconds for packets to arrive");
298  sleep(10);
299 
302  return result;
303 
304 err:
307  return result;
308 }
#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
#define SET_MAC_ADDR(addr, a, b, c, d, e, f)
Definition: flow_common.h:60
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static doca_error_t create_gtp_encap_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
static doca_error_t create_classifier_pipe(struct doca_flow_port *port, int port_id, struct entries_status *status, struct doca_flow_pipe **pipe)
static doca_error_t add_gtp_encap_pipe_entry(struct doca_flow_pipe *pipe, struct entries_status *status)
doca_error_t flow_gtp_encap(int nb_queues)
DOCA_LOG_REGISTER(FLOW_GTP_ENCAP)
static struct doca_flow_actions actions
Definition: flow_parser.c:107
#define BE_IPV4_ADDR(a, b, c, d)
Definition: flow_parser.c:64
static struct doca_flow_fwd fwd
Definition: flow_parser.c:109
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
#define DOCA_HTOBE32(_x)
#define DOCA_HTOBE16(_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_SUCCESS
Definition: doca_error.h:38
#define DOCA_FLOW_GTPU_DEFAULT_PORT
Definition: doca_flow_net.h:48
#define DOCA_FLOW_GTP_EXT_PSC
@ DOCA_FLOW_L4_TYPE_EXT_UDP
@ DOCA_FLOW_L3_TYPE_IP4
@ DOCA_FLOW_IP4_FLAG_DONT_FRAGMENT
@ 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_STABLE doca_error_t doca_flow_pipe_cfg_set_domain(struct doca_flow_pipe_cfg *cfg, enum doca_flow_pipe_domain domain)
Set pipe's domain.
@ DOCA_FLOW_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_L3_META_IPV4
Definition: doca_flow.h:296
@ DOCA_FLOW_RESOURCE_TYPE_NON_SHARED
Definition: doca_flow.h:615
@ DOCA_FLOW_FWD_PORT
Definition: doca_flow.h:744
@ DOCA_FLOW_PIPE_DOMAIN_EGRESS
Definition: doca_flow.h:245
#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
uint32_t doca_be32_t
Definition: doca_types.h:121
uint16_t doca_be16_t
Declare DOCA endianity types.
Definition: doca_types.h:120
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_resource_encap_cfg encap_cfg
Definition: doca_flow.h:710
enum doca_flow_resource_type encap_type
Definition: doca_flow.h:707
uint8_t action_idx
Definition: doca_flow.h:685
struct doca_flow_tun tun
Definition: doca_flow.h:569
struct doca_flow_header_format outer
Definition: doca_flow.h:567
forwarding configuration
Definition: doca_flow.h:779
uint16_t port_id
Definition: doca_flow.h:795
enum doca_flow_fwd_type type
Definition: doca_flow.h:780
uint8_t dst_mac[DOCA_FLOW_ETHER_ADDR_LEN]
uint8_t src_mac[DOCA_FLOW_ETHER_ADDR_LEN]
struct doca_flow_header_ip4 ip4
Definition: doca_flow.h:449
enum doca_flow_l4_type_ext l4_type_ext
Definition: doca_flow.h:454
struct doca_flow_header_eth eth
Definition: doca_flow.h:440
struct doca_flow_header_udp udp
Definition: doca_flow.h:459
enum doca_flow_l3_type l3_type
Definition: doca_flow.h:446
doca_be16_t flags_fragment_offset
struct doca_flow_header_l4_port l4_port
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_parser_meta parser_meta
Definition: doca_flow.h:496
enum doca_flow_l3_meta outer_l3_type
Definition: doca_flow.h:382
struct doca_flow_encap_action encap
Definition: doca_flow.h:663
enum doca_flow_tun_type type
uint8_t gtp_ext_psc_qfi
doca_be32_t gtp_teid
uint8_t gtp_next_ext_hdr_type
user context struct that will be used in entries process callback
Definition: flow_common.h:78
static int nb_ports
Definition: switch_core.c:44
static uint32_t actions_mem_size[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:43
static struct doca_flow_port * ports[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:42