xref: /f-stack/dpdk/examples/l3fwd/l3fwd_common.h (revision 4418919f)
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
rfc1812_process(struct rte_ipv4_hdr * ipv4_hdr,uint16_t * dp,uint32_t ptype)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
send_packetsx4(struct lcore_conf * qconf,uint16_t port,struct rte_mbuf * m[],uint32_t num)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_ */
265