2 * Copyright (c) 2016-2017 Intel Corporation.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
21 #include <rte_cycles.h>
29 * TCP protocols related structures/functions definitions.
30 * Main purpose to simplify (and optimise) processing and representation
31 * of protocol related data.
34 #define TCP_WSCALE_DEFAULT 7
35 #define TCP_WSCALE_NONE 0
37 #define TCP_TX_HDR_MAX (sizeof(struct rte_tcp_hdr) + TCP_TX_OPT_LEN_MAX)
39 /* max header size for normal data+ack packet */
40 #define TCP_TX_HDR_DACK (sizeof(struct rte_tcp_hdr) + TCP_TX_OPT_LEN_TMS)
42 #define TCP4_MIN_MSS 536
44 #define TCP6_MIN_MSS 1220
46 /* default MTU, no TCP options. */
47 #define TCP4_NOP_MSS \
48 (RTE_ETHER_MTU - sizeof(struct rte_ipv4_hdr) - \
49 sizeof(struct rte_tcp_hdr))
51 #define TCP6_NOP_MSS \
52 (RTE_ETHER_MTU - sizeof(struct rte_ipv6_hdr) - \
53 sizeof(struct rte_tcp_hdr))
55 /* default MTU, TCP options present */
56 #define TCP4_OP_MSS (TCP4_NOP_MSS - TCP_TX_OPT_LEN_MAX)
58 #define TCP6_OP_MSS (TCP6_NOP_MSS - TCP_TX_OPT_LEN_MAX)
60 /* Initial Window Configuration parameter, probably will be configured during
61 * the startup in future */
62 #define TCP_INITIAL_CWND_MAX 14600
67 #define TCP_FLAG_FIN 0x01
68 #define TCP_FLAG_SYN 0x02
69 #define TCP_FLAG_RST 0x04
70 #define TCP_FLAG_PSH 0x08
71 #define TCP_FLAG_ACK 0x10
72 #define TCP_FLAG_URG 0x20
75 #define TCP_FLAG_MASK UINT8_MAX
80 uint8_t type; /* TLE_V4/TLE_V6 */
81 uint8_t flags; /* TCP header flags */
89 uint16_t csf; /* checksum flags */
92 union ipv4_addrs addr4;
93 const union ipv6_addrs *addr6;
104 uint16_t mss; /* valid only at SYN time */
116 #define TCP_DATA_ALIGN 4
118 #define TCP_DATA_OFFSET 4
121 * recognizable options.
123 #define TCP_OPT_KIND_EOL 0x00
124 #define TCP_OPT_KIND_NOP 0x01
125 #define TCP_OPT_KIND_MSS 0x02
126 #define TCP_OPT_KIND_WSC 0x03
127 #define TCP_OPT_KIND_TMS 0x08
129 #define TCP_OPT_LEN_EOL 0x01
130 #define TCP_OPT_LEN_NOP 0x01
131 #define TCP_OPT_LEN_MSS 0x04
132 #define TCP_OPT_LEN_WSC 0x03
133 #define TCP_OPT_LEN_TMS 0x0a
135 #define TCP_TX_OPT_LEN_MAX \
136 RTE_ALIGN_CEIL(TCP_OPT_LEN_MSS + TCP_OPT_LEN_WSC + TCP_OPT_LEN_TMS + \
137 TCP_OPT_LEN_EOL, TCP_DATA_ALIGN)
140 * recomended format for TSOPT from RFC 1323, appendix A:
141 * +--------+--------+--------+--------+
142 * | NOP | NOP | TSopt | 10 |
143 * +--------+--------+--------+--------+
144 * | TSval timestamp |
145 * +--------+--------+--------+--------+
146 * | TSecr timestamp |
147 * +--------+--------+--------+--------+
149 #define TCP_TX_OPT_LEN_TMS (TCP_OPT_LEN_TMS + 2 * TCP_OPT_LEN_NOP)
151 #define TCP_OPT_TMS_HDR (rte_be_to_cpu_32( \
152 TCP_OPT_KIND_NOP << 3 * CHAR_BIT | \
153 TCP_OPT_KIND_NOP << 2 * CHAR_BIT | \
154 TCP_OPT_KIND_TMS << CHAR_BIT | \
157 #define TCP_OPT_KL(k, l) (rte_be_to_cpu_16((k) << CHAR_BIT | (l)))
159 #define TCP_OPT_KL_MSS TCP_OPT_KL(TCP_OPT_KIND_MSS, TCP_OPT_LEN_MSS)
160 #define TCP_OPT_KL_WSC TCP_OPT_KL(TCP_OPT_KIND_WSC, TCP_OPT_LEN_WSC)
161 #define TCP_OPT_KL_TMS TCP_OPT_KL(TCP_OPT_KIND_TMS, TCP_OPT_LEN_TMS)
174 union tle_tcp_tsopt ts;
176 } __attribute__((__packed__));
183 /* window update information (RFC 793 WL1, WL2) */
193 * helper structure: holds aggregated information about group
194 * of processed data+ack packets.
197 struct { /* # of received segments with: */
198 uint32_t data; /* incoming data */
199 uint32_t ack; /* newly acked data */
200 uint32_t dup; /* duplicate acks */
201 uint32_t badseq; /* bad seq/ack */
202 uint32_t ofo; /* OFO incoming data */
204 uint32_t ack; /* highest received ACK */
205 union tle_tcp_tsopt ts; /* TS of highest ACK */
206 union wui wu; /* window update information */
208 struct { /* 3 duplicate ACKs were observed after */
209 uint32_t seg; /* # of meaningful ACK segments */
210 uint32_t ack; /* ACK sequence */
214 /* get current timestamp in ms */
215 static inline uint32_t
216 tcp_get_tms(uint32_t mshift)
219 ts = rte_get_tsc_cycles() >> mshift;
224 tcp_seq_lt(uint32_t l, uint32_t r)
226 return (int32_t)(l - r) < 0;
230 tcp_seq_leq(uint32_t l, uint32_t r)
232 return (int32_t)(l - r) <= 0;
235 static inline uint32_t
236 tcp_seq_min(uint32_t l, uint32_t r)
238 if (tcp_seq_lt(l, r))
245 get_seg_info(const struct rte_tcp_hdr *th, union seg_info *si)
248 const __m128i bswap_mask =
249 _mm_set_epi8(UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX,
250 UINT8_MAX, UINT8_MAX, 10, 11,
254 v = _mm_loadu_si128((const __m128i *)&th->sent_seq);
255 si->raw.x = _mm_shuffle_epi8(v, bswap_mask);
259 get_syn_opts(struct tle_tcp_syn_opts *so, uintptr_t p, uint32_t len)
262 const struct tcpopt *opt;
264 memset(so, 0, sizeof(*so));
268 opt = (const struct tcpopt *)(p + i);
270 if (kind == TCP_OPT_KIND_EOL)
272 else if (kind == TCP_OPT_KIND_NOP)
273 i += sizeof(opt->kl.kind);
277 if (opt->kl.raw == TCP_OPT_KL_MSS)
278 so->mss = rte_be_to_cpu_16(opt->mss);
279 else if (opt->kl.raw == TCP_OPT_KL_WSC)
280 so->wscale = opt->wscale;
281 else if (opt->kl.raw == TCP_OPT_KL_TMS) {
283 rte_be_to_cpu_32(opt->ts.val);
285 rte_be_to_cpu_32(opt->ts.ecr);
293 * generates SYN options, assumes that there are
294 * at least TCP_TX_OPT_LEN_MAX bytes available.
297 fill_syn_opts(void *p, const struct tle_tcp_syn_opts *so)
305 opt = (struct tcpopt *)to;
306 opt->kl.raw = TCP_OPT_KL_MSS;
307 opt->mss = rte_cpu_to_be_16(so->mss);
309 to += TCP_OPT_LEN_MSS;
310 opt = (struct tcpopt *)to;
313 if (so->ts.val != 0) {
315 opt->kl.raw = TCP_OPT_KL_TMS;
316 opt->ts.val = rte_cpu_to_be_32(so->ts.val);
317 opt->ts.ecr = rte_cpu_to_be_32(so->ts.ecr);
319 to += TCP_OPT_LEN_TMS;
320 opt = (struct tcpopt *)to;
324 if (so->wscale != 0) {
326 opt->kl.raw = TCP_OPT_KL_WSC;
327 opt->wscale = so->wscale;
329 to += TCP_OPT_LEN_WSC;
330 opt = (struct tcpopt *)to;
333 to[0] = TCP_OPT_KIND_EOL;
337 * generate TMS option, for non SYN packet, make sure
338 * there at least TCP_TX_OPT_LEN_TMS available.
341 fill_tms_opts(void *p, uint32_t val, uint32_t ecr)
346 opt[0] = TCP_OPT_TMS_HDR;
347 opt[1] = rte_cpu_to_be_32(val);
348 opt[2] = rte_cpu_to_be_32(ecr);
351 static inline union tle_tcp_tsopt
352 get_tms_opts(uintptr_t p, uint32_t len)
354 union tle_tcp_tsopt ts;
357 const struct tcpopt *to;
359 opt = (const uint32_t *)p;
361 /* TS option is presented in recommended way */
362 if (len >= TCP_TX_OPT_LEN_TMS && opt[0] == TCP_OPT_TMS_HDR) {
363 ts.val = rte_be_to_cpu_32(opt[1]);
364 ts.ecr = rte_be_to_cpu_32(opt[2]);
368 /* parse through whole list of options. */
372 to = (const struct tcpopt *)(p + i);
374 if (kind == TCP_OPT_KIND_EOL)
376 else if (kind == TCP_OPT_KIND_NOP)
377 i += sizeof(to->kl.kind);
380 if (i <= len && to->kl.raw == TCP_OPT_KL_TMS) {
381 ts.val = rte_be_to_cpu_32(to->ts.val);
382 ts.ecr = rte_be_to_cpu_32(to->ts.ecr);
391 static inline uint8_t
392 get_pkt_type(const struct rte_mbuf *m)
397 (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_MASK);
398 if (v == (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP))
400 else if (v == (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP))
407 get_pkt_info(const struct rte_mbuf *m, union pkt_info *pi, union seg_info *si)
410 const struct rte_tcp_hdr *tcph;
411 const union l4_ports *prt;
412 const union ipv4_addrs *pa4;
414 type = get_pkt_type(m);
418 * this line is here just to avoid gcc warning:
419 * error: .<U6098>.<U6000>.addr4.raw may be used uninitialized.
423 if (type == TLE_V4) {
424 pa4 = rte_pktmbuf_mtod_offset(m, const union ipv4_addrs *,
425 len + offsetof(struct rte_ipv4_hdr, src_addr));
426 pi->addr4.raw = pa4->raw;
427 } else if (type == TLE_V6) {
428 pi->addr6 = rte_pktmbuf_mtod_offset(m, const union ipv6_addrs *,
429 len + offsetof(struct rte_ipv6_hdr, src_addr));
433 tcph = rte_pktmbuf_mtod_offset(m, const struct rte_tcp_hdr *, len);
434 prt = (const union l4_ports *)
435 ((uintptr_t)tcph + offsetof(struct rte_tcp_hdr, src_port));
436 pi->tf.flags = tcph->tcp_flags;
438 pi->csf = m->ol_flags & (PKT_RX_IP_CKSUM_MASK | PKT_RX_L4_CKSUM_MASK);
439 pi->port.raw = prt->raw;
441 get_seg_info(tcph, si);
444 static inline uint32_t
445 tcp_mbuf_seq_free(struct rte_mbuf *mb[], uint32_t num)
450 for (i = 0; i != num; i++) {
451 len += mb[i]->pkt_len;
452 rte_pktmbuf_free(mb[i]);
462 #endif /* _TCP_MISC_H_ */