NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
simple_fwd_pkt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 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_ether.h>
27 #include <rte_mbuf.h>
28 #include <rte_ip.h>
29 #include <rte_tcp.h>
30 #include <rte_udp.h>
31 #include <rte_gre.h>
32 #include <rte_gtp.h>
33 #include <rte_vxlan.h>
34 
35 #include <doca_log.h>
36 
37 #include "simple_fwd_pkt.h"
38 
39 DOCA_LOG_REGISTER(SIMPLE_FWD_PKT);
40 
41 #define GTP_ESPN_FLAGS_ON(p) (p & 0x7) /* A macro for setting GTP ESPN flags on */
42 #define GTP_EXT_FLAGS_ON(p) (p & 0x4) /* A macro for setting GTP EXT flags on */
43 
45 {
46  return ((struct rte_ether_hdr *)pinfo->outer.l2)->dst_addr.addr_bytes;
47 }
48 
50 {
51  return ((struct rte_ether_hdr *)pinfo->outer.l2)->src_addr.addr_bytes;
52 }
53 
55 {
56  return ((struct rte_ipv4_hdr *)pinfo->outer.l3)->dst_addr;
57 }
58 
60 {
61  return ((struct rte_ipv4_hdr *)pinfo->outer.l3)->src_addr;
62 }
63 
65 {
66  return ((struct rte_ipv4_hdr *)pinfo->inner.l3)->dst_addr;
67 }
68 
70 {
71  return ((struct rte_ipv4_hdr *)pinfo->inner.l3)->src_addr;
72 }
73 
74 /*
75  * Extracts the source port address from the packet's info based on layer 4 type
76  *
77  * @fmt [in]: the packet format as represented in the application
78  * @return: source port
79  *
80  * @NOTE: the returned value is converted to big endian
81  */
83 {
84  switch (fmt->l4_type) {
86  return ((struct rte_tcp_hdr *)fmt->l4)->src_port;
88  return ((struct rte_udp_hdr *)fmt->l4)->src_port;
89  default:
90  return 0;
91  }
92 }
93 
94 /*
95  * Extracts the destination port address from the packet's info based on layer 4 type
96  *
97  * @fmt [in]: the packet format as represented in the application
98  * @return: destination port
99  *
100  * @NOTE: the returned value is converted to big endian
101  */
103 {
104  switch (fmt->l4_type) {
105  case DOCA_FLOW_PROTO_TCP:
106  return ((struct rte_tcp_hdr *)fmt->l4)->dst_port;
107  case DOCA_FLOW_PROTO_UDP:
108  return ((struct rte_udp_hdr *)fmt->l4)->dst_port;
109  default:
110  return 0;
111  }
112 }
113 
115 {
116  return simple_fwd_pinfo_src_port(&pinfo->inner);
117 }
118 
120 {
121  return simple_fwd_pinfo_dst_port(&pinfo->inner);
122 }
123 
125 {
126  return simple_fwd_pinfo_src_port(&pinfo->outer);
127 }
128 
130 {
131  return simple_fwd_pinfo_dst_port(&pinfo->outer);
132 }
133 
134 /*
135  * Parse the packet and set the packet format as represented in the application
136  *
137  * @data [in]: packet raw data
138  * @len [in]: length of the packet raw data in bytes
139  * @l2 [in]: whther or not to set the data pointer in layer 2 field in the packet representation in the application\
140  * @fmt [out]: the parsed packet as should be represented in the application fo further processing
141  * @return: 0 on success, negative value otherwise
142  */
143 static int simple_fwd_parse_pkt_format(uint8_t *data, int len, bool l2, struct simple_fwd_pkt_format *fmt)
144 {
145  struct rte_ether_hdr *eth = NULL;
146  struct rte_ipv4_hdr *iphdr;
147  int l3_off = 0;
148  int l4_off = 0;
149  int l7_off = 0;
150 
151  fmt->l2 = data;
152  if (l2) {
153  eth = (struct rte_ether_hdr *)data;
154  fmt->l2 = data;
155  switch (rte_be_to_cpu_16(eth->ether_type)) {
156  case RTE_ETHER_TYPE_IPV4:
157  l3_off = sizeof(struct rte_ether_hdr);
158  break;
159  case RTE_ETHER_TYPE_IPV6:
160  l3_off = sizeof(struct rte_ether_hdr);
161  fmt->l3_type = IPV6;
162  return -1;
163  case RTE_ETHER_TYPE_ARP:
164  return -1;
165  default:
166  DOCA_LOG_WARN("Unsupported L2 type 0x%x", eth->ether_type);
167  return -1;
168  }
169  }
170 
171  iphdr = (struct rte_ipv4_hdr *)(data + l3_off);
172  if ((iphdr->version_ihl >> 4) != 4)
173  return -1;
174  if (iphdr->src_addr == 0 || iphdr->dst_addr == 0)
175  return -1;
176  fmt->l3 = (data + l3_off);
177  fmt->l3_type = IPV4;
178  l4_off = l3_off + rte_ipv4_hdr_len(iphdr);
179  fmt->l4 = data + l4_off;
180  switch (iphdr->next_proto_id) {
181  case DOCA_FLOW_PROTO_TCP: {
182  struct rte_tcp_hdr *tcphdr = (struct rte_tcp_hdr *)(data + l4_off);
183 
184  l7_off = l4_off + ((tcphdr->data_off & 0xf0) >> 2);
185  if (l7_off > len)
186  return -1;
188  fmt->l7 = (data + l7_off);
189  break;
190  }
191  case DOCA_FLOW_PROTO_UDP: {
192  struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(data + l4_off);
193 
194  l7_off = l4_off + sizeof(*udphdr);
196  if (l7_off > len)
197  return -1;
198  fmt->l7 = (data + l7_off);
199  break;
200  }
201  case DOCA_FLOW_PROTO_GRE:
203  break;
204  case IPPROTO_ICMP:
205  fmt->l4_type = IPPROTO_ICMP;
206  break;
207  default:
208  DOCA_LOG_INFO("Unsupported L4 %d", iphdr->next_proto_id);
209  return -1;
210  }
211  return 0;
212 }
213 
214 /*
215  * Parse the packet tunneling info
216  *
217  * @pinfo [in/out]: the packet representation in the application
218  * @return: 0 on success, negative value otherwise
219  */
221 {
222  if (pinfo->outer.l3_type != IPV4)
223  return 0;
224 
225  if (pinfo->outer.l4_type == DOCA_FLOW_PROTO_GRE) {
226  int optional_off = 0;
227  struct rte_gre_hdr *gre_hdr = (struct rte_gre_hdr *)pinfo->outer.l4;
228  if (gre_hdr->c)
229  return -1;
230  if (gre_hdr->k) {
231  optional_off += 4;
232  pinfo->tun.gre_key = *(uint32_t *)(pinfo->outer.l4 + sizeof(struct rte_gre_hdr));
233  pinfo->tun.l2 = true;
234  }
235  if (gre_hdr->s)
236  optional_off += 4;
237  pinfo->tun_type = DOCA_FLOW_TUN_GRE;
238  pinfo->tun.proto = gre_hdr->proto;
239  return sizeof(struct rte_gre_hdr) + optional_off;
240  }
241 
242  if (pinfo->outer.l4_type == DOCA_FLOW_PROTO_UDP) {
243  struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)pinfo->outer.l4;
244  uint8_t *udp_data = pinfo->outer.l4 + sizeof(struct rte_udp_hdr);
245 
246  switch (rte_cpu_to_be_16(udphdr->dst_port)) {
248  struct rte_vxlan_gpe_hdr *vxlanhdr = (struct rte_vxlan_gpe_hdr *)udp_data;
249 
250  if (vxlanhdr->vx_flags & 0x08) {
251  /*need to check if this gpe*/
252  pinfo->tun_type = DOCA_FLOW_TUN_VXLAN;
253  pinfo->tun.vni = vxlanhdr->vx_vni;
254  pinfo->tun.l2 = true;
255  }
256  return sizeof(struct rte_vxlan_gpe_hdr) + sizeof(struct rte_udp_hdr);
257  }
259  int off = sizeof(struct rte_gtp_hdr) + sizeof(struct rte_udp_hdr);
260  struct rte_gtp_hdr *gtphdr = (struct rte_gtp_hdr *)udp_data;
261 
262  pinfo->tun_type = DOCA_FLOW_TUN_GTPU;
263  pinfo->tun.teid = gtphdr->teid;
264  pinfo->tun.gtp_msg_type = gtphdr->msg_type;
265  pinfo->tun.gtp_flags = gtphdr->gtp_hdr_info;
266  pinfo->tun.l2 = false;
267  if (GTP_ESPN_FLAGS_ON(pinfo->tun.gtp_flags))
268  off += 4;
269  DOCA_LOG_DBG("GTP tun = %u", rte_cpu_to_be_32(pinfo->tun.teid));
270  return off;
271  }
272  default:
273  return 0;
274  }
275  }
276  return 0;
277 }
278 
279 int simple_fwd_parse_packet(uint8_t *data, int len, struct simple_fwd_pkt_info *pinfo)
280 {
281  int off = 0;
282  int inner_off = 0;
283 
284  if (!pinfo) {
285  DOCA_LOG_ERR("Pinfo =%p", pinfo);
286  return -1;
287  }
288  pinfo->len = len;
289  if (simple_fwd_parse_pkt_format(data, len, true, &pinfo->outer))
290  return -1;
291 
292  off = simple_fwd_parse_is_tun(pinfo);
293  if (pinfo->tun_type == DOCA_FLOW_TUN_NONE || off < 0)
294  return 0;
295 
296  switch (pinfo->tun_type) {
297  case DOCA_FLOW_TUN_GRE:
298  inner_off = (pinfo->outer.l4 - data) + off;
299  if (simple_fwd_parse_pkt_format(data + inner_off, len - inner_off, false, &pinfo->inner))
300  return -1;
301  break;
302  case DOCA_FLOW_TUN_VXLAN:
303  inner_off = (pinfo->outer.l4 - data) + off;
304  if (simple_fwd_parse_pkt_format(data + inner_off, len - inner_off, pinfo->tun.l2, &pinfo->inner))
305  return -1;
306  break;
307  case DOCA_FLOW_TUN_GTPU:
308  inner_off = (pinfo->outer.l4 - data) + off;
309  if (simple_fwd_parse_pkt_format(data + inner_off, len - inner_off, pinfo->tun.l2, &pinfo->inner))
310  return -1;
311  break;
312  default:
313  break;
314  }
315  return 0;
316 }
317 
319 {
320  switch (pinfo->tun_type) {
321  case DOCA_FLOW_TUN_GRE:
322  DOCA_LOG_ERR("Decap for GRE is not supported");
323  break;
324  case DOCA_FLOW_TUN_VXLAN:
325  pinfo->outer.l2 = pinfo->inner.l2;
326  pinfo->outer.l3 = pinfo->inner.l3;
327  pinfo->outer.l4 = pinfo->inner.l4;
328  pinfo->outer.l7 = pinfo->inner.l7;
329  pinfo->tun_type = DOCA_FLOW_TUN_NONE;
330  break;
331  default:
332  break;
333  }
334 }
#define NULL
Definition: __stddef_null.h:26
uint64_t len
if(bitoffset % 64+bitlength > 64) result|
#define DOCA_FLOW_VXLAN_DEFAULT_PORT
Definition: doca_flow_net.h:49
#define DOCA_FLOW_PROTO_GRE
Definition: doca_flow_net.h:44
#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_FLOW_TUN_GRE
@ DOCA_FLOW_TUN_GTPU
@ DOCA_FLOW_TUN_VXLAN
@ DOCA_FLOW_TUN_NONE
#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_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
uint32_t doca_be32_t
Definition: doca_types.h:121
uint16_t doca_be16_t
Declare DOCA endianity types.
Definition: doca_types.h:120
rte_ether_hdr eth
Definition: psp_gw_flows.cpp:1
doca_be16_t simple_fwd_pinfo_inner_dst_port(struct simple_fwd_pkt_info *pinfo)
doca_be16_t simple_fwd_pinfo_outer_dst_port(struct simple_fwd_pkt_info *pinfo)
static int simple_fwd_parse_is_tun(struct simple_fwd_pkt_info *pinfo)
void simple_fwd_pinfo_decap(struct simple_fwd_pkt_info *pinfo)
doca_be32_t simple_fwd_pinfo_outer_ipv4_src(struct simple_fwd_pkt_info *pinfo)
#define GTP_ESPN_FLAGS_ON(p)
DOCA_LOG_REGISTER(SIMPLE_FWD_PKT)
doca_be16_t simple_fwd_pinfo_inner_src_port(struct simple_fwd_pkt_info *pinfo)
doca_be16_t simple_fwd_pinfo_outer_src_port(struct simple_fwd_pkt_info *pinfo)
doca_be32_t simple_fwd_pinfo_inner_ipv4_src(struct simple_fwd_pkt_info *pinfo)
doca_be32_t simple_fwd_pinfo_inner_ipv4_dst(struct simple_fwd_pkt_info *pinfo)
static doca_be16_t simple_fwd_pinfo_dst_port(struct simple_fwd_pkt_format *fmt)
static doca_be16_t simple_fwd_pinfo_src_port(struct simple_fwd_pkt_format *fmt)
int simple_fwd_parse_packet(uint8_t *data, int len, struct simple_fwd_pkt_info *pinfo)
uint8_t * simple_fwd_pinfo_outer_mac_src(struct simple_fwd_pkt_info *pinfo)
doca_be32_t simple_fwd_pinfo_outer_ipv4_dst(struct simple_fwd_pkt_info *pinfo)
static int simple_fwd_parse_pkt_format(uint8_t *data, int len, bool l2, struct simple_fwd_pkt_format *fmt)
uint8_t * simple_fwd_pinfo_outer_mac_dst(struct simple_fwd_pkt_info *pinfo)
#define IPV6
struct simple_fwd_pkt_format outer
enum doca_flow_tun_type tun_type
struct simple_fwd_pkt_format inner
struct simple_fwd_pkt_tun_format tun