summaryrefslogtreecommitdiffstats
path: root/src/vnet/cop/cop.h
blob: ee848ce872e45bd1be1444c13a89b24a294b0e95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __vnet_cop_h__
#define __vnet_cop_h__

#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>

#include <vppinfra/error.h>
#include <vppinfra/hash.h>
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/l2/l2_input.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/ip/ip4_packet.h>
#include <vnet/ip/ip6_packet.h>

typedef enum {
  VNET_COP_IP4,
  VNET_COP_IP6,
  VNET_COP_DEFAULT,
  VNET_N_COPS,
} vnet_cop_t;

typedef enum {
  /* First check src address against whitelist */
  IP4_RX_COP_WHITELIST,
  IP6_RX_COP_WHITELIST,
  DEFAULT_RX_COP_WHITELIST,

  /* Pkts not otherwise dropped go to xxx-input */
  IP4_RX_COP_INPUT,
  IP6_RX_COP_INPUT,
  DEFAULT_RX_COP_INPUT,

  /* Going, going, gone... */
  RX_COP_DROP,

  COP_RX_N_FEATURES,
} cop_feature_type_t;

typedef struct {
  vnet_config_main_t config_main;
  u32 * config_index_by_sw_if_index;
} cop_config_main_t;

typedef struct {
  u32 fib_index;
} cop_config_data_t;

typedef struct {
  cop_config_main_t cop_config_mains[VNET_N_COPS];

  /* convenience */
  vlib_main_t * vlib_main;
  vnet_main_t * vnet_main;
} cop_main_t;

extern cop_main_t cop_main;

extern vlib_node_registration_t cop_input_node;

int cop_interface_enable_disable (u32 sw_if_index, int enable_disable);

typedef struct {
  u32 sw_if_index;
  u8 ip4;
  u8 ip6;
  u8 default_cop;
  u32 fib_id;
} cop_whitelist_enable_disable_args_t;

int cop_whitelist_enable_disable (cop_whitelist_enable_disable_args_t *a);

#endif /* __vnet_cop_h__ */
ing.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
* Copyright (c) 2015-2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <vnet/vnet.h>
#include <vlibmemory/api.h>
#include <vnet/session/application.h>
#include <vnet/session/application_interface.h>

typedef struct
{
  /*
   * Server app parameters
   */
  unix_shared_memory_queue_t **vpp_queue;
  unix_shared_memory_queue_t *vl_input_queue;	/**< Sever's event queue */

  u32 app_index;		/**< Server app index */
  u32 my_client_index;		/**< API client handle */
  u32 node_index;		/**< process node index for evnt scheduling */

  /*
   * Config params
   */
  u8 no_echo;			/**< Don't echo traffic */
  u32 fifo_size;			/**< Fifo size */
  u32 rcv_buffer_size;		/**< Rcv buffer size */
  u32 prealloc_fifos;		/**< Preallocate fifos */
  u32 private_segment_count;	/**< Number of private segments  */
  u32 private_segment_size;	/**< Size of private segments  */
  char *server_uri;		/**< Server URI */

  /*
   * Test state
   */
  u8 **rx_buf;			/**< Per-thread RX buffer */
  u64 byte_index;
  u32 **rx_retries;

  vlib_main_t *vlib_main;
} builtin_server_main_t;

builtin_server_main_t builtin_server_main;

int
builtin_session_accept_callback (stream_session_t * s)
{
  builtin_server_main_t *bsm = &builtin_server_main;

  bsm->vpp_queue[s->thread_index] =
    session_manager_get_vpp_event_queue (s->thread_index);
  s->session_state = SESSION_STATE_READY;
  bsm->byte_index = 0;
  vec_validate (bsm->rx_retries[s->thread_index], s->session_index);
  bsm->rx_retries[s->thread_index][s->session_index] = 0;
  return 0;
}

void
builtin_session_disconnect_callback (stream_session_t * s)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  vnet_disconnect_args_t _a, *a = &_a;

  a->handle = stream_session_handle (s);
  a->app_index = bsm->app_index;
  vnet_disconnect_session (a);
}

void
builtin_session_reset_callback (stream_session_t * s)
{
  clib_warning ("Reset session %U", format_stream_session, s, 2);
  stream_session_cleanup (s);
}


int
builtin_session_connected_callback (u32 app_index, u32 api_context,
				    stream_session_t * s, u8 is_fail)
{
  clib_warning ("called...");
  return -1;
}

int
builtin_add_segment_callback (u32 client_index,
			      const u8 * seg_name, u32 seg_size)
{
  clib_warning ("called...");
  return -1;
}

int
builtin_redirect_connect_callback (u32 client_index, void *mp)
{
  clib_warning ("called...");
  return -1;
}

void
test_bytes (builtin_server_main_t * bsm, int actual_transfer)
{
  int i;
  u32 my_thread_id = vlib_get_thread_index ();

  for (i = 0; i < actual_transfer; i++)
    {
      if (bsm->rx_buf[my_thread_id][i] != ((bsm->byte_index + i) & 0xff))
	{
	  clib_warning ("at %lld expected %d got %d", bsm->byte_index + i,
			(bsm->byte_index + i) & 0xff,
			bsm->rx_buf[my_thread_id][i]);
	}
    }
  bsm->byte_index += actual_transfer;
}

