aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libtle_l4p
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtle_l4p')
-rw-r--r--lib/libtle_l4p/ctx.c10
-rw-r--r--lib/libtle_l4p/halfsiphash.h100
-rw-r--r--lib/libtle_l4p/syncookie.h76
-rw-r--r--lib/libtle_l4p/tcp_rxtx.c21
-rw-r--r--lib/libtle_l4p/tle_ctx.h11
5 files changed, 188 insertions, 30 deletions
diff --git a/lib/libtle_l4p/ctx.c b/lib/libtle_l4p/ctx.c
index 7ebef9d..6eb33eb 100644
--- a/lib/libtle_l4p/ctx.c
+++ b/lib/libtle_l4p/ctx.c
@@ -21,6 +21,7 @@
#include "stream.h"
#include "misc.h"
+#include <halfsiphash.h>
#define LPORT_START 0x8000
#define LPORT_END MAX_PORT_NUM
@@ -66,6 +67,8 @@ check_ctx_prm(const struct tle_ctx_param *prm)
{
if (prm->proto >= TLE_PROTO_NUM)
return -EINVAL;
+ if (prm->hash_alg >= TLE_HASH_NUM)
+ return -EINVAL;
return 0;
}
@@ -108,6 +111,13 @@ tle_ctx_create(const struct tle_ctx_param *ctx_prm)
tle_pbm_init(ctx->use + i, LPORT_START_BLK);
ctx->streams.nb_free = ctx->prm.max_streams;
+
+ /* Initialization of siphash state is done here to speed up the
+ * fastpath processing.
+ */
+ if (ctx->prm.hash_alg == TLE_SIPHASH)
+ siphash_initialization(&ctx->prm.secret_key,
+ &ctx->prm.secret_key);
return ctx;
}
diff --git a/lib/libtle_l4p/halfsiphash.h b/lib/libtle_l4p/halfsiphash.h
new file mode 100644
index 0000000..e8e21e4
--- /dev/null
+++ b/lib/libtle_l4p/halfsiphash.h
@@ -0,0 +1,100 @@
+/*
+ * SipHash reference C implementation
+
+ * Copyright (c) 2016 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
+
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef _SIPHASH_
+#define _SIPHASH_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The below siphash logic is taken from the source
+ * https://github.com/veorq/SipHash
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_debug.h>
+
+#define STATE_V2 0x6c796765
+#define STATE_V3 0x74656462
+
+#define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
+
+/*
+ * Siphash hash functionality logically divided into different
+ * phases and the functions are named based on the same.
+ * SipHash-2-4 is used i.e: 2 compression rounds and 4 finalization rounds.
+ */
+static inline void
+sipround(rte_xmm_t *v)
+{
+ v->u32[0] += v->u32[1];
+ v->u32[1] = ROTL(v->u32[1], 5);
+ v->u32[1] ^= v->u32[0];
+ v->u32[0] = ROTL(v->u32[0], 16);
+ v->u32[2] += v->u32[3];
+ v->u32[3] = ROTL(v->u32[3], 8);
+ v->u32[3] ^= v->u32[2];
+ v->u32[0] += v->u32[3];
+ v->u32[3] = ROTL(v->u32[3], 7);
+ v->u32[3] ^= v->u32[0];
+ v->u32[2] += v->u32[1];
+ v->u32[1] = ROTL(v->u32[1], 13);
+ v->u32[1] ^= v->u32[2];
+ v->u32[2] = ROTL(v->u32[2], 16);
+}
+
+static inline void
+siphash_initialization(rte_xmm_t *v, const rte_xmm_t *k)
+{
+ uint32_t k0 = k->u32[0];
+ uint32_t k1 = k->u32[1];
+
+ v->u32[0] = k0;
+ v->u32[1] = k1;
+ v->u32[2] = STATE_V2 ^ k0;
+ v->u32[3] = STATE_V3 ^ k1;
+}
+
+static inline void
+siphash_compression(const uint32_t *in, size_t len, rte_xmm_t *v)
+{
+ uint32_t i;
+
+ for (i = 0; i < len; i++) {
+ v->u32[3] ^= in[i];
+ sipround(v);
+ sipround(v);
+ v->u32[0] ^= in[i];
+ }
+}
+
+static inline void
+siphash_finalization(rte_xmm_t *v)
+{
+ v->u32[2] ^= 0xff;
+ sipround(v);
+ sipround(v);
+ sipround(v);
+ sipround(v);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SIPHASH__ */
diff --git a/lib/libtle_l4p/syncookie.h b/lib/libtle_l4p/syncookie.h
index ad70b7d..da2e166 100644
--- a/lib/libtle_l4p/syncookie.h
+++ b/lib/libtle_l4p/syncookie.h
@@ -16,16 +16,16 @@
#ifndef _SYNCOOKIE_H_
#define _SYNCOOKIE_H_
-#include "tcp_misc.h"
#include <rte_jhash.h>
+#include "tcp_misc.h"
+#include <tle_ctx.h>
+#include <halfsiphash.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#define SYNC_SEED0 0x736f6d65
-#define SYNC_SEED1 0x646f7261
-
struct sync_in4 {
uint32_t seq;
union l4_ports port;
@@ -64,35 +64,61 @@ static const rte_xmm_t mss6len = {
/* allow around 2 minutes for 3-way handshake. */
#define SYNC_MAX_TMO 0x20000
-
/* ??? use SipHash as FreeBSD does. ??? */
static inline uint32_t
-sync_hash4(const union pkt_info *pi, uint32_t seq)
+sync_hash4(const union pkt_info *pi, uint32_t seq, rte_xmm_t *secret_key,
+ uint32_t hash_alg)
{
- uint32_t v0, v1;
struct sync_in4 in4;
+ rte_xmm_t state;
+ uint32_t v0, v1;
in4.seq = seq;
in4.port = pi->port;
in4.addr = pi->addr4;
- v0 = SYNC_SEED0;
- v1 = SYNC_SEED1;
- rte_jhash_32b_2hashes(&in4.seq, sizeof(in4) / sizeof(uint32_t),
- &v0, &v1);
- return v0 + v1;
+ if (hash_alg == TLE_JHASH) {
+ v0 = secret_key->u32[0];
+ v1 = secret_key->u32[1];
+ rte_jhash_32b_2hashes(&in4.seq, sizeof(in4) / sizeof(uint32_t),
+ &v0, &v1);
+ return v0 + v1;
+ } else {
+ state = *secret_key;
+ siphash_compression(&in4.seq, sizeof(in4) / sizeof(uint32_t),
+ &state);
+ siphash_finalization(&state);
+ return (state.u32[0] ^ state.u32[1] ^
+ state.u32[2] ^ state.u32[3]);
+ }
}
static inline uint32_t
-sync_hash6(const union pkt_info *pi, uint32_t seq)
+sync_hash6(const union pkt_info *pi, uint32_t seq, rte_xmm_t *secret_key,
+ uint32_t hash_alg)
{
+ uint32_t port_seq[2];
+ rte_xmm_t state;
uint32_t v0, v1;
- v0 = SYNC_SEED0;
- v1 = SYNC_SEED1;
- rte_jhash_32b_2hashes(pi->addr6->raw.u32,
- sizeof(*pi->addr6) / sizeof(uint32_t), &v0, &v1);
- return rte_jhash_3words(v0, seq, pi->port.raw, v1);
+ if (hash_alg == TLE_JHASH) {
+ v0 = secret_key->u32[0];
+ v1 = secret_key->u32[1];
+ rte_jhash_32b_2hashes(pi->addr6->raw.u32,
+ sizeof(*pi->addr6) / sizeof(uint32_t),
+ &v0, &v1);
+ return rte_jhash_3words(v0, seq, pi->port.raw, v1);
+ } else {
+ state = *secret_key;
+ siphash_compression(pi->addr6->raw.u32,
+ sizeof(*pi->addr6) / sizeof(uint32_t), &state);
+ port_seq[0] = pi->port.raw;
+ port_seq[1] = seq;
+ siphash_compression(port_seq, RTE_DIM(port_seq), &state);
+ siphash_finalization(&state);
+ return (state.u32[0] ^ state.u32[1] ^
+ state.u32[2] ^ state.u32[3]);
+ }
}
static inline uint32_t
@@ -105,15 +131,16 @@ sync_mss2idx(uint16_t mss, const rte_xmm_t *msl)
}
static inline uint32_t
-sync_gen_seq(const union pkt_info *pi, uint32_t seq, uint32_t ts, uint16_t mss)
+sync_gen_seq(const union pkt_info *pi, uint32_t seq, uint32_t ts, uint16_t mss,
+ uint32_t hash_alg, rte_xmm_t *secret_key)
{
uint32_t h, mi;
if (pi->tf.type == TLE_V4) {
- h = sync_hash4(pi, seq);
+ h = sync_hash4(pi, seq, secret_key, hash_alg);
mi = sync_mss2idx(mss, &mss4len);
} else {
- h = sync_hash6(pi, seq);
+ h = sync_hash6(pi, seq, secret_key, hash_alg);
mi = sync_mss2idx(mss, &mss6len);
}
@@ -131,11 +158,14 @@ sync_gen_ts(uint32_t ts, uint32_t wscale)
static inline int
sync_check_ack(const union pkt_info *pi, uint32_t seq, uint32_t ack,
- uint32_t ts)
+ uint32_t ts, uint32_t hash_alg, rte_xmm_t *secret_key)
{
uint32_t h, mi, pts;
- h = (pi->tf.type == TLE_V4) ? sync_hash4(pi, seq) : sync_hash6(pi, seq);
+ if (pi->tf.type == TLE_V4)
+ h = sync_hash4(pi, seq, secret_key, hash_alg);
+ else
+ h = sync_hash6(pi, seq, secret_key, hash_alg);
h = ack - h;
pts = h & ~SYNC_MSS_MASK;
diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c
index b525751..d4b6fdd 100644
--- a/lib/libtle_l4p/tcp_rxtx.c
+++ b/lib/libtle_l4p/tcp_rxtx.c
@@ -641,7 +641,9 @@ sync_ack(struct tle_tcp_stream *s, const union pkt_info *pi,
get_syn_opts(&s->tcb.so, (uintptr_t)(th + 1), m->l4_len - sizeof(*th));
s->tcb.rcv.nxt = si->seq + 1;
- seq = sync_gen_seq(pi, s->tcb.rcv.nxt, ts, s->tcb.so.mss);
+ seq = sync_gen_seq(pi, s->tcb.rcv.nxt, ts, s->tcb.so.mss,
+ s->s.ctx->prm.hash_alg,
+ &s->s.ctx->prm.secret_key);
s->tcb.so.ts.ecr = s->tcb.so.ts.val;
s->tcb.so.ts.val = sync_gen_ts(ts, s->tcb.so.wscale);
s->tcb.so.wscale = (s->tcb.so.wscale == TCP_WSCALE_NONE) ?
@@ -762,14 +764,17 @@ rx_check_seqack(struct tcb *tcb, uint32_t seq, uint32_t ack, uint32_t len,
static inline int
restore_syn_opt(struct syn_opts *so, const union pkt_info *pi,
- const union seg_info *si, uint32_t ts, const struct rte_mbuf *mb)
+ const union seg_info *si, uint32_t ts, const struct rte_mbuf *mb,
+ uint32_t hash_alg, rte_xmm_t *secret_key)
{
int32_t rc;
uint32_t len;
const struct tcp_hdr *th;
/* check that ACK, etc fields are what we expected. */
- rc = sync_check_ack(pi, si->seq, si->ack - 1, ts);
+ rc = sync_check_ack(pi, si->seq, si->ack - 1, ts,
+ hash_alg,
+ secret_key);
if (rc < 0)
return rc;
@@ -918,12 +923,12 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st,
if (pi->tf.flags != TCP_FLAG_ACK || rx_check_stream(s, pi) != 0)
return -EINVAL;
- rc = restore_syn_opt(&so, pi, si, tms, mb);
+ ctx = s->s.ctx;
+ rc = restore_syn_opt(&so, pi, si, tms, mb, ctx->prm.hash_alg,
+ &ctx->prm.secret_key);
if (rc < 0)
return rc;
- ctx = s->s.ctx;
-
/* allocate new stream */
ts = get_stream(ctx);
cs = TCP_STREAM(ts);
@@ -2059,7 +2064,9 @@ tx_syn(struct tle_tcp_stream *s, const struct sockaddr *addr)
s->tcb.so.mss = calc_smss(s->tx.dst.mtu, &s->tx.dst);
/* note that rcv.nxt is 0 here for sync_gen_seq.*/
- seq = sync_gen_seq(&pi, s->tcb.rcv.nxt, tms, s->tcb.so.mss);
+ seq = sync_gen_seq(&pi, s->tcb.rcv.nxt, tms, s->tcb.so.mss,
+ s->s.ctx->prm.hash_alg,
+ &s->s.ctx->prm.secret_key);
s->tcb.snd.iss = seq;
s->tcb.snd.rcvr = seq;
s->tcb.snd.una = seq;
diff --git a/lib/libtle_l4p/tle_ctx.h b/lib/libtle_l4p/tle_ctx.h
index a3516bf..144dbe7 100644
--- a/lib/libtle_l4p/tle_ctx.h
+++ b/lib/libtle_l4p/tle_ctx.h
@@ -97,6 +97,12 @@ enum {
TLE_PROTO_NUM
};
+enum {
+ TLE_JHASH,
+ TLE_SIPHASH,
+ TLE_HASH_NUM
+};
+
struct tle_ctx_param {
int32_t socket_id; /**< socket ID to allocate memory for. */
uint32_t proto; /**< L4 proto to handle. */
@@ -116,6 +122,11 @@ struct tle_ctx_param {
/**< will be called by send() to get IPv6 packet destination info. */
void *lookup6_data;
/**< opaque data pointer for lookup6() callback. */
+
+ uint32_t hash_alg;
+ /**< hash algorithm to be used to generate sequence number. */
+ rte_xmm_t secret_key;
+ /**< secret key to be used to calculate the hash. */
};
/**