TAS
TCP Acceleration as an OS Service
tcp_common.h
1 /*
2  * Copyright 2019 University of Washington, Max Planck Institute for
3  * Software Systems, and The University of Texas at Austin
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #ifndef TCP_COMMON_H_
26 #define TCP_COMMON_H_
27 
28 #include <tas_memif.h>
29 #include <utils.h>
30 
31 #define ALLOW_FUTURE_ACKS 1
32 
47 static inline int tcp_valid_rxseq(struct flextcp_pl_flowst *fs,
48  uint32_t pkt_seq, uint16_t pkt_bytes, uint16_t *trim_start,
49  uint16_t *trim_end)
50 {
51  uint32_t pseq_a = pkt_seq, pseq_b = pkt_seq + pkt_bytes;
52  uint32_t sseq_a = fs->rx_next_seq, sseq_b = fs->rx_next_seq + fs->rx_avail;
53 
54  if (pseq_a <= pseq_b && sseq_a <= sseq_b) {
55  /* neither packet interval nor receive buffer split */
56 
57  /* packet ends before start of receive buffer */
58  if (pseq_b < sseq_a)
59  return -1;
60 
61  /* packet starts after beginning of receive buffer */
62  if (pseq_a > sseq_a)
63  return -1;
64 
65  *trim_start = sseq_a - pseq_a;
66  *trim_end = (pseq_b > sseq_b ? pseq_b - sseq_b : 0);
67  } else if (pseq_a <= pseq_b && sseq_a > sseq_b) {
68  /* packet interval not split, but receive buffer split */
69 
70  /* packet ends before start of receive buffer */
71  if (pseq_a >= sseq_b && pseq_b < sseq_a)
72  return -1;
73 
74  /* packet starts after beginning of receive buffer */
75  if (pseq_a > sseq_a || pseq_a < sseq_b)
76  return -1;
77 
78  *trim_start = sseq_a - pseq_a;
79  *trim_end = 0;
80  } else if (pseq_a > pseq_b && sseq_a <= sseq_b) {
81  /* packet interval split, receive buffer not split */
82 
83  /* packet ends before start of receive buffer */
84  if (pseq_b < sseq_a)
85  return -1;
86 
87  /* packet starts after beginning of receive buffer */
88  if (pseq_a > sseq_a)
89  return -1;
90 
91  *trim_start = sseq_a - pseq_a;
92  *trim_end = (pseq_b > sseq_b ? pseq_b - sseq_b : 0);
93  } else {
94  /* both intervals split
95  * Note this means that there is at least some overlap. */
96 
97  /* packet starts after beginning of receive buffer */
98  if (pseq_a > sseq_a)
99  return -1;
100 
101  *trim_start = sseq_a - pseq_a;
102  *trim_end = (pseq_b > sseq_b ? pseq_b - sseq_b : 0);
103  }
104 
105  return 0;
106 }
107 
122 static inline int tcp_trim_rxbuf(struct flextcp_pl_flowst *fs,
123  uint32_t pkt_seq, uint16_t pkt_bytes, uint16_t *trim_start,
124  uint16_t *trim_end)
125 {
126  uint32_t pseq_a = pkt_seq, pseq_b = pkt_seq + pkt_bytes;
127  uint32_t sseq_a = fs->rx_next_seq, sseq_b = fs->rx_next_seq + fs->rx_avail;
128 
129  if (pseq_a <= pseq_b && sseq_a <= sseq_b) {
130  /* neither packet interval nor receive buffer split */
131 
132  /* packet ends before start of receive buffer */
133  if (pseq_b < sseq_a)
134  return -1;
135 
136  /* packet starts after end of receive buffer */
137  if (pseq_a > sseq_b)
138  return -1;
139 
140  *trim_start = (pseq_a < sseq_a ? sseq_a - pseq_a : 0);
141  *trim_end = (pseq_b > sseq_b ? pseq_b - sseq_b : 0);
142  } else if (pseq_a <= pseq_b && sseq_a > sseq_b) {
143  /* packet interval not split, but receive buffer split */
144 
145  /* packet ends before start of receive buffer */
146  if (pseq_a > sseq_b && pseq_b < sseq_a)
147  return -1;
148 
149  *trim_start = (pseq_a > sseq_b && pseq_a < sseq_a ? sseq_a - pseq_a : 0);
150  *trim_end = (pseq_b >= sseq_b && pseq_b < sseq_a ? pseq_b - sseq_b : 0);
151  } else if (pseq_a > pseq_b && sseq_a <= sseq_b) {
152  /* packet interval split, receive buffer not split */
153 
154  /* packet ends before start of receive buffer */
155  if (pseq_a > sseq_b && pseq_b < sseq_a)
156  return -1;
157 
158  *trim_start = (sseq_a <= pseq_b || sseq_a > pseq_a ? sseq_a - pseq_a : 0);
159  *trim_end = (pseq_b > sseq_b || sseq_a >= pseq_a ? pseq_b - sseq_b : 0);
160  } else {
161  /* both intervals split
162  * Note this means that there is at least some overlap. */
163  *trim_start = (pseq_a < sseq_a ? sseq_a - pseq_a: 0);
164  *trim_end = (pseq_b > sseq_b ? pseq_b - sseq_b : 0);
165  }
166 
167  return 0;
168 }
169 
180 static inline int tcp_valid_rxack(struct flextcp_pl_flowst *fs, uint32_t ack,
181  uint32_t *bump)
182 {
183  uint32_t fsack_a = fs->tx_next_seq - fs->tx_sent, fsack_b = fs->tx_next_seq;
184 
185 #ifdef ALLOW_FUTURE_ACKS
186  /* number of available unsent bytes in send buffer */
187  fsack_b += fs->tx_avail;
188 #endif
189 
190  if (fsack_a <= fsack_b) {
191  if (ack < fsack_a || ack > fsack_b)
192  return -1;
193 
194  *bump = ack - fsack_a;
195  return 0;
196  } else {
197  if (fsack_a > ack && ack > fsack_b)
198  return -1;
199 
200  *bump = ack - fsack_a;
201  return 0;
202  }
203 }
204 
214 static inline uint32_t tcp_txavail(const struct flextcp_pl_flowst *fs,
215  const uint32_t *pavail)
216 {
217  uint32_t buf_avail, fc_avail;
218 
219  buf_avail = (pavail != NULL ? *pavail : fs->tx_avail);
220 
221  /* flow control window */
222  fc_avail = fs->rx_remote_avail - fs->tx_sent;
223 
224  return MIN(buf_avail, fc_avail);
225 }
226 
228 struct tcp_opts {
231 };
232 
243 static inline int tcp_parse_options(const struct pkt_tcp *p, uint16_t len,
244  struct tcp_opts *opts)
245 {
246  uint8_t *opt = (uint8_t *) (p + 1);
247  uint16_t opts_len = TCPH_HDRLEN(&p->tcp) * 4 - 20;
248  uint16_t off = 0;
249  uint8_t opt_kind, opt_len, opt_avail;
250 
251  opts->ts = NULL;
252 
253  /* whole header not in buf */
254  if (TCPH_HDRLEN(&p->tcp) < 5 || opts_len > (len - sizeof(*p))) {
255  fprintf(stderr, "hlen=%u opts_len=%u len=%u so=%zu\n", TCPH_HDRLEN(&p->tcp), opts_len, len, sizeof(*p));
256  return -1;
257  }
258 
259  while (off < opts_len) {
260  opt_kind = opt[off];
261  opt_avail = opts_len - off;
262  if (opt_kind == TCP_OPT_END_OF_OPTIONS) {
263  /* end of options list option */
264  break;
265  } else if (opt_kind == TCP_OPT_NO_OP) {
266  /* no-op, ignore */
267  opt_len = 1;
268  } else {
269  /* variable length option */
270  if (opt_avail < 2) {
271  fprintf(stderr, "parse_options: opt_avail=%u kind=%u off=%u\n", opt_avail, opt_kind, off);
272  return -1;
273  }
274 
275  opt_len = opt[off + 1];
276  if (opt_kind == TCP_OPT_TIMESTAMP) {
277  if (opt_len != sizeof(struct tcp_timestamp_opt)) {
278  fprintf(stderr, "parse_options: opt_len=%u so=%zu\n", opt_len, sizeof(struct tcp_timestamp_opt));
279  return -1;
280  }
281 
282  opts->ts = (struct tcp_timestamp_opt *) (opt + off);
283  }
284  }
285  off += opt_len;
286  }
287 
288  return 0;
289 }
290 
291 #endif /* ndef TCP_COMMON_H_ */
uint32_t tx_next_seq
Definition: tas_memif.h:300
uint32_t tx_avail
Definition: tas_memif.h:293
uint32_t rx_remote_avail
Definition: tas_memif.h:281
struct tcp_timestamp_opt * ts
Definition: tcp_common.h:230
uint32_t rx_next_seq
Definition: tas_memif.h:279
uint32_t rx_avail
Definition: tas_memif.h:274
uint32_t tx_sent
Definition: tas_memif.h:296