TAS
TCP Acceleration as an OS Service
appif_ctx.c
Go to the documentation of this file.
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 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 
34 #include <tas.h>
35 #include "internal.h"
36 #include "appif.h"
37 
38 static int kin_conn_open(struct application *app, struct app_context *ctx,
39  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
40 static int kin_conn_move(struct application *app, struct app_context *ctx,
41  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
42 static int kin_conn_close(struct application *app, struct app_context *ctx,
43  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
44 static int kin_listen_open(struct application *app, struct app_context *ctx,
45  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
46 static int kin_accept_conn(struct application *app, struct app_context *ctx,
47  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
48 static int kin_req_scale(struct application *app, struct app_context *ctx,
49  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout);
50 
51 static void appif_ctx_kick(struct app_context *ctx)
52 {
53  assert(ctx->evfd != 0);
54  notify_app_core(ctx->evfd, &ctx->last_ts);
55 }
56 
57 void appif_conn_opened(struct connection *c, int status)
58 {
59  struct app_context *ctx = c->ctx;
60  volatile struct kernel_appin *kout = ctx->kout_base;
61  uint32_t kout_pos = ctx->kout_pos;
62 
63  kout += kout_pos;
64 
65  /* make sure we have room for a response */
66  if (kout->type != KERNEL_APPIN_INVALID) {
67  fprintf(stderr, "appif_conn_opened: No space in kout queue (TODO)\n");
68  return;
69  }
70 
71  kout->data.conn_opened.opaque = c->opaque;
72  kout->data.conn_opened.status = status;
73  if (status == 0) {
74  kout->data.conn_opened.rx_off = c->rx_buf - (uint8_t *) tas_shm;
75  kout->data.conn_opened.tx_off = c->tx_buf - (uint8_t *) tas_shm;
76  kout->data.conn_opened.rx_len = c->rx_len;
77  kout->data.conn_opened.tx_len = c->tx_len;
78 
79  kout->data.conn_opened.seq_rx = c->remote_seq;
80  kout->data.conn_opened.seq_tx = c->local_seq;
81  kout->data.conn_opened.local_ip = config.ip;
82  kout->data.conn_opened.local_port = c->local_port;
83  kout->data.conn_opened.flow_id = c->flow_id;
84  kout->data.conn_opened.fn_core = c->fn_core;
85  } else {
86  tcp_destroy(c);
87  }
88 
89  MEM_BARRIER();
90  kout->type = KERNEL_APPIN_CONN_OPENED;
91  appif_ctx_kick(ctx);
92 
93  kout_pos++;
94  if (kout_pos >= ctx->kout_len) {
95  kout_pos = 0;
96  }
97  ctx->kout_pos = kout_pos;
98 }
99 
100 void appif_conn_closed(struct connection *c, int status)
101 {
102  struct app_context *ctx = c->ctx;
103  struct application *app = ctx->app;
104  struct connection *c_i;
105  volatile struct kernel_appin *kout = ctx->kout_base;
106  uint32_t kout_pos = ctx->kout_pos;
107 
108  kout += kout_pos;
109 
110  /* make sure we have room for a response */
111  if (kout->type != KERNEL_APPIN_INVALID) {
112  fprintf(stderr, "appif_conn_closed: No space in kout queue (TODO)\n");
113  return;
114  }
115 
116  kout->data.status.opaque = c->opaque;
117  kout->data.status.status = status;
118 
119  MEM_BARRIER();
120  kout->type = KERNEL_APPIN_STATUS_CONN_CLOSE;
121  appif_ctx_kick(ctx);
122 
123  kout_pos++;
124  if (kout_pos >= ctx->kout_len) {
125  kout_pos = 0;
126  }
127  ctx->kout_pos = kout_pos;
128 
129  /* remove from app connection list */
130  if (app->conns == c) {
131  app->conns = c->app_next;
132  } else {
133  for (c_i = app->conns; c_i != NULL && c_i->app_next != c;
134  c_i = c_i->app_next);
135  if (c_i == NULL) {
136  fprintf(stderr, "appif_conn_closed: connection not found\n");
137  abort();
138  }
139  c_i->app_next = c->app_next;
140  }
141 }
142 
143 void appif_listen_newconn(struct listener *l, uint32_t remote_ip,
144  uint16_t remote_port)
145 {
146  struct app_context *ctx = l->ctx;
147  volatile struct kernel_appin *kout = ctx->kout_base;
148  uint32_t kout_pos = ctx->kout_pos;
149 
150  kout += kout_pos;
151 
152  /* make sure we have room for a response */
153  if (kout->type != KERNEL_APPIN_INVALID) {
154  fprintf(stderr, "appif_listen_newconn: No space in kout queue (TODO)\n");
155  return;
156  }
157 
158  kout->data.listen_newconn.opaque = l->opaque;
159  kout->data.listen_newconn.remote_ip = remote_ip;
160  kout->data.listen_newconn.remote_port = remote_port;
161  MEM_BARRIER();
162  kout->type = KERNEL_APPIN_LISTEN_NEWCONN;
163  appif_ctx_kick(ctx);
164 
165  kout_pos++;
166  if (kout_pos >= ctx->kout_len) {
167  kout_pos = 0;
168  }
169  ctx->kout_pos = kout_pos;
170 
171 }
172 
173 void appif_accept_conn(struct connection *c, int status)
174 {
175  struct app_context *ctx = c->ctx;
176  struct application *app = ctx->app;
177  volatile struct kernel_appin *kout = ctx->kout_base;
178  uint32_t kout_pos = ctx->kout_pos;
179 
180  kout += kout_pos;
181 
182  /* make sure we have room for a response */
183  if (kout->type != KERNEL_APPIN_INVALID) {
184  fprintf(stderr, "appif_accept_conn: No space in kout queue (TODO)\n");
185  return;
186  }
187 
188  kout->data.accept_connection.opaque = c->opaque;
189  kout->data.accept_connection.status = status;
190  if (status == 0) {
191  kout->data.accept_connection.rx_off = c->rx_buf - (uint8_t *) tas_shm;
192  kout->data.accept_connection.tx_off = c->tx_buf - (uint8_t *) tas_shm;
193  kout->data.accept_connection.rx_len = c->rx_len;
194  kout->data.accept_connection.tx_len = c->tx_len;
195 
196  kout->data.accept_connection.seq_rx = c->remote_seq;
197  kout->data.accept_connection.seq_tx = c->local_seq;
198  kout->data.accept_connection.local_ip = config.ip;
199  kout->data.accept_connection.remote_ip = c->remote_ip;
200  kout->data.accept_connection.remote_port = c->remote_port;
201  kout->data.accept_connection.flow_id = c->flow_id;
202  kout->data.accept_connection.fn_core = c->fn_core;
203 
204  c->app_next = app->conns;
205  app->conns = c;
206  } else {
207  tcp_destroy(c);
208  }
209 
210  MEM_BARRIER();
211  kout->type = KERNEL_APPIN_ACCEPTED_CONN;
212  appif_ctx_kick(ctx);
213 
214  kout_pos++;
215  if (kout_pos >= ctx->kout_len) {
216  kout_pos = 0;
217  }
218  ctx->kout_pos = kout_pos;
219 }
220 
221 
222 unsigned appif_ctx_poll(struct application *app, struct app_context *ctx)
223 {
224  volatile struct kernel_appout *kin = ctx->kin_base;
225  volatile struct kernel_appin *kout = ctx->kout_base;
226  uint32_t kin_pos = ctx->kin_pos;
227  uint32_t kout_pos = ctx->kout_pos;
228  uint8_t type;
229  int kout_inc = 0;
230 
231  kin += kin_pos;
232  kout += kout_pos;
233 
234  /* make sure we have room for a response */
235  if (kout->type != KERNEL_APPIN_INVALID) {
236  return 0;
237  }
238 
239  type = kin->type;
240  MEM_BARRIER();
241 
242  switch (type) {
243  case KERNEL_APPOUT_INVALID:
244  /* nothing yet */
245  return 0;
246 
247  case KERNEL_APPOUT_CONN_OPEN:
248  /* connection request */
249  kout_inc += kin_conn_open(app, ctx, kin, kout);
250  break;
251 
252  case KERNEL_APPOUT_CONN_MOVE:
253  /* connection move request */
254  kout_inc += kin_conn_move(app, ctx, kin, kout);
255  break;
256 
257  case KERNEL_APPOUT_CONN_CLOSE:
258  /* connection close request */
259  kout_inc += kin_conn_close(app, ctx, kin, kout);
260  break;
261 
262  case KERNEL_APPOUT_LISTEN_OPEN:
263  /* listen request */
264  kout_inc += kin_listen_open(app, ctx, kin, kout);
265  break;
266 
267  case KERNEL_APPOUT_ACCEPT_CONN:
268  /* accept request */
269  kout_inc += kin_accept_conn(app, ctx, kin, kout);
270  break;
271 
272  case KERNEL_APPOUT_REQ_SCALE:
273  /* scaling request */
274  kout_inc += kin_req_scale(app, ctx, kin, kout);
275  break;
276 
277  case KERNEL_APPOUT_LISTEN_CLOSE:
278  default:
279  fprintf(stderr, "kin_poll: unsupported request type %u\n", kin->type);
280  break;
281  }
282 
283  MEM_BARRIER();
284  kin->type = 0;
285 
286  /* update kin queue position */
287  kin_pos++;
288  if (kin_pos >= ctx->kin_len) {
289  kin_pos = 0;
290  }
291  ctx->kin_pos = kin_pos;
292 
293  /* update kout queue position if the entry was used */
294  if (kout_inc > 0) {
295  kout_pos += kout_inc;
296  if (kout_pos >= ctx->kout_len) {
297  kout_pos = 0;
298  }
299  ctx->kout_pos = kout_pos;
300  }
301 
302  return 1;
303 }
304 
305 static int kin_conn_open(struct application *app, struct app_context *ctx,
306  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
307 {
308  struct connection *conn;
309 
310  if (tcp_open(ctx, kin->data.conn_open.opaque, kin->data.conn_open.remote_ip,
311  kin->data.conn_open.remote_port, ctx->doorbell->id, &conn) != 0)
312  {
313  fprintf(stderr, "kin_conn_open: tcp_open failed\n");
314  goto error;
315  }
316 
317  conn->app_next = app->conns;
318  app->conns = conn;
319 
320  return 0;
321 
322 error:
323  kout->data.conn_opened.opaque = kin->data.conn_open.opaque;
324  kout->data.conn_opened.status = -1;
325  MEM_BARRIER();
326  kout->type = KERNEL_APPIN_CONN_OPENED;
327  appif_ctx_kick(ctx);
328  return 1;
329 }
330 
331 static int kin_conn_move(struct application *app, struct app_context *ctx,
332  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
333 {
334  struct connection *conn;
335  struct app_context *new_ctx;
336 
337  for (conn = app->conns; conn != NULL; conn = conn->app_next) {
338  if (conn->local_ip == kin->data.conn_move.local_ip &&
339  conn->remote_ip == kin->data.conn_move.remote_ip &&
340  conn->local_port == kin->data.conn_move.local_port &&
341  conn->remote_port == kin->data.conn_move.remote_port &&
342  conn->opaque == kin->data.conn_move.opaque)
343  {
344  break;
345  }
346  }
347  if (conn == NULL) {
348  fprintf(stderr, "kin_conn_move: connection not found\n");
349  goto error;
350  }
351 
352  for (new_ctx = app->contexts; new_ctx != NULL; new_ctx = new_ctx->next) {
353  if (new_ctx->doorbell->id == kin->data.conn_move.db_id) {
354  break;
355  }
356  }
357  if (new_ctx == NULL) {
358  fprintf(stderr, "kin_conn_move: destination context not found\n");
359  goto error;
360  }
361 
362  if (conn->status != CONN_OPEN) {
363  fprintf(stderr, "kin_conn_move: connection not open\n");
364  goto error;
365  }
366 
367  if (nicif_connection_move(new_ctx->doorbell->id, conn->flow_id) != 0) {
368  fprintf(stderr, "kin_conn_move: nicif_connection_move failed\n");
369  goto error;
370  }
371 
372  kout->data.status.opaque = kin->data.conn_move.opaque;
373  kout->data.status.status = 0;
374  MEM_BARRIER();
375  kout->type = KERNEL_APPIN_STATUS_CONN_MOVE;
376  appif_ctx_kick(ctx);
377  return 1;
378 
379 error:
380  kout->data.status.opaque = kin->data.conn_move.opaque;
381  kout->data.status.status = -1;
382  MEM_BARRIER();
383  kout->type = KERNEL_APPIN_STATUS_CONN_MOVE;
384  appif_ctx_kick(ctx);
385  return 1;
386 }
387 
388 static int kin_conn_close(struct application *app, struct app_context *ctx,
389  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
390 {
391  struct connection *conn;
392 
393  for (conn = app->conns; conn != NULL; conn = conn->app_next) {
394  if (conn->local_ip == kin->data.conn_close.local_ip &&
395  conn->remote_ip == kin->data.conn_close.remote_ip &&
396  conn->local_port == kin->data.conn_close.local_port &&
397  conn->remote_port == kin->data.conn_close.remote_port &&
398  conn->opaque == kin->data.conn_close.opaque)
399  {
400  break;
401  }
402  }
403  if (conn == NULL) {
404  fprintf(stderr, "kin_conn_close: connection not found\n");
405  goto error;
406  }
407 
408  if (tcp_close(conn) != 0) {
409  fprintf(stderr, "kin_conn_close: tcp_close failed\n");
410  goto error;
411  }
412 
413  return 0;
414 
415 error:
416  kout->data.status.opaque = kin->data.conn_close.opaque;
417  kout->data.status.status = -1;
418  MEM_BARRIER();
419  kout->type = KERNEL_APPIN_STATUS_CONN_CLOSE;
420  appif_ctx_kick(ctx);
421  return 1;
422 }
423 
424 static int kin_listen_open(struct application *app, struct app_context *ctx,
425  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
426 {
427  struct listener *listen;
428 
429  if (tcp_listen(ctx, kin->data.listen_open.opaque,
430  kin->data.listen_open.local_port, kin->data.listen_open.backlog,
431  !!(kin->data.listen_open.flags & KERNEL_APPOUT_LISTEN_REUSEPORT),
432  &listen) != 0)
433  {
434  fprintf(stderr, "kin_listen_open: tcp_listen failed\n");
435  goto error;
436  }
437 
438  listen->app_next = app->listeners;
439  app->listeners = listen;
440 
441  kout->data.status.opaque = kin->data.listen_open.opaque;
442  kout->data.status.status = 0;
443  MEM_BARRIER();
444  kout->type = KERNEL_APPIN_STATUS_LISTEN_OPEN;
445  appif_ctx_kick(ctx);
446 
447  return 1;
448 
449 error:
450  kout->data.status.opaque = kin->data.listen_open.opaque;
451  kout->data.status.status = -1;
452  MEM_BARRIER();
453  kout->type = KERNEL_APPIN_STATUS_LISTEN_OPEN;
454  appif_ctx_kick(ctx);
455  return 1;
456 }
457 
458 static int kin_accept_conn(struct application *app, struct app_context *ctx,
459  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
460 {
461  struct listener *listen;
462 
463  /* look for listen struct */
464  for (listen = app->listeners; listen != NULL; listen = listen->app_next) {
465  if (listen->port == kin->data.accept_conn.local_port &&
466  listen->opaque == kin->data.accept_conn.listen_opaque)
467  {
468  break;
469  }
470  }
471 
472  if (tcp_accept(ctx, kin->data.accept_conn.conn_opaque, listen,
473  ctx->doorbell->id) != 0)
474  {
475  fprintf(stderr, "kin_accept_conn\n");
476  goto error;
477  }
478 
479  return 0;
480 
481 error:
482  kout->data.accept_connection.opaque = kin->data.accept_conn.conn_opaque;
483  kout->data.accept_connection.status = -1;
484  MEM_BARRIER();
485  kout->type = KERNEL_APPIN_ACCEPTED_CONN;
486  appif_ctx_kick(ctx);
487  return 1;
488 }
489 
490 extern int flexnic_scale_to(uint32_t cores);
491 
492 static int kin_req_scale(struct application *app, struct app_context *ctx,
493  volatile struct kernel_appout *kin, volatile struct kernel_appin *kout)
494 {
495  uint32_t num_cores = kin->data.req_scale.num_cores;
496 
497  flexnic_scale_to(num_cores);
498 
499  return 0;
500 }
void tcp_destroy(struct connection *conn)
Definition: tcp.c:428
void appif_conn_closed(struct connection *c, int status)
Definition: appif_ctx.c:100
uint16_t local_port
Definition: internal.h:464
uint32_t fn_core
Definition: internal.h:540
uint16_t remote_port
Definition: internal.h:462
uint32_t local_ip
Definition: internal.h:460
struct app_context * ctx
Definition: internal.h:424
uint32_t flow_id
Definition: internal.h:538
int tcp_listen(struct app_context *ctx, uint64_t opaque, uint16_t local_port, uint32_t backlog, int reuseport, struct listener **listen)
Definition: tcp.c:211
struct listener * app_next
Definition: internal.h:558
int nicif_connection_move(uint32_t dst_db, uint32_t f_id)
Definition: nicif.c:278
enum connection_status status
Definition: internal.h:472
uint32_t remote_ip
Definition: internal.h:458
void appif_listen_newconn(struct listener *l, uint32_t remote_ip, uint16_t remote_port)
Definition: appif_ctx.c:143
uint32_t local_seq
Definition: internal.h:476
uint8_t * tx_buf
Definition: internal.h:444
int tcp_accept(struct app_context *ctx, uint64_t opaque, struct listener *listen, uint32_t db_id)
Definition: tcp.c:322
uint32_t rx_len
Definition: internal.h:446
struct app_context * ctx
Definition: internal.h:556
int tcp_open(struct app_context *ctx, uint64_t opaque, uint32_t remote_ip, uint16_t remote_port, uint32_t db_id, struct connection **conn)
Definition: tcp.c:147
uint64_t opaque
Definition: internal.h:422
uint64_t opaque
Definition: internal.h:554
uint16_t port
Definition: internal.h:584
int tcp_close(struct connection *conn)
Definition: tcp.c:392
void appif_conn_opened(struct connection *c, int status)
Definition: appif_ctx.c:57
uint32_t tx_len
Definition: internal.h:448
void appif_accept_conn(struct connection *c, int status)
Definition: appif_ctx.c:173
uint32_t ip
Definition: config.h:67
uint32_t remote_seq
Definition: internal.h:474
struct connection * app_next
Definition: internal.h:428
uint8_t * rx_buf
Definition: internal.h:442
unsigned appif_ctx_poll(struct application *app, struct app_context *ctx)
Definition: appif_ctx.c:222