examples/ipsec-secgw: support fallback session
[dpdk.git] / examples / l3fwd / l3fwd_common.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2018 Intel Corporation.
3  * Copyright(c) 2017-2018 Linaro Limited.
4  */
5
6
7 #ifndef _L3FWD_COMMON_H_
8 #define _L3FWD_COMMON_H_
9
10 #ifdef DO_RFC_1812_CHECKS
11
12 #define IPV4_MIN_VER_IHL        0x45
13 #define IPV4_MAX_VER_IHL        0x4f
14 #define IPV4_MAX_VER_IHL_DIFF   (IPV4_MAX_VER_IHL - IPV4_MIN_VER_IHL)
15
16 /* Minimum value of IPV4 total length (20B) in network byte order. */
17 #define IPV4_MIN_LEN_BE (sizeof(struct rte_ipv4_hdr) << 8)
18
19 /*
20  * From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2:
21  * - The IP version number must be 4.
22  * - The IP header length field must be large enough to hold the
23  *    minimum length legal IP datagram (20 bytes = 5 words).
24  * - The IP total length field must be large enough to hold the IP
25  *   datagram header, whose length is specified in the IP header length
26  *   field.
27  * If we encounter invalid IPV4 packet, then set destination port for it
28  * to BAD_PORT value.
29  */
30 static __rte_always_inline void
31 rfc1812_process(struct rte_ipv4_hdr *ipv4_hdr, uint16_t *dp, uint32_t ptype)
32 {
33         uint8_t ihl;
34
35         if (RTE_ETH_IS_IPV4_HDR(ptype)) {
36                 ihl = ipv4_hdr->version_ihl - IPV4_MIN_VER_IHL;
37
38                 ipv4_hdr->time_to_live--;
39                 ipv4_hdr->hdr_checksum++;
40
41                 if (ihl > IPV4_MAX_VER_IHL_DIFF ||
42                                 ((uint8_t)ipv4_hdr->total_length == 0 &&
43                                 ipv4_hdr->total_length < IPV4_MIN_LEN_BE))
44                         dp[0] = BAD_PORT;
45
46         }
47 }
48
49 #else
50 #define rfc1812_process(mb, dp, ptype)  do { } while (0)
51 #endif /* DO_RFC_1812_CHECKS */
52
53 /*
54  * We group consecutive packets with the same destionation port into one burst.
55  * To avoid extra latency this is done together with some other packet
56  * processing, but after we made a final decision about packet's destination.
57  * To do this we maintain:
58  * pnum - array of number of consecutive packets with the same dest port for
59  * each packet in the input burst.
60  * lp - pointer to the last updated element in the pnum.
61  * dlp - dest port value lp corresponds to.
62  */
63
64 #define GRPSZ   (1 << FWDSTEP)
65 #define GRPMSK  (GRPSZ - 1)
66
67 #define GROUP_PORT_STEP(dlp, dcp, lp, pn, idx)  do { \
68         if (likely((dlp) == (dcp)[(idx)])) {             \
69                 (lp)[0]++;                                   \
70         } else {                                         \
71                 (dlp) = (dcp)[idx];                          \
72                 (lp) = (pn) + (idx);                         \
73                 (lp)[0] = 1;                                 \
74         }                                                \
75 } while (0)
76
77 static const struct {
78         uint64_t pnum; /* prebuild 4 values for pnum[]. */
79         int32_t  idx;  /* index for new last updated elemnet. */
80         uint16_t lpv;  /* add value to the last updated element. */
81 } gptbl[GRPSZ] = {
82         {
83                 /* 0: a != b, b != c, c != d, d != e */
84                 .pnum = UINT64_C(0x0001000100010001),
85                 .idx = 4,
86                 .lpv = 0,
87         },
88         {
89                 /* 1: a == b, b != c, c != d, d != e */
90                 .pnum = UINT64_C(0x0001000100010002),
91                 .idx = 4,
92                 .lpv = 1,
93         },
94         {
95                 /* 2: a != b, b == c, c != d, d != e */
96                 .pnum = UINT64_C(0x0001000100020001),
97                 .idx = 4,
98                 .lpv = 0,
99         },
100         {
101                 /* 3: a == b, b == c, c != d, d != e */
102                 .pnum = UINT64_C(0x0001000100020003),
103                 .idx = 4,
104                 .lpv = 2,
105         },
106         {
107                 /* 4: a != b, b != c, c == d, d != e */
108                 .pnum = UINT64_C(0x0001000200010001),
109                 .idx = 4,
110                 .lpv = 0,
111         },
112         {
113                 /* 5: a == b, b != c, c == d, d != e */
114                 .pnum = UINT64_C(0x0001000200010002),
115                 .idx = 4,
116                 .lpv = 1,
117         },
118         {
119                 /* 6: a != b, b == c, c == d, d != e */
120                 .pnum = UINT64_C(0x0001000200030001),
121                 .idx = 4,
122                 .lpv = 0,
123         },
124         {
125                 /* 7: a == b, b == c, c == d, d != e */
126                 .pnum = UINT64_C(0x0001000200030004),
127                 .idx = 4,
128                 .lpv = 3,
129         },
130         {
131                 /* 8: a != b, b != c, c != d, d == e */
132                 .pnum = UINT64_C(0x0002000100010001),
133                 .idx = 3,
134                 .lpv = 0,
135         },
136         {
137                 /* 9: a == b, b != c, c != d, d == e */
138                 .pnum = UINT64_C(0x0002000100010002),
139                 .idx = 3,
140                 .lpv = 1,
141         },
142         {
143                 /* 0xa: a != b, b == c, c != d, d == e */
144                 .pnum = UINT64_C(0x0002000100020001),
145                 .idx = 3,
146                 .lpv = 0,
147         },
148         {
149                 /* 0xb: a == b, b == c, c != d, d == e */
150                 .pnum = UINT64_C(0x0002000100020003),
151                 .idx = 3,
152                 .lpv = 2,
153         },
154         {
155                 /* 0xc: a != b, b != c, c == d, d == e */
156                 .pnum = UINT64_C(0x0002000300010001),
157                 .idx = 2,
158                 .lpv = 0,
159         },
160         {
161                 /* 0xd: a == b, b != c, c == d, d == e */
162                 .pnum = UINT64_C(0x0002000300010002),
163                 .idx = 2,
164                 .lpv = 1,
165         },
166         {
167                 /* 0xe: a != b, b == c, c == d, d == e */
168                 .pnum = UINT64_C(0x0002000300040001),
169                 .idx = 1,
170                 .lpv = 0,
171         },
172         {
173                 /* 0xf: a == b, b == c, c == d, d == e */
174                 .pnum = UINT64_C(0x0002000300040005),
175                 .idx = 0,
176                 .lpv = 4,
177         },
178 };
179
180 static __rte_always_inline void
181 send_packetsx4(struct lcore_conf *qconf, uint16_t port, struct rte_mbuf *m[],
182                 uint32_t num)
183 {
184         uint32_t len, j, n;
185
186         len = qconf->tx_mbufs[port].len;
187
188         /*
189          * If TX buffer for that queue is empty, and we have enough packets,
190          * then send them straightway.
191          */
192         if (num >= MAX_TX_BURST && len == 0) {
193                 n = rte_eth_tx_burst(port, qconf->tx_queue_id[port], m, num);
194                 if (unlikely(n < num)) {
195                         do {
196                                 rte_pktmbuf_free(m[n]);
197                         } while (++n < num);
198                 }
199                 return;
200         }
201
202         /*
203          * Put packets into TX buffer for that queue.
204          */
205
206         n = len + num;
207         n = (n > MAX_PKT_BURST) ? MAX_PKT_BURST - len : num;
208
209         j = 0;
210         switch (n % FWDSTEP) {
211         while (j < n) {
212         case 0:
213                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
214                 j++;
215                 /* fallthrough */
216         case 3:
217                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
218                 j++;
219                 /* fallthrough */
220         case 2:
221                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
222                 j++;
223                 /* fallthrough */
224         case 1:
225                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
226                 j++;
227         }
228         }
229
230         len += n;
231
232         /* enough pkts to be sent */
233         if (unlikely(len == MAX_PKT_BURST)) {
234
235                 send_burst(qconf, MAX_PKT_BURST, port);
236
237                 /* copy rest of the packets into the TX buffer. */
238                 len = num - n;
239                 j = 0;
240                 switch (len % FWDSTEP) {
241                 while (j < len) {
242                 case 0:
243                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
244                         j++;
245                         /* fallthrough */
246                 case 3:
247                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
248                         j++;
249                         /* fallthrough */
250                 case 2:
251                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
252                         j++;
253                         /* fallthrough */
254                 case 1:
255                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
256                         j++;
257                 }
258                 }
259         }
260
261         qconf->tx_mbufs[port].len = len;
262 }
263
264 #endif /* _L3FWD_COMMON_H_ */