* Add siphash file for calculating the sequence number. 07/6207/1
authorReshma Pattan <reshma.pattan@intel.com>
Fri, 7 Apr 2017 15:51:27 +0000 (16:51 +0100)
committerReshma Pattan <reshma.pattan@intel.com>
Fri, 14 Apr 2017 09:30:57 +0000 (10:30 +0100)
* l4fwd app changed to include new command line parameters
  hash and secret key for hash calculation.
* Changed l4fwd library to integrate siphash support for
  calculating the sequence number.

Change-Id: I29c60836c8b17a118d76b619fd79398fac200f67
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
README
examples/l4fwd/README
examples/l4fwd/lcore.h
examples/l4fwd/parse.c
lib/libtle_l4p/ctx.c
lib/libtle_l4p/halfsiphash.h [new file with mode: 0644]
lib/libtle_l4p/syncookie.h
lib/libtle_l4p/tcp_rxtx.c
lib/libtle_l4p/tle_ctx.h

diff --git a/README b/README
index f6ff9ed..d33b2df 100644 (file)
--- a/README
+++ b/README
    to make the resulting host stack easily usable by existing non-vpp aware
    software.
 
+   The library uses siphash logic from the below source
+   https://github.com/veorq/SipHash
+
+
 2. INSTALLATION GUIDE
 
    1) Obtain latest DPDK and build it.
index 658fe3a..a232537 100644 (file)
       -L | --listen /* open TCP streams in server mode (listen). */ \
       -a | --enable-arp /* enable arp responses (request not supported) */ \
       -v | --verbose /* different level of verbose mode */ \
+      -H | --hash <string> /* hash algorithm i.e. siphash or jhash to be */ \
+                           /* used to generate the sequence number. */ \
+      -K | --seckey <string> /* 16 character long secret key used by */ \
+                             /* hash algorithms to generate the */ \
+                             /* sequence number. */ \
       <port0_params> <port1_params> ... <portN_params>
 
    Note that: options -U and -T cannot be used together.
index d88e434..11cc239 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef LCORE_H_
 #define LCORE_H_
 
+#include <rte_random.h>
+
 #include "dpdk_legacy.h"
 
 /*
@@ -64,6 +66,11 @@ create_context(struct netbe_lcore *lc, const struct tle_ctx_param *ctx_prm)
                cprm.lookup4_data = lc;
                cprm.lookup6 = lpm6_dst_lookup;
                cprm.lookup6_data = lc;
+               if (cprm.secret_key.u64[0] == 0 &&
+                       cprm.secret_key.u64[1] == 0) {
+                       cprm.secret_key.u64[0] = rte_rand();
+                       cprm.secret_key.u64[1] = rte_rand();
+               }
 
                frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) /
                                                MS_PER_S * FRAG_TTL;
index 6593221..ac11517 100644 (file)
@@ -13,6 +13,9 @@
  * limitations under the License.
  */
 
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
 #include "netbe.h"
 #include "parse.h"
 
@@ -61,6 +64,12 @@ static const struct {
 #define        OPT_SHORT_LISTEN        'L'
 #define        OPT_LONG_LISTEN         "listen"
 
+#define OPT_SHORT_HASH         'H'
+#define OPT_LONG_HASH          "hash"
+
+#define OPT_SHORT_SEC_KEY         'K'
+#define OPT_LONG_SEC_KEY          "seckey"
+
 #define        OPT_SHORT_VERBOSE       'v'
 #define        OPT_LONG_VERBOSE        "verbose"
 
@@ -75,6 +84,8 @@ static const struct option long_opt[] = {
        {OPT_LONG_STREAMS, 1, 0, OPT_SHORT_STREAMS},
        {OPT_LONG_UDP, 0, 0, OPT_SHORT_UDP},
        {OPT_LONG_TCP, 0, 0, OPT_SHORT_TCP},
+       {OPT_LONG_HASH, 1, 0, OPT_SHORT_HASH},
+       {OPT_LONG_SEC_KEY, 1, 0, OPT_SHORT_SEC_KEY},
        {OPT_LONG_LISTEN, 0, 0, OPT_SHORT_LISTEN},
        {OPT_LONG_VERBOSE, 1, 0, OPT_SHORT_VERBOSE},
        {NULL, 0, 0, 0}
@@ -709,6 +720,17 @@ netfe_parse_cfg(const char *fname, struct netfe_lcore_prm *lp)
        return rc;
 }
 
+static uint32_t
+parse_hash_alg(const char *val)
+{
+       if (strcmp(val, "jhash") == 0)
+               return TLE_JHASH;
+       else if (strcmp(val, "siphash") == 0)
+               return TLE_SIPHASH;
+       else
+               return TLE_HASH_NUM;
+}
+
 int
 parse_app_options(int argc, char **argv, struct netbe_cfg *cfg,
        struct tle_ctx_param *ctx_prm,
@@ -722,8 +744,8 @@ parse_app_options(int argc, char **argv, struct netbe_cfg *cfg,
 
        optind = 0;
        optarg = NULL;
-       while ((opt = getopt_long(argc, argv, "aB:LPR:S:TUb:f:s:v:", long_opt,
-                       &opt_idx)) != EOF) {
+       while ((opt = getopt_long(argc, argv, "aB:LPR:S:TUb:f:s:v:H:K:",
+                       long_opt, &opt_idx)) != EOF) {
                if (opt == OPT_SHORT_ARP) {
                        cfg->arp = 1;
                } else if (opt == OPT_SHORT_SBULK) {
@@ -778,7 +800,28 @@ parse_app_options(int argc, char **argv, struct netbe_cfg *cfg,
                } else if (opt == OPT_SHORT_LISTEN) {
                        listen = 1;
                        cfg->server = 1;
-               } else {
+               } else if (opt == OPT_SHORT_HASH) {
+                       ctx_prm->hash_alg = parse_hash_alg(optarg);
+                       if (ctx_prm->hash_alg >= TLE_HASH_NUM) {
+                               rte_exit(EXIT_FAILURE,
+                                       "%s: invalid hash algorithm %s "
+                                       "for option: \'%c\'\n",
+                                       __func__, optarg, opt);
+                       }
+               } else if (opt == OPT_SHORT_SEC_KEY) {
+                       n = strlen(optarg);
+                       if (n != sizeof(ctx_prm->secret_key)) {
+                               rte_exit(EXIT_FAILURE,
+                                       "%s: invalid length %s "
+                                       "for option \'%c\' "
+                                       "must be 16 characters long\n",
+                                       __func__, optarg, opt);
+                       }
+                       memcpy(&ctx_prm->secret_key, optarg,
+                               sizeof(ctx_prm->secret_key));
+               }
+
+               else {
                        rte_exit(EXIT_FAILURE,
                                "%s: unknown option: \'%c\'\n",
                                __func__, opt);
index 7ebef9d..6eb33eb 100644 (file)
@@ -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 (file)
index 0000000..e8e21e4
--- /dev/null
@@ -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__ */
index ad70b7d..da2e166 100644 (file)
 #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;
index b525751..d4b6fdd 100644 (file)
@@ -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;
index a3516bf..144dbe7 100644 (file)
@@ -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. */
 };
 
 /**