/*
 * If no-echo, just read the data and be done with it
 */
int
builtin_server_rx_callback_no_echo (stream_session_t * s)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  u32 my_thread_id = vlib_get_thread_index ();
  int actual_transfer;
  svm_fifo_t *rx_fifo;

  rx_fifo = s->server_rx_fifo;

  do
    {
      actual_transfer =
	svm_fifo_dequeue_nowait (rx_fifo, bsm->rcv_buffer_size,
				 bsm->rx_buf[my_thread_id]);
    }
  while (actual_transfer > 0);
  return 0;
}

int
builtin_server_rx_callback (stream_session_t * s)
{
  u32 n_written, max_dequeue, max_enqueue, max_transfer;
  int actual_transfer;
  svm_fifo_t *tx_fifo, *rx_fifo;
  builtin_server_main_t *bsm = &builtin_server_main;
  session_fifo_event_t evt;
  static int serial_number = 0;
  u32 thread_index = vlib_get_thread_index ();

  ASSERT (s->thread_index == thread_index);

  rx_fifo = s->server_rx_fifo;
  tx_fifo = s->server_tx_fifo;

  ASSERT (rx_fifo->master_thread_index == thread_index);
  ASSERT (tx_fifo->master_thread_index == thread_index);

  max_dequeue = svm_fifo_max_dequeue (s->server_rx_fifo);
  max_enqueue = svm_fifo_max_enqueue (s->server_tx_fifo);

  if (PREDICT_FALSE (max_dequeue == 0))
    return 0;

  /* Number of bytes we're going to copy */
  max_transfer = (max_dequeue < max_enqueue) ? max_dequeue : max_enqueue;

  /* No space in tx fifo */
  if (PREDICT_FALSE (max_transfer == 0))
    {
      /* XXX timeout for session that are stuck */

    rx_event:
      /* Program self-tap to retry */
      if (svm_fifo_set_event (rx_fifo))
	{
	  unix_shared_memory_queue_t *q;
	  evt.fifo = rx_fifo;
	  evt.event_type = FIFO_EVENT_BUILTIN_RX;
	  evt.event_id = 0;

	  q = bsm->vpp_queue[thread_index];
	  if (PREDICT_FALSE (q->cursize == q->maxsize))
	    clib_warning ("out of event queue space");
	  else if (unix_shared_memory_queue_add (q, (u8 *) & evt, 0))
	    clib_warning ("failed to enqueue self-tap");

	  if (bsm->rx_retries[thread_index][s->session_index] == 500000)
	    {
	      clib_warning ("session stuck: %U", format_stream_session, s, 2);
	    }
	  if (bsm->rx_retries[thread_index][s->session_index] < 500001)
	    bsm->rx_retries[thread_index][s->session_index]++;
	}

      return 0;
    }

  _vec_len (bsm->rx_buf[thread_index]) = max_transfer;

  actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_transfer,
					     bsm->rx_buf[thread_index]);
  ASSERT (actual_transfer == max_transfer);

//  test_bytes (bsm, actual_transfer);

  /*
   * Echo back
   */

  n_written = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer,
				       bsm->rx_buf[thread_index]);

  if (n_written != max_transfer)
    clib_warning ("short trout!");

  if (svm_fifo_set_event (tx_fifo))
    {
      /* Fabricate TX event, send to vpp */
      evt.fifo = tx_fifo;
      evt.event_type = FIFO_EVENT_APP_TX;
      evt.event_id = serial_number++;

      if (unix_shared_memory_queue_add (bsm->vpp_queue[s->thread_index],
					(u8 *) & evt,
					0 /* do wait for mutex */ ))
	clib_warning ("failed to enqueue tx evt");
    }

  if (PREDICT_FALSE (n_written < max_dequeue))
    goto rx_event;

  return 0;
}

static session_cb_vft_t builtin_session_cb_vft = {
  .session_accept_callback = builtin_session_accept_callback,
  .session_disconnect_callback = builtin_session_disconnect_callback,
  .session_connected_callback = builtin_session_connected_callback,
  .add_segment_callback = builtin_add_segment_callback,
  .redirect_connect_callback = builtin_redirect_connect_callback,
  .builtin_server_rx_callback = builtin_server_rx_callback,
  .session_reset_callback = builtin_session_reset_callback
};

/* Abuse VPP's input queue */
static int
create_api_loopback (vlib_main_t * vm)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  api_main_t *am = &api_main;
  vl_shmem_hdr_t *shmem_hdr;

  shmem_hdr = am->shmem_hdr;
  bsm->vl_input_queue = shmem_hdr->vl_input_queue;
  bsm->my_client_index =
    vl_api_memclnt_create_internal ("tcp_test_server", bsm->vl_input_queue);
  return 0;
}

