]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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. */ | |
f67539c2 | 17 | #define IPV4_MIN_LEN_BE (sizeof(struct rte_ipv4_hdr) << 8) |
11fdf7f2 TL |
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 | |
f67539c2 | 31 | rfc1812_process(struct rte_ipv4_hdr *ipv4_hdr, uint16_t *dp, uint32_t ptype) |
11fdf7f2 TL |
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_ */ |