syncookie.h revision 7e18fa1b
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 _SYNCOOKIE_H_
17#define _SYNCOOKIE_H_
18
19#include <rte_jhash.h>
20
21#include "tcp_misc.h"
22#include <tle_ctx.h>
23#include <halfsiphash.h>
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29struct sync_in4 {
30	uint32_t seq;
31	union l4_ports port;
32	union ipv4_addrs addr;
33};
34
35static const rte_xmm_t mss4len = {
36	.u32 = {
37		TCP4_MIN_MSS, /* 536 */
38		1300,
39		TCP4_OP_MSS,  /* 1440 */
40		TCP4_NOP_MSS, /* 1460 */
41	},
42};
43
44static const rte_xmm_t mss6len = {
45	.u32 = {
46		TCP6_MIN_MSS, /* 1220 */
47		TCP6_OP_MSS,  /* 1420 */
48		TCP6_NOP_MSS, /* 1440 */
49		8940,
50	},
51};
52
53#define	SYNC_MSS_BITS	2
54#define	SYNC_MSS_MASK	((1 << SYNC_MSS_BITS) - 1)
55
56#define	SYNC_TMS_WSCALE_BITS	4
57#define	SYNC_TMS_WSCALE_MASK	((1 << SYNC_TMS_WSCALE_BITS) - 1)
58
59#define	SYNC_TMS_RESERVE_BITS	2
60
61#define	SYNC_TMS_OPT_BITS	(SYNC_TMS_WSCALE_BITS + SYNC_TMS_RESERVE_BITS)
62#define	SYNC_TMS_OPT_MASK	((1 << SYNC_TMS_OPT_BITS) - 1)
63
64/* allow around 2 minutes for 3-way handshake. */
65#define	SYNC_MAX_TMO	0x20000
66
67/* ??? use SipHash as FreeBSD does. ??? */
68static inline uint32_t
69sync_hash4(const union pkt_info *pi, uint32_t seq, rte_xmm_t *secret_key,
70		uint32_t hash_alg)
71{
72	struct sync_in4 in4;
73	rte_xmm_t state;
74	uint32_t v0, v1;
75
76	in4.seq = seq;
77	in4.port = pi->port;
78	in4.addr = pi->addr4;
79
80	if (hash_alg == TLE_JHASH) {
81		v0 = secret_key->u32[0];
82		v1 = secret_key->u32[1];
83		rte_jhash_32b_2hashes(&in4.seq, sizeof(in4) / sizeof(uint32_t),
84				&v0, &v1);
85		return v0 + v1;
86	} else {
87		state = *secret_key;
88		siphash_compression(&in4.seq, sizeof(in4) / sizeof(uint32_t),
89				&state);
90		siphash_finalization(&state);
91		return (state.u32[0] ^ state.u32[1] ^
92			state.u32[2] ^ state.u32[3]);
93	}
94}
95
96static inline uint32_t
97sync_hash6(const union pkt_info *pi, uint32_t seq, rte_xmm_t *secret_key,
98		uint32_t hash_alg)
99{
100	uint32_t port_seq[2];
101	rte_xmm_t state;
102	uint32_t v0, v1;
103
104	if (hash_alg == TLE_JHASH) {
105		v0 = secret_key->u32[0];
106		v1 = secret_key->u32[1];
107		rte_jhash_32b_2hashes(pi->addr6->raw.u32,
108				sizeof(*pi->addr6) / sizeof(uint32_t),
109				&v0, &v1);
110		return rte_jhash_3words(v0, seq, pi->port.raw, v1);
111	} else {
112		state = *secret_key;
113		siphash_compression(pi->addr6->raw.u32,
114				sizeof(*pi->addr6) / sizeof(uint32_t), &state);
115		port_seq[0] = pi->port.raw;
116		port_seq[1] = seq;
117		siphash_compression(port_seq, RTE_DIM(port_seq), &state);
118		siphash_finalization(&state);
119		return (state.u32[0] ^ state.u32[1] ^
120			state.u32[2] ^ state.u32[3]);
121	}
122}
123
124static inline uint32_t
125sync_mss2idx(uint16_t mss, const rte_xmm_t *msl)
126{
127	if (mss >= msl->u32[2])
128		return (mss >= msl->u32[3]) ? 3 : 2;
129	else
130		return (mss >= msl->u32[1]) ? 1 : 0;
131}
132
133static inline uint32_t
134sync_gen_seq(const union pkt_info *pi, uint32_t seq, uint32_t ts, uint16_t mss,
135		uint32_t hash_alg, rte_xmm_t *secret_key)
136{
137	uint32_t h, mi;
138
139	if (pi->tf.type == TLE_V4) {
140		h = sync_hash4(pi, seq, secret_key, hash_alg);
141		mi = sync_mss2idx(mss, &mss4len);
142	} else {
143		h = sync_hash6(pi, seq, secret_key, hash_alg);
144		mi = sync_mss2idx(mss, &mss6len);
145	}
146
147	h += (ts & ~SYNC_MSS_MASK) | mi;
148	return h;
149}
150
151static inline uint32_t
152sync_gen_ts(uint32_t ts, uint32_t wscale)
153{
154	ts = (ts - (SYNC_TMS_OPT_MASK + 1)) & ~SYNC_TMS_OPT_MASK;
155	ts |= wscale;
156	return ts;
157}
158
159static inline int
160sync_check_ack(const union pkt_info *pi, uint32_t seq, uint32_t ack,
161	uint32_t ts, uint32_t hash_alg, rte_xmm_t *secret_key)
162{
163	uint32_t h, mi, pts;
164
165	if (pi->tf.type == TLE_V4)
166		h = sync_hash4(pi, seq, secret_key, hash_alg);
167	else
168		h = sync_hash6(pi, seq, secret_key, hash_alg);
169
170	h = ack - h;
171	pts = h & ~SYNC_MSS_MASK;
172	mi = h & SYNC_MSS_MASK;
173
174	if (ts - pts > SYNC_MAX_TMO)
175		return -ERANGE;
176
177	return (pi->tf.type == TLE_V4) ? mss4len.u32[mi] : mss6len.u32[mi];
178}
179
180static inline void
181sync_fill_tcb(struct tcb *tcb, const union seg_info *si, const union tsopt *to)
182{
183	uint32_t ack, mss, seq, wscale;
184
185	seq = si->seq;
186
187	tcb->rcv.nxt = seq;
188	tcb->rcv.irs = seq - 1;
189	tcb->snd.wu.wl1 = seq;
190
191	ack = si->ack;
192
193	tcb->snd.nxt = ack;
194	tcb->snd.una = ack;
195	tcb->snd.iss = ack - 1;
196	tcb->snd.rcvr = ack - 1;
197	tcb->snd.wu.wl2 = ack;
198
199	mss = si->mss;
200
201	tcb->snd.mss = mss;
202	tcb->so.mss = mss;
203
204	tcb->snd.ts = to->ecr;
205	tcb->rcv.ts = to->val;
206	tcb->so.ts.raw = to->raw;
207
208	wscale = to->ecr & SYNC_TMS_WSCALE_MASK;
209
210	tcb->snd.wscale = wscale;
211	tcb->snd.wnd = si->wnd << wscale;
212	tcb->so.wscale = wscale;
213
214	tcb->rcv.wscale = (wscale == TCP_WSCALE_NONE) ?
215		TCP_WSCALE_NONE : TCP_WSCALE_DEFAULT;
216}
217
218#ifdef __cplusplus
219}
220#endif
221
222#endif /* _STREAM_TABLE_H_ */
223