static int
server_attach ()
{
  builtin_server_main_t *bsm = &builtin_server_main;
  u8 segment_name[128];
  u64 options[SESSION_OPTIONS_N_OPTIONS];
  vnet_app_attach_args_t _a, *a = &_a;

  memset (a, 0, sizeof (*a));
  memset (options, 0, sizeof (options));

  if (bsm->no_echo)
    builtin_session_cb_vft.builtin_server_rx_callback =
      builtin_server_rx_callback_no_echo;
  else
    builtin_session_cb_vft.builtin_server_rx_callback =
      builtin_server_rx_callback;
  a->api_client_index = bsm->my_client_index;
  a->session_cb_vft = &builtin_session_cb_vft;
  a->options = options;
  a->options[SESSION_OPTIONS_SEGMENT_SIZE] = 512 << 20;
  a->options[SESSION_OPTIONS_RX_FIFO_SIZE] = bsm->fifo_size;
  a->options[SESSION_OPTIONS_TX_FIFO_SIZE] = bsm->fifo_size;
  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = bsm->private_segment_count;
  a->options[APP_OPTIONS_PRIVATE_SEGMENT_SIZE] = bsm->private_segment_size;
  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
    bsm->prealloc_fifos ? bsm->prealloc_fifos : 1;

  a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_BUILTIN_APP;

  a->segment_name = segment_name;
  a->segment_name_length = ARRAY_LEN (segment_name);

  if (vnet_application_attach (a))
    {
      clib_warning ("failed to attach server");
      return -1;
    }
  bsm->app_index = a->app_index;
  return 0;
}

static int
server_listen ()
{
  builtin_server_main_t *bsm = &builtin_server_main;
  vnet_bind_args_t _a, *a = &_a;
  memset (a, 0, sizeof (*a));
  a->app_index = bsm->app_index;
  a->uri = bsm->server_uri;
  return vnet_bind_uri (a);
}

static int
server_create (vlib_main_t * vm)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  vlib_thread_main_t *vtm = vlib_get_thread_main ();
  u32 num_threads;
  int i;

  if (bsm->my_client_index == (u32) ~ 0)
    {
      if (create_api_loopback (vm))
	{
	  clib_warning ("failed to create api loopback");
	  return -1;
	}
    }

  num_threads = 1 /* main thread */  + vtm->n_threads;
  vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
  vec_validate (bsm->rx_buf, num_threads - 1);
  vec_validate (bsm->rx_retries, num_threads - 1);

  for (i = 0; i < num_threads; i++)
    vec_validate (bsm->rx_buf[i], bsm->rcv_buffer_size);

  if (server_attach ())
    {
      clib_warning ("failed to attach server");
      return -1;
    }
  if (server_listen ())
    {
      clib_warning ("failed to start listening");
      return -1;
    }
  return 0;
}

static clib_error_t *
server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
			  vlib_cli_command_t * cmd)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  u8 server_uri_set = 0;
  int rv;
  u64 tmp;

  bsm->no_echo = 0;
  bsm->fifo_size = 64 << 10;
  bsm->rcv_buffer_size = 128 << 10;
  bsm->prealloc_fifos = 0;
  bsm->private_segment_count = 0;
  bsm->private_segment_size = 0;
  vec_free (bsm->server_uri);

  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "no-echo"))
	bsm->no_echo = 1;
      else if (unformat (input, "fifo-size %d", &bsm->fifo_size))
	bsm->fifo_size <<= 10;
      else if (unformat (input, "rcv-buf-size %d", &bsm->rcv_buffer_size))
	;
      else if (unformat (input, "prealloc-fifos %d", &bsm->prealloc_fifos))
	;
      else if (unformat (input, "private-segment-count %d",
			 &bsm->private_segment_count))
	;
      else if (unformat (input, "private-segment-size %U",
			 unformat_memory_size, &tmp))
	{
	  if (tmp >= 0x100000000ULL)
	    return clib_error_return
	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
	  bsm->private_segment_size = tmp;
	}
      else if (unformat (input, "uri %s", &bsm->server_uri))
	server_uri_set = 1;
      else
	return clib_error_return (0, "unknown input `%U'",
				  format_unformat_error, input);
    }

  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );

  if (!server_uri_set)
    bsm->server_uri = (char *) format (0, "tcp://0.0.0.0/1234%c", 0);

  rv = server_create (vm);
  switch (rv)
    {
    case 0:
      break;
    default:
      return clib_error_return (0, "server_create returned %d", rv);
    }

  return 0;
}

/* *INDENT-OFF* */
VLIB_CLI_COMMAND (server_create_command, static) =
{
  .path = "test tcp server",
  .short_help = "test tcp server [no echo][fifo-size <mbytes>] "
      "[rcv-buf-size <bytes>][prealloc-fifos <count>]"
      "[private-segment-count <count>][private-segment-size <bytes[m|g]>]"
      "[uri <tcp://ip/port>]",
  .function = server_create_command_fn,
};
/* *INDENT-ON* */

clib_error_t *
builtin_tcp_server_main_init (vlib_main_t * vm)
{
  builtin_server_main_t *bsm = &builtin_server_main;
  bsm->my_client_index = ~0;
  return 0;
}

VLIB_INIT_FUNCTION (builtin_tcp_server_main_init);

/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/