2867365d0e1356ef15c35e5ed0f4e51a62dc0864
[deb_dpdk.git] / examples / l3fwd / l3fwd_common.h
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5  *   Copyright(c) 2017, Linaro Limited
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35
36 #ifndef _L3FWD_COMMON_H_
37 #define _L3FWD_COMMON_H_
38
39 #ifdef DO_RFC_1812_CHECKS
40
41 #define IPV4_MIN_VER_IHL        0x45
42 #define IPV4_MAX_VER_IHL        0x4f
43 #define IPV4_MAX_VER_IHL_DIFF   (IPV4_MAX_VER_IHL - IPV4_MIN_VER_IHL)
44
45 /* Minimum value of IPV4 total length (20B) in network byte order. */
46 #define IPV4_MIN_LEN_BE (sizeof(struct ipv4_hdr) << 8)
47
48 /*
49  * From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2:
50  * - The IP version number must be 4.
51  * - The IP header length field must be large enough to hold the
52  *    minimum length legal IP datagram (20 bytes = 5 words).
53  * - The IP total length field must be large enough to hold the IP
54  *   datagram header, whose length is specified in the IP header length
55  *   field.
56  * If we encounter invalid IPV4 packet, then set destination port for it
57  * to BAD_PORT value.
58  */
59 static __rte_always_inline void
60 rfc1812_process(struct ipv4_hdr *ipv4_hdr, uint16_t *dp, uint32_t ptype)
61 {
62         uint8_t ihl;
63
64         if (RTE_ETH_IS_IPV4_HDR(ptype)) {
65                 ihl = ipv4_hdr->version_ihl - IPV4_MIN_VER_IHL;
66
67                 ipv4_hdr->time_to_live--;
68                 ipv4_hdr->hdr_checksum++;
69
70                 if (ihl > IPV4_MAX_VER_IHL_DIFF ||
71                                 ((uint8_t)ipv4_hdr->total_length == 0 &&
72                                 ipv4_hdr->total_length < IPV4_MIN_LEN_BE))
73                         dp[0] = BAD_PORT;
74
75         }
76 }
77
78 #else
79 #define rfc1812_process(mb, dp, ptype)  do { } while (0)
80 #endif /* DO_RFC_1812_CHECKS */
81
82 /*
83  * We group consecutive packets with the same destionation port into one burst.
84  * To avoid extra latency this is done together with some other packet
85  * processing, but after we made a final decision about packet's destination.
86  * To do this we maintain:
87  * pnum - array of number of consecutive packets with the same dest port for
88  * each packet in the input burst.
89  * lp - pointer to the last updated element in the pnum.
90  * dlp - dest port value lp corresponds to.
91  */
92
93 #define GRPSZ   (1 << FWDSTEP)
94 #define GRPMSK  (GRPSZ - 1)
95
96 #define GROUP_PORT_STEP(dlp, dcp, lp, pn, idx)  do { \
97         if (likely((dlp) == (dcp)[(idx)])) {             \
98                 (lp)[0]++;                                   \
99         } else {                                         \
100                 (dlp) = (dcp)[idx];                          \
101                 (lp) = (pn) + (idx);                         \
102                 (lp)[0] = 1;                                 \
103         }                                                \
104 } while (0)
105
106 static const struct {
107         uint64_t pnum; /* prebuild 4 values for pnum[]. */
108         int32_t  idx;  /* index for new last updated elemnet. */
109         uint16_t lpv;  /* add value to the last updated element. */
110 } gptbl[GRPSZ] = {
111         {
112                 /* 0: a != b, b != c, c != d, d != e */
113                 .pnum = UINT64_C(0x0001000100010001),
114                 .idx = 4,
115                 .lpv = 0,
116         },
117         {
118                 /* 1: a == b, b != c, c != d, d != e */
119                 .pnum = UINT64_C(0x0001000100010002),
120                 .idx = 4,
121                 .lpv = 1,
122         },
123         {
124                 /* 2: a != b, b == c, c != d, d != e */
125                 .pnum = UINT64_C(0x0001000100020001),
126                 .idx = 4,
127                 .lpv = 0,
128         },
129         {
130                 /* 3: a == b, b == c, c != d, d != e */
131                 .pnum = UINT64_C(0x0001000100020003),
132                 .idx = 4,
133                 .lpv = 2,
134         },
135         {
136                 /* 4: a != b, b != c, c == d, d != e */
137                 .pnum = UINT64_C(0x0001000200010001),
138                 .idx = 4,
139                 .lpv = 0,
140         },
141         {
142                 /* 5: a == b, b != c, c == d, d != e */
143                 .pnum = UINT64_C(0x0001000200010002),
144                 .idx = 4,
145                 .lpv = 1,
146         },
147         {
148                 /* 6: a != b, b == c, c == d, d != e */
149                 .pnum = UINT64_C(0x0001000200030001),
150                 .idx = 4,
151                 .lpv = 0,
152         },
153         {
154                 /* 7: a == b, b == c, c == d, d != e */
155                 .pnum = UINT64_C(0x0001000200030004),
156                 .idx = 4,
157                 .lpv = 3,
158         },
159         {
160                 /* 8: a != b, b != c, c != d, d == e */
161                 .pnum = UINT64_C(0x0002000100010001),
162                 .idx = 3,
163                 .lpv = 0,
164         },
165         {
166                 /* 9: a == b, b != c, c != d, d == e */
167                 .pnum = UINT64_C(0x0002000100010002),
168                 .idx = 3,
169                 .lpv = 1,
170         },
171         {
172                 /* 0xa: a != b, b == c, c != d, d == e */
173                 .pnum = UINT64_C(0x0002000100020001),
174                 .idx = 3,
175                 .lpv = 0,
176         },
177         {
178                 /* 0xb: a == b, b == c, c != d, d == e */
179                 .pnum = UINT64_C(0x0002000100020003),
180                 .idx = 3,
181                 .lpv = 2,
182         },
183         {
184                 /* 0xc: a != b, b != c, c == d, d == e */
185                 .pnum = UINT64_C(0x0002000300010001),
186                 .idx = 2,
187                 .lpv = 0,
188         },
189         {
190                 /* 0xd: a == b, b != c, c == d, d == e */
191                 .pnum = UINT64_C(0x0002000300010002),
192                 .idx = 2,
193                 .lpv = 1,
194         },
195         {
196                 /* 0xe: a != b, b == c, c == d, d == e */
197                 .pnum = UINT64_C(0x0002000300040001),
198                 .idx = 1,
199                 .lpv = 0,
200         },
201         {
202                 /* 0xf: a == b, b == c, c == d, d == e */
203                 .pnum = UINT64_C(0x0002000300040005),
204                 .idx = 0,
205                 .lpv = 4,
206         },
207 };
208
209 static __rte_always_inline void
210 send_packetsx4(struct lcore_conf *qconf, uint8_t port, struct rte_mbuf *m[],
211                 uint32_t num)
212 {
213         uint32_t len, j, n;
214
215         len = qconf->tx_mbufs[port].len;
216
217         /*
218          * If TX buffer for that queue is empty, and we have enough packets,
219          * then send them straightway.
220          */
221         if (num >= MAX_TX_BURST && len == 0) {
222                 n = rte_eth_tx_burst(port, qconf->tx_queue_id[port], m, num);
223                 if (unlikely(n < num)) {
224                         do {
225                                 rte_pktmbuf_free(m[n]);
226                         } while (++n < num);
227                 }
228                 return;
229         }
230
231         /*
232          * Put packets into TX buffer for that queue.
233          */
234
235         n = len + num;
236         n = (n > MAX_PKT_BURST) ? MAX_PKT_BURST - len : num;
237
238         j = 0;
239         switch (n % FWDSTEP) {
240         while (j < n) {
241         case 0:
242                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
243                 j++;
244                 /* fallthrough */
245         case 3:
246                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
247                 j++;
248                 /* fallthrough */
249         case 2:
250                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
251                 j++;
252                 /* fallthrough */
253         case 1:
254                 qconf->tx_mbufs[port].m_table[len + j] = m[j];
255                 j++;
256         }
257         }
258
259         len += n;
260
261         /* enough pkts to be sent */
262         if (unlikely(len == MAX_PKT_BURST)) {
263
264                 send_burst(qconf, MAX_PKT_BURST, port);
265
266                 /* copy rest of the packets into the TX buffer. */
267                 len = num - n;
268                 j = 0;
269                 switch (len % FWDSTEP) {
270                 while (j < len) {
271                 case 0:
272                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
273                         j++;
274                         /* fallthrough */
275                 case 3:
276                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
277                         j++;
278                         /* fallthrough */
279                 case 2:
280                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
281                         j++;
282                         /* fallthrough */
283                 case 1:
284                         qconf->tx_mbufs[port].m_table[j] = m[n + j];
285                         j++;
286                 }
287                 }
288         }
289
290         qconf->tx_mbufs[port].len = len;
291 }
292
293 #endif /* _L3FWD_COMMON_H_ */