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>
28 * TCP protocols related structures/functions definitions.
29 * Main purpose to simplify (and optimise) processing and representation
30 * of protocol related data.
33 #define TCP_WSCALE_DEFAULT 7
34 #define TCP_WSCALE_NONE 0
36 #define TCP_TX_HDR_MAX (sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_MAX)
38 /* max header size for normal data+ack packet */
39 #define TCP_TX_HDR_DACK (sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_TMS)
41 #define TCP4_MIN_MSS 536
43 #define TCP6_MIN_MSS 1220
45 /* default MTU, no TCP options. */
46 #define TCP4_NOP_MSS \
47 (ETHER_MTU - sizeof(struct ipv4_hdr) - sizeof(struct tcp_hdr))
49 #define TCP6_NOP_MSS \
50 (ETHER_MTU - sizeof(struct ipv6_hdr) - sizeof(struct tcp_hdr))
52 /* default MTU, TCP options present */
53 #define TCP4_OP_MSS (TCP4_NOP_MSS - TCP_TX_OPT_LEN_MAX)
55 #define TCP6_OP_MSS (TCP6_NOP_MSS - TCP_TX_OPT_LEN_MAX)
57 /* Initial Window Configuration parameter, probably will be configured during
58 * the startup in future */
59 #define TCP_INITIAL_CWND_MAX 14600
64 #define TCP_FLAG_FIN 0x01
65 #define TCP_FLAG_SYN 0x02
66 #define TCP_FLAG_RST 0x04
67 #define TCP_FLAG_PSH 0x08
68 #define TCP_FLAG_ACK 0x10
69 #define TCP_FLAG_URG 0x20
72 #define TCP_FLAG_MASK UINT8_MAX
77 uint8_t type; /* TLE_V4/TLE_V6 */
78 uint8_t flags; /* TCP header flags */
86 uint16_t csf; /* checksum flags */
89 union ipv4_addrs addr4;
90 const union ipv6_addrs *addr6;
101 uint16_t mss; /* valid only at SYN time */
113 #define TCP_DATA_ALIGN 4
115 #define TCP_DATA_OFFSET 4
118 * recognizable options.
120 #define TCP_OPT_KIND_EOL 0x00
121 #define TCP_OPT_KIND_NOP 0x01
122 #define TCP_OPT_KIND_MSS 0x02
123 #define TCP_OPT_KIND_WSC 0x03
124 #define TCP_OPT_KIND_TMS 0x08
126 #define TCP_OPT_LEN_EOL 0x01
127 #define TCP_OPT_LEN_NOP 0x01
128 #define TCP_OPT_LEN_MSS 0x04
129 #define TCP_OPT_LEN_WSC 0x03
130 #define TCP_OPT_LEN_TMS 0x0a
132 #define TCP_TX_OPT_LEN_MAX \
133 RTE_ALIGN_CEIL(TCP_OPT_LEN_MSS + TCP_OPT_LEN_WSC + TCP_OPT_LEN_TMS + \
134 TCP_OPT_LEN_EOL, TCP_DATA_ALIGN)
137 * recomended format for TSOPT from RFC 1323, appendix A:
138 * +--------+--------+--------+--------+
139 * | NOP | NOP | TSopt | 10 |
140 * +--------+--------+--------+--------+
141 * | TSval timestamp |
142 * +--------+--------+--------+--------+
143 * | TSecr timestamp |
144 * +--------+--------+--------+--------+
146 #define TCP_TX_OPT_LEN_TMS (TCP_OPT_LEN_TMS + 2 * TCP_OPT_LEN_NOP)
148 #define TCP_OPT_TMS_HDR (rte_be_to_cpu_32( \
149 TCP_OPT_KIND_NOP << 3 * CHAR_BIT | \
150 TCP_OPT_KIND_NOP << 2 * CHAR_BIT | \
151 TCP_OPT_KIND_TMS << CHAR_BIT | \
154 #define TCP_OPT_KL(k, l) (rte_be_to_cpu_16((k) << CHAR_BIT | (l)))
156 #define TCP_OPT_KL_MSS TCP_OPT_KL(TCP_OPT_KIND_MSS, TCP_OPT_LEN_MSS)
157 #define TCP_OPT_KL_WSC TCP_OPT_KL(TCP_OPT_KIND_WSC, TCP_OPT_LEN_WSC)
158 #define TCP_OPT_KL_TMS TCP_OPT_KL(TCP_OPT_KIND_TMS, TCP_OPT_LEN_TMS)
184 } __attribute__((__packed__));
197 /* window update information (RFC 793 WL1, WL2) */
207 * helper structure: holds aggregated information about group
208 * of processed data+ack packets.
211 struct { /* # of received segments with: */
212 uint32_t data; /* incoming data */
213 uint32_t ack; /* newly acked data */
214 uint32_t dup; /* duplicate acks */
215 uint32_t badseq; /* bad seq/ack */
216 uint32_t ofo; /* OFO incoming data */
218 uint32_t ack; /* highest received ACK */
219 union tsopt ts; /* TS of highest ACK */
220 union wui wu; /* window update information */
222 struct { /* 3 duplicate ACKs were observed after */
223 uint32_t seg; /* # of meaningful ACK segments */
224 uint32_t ack; /* ACK sequence */
228 /* get current timestamp in ms */
229 static inline uint32_t
230 tcp_get_tms(uint32_t mshift)
233 ts = rte_get_tsc_cycles() >> mshift;
238 tcp_seq_lt(uint32_t l, uint32_t r)
240 return (int32_t)(l - r) < 0;
244 tcp_seq_leq(uint32_t l, uint32_t r)
246 return (int32_t)(l - r) <= 0;
251 get_seg_info(const struct tcp_hdr *th, union seg_info *si)
254 const __m128i bswap_mask =
255 _mm_set_epi8(UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX,
256 UINT8_MAX, UINT8_MAX, 10, 11,
260 v = _mm_loadu_si128((const __m128i *)&th->sent_seq);
261 si->raw.x = _mm_shuffle_epi8(v, bswap_mask);
265 get_syn_opts(struct syn_opts *so, uintptr_t p, uint32_t len)
268 const struct tcpopt *opt;
270 memset(so, 0, sizeof(*so));
274 opt = (const struct tcpopt *)(p + i);
276 if (kind == TCP_OPT_KIND_EOL)
278 else if (kind == TCP_OPT_KIND_NOP)
279 i += sizeof(opt->kl.kind);
283 if (opt->kl.raw == TCP_OPT_KL_MSS)
284 so->mss = rte_be_to_cpu_16(opt->mss);
285 else if (opt->kl.raw == TCP_OPT_KL_WSC)
286 so->wscale = opt->wscale;
287 else if (opt->kl.raw == TCP_OPT_KL_TMS) {
289 rte_be_to_cpu_32(opt->ts.val);
291 rte_be_to_cpu_32(opt->ts.ecr);
299 * generates SYN options, assumes that there are
300 * at least TCP_TX_OPT_LEN_MAX bytes available.
303 fill_syn_opts(void *p, const struct syn_opts *so)
311 opt = (struct tcpopt *)to;
312 opt->kl.raw = TCP_OPT_KL_MSS;
313 opt->mss = rte_cpu_to_be_16(so->mss);
315 to += TCP_OPT_LEN_MSS;
316 opt = (struct tcpopt *)to;
319 if (so->ts.val != 0) {
321 opt->kl.raw = TCP_OPT_KL_TMS;
322 opt->ts.val = rte_cpu_to_be_32(so->ts.val);
323 opt->ts.ecr = rte_cpu_to_be_32(so->ts.ecr);
325 to += TCP_OPT_LEN_TMS;
326 opt = (struct tcpopt *)to;
330 if (so->wscale != 0) {
332 opt->kl.raw = TCP_OPT_KL_WSC;
333 opt->wscale = so->wscale;
335 to += TCP_OPT_LEN_WSC;
336 opt = (struct tcpopt *)to;
339 to[0] = TCP_OPT_KIND_EOL;
343 * generate TMS option, for non SYN packet, make sure
344 * there at least TCP_TX_OPT_LEN_TMS available.
347 fill_tms_opts(void *p, uint32_t val, uint32_t ecr)
352 opt[0] = TCP_OPT_TMS_HDR;
353 opt[1] = rte_cpu_to_be_32(val);
354 opt[2] = rte_cpu_to_be_32(ecr);
357 static inline union tsopt
358 get_tms_opts(uintptr_t p, uint32_t len)
363 const struct tcpopt *to;
365 opt = (const uint32_t *)p;
367 /* TS option is presented in recommended way */
368 if (len >= TCP_TX_OPT_LEN_TMS && opt[0] == TCP_OPT_TMS_HDR) {
369 ts.val = rte_be_to_cpu_32(opt[1]);
370 ts.ecr = rte_be_to_cpu_32(opt[2]);
374 /* parse through whole list of options. */
378 to = (const struct tcpopt *)(p + i);
380 if (kind == TCP_OPT_KIND_EOL)
382 else if (kind == TCP_OPT_KIND_NOP)
383 i += sizeof(to->kl.kind);
386 if (i <= len && to->kl.raw == TCP_OPT_KL_TMS) {
387 ts.val = rte_be_to_cpu_32(to->ts.val);
388 ts.ecr = rte_be_to_cpu_32(to->ts.ecr);
397 static inline uint8_t
398 get_pkt_type(const struct rte_mbuf *m)
403 (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_MASK);
404 if (v == (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP))
406 else if (v == (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP))
413 get_pkt_info(const struct rte_mbuf *m, union pkt_info *pi, union seg_info *si)
416 const struct tcp_hdr *tcph;
417 const union l4_ports *prt;
418 const union ipv4_addrs *pa4;
420 type = get_pkt_type(m);
424 * this line is here just to avoid gcc warning:
425 * error: .<U6098>.<U6000>.addr4.raw may be used uninitialized.
429 if (type == TLE_V4) {
430 pa4 = rte_pktmbuf_mtod_offset(m, const union ipv4_addrs *,
431 len + offsetof(struct ipv4_hdr, src_addr));
432 pi->addr4.raw = pa4->raw;
433 } else if (type == TLE_V6) {
434 pi->addr6 = rte_pktmbuf_mtod_offset(m, const union ipv6_addrs *,
435 len + offsetof(struct ipv6_hdr, src_addr));
439 tcph = rte_pktmbuf_mtod_offset(m, const struct tcp_hdr *, len);
440 prt = (const union l4_ports *)
441 ((uintptr_t)tcph + offsetof(struct tcp_hdr, src_port));
442 pi->tf.flags = tcph->tcp_flags;
444 pi->csf = m->ol_flags & (PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD);
445 pi->port.raw = prt->raw;
447 get_seg_info(tcph, si);
450 static inline uint32_t
451 tcp_mbuf_seq_free(struct rte_mbuf *mb[], uint32_t num)
456 for (i = 0; i != num; i++) {
457 len += mb[i]->pkt_len;
458 rte_pktmbuf_free(mb[i]);
468 #endif /* _TCP_MISC_H_ */