46a0a5fdc4f1daea0156cb18a98ec5d402e5d3be
[tldk.git] / lib / libtle_l4p / tcp_misc.h
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #ifndef _TCP_MISC_H_
17 #define _TCP_MISC_H_
18
19 #include "net_misc.h"
20 #include <rte_tcp.h>
21 #include <rte_cycles.h>
22 #include <tle_tcp.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 /*
29  * TCP protocols related structures/functions definitions.
30  * Main purpose to simplify (and optimise) processing and representation
31  * of protocol related data.
32  */
33
34 #define TCP_WSCALE_DEFAULT      7
35 #define TCP_WSCALE_NONE         0
36
37 #define TCP_TX_HDR_MAX  (sizeof(struct rte_tcp_hdr) + TCP_TX_OPT_LEN_MAX)
38
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)
41
42 #define TCP4_MIN_MSS    536
43
44 #define TCP6_MIN_MSS    1220
45
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))
50
51 #define TCP6_NOP_MSS    \
52         (RTE_ETHER_MTU - sizeof(struct rte_ipv6_hdr) - \
53          sizeof(struct rte_tcp_hdr))
54
55 /* default MTU, TCP options present */
56 #define TCP4_OP_MSS     (TCP4_NOP_MSS - TCP_TX_OPT_LEN_MAX)
57
58 #define TCP6_OP_MSS     (TCP6_NOP_MSS - TCP_TX_OPT_LEN_MAX)
59
60 /* Initial Window Configuration parameter, probably will be configured during
61  * the startup in future */
62 #define TCP_INITIAL_CWND_MAX 14600
63
64 /*
65  * TCP flags
66  */
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
73
74 /* TCP flags mask. */
75 #define TCP_FLAG_MASK   UINT8_MAX
76
77 union typflg {
78         uint16_t raw;
79         struct {
80                 uint8_t type;  /* TLE_V4/TLE_V6 */
81                 uint8_t flags; /* TCP header flags */
82         };
83 };
84
85 union pkt_info {
86         rte_xmm_t raw;
87         struct {
88                 union typflg tf;
89                 uint16_t csf;  /* checksum flags */
90                 union l4_ports port;
91                 union {
92                         union ipv4_addrs addr4;
93                         const union ipv6_addrs *addr6;
94                 };
95         };
96 };
97
98 union seg_info {
99         rte_xmm_t raw;
100         struct {
101                 uint32_t seq;
102                 uint32_t ack;
103                 uint16_t wnd;
104                 uint16_t mss; /* valid only at SYN time */
105         };
106 };
107
108 union seqlen {
109         uint64_t raw;
110         struct {
111                 uint32_t seq;
112                 uint32_t len;
113         };
114 };
115
116 #define TCP_DATA_ALIGN  4
117
118 #define TCP_DATA_OFFSET 4
119
120 /*
121  * recognizable options.
122  */
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
128
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
134
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)
138
139 /*
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  *  +--------+--------+--------+--------+
148  */
149 #define TCP_TX_OPT_LEN_TMS      (TCP_OPT_LEN_TMS + 2 * TCP_OPT_LEN_NOP)
150
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 | \
155         TCP_OPT_LEN_TMS))
156
157 #define TCP_OPT_KL(k, l)        (rte_be_to_cpu_16((k) << CHAR_BIT | (l)))
158
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)
162
163 struct tcpopt {
164         union {
165                 uint16_t raw;
166                 struct {
167                         uint8_t kind;
168                         uint8_t len;
169                 };
170         } kl;
171         union {
172                 uint16_t mss;
173                 uint8_t  wscale;
174                 union tle_tcp_tsopt ts;
175         };
176 } __attribute__((__packed__));
177
178 struct resp_info {
179         uint32_t flags;
180 };
181
182
183 /* window update information (RFC 793 WL1, WL2) */
184 union wui {
185         uint64_t raw;
186         struct {
187                 uint32_t wl1;
188                 uint32_t wl2;
189         };
190 };
191
192 /*
193  * helper structure: holds aggregated information about group
194  * of processed data+ack packets.
195  */
196 struct dack_info {
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 */
203         } segs;
204         uint32_t ack;               /* highest received ACK */
205         union tle_tcp_tsopt ts;     /* TS of highest ACK */
206         union wui wu;               /* window update information */
207         uint32_t wnd;
208         struct {               /* 3 duplicate ACKs were observed after */
209                 uint32_t seg;  /* # of meaningful ACK segments */
210                 uint32_t ack;  /* ACK sequence */
211         } dup3;
212 };
213
214 /* get current timestamp in ms */
215 static inline uint32_t
216 tcp_get_tms(uint32_t mshift)
217 {
218         uint64_t ts;
219         ts = rte_get_tsc_cycles() >> mshift;
220         return ts;
221 }
222
223 static inline int
224 tcp_seq_lt(uint32_t l, uint32_t r)
225 {
226         return (int32_t)(l - r) < 0;
227 }
228
229 static inline int
230 tcp_seq_leq(uint32_t l, uint32_t r)
231 {
232         return (int32_t)(l - r) <= 0;
233 }
234
235 static inline uint32_t
236 tcp_seq_min(uint32_t l, uint32_t r)
237 {
238         if (tcp_seq_lt(l, r))
239                 return l;
240         else
241                 return r;
242 }
243
244 static inline void
245 get_seg_info(const struct rte_tcp_hdr *th, union seg_info *si)
246 {
247         __m128i v;
248         const  __m128i bswap_mask =
249                 _mm_set_epi8(UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX,
250                         UINT8_MAX, UINT8_MAX, 10, 11,
251                         4, 5, 6, 7,
252                         0, 1, 2, 3);
253
254         v = _mm_loadu_si128((const __m128i *)&th->sent_seq);
255         si->raw.x = _mm_shuffle_epi8(v, bswap_mask);
256 }
257
258 static inline void
259 get_syn_opts(struct tle_tcp_syn_opts *so, uintptr_t p, uint32_t len)
260 {
261         uint32_t i, kind;
262         const struct tcpopt *opt;
263
264         memset(so, 0, sizeof(*so));
265
266         i = 0;
267         while (i < len) {
268                 opt = (const struct tcpopt *)(p + i);
269                 kind = opt->kl.kind;
270                 if (kind == TCP_OPT_KIND_EOL)
271                         return;
272                 else if (kind == TCP_OPT_KIND_NOP)
273                         i += sizeof(opt->kl.kind);
274                 else {
275                         i += opt->kl.len;
276                         if (i <= len) {
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) {
282                                         so->ts.val =
283                                                 rte_be_to_cpu_32(opt->ts.val);
284                                         so->ts.ecr =
285                                                 rte_be_to_cpu_32(opt->ts.ecr);
286                                 }
287                         }
288                 }
289         }
290 }
291
292 /*
293  * generates SYN options, assumes that there are
294  * at least TCP_TX_OPT_LEN_MAX bytes available.
295  */
296 static inline void
297 fill_syn_opts(void *p, const struct tle_tcp_syn_opts *so)
298 {
299         uint8_t *to;
300         struct tcpopt *opt;
301
302         to = (uint8_t *)p;
303
304         /* setup MSS*/
305         opt = (struct tcpopt *)to;
306         opt->kl.raw = TCP_OPT_KL_MSS;
307         opt->mss = rte_cpu_to_be_16(so->mss);
308
309         to += TCP_OPT_LEN_MSS;
310         opt = (struct tcpopt *)to;
311
312         /* setup TMS*/
313         if (so->ts.val != 0) {
314
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);
318
319                 to += TCP_OPT_LEN_TMS;
320                 opt = (struct tcpopt *)to;
321         }
322
323         /* setup TMS*/
324         if (so->wscale != 0) {
325
326                 opt->kl.raw = TCP_OPT_KL_WSC;
327                 opt->wscale = so->wscale;
328
329                 to += TCP_OPT_LEN_WSC;
330                 opt = (struct tcpopt *)to;
331         }
332
333         to[0] = TCP_OPT_KIND_EOL;
334 }
335
336 /*
337  * generate TMS option, for non SYN packet, make sure
338  * there at least TCP_TX_OPT_LEN_TMS available.
339  */
340 static inline void
341 fill_tms_opts(void *p, uint32_t val, uint32_t ecr)
342 {
343         uint32_t *opt;
344
345         opt = (uint32_t *)p;
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);
349 }
350
351 static inline union tle_tcp_tsopt
352 get_tms_opts(uintptr_t p, uint32_t len)
353 {
354         union tle_tcp_tsopt ts;
355         uint32_t i, kind;
356         const uint32_t *opt;
357         const struct tcpopt *to;
358
359         opt = (const uint32_t *)p;
360
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]);
365                 return ts;
366         }
367
368         /* parse through whole list of options. */
369         ts.raw = 0;
370         i = 0;
371         while (i < len) {
372                 to = (const struct tcpopt *)(p + i);
373                 kind = to->kl.kind;
374                 if (kind == TCP_OPT_KIND_EOL)
375                         break;
376                 else if (kind == TCP_OPT_KIND_NOP)
377                         i += sizeof(to->kl.kind);
378                 else {
379                         i += to->kl.len;
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);
383                                 break;
384                         }
385                 }
386         }
387
388         return ts;
389 }
390
391 static inline uint8_t
392 get_pkt_type(const struct rte_mbuf *m)
393 {
394         uint32_t v;
395
396         v = m->packet_type &
397                 (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_MASK);
398         if (v == (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP))
399                 return TLE_V4;
400         else if (v == (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP))
401                 return TLE_V6;
402         else
403                 return TLE_VNUM;
404 }
405
406 static inline void
407 get_pkt_info(const struct rte_mbuf *m, union pkt_info *pi, union seg_info *si)
408 {
409         uint32_t len, type;
410         const struct rte_tcp_hdr *tcph;
411         const union l4_ports *prt;
412         const union ipv4_addrs *pa4;
413
414         type = get_pkt_type(m);
415         len = m->l2_len;
416
417         /*
418          * this line is here just to avoid gcc warning:
419          * error: .<U6098>.<U6000>.addr4.raw may be used uninitialized.
420          */
421         pi->addr4.raw = 0;
422
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));
430         }
431
432         len += m->l3_len;
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;
437         pi->tf.type = type;
438         pi->csf = m->ol_flags & (PKT_RX_IP_CKSUM_MASK | PKT_RX_L4_CKSUM_MASK);
439         pi->port.raw = prt->raw;
440
441         get_seg_info(tcph, si);
442 }
443
444 static inline uint32_t
445 tcp_mbuf_seq_free(struct rte_mbuf *mb[], uint32_t num)
446 {
447         uint32_t i, len;
448
449         len = 0;
450         for (i = 0; i != num; i++) {
451                 len += mb[i]->pkt_len;
452                 rte_pktmbuf_free(mb[i]);
453         }
454
455         return len;
456 }
457
458 #ifdef __cplusplus
459 }
460 #endif
461
462 #endif /* _TCP_MISC_H_ */