aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libtle_l4p/tcp_misc.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtle_l4p/tcp_misc.h')
-rw-r--r--lib/libtle_l4p/tcp_misc.h462
1 files changed, 462 insertions, 0 deletions
diff --git a/lib/libtle_l4p/tcp_misc.h b/lib/libtle_l4p/tcp_misc.h
new file mode 100644
index 0000000..beb6699
--- /dev/null
+++ b/lib/libtle_l4p/tcp_misc.h
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TCP_MISC_H_
+#define _TCP_MISC_H_
+
+#include "net_misc.h"
+#include <rte_tcp.h>
+#include <rte_cycles.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TCP protocols related structures/functions definitions.
+ * Main purpose to simplify (and optimise) processing and representation
+ * of protocol related data.
+ */
+
+#define TCP_WSCALE_DEFAULT 7
+#define TCP_WSCALE_NONE 0
+
+#define TCP_TX_HDR_MAX (sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_MAX)
+
+/* max header size for normal data+ack packet */
+#define TCP_TX_HDR_DACK (sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_TMS)
+
+#define TCP4_MIN_MSS 536
+
+#define TCP6_MIN_MSS 1220
+
+/* default MTU, no TCP options. */
+#define TCP4_NOP_MSS \
+ (ETHER_MTU - sizeof(struct ipv4_hdr) - sizeof(struct tcp_hdr))
+
+#define TCP6_NOP_MSS \
+ (ETHER_MTU - sizeof(struct ipv6_hdr) - sizeof(struct tcp_hdr))
+
+/* default MTU, TCP options present */
+#define TCP4_OP_MSS (TCP4_NOP_MSS - TCP_TX_OPT_LEN_MAX)
+
+#define TCP6_OP_MSS (TCP6_NOP_MSS - TCP_TX_OPT_LEN_MAX)
+
+/*
+ * TCP flags
+ */
+#define TCP_FLAG_FIN 0x01
+#define TCP_FLAG_SYN 0x02
+#define TCP_FLAG_RST 0x04
+#define TCP_FLAG_PSH 0x08
+#define TCP_FLAG_ACK 0x10
+#define TCP_FLAG_URG 0x20
+
+/* TCP flags mask. */
+#define TCP_FLAG_MASK UINT8_MAX
+
+union typflg {
+ uint16_t raw;
+ struct {
+ uint8_t type; /* TLE_V4/TLE_V6 */
+ uint8_t flags; /* TCP header flags */
+ };
+};
+
+union pkt_info {
+ rte_xmm_t raw;
+ struct {
+ union typflg tf;
+ uint16_t csf; /* checksum flags */
+ union l4_ports port;
+ union {
+ union ipv4_addrs addr4;
+ const union ipv6_addrs *addr6;
+ };
+ };
+};
+
+union seg_info {
+ rte_xmm_t raw;
+ struct {
+ uint32_t seq;
+ uint32_t ack;
+ uint16_t hole1;
+ uint16_t wnd;
+ };
+};
+
+union seqlen {
+ uint64_t raw;
+ struct {
+ uint32_t seq;
+ uint32_t len;
+ };
+};
+
+#define TCP_DATA_ALIGN 4
+
+#define TCP_DATA_OFFSET 4
+
+/*
+ * recognizable options.
+ */
+#define TCP_OPT_KIND_EOL 0x00
+#define TCP_OPT_KIND_NOP 0x01
+#define TCP_OPT_KIND_MSS 0x02
+#define TCP_OPT_KIND_WSC 0x03
+#define TCP_OPT_KIND_TMS 0x08
+
+#define TCP_OPT_LEN_EOL 0x01
+#define TCP_OPT_LEN_NOP 0x01
+#define TCP_OPT_LEN_MSS 0x04
+#define TCP_OPT_LEN_WSC 0x03
+#define TCP_OPT_LEN_TMS 0x0a
+
+#define TCP_TX_OPT_LEN_MAX \
+ RTE_ALIGN_CEIL(TCP_OPT_LEN_MSS + TCP_OPT_LEN_WSC + TCP_OPT_LEN_TMS + \
+ TCP_OPT_LEN_EOL, TCP_DATA_ALIGN)
+
+/*
+ * recomended format for TSOPT from RFC 1323, appendix A:
+ * +--------+--------+--------+--------+
+ * | NOP | NOP | TSopt | 10 |
+ * +--------+--------+--------+--------+
+ * | TSval timestamp |
+ * +--------+--------+--------+--------+
+ * | TSecr timestamp |
+ * +--------+--------+--------+--------+
+ */
+#define TCP_TX_OPT_LEN_TMS (TCP_OPT_LEN_TMS + 2 * TCP_OPT_LEN_NOP)
+
+#define TCP_OPT_TMS_HDR (rte_be_to_cpu_32( \
+ TCP_OPT_KIND_NOP << 3 * CHAR_BIT | \
+ TCP_OPT_KIND_NOP << 2 * CHAR_BIT | \
+ TCP_OPT_KIND_TMS << CHAR_BIT | \
+ TCP_OPT_LEN_TMS))
+
+#define TCP_OPT_KL(k, l) (rte_be_to_cpu_16((k) << CHAR_BIT | (l)))
+
+#define TCP_OPT_KL_MSS TCP_OPT_KL(TCP_OPT_KIND_MSS, TCP_OPT_LEN_MSS)
+#define TCP_OPT_KL_WSC TCP_OPT_KL(TCP_OPT_KIND_WSC, TCP_OPT_LEN_WSC)
+#define TCP_OPT_KL_TMS TCP_OPT_KL(TCP_OPT_KIND_TMS, TCP_OPT_LEN_TMS)
+
+/*
+ * Timestamp option.
+ */
+union tsopt {
+ uint64_t raw;
+ struct {
+ uint32_t val;
+ uint32_t ecr;
+ };
+};
+
+struct tcpopt {
+ union {
+ uint16_t raw;
+ struct {
+ uint8_t kind;
+ uint8_t len;
+ };
+ } kl;
+ union {
+ uint16_t mss;
+ uint8_t wscale;
+ union tsopt ts;
+ };
+} __attribute__((__packed__));
+
+struct syn_opts {
+ uint16_t mss;
+ uint8_t wscale;
+ union tsopt ts;
+};
+
+struct resp_info {
+ uint32_t flags;
+};
+
+
+/* window update information (RFC 793 WL1, WL2) */
+union wui {
+ uint64_t raw;
+ union {
+ uint32_t wl1;
+ uint32_t wl2;
+ };
+};
+
+/*
+ * helper structure: holds aggregated information about group
+ * of processed data+ack packets.
+ */
+struct dack_info {
+ struct { /* # of received segments with: */
+ uint32_t data; /* incoming data */
+ uint32_t ack; /* newly acked data */
+ uint32_t dup; /* duplicate acks */
+ uint32_t badseq; /* bad seq/ack */
+ uint32_t ofo; /* OFO incoming data */
+ } segs;
+ uint32_t ack; /* highest received ACK */
+ union tsopt ts; /* TS of highest ACK */
+ union wui wu; /* window update information */
+ uint32_t wnd;
+ struct { /* 3 duplicate ACKs were observed after */
+ uint32_t seg; /* # of meaningful ACK segments */
+ uint32_t ack; /* ACK sequence */
+ } dup3;
+};
+
+/* get current timestamp in ms */
+static inline uint32_t
+tcp_get_tms(void)
+{
+ uint64_t ts, ms;
+ ms = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S;
+ ts = rte_get_tsc_cycles() / ms;
+ return ts;
+}
+
+static inline int
+tcp_seq_lt(uint32_t l, uint32_t r)
+{
+ return (int32_t)(l - r) < 0;
+}
+
+static inline int
+tcp_seq_leq(uint32_t l, uint32_t r)
+{
+ return (int32_t)(l - r) <= 0;
+}
+
+
+static inline void
+get_seg_info(const struct tcp_hdr *th, union seg_info *si)
+{
+ __m128i v;
+ const __m128i bswap_mask = _mm_set_epi8(15, 14, 13, 12, 10, 11, 9, 8,
+ 4, 5, 6, 7, 0, 1, 2, 3);
+
+ v = _mm_loadu_si128((const __m128i *)&th->sent_seq);
+ si->raw.x = _mm_shuffle_epi8(v, bswap_mask);
+}
+
+static inline void
+get_syn_opts(struct syn_opts *so, uintptr_t p, uint32_t len)
+{
+ uint32_t i, kind;
+ const struct tcpopt *opt;
+
+ memset(so, 0, sizeof(*so));
+
+ i = 0;
+ while (i < len) {
+ opt = (const struct tcpopt *)(p + i);
+ kind = opt->kl.kind;
+ if (kind == TCP_OPT_KIND_EOL)
+ return;
+ else if (kind == TCP_OPT_KIND_NOP)
+ i += sizeof(opt->kl.kind);
+ else {
+ i += opt->kl.len;
+ if (i <= len) {
+ if (opt->kl.raw == TCP_OPT_KL_MSS)
+ so->mss = rte_be_to_cpu_16(opt->mss);
+ else if (opt->kl.raw == TCP_OPT_KL_WSC)
+ so->wscale = opt->wscale;
+ else if (opt->kl.raw == TCP_OPT_KL_TMS) {
+ so->ts.val =
+ rte_be_to_cpu_32(opt->ts.val);
+ so->ts.ecr =
+ rte_be_to_cpu_32(opt->ts.ecr);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * generates SYN options, assumes that there are
+ * at least TCP_TX_OPT_LEN_MAX bytes available.
+ */
+static inline void
+fill_syn_opts(void *p, const struct syn_opts *so)
+{
+ uint8_t *to;
+ struct tcpopt *opt;
+
+ to = (uint8_t *)p;
+
+ /* setup MSS*/
+ opt = (struct tcpopt *)to;
+ opt->kl.raw = TCP_OPT_KL_MSS;
+ opt->mss = rte_cpu_to_be_16(so->mss);
+
+ to += TCP_OPT_LEN_MSS;
+ opt = (struct tcpopt *)to;
+
+ /* setup TMS*/
+ if (so->ts.val != 0) {
+
+ opt->kl.raw = TCP_OPT_KL_TMS;
+ opt->ts.val = rte_cpu_to_be_32(so->ts.val);
+ opt->ts.ecr = rte_cpu_to_be_32(so->ts.ecr);
+
+ to += TCP_OPT_LEN_TMS;
+ opt = (struct tcpopt *)to;
+ }
+
+ /* setup TMS*/
+ if (so->wscale != 0) {
+
+ opt->kl.raw = TCP_OPT_KL_WSC;
+ opt->wscale = so->wscale;
+
+ to += TCP_OPT_LEN_WSC;
+ opt = (struct tcpopt *)to;
+ }
+
+ to[0] = TCP_OPT_KIND_EOL;
+}
+
+/*
+ * generate TMS option, for non SYN packet, make sure
+ * there at least TCP_TX_OPT_LEN_TMS available.
+ */
+static inline void
+fill_tms_opts(void *p, uint32_t val, uint32_t ecr)
+{
+ uint32_t *opt;
+
+ opt = (uint32_t *)p;
+ opt[0] = TCP_OPT_TMS_HDR;
+ opt[1] = rte_cpu_to_be_32(val);
+ opt[2] = rte_cpu_to_be_32(ecr);
+}
+
+static inline union tsopt
+get_tms_opts(uintptr_t p, uint32_t len)
+{
+ union tsopt ts;
+ uint32_t i, kind;
+ const uint32_t *opt;
+ const struct tcpopt *to;
+
+ opt = (const uint32_t *)p;
+
+ /* TS option is presented in recommended way */
+ if (len >= TCP_TX_OPT_LEN_TMS && opt[0] == TCP_OPT_TMS_HDR) {
+ ts.val = rte_be_to_cpu_32(opt[1]);
+ ts.ecr = rte_be_to_cpu_32(opt[2]);
+ return ts;
+ }
+
+ /* parse through whole list of options. */
+ ts.raw = 0;
+ i = 0;
+ while (i < len) {
+ to = (const struct tcpopt *)(p + i);
+ kind = to->kl.kind;
+ if (kind == TCP_OPT_KIND_EOL)
+ break;
+ else if (kind == TCP_OPT_KIND_NOP)
+ i += sizeof(to->kl.kind);
+ else {
+ i += to->kl.len;
+ if (i <= len && to->kl.raw == TCP_OPT_KL_TMS) {
+ ts.val = rte_be_to_cpu_32(to->ts.val);
+ ts.ecr = rte_be_to_cpu_32(to->ts.ecr);
+ break;
+ }
+ }
+ }
+
+ return ts;
+}
+
+static inline uint8_t
+get_pkt_type(const struct rte_mbuf *m)
+{
+ uint32_t v;
+
+ v = m->packet_type &
+ (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_MASK);
+ if (v == (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP))
+ return TLE_V4;
+ else if (v == (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP))
+ return TLE_V6;
+ else
+ return TLE_VNUM;
+}
+
+static inline void
+get_pkt_info(const struct rte_mbuf *m, union pkt_info *pi, union seg_info *si)
+{
+ uint32_t len, type;
+ const struct tcp_hdr *tcph;
+ const union l4_ports *prt;
+ const union ipv4_addrs *pa4;
+
+ type = get_pkt_type(m);
+ len = m->l2_len;
+
+ /*
+ * this line is here just to avoid gcc warning:
+ * error: .<U6098>.<U6000>.addr4.raw may be used uninitialized.
+ */
+ pi->addr4.raw = 0;
+
+ if (type == TLE_V4) {
+ pa4 = rte_pktmbuf_mtod_offset(m, const union ipv4_addrs *,
+ len + offsetof(struct ipv4_hdr, src_addr));
+ pi->addr4.raw = pa4->raw;
+ } else if (type == TLE_V6) {
+ pi->addr6 = rte_pktmbuf_mtod_offset(m, const union ipv6_addrs *,
+ len + offsetof(struct ipv6_hdr, src_addr));
+ }
+
+ len += m->l3_len;
+ tcph = rte_pktmbuf_mtod_offset(m, const struct tcp_hdr *, len);
+ prt = (const union l4_ports *)
+ ((uintptr_t)tcph + offsetof(struct tcp_hdr, src_port));
+ pi->tf.flags = tcph->tcp_flags;
+ pi->tf.type = type;
+ pi->csf = m->ol_flags & (PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD);
+ pi->port.raw = prt->raw;
+
+ get_seg_info(tcph, si);
+}
+
+static inline uint32_t
+tcp_mbuf_seq_free(struct rte_mbuf *mb[], uint32_t num)
+{
+ uint32_t i, len;
+
+ len = 0;
+ for (i = 0; i != num; i++) {
+ len += mb[i]->pkt_len;
+ rte_pktmbuf_free(mb[i]);
+ }
+
+ return len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TCP_MISC_H_ */