memif: complete refactor of socket handling code

Change-Id: I4d41def83a23f13701f1ddcea722d481e4c85cbc
Signed-off-by: Damjan Marion <damarion@cisco.com>
This commit is contained in:
Damjan Marion
2017-06-05 15:37:58 +02:00
committed by Damjan Marion
parent b32fde58fd
commit d51a1f6ffe
11 changed files with 1822 additions and 1172 deletions

View File

@ -19,6 +19,7 @@ memif_plugin_la_SOURCES = memif/memif.c \
memif/cli.c \
memif/node.c \
memif/device.c \
memif/socket.c \
memif/memif_plugin.api.h
memif_test_plugin_la_SOURCES = \

View File

@ -24,20 +24,7 @@
#include <vnet/ethernet/ethernet.h>
#include <memif/memif.h>
static uword
unformat_memif_queues (unformat_input_t * input, va_list * args)
{
u32 *rx_queues = va_arg (*args, u32 *);
u32 *tx_queues = va_arg (*args, u32 *);
if (unformat (input, "rx-queues %u", rx_queues))
;
if (unformat (input, "tx-queues %u", tx_queues))
;
return 1;
}
#include <memif/private.h>
static clib_error_t *
memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
@ -57,18 +44,23 @@ memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "key 0x%" PRIx64, &args.key))
if (unformat (line_input, "id %u", &args.id))
;
else if (unformat (line_input, "socket %s", &args.socket_filename))
;
else if (unformat (line_input, "secret %s", &args.secret))
;
else if (unformat (line_input, "ring-size %u", &ring_size))
;
else if (unformat (line_input, "rx-queues %u", &rx_queues))
;
else if (unformat (line_input, "tx-queues %u", &tx_queues))
;
else if (unformat (line_input, "buffer-size %u", &args.buffer_size))
;
else if (unformat (line_input, "master"))
args.is_master = 1;
else if (unformat (line_input, "slave %U",
unformat_memif_queues, &rx_queues, &tx_queues))
else if (unformat (line_input, "slave"))
args.is_master = 0;
else if (unformat (line_input, "hw-addr %U",
unformat_ethernet_address, args.hw_addr))
@ -94,6 +86,9 @@ memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
r = memif_create_if (vm, &args);
vec_free (args.socket_filename);
vec_free (args.secret);
if (r <= VNET_API_ERROR_SYSCALL_ERROR_1
&& r >= VNET_API_ERROR_SYSCALL_ERROR_10)
return clib_error_return (0, "%s (errno %d)", strerror (errno), errno);
@ -102,7 +97,7 @@ memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
return clib_error_return (0, "Invalid interface name");
if (r == VNET_API_ERROR_SUBIF_ALREADY_EXISTS)
return clib_error_return (0, "Interface already exists");
return clib_error_return (0, "Interface with same id already exists");
return 0;
}
@ -110,9 +105,9 @@ memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (memif_create_command, static) = {
.path = "create memif",
.short_help = "create memif [key <key>] [socket <path>] "
.short_help = "create memif [id <id>] [socket <path>] "
"[ring-size <size>] [buffer-size <size>] [hw-addr <mac-address>] "
"<master|slave [rx-queues <number>] [tx-queues <number>]>",
"<master|slave> [rx-queues <number>] [tx-queues <number>]",
.function = memif_create_command_fn,
};
/* *INDENT-ON* */
@ -122,8 +117,11 @@ memif_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
u64 key = 0;
u8 key_defined = 0;
u32 sw_if_index = ~0;
vnet_hw_interface_t *hw;
memif_main_t *mm = &memif_main;
memif_if_t *mif;
vnet_main_t *vnm = vnet_get_main ();
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
@ -131,18 +129,27 @@ memif_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "key 0x%" PRIx64, &key))
key_defined = 1;
if (unformat (line_input, "sw_if_index %d", &sw_if_index))
;
else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
vnm, &sw_if_index))
;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
unformat_free (line_input);
if (!key_defined)
return clib_error_return (0, "missing key");
if (sw_if_index == ~0)
return clib_error_return (0,
"please specify interface name or sw_if_index");
memif_delete_if (vm, key);
hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
if (hw == NULL || memif_device_class.index != hw->dev_class_index)
return clib_error_return (0, "not a memif interface");
mif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
memif_delete_if (vm, mif);
return 0;
}
@ -150,11 +157,59 @@ memif_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (memif_delete_command, static) = {
.path = "delete memif",
.short_help = "delete memif key <key-value>",
.short_help = "delete memif {<interface> | sw_if_index <sw_idx>}",
.function = memif_delete_command_fn,
};
/* *INDENT-ON* */
static u8 *
format_memif_if_flags (u8 * s, va_list * args)
{
u32 flags = va_arg (*args, u32);
#define _(a,b,c) if ( flags & (1 << a)) s = format (s, " %s", c);
foreach_memif_if_flag
#undef _
return s;
}
static u8 *
format_memif_if_mode (u8 * s, va_list * args)
{
memif_if_t *mif = va_arg (*args, memif_if_t *);
if (mif->mode == MEMIF_INTERFACE_MODE_ETHERNET)
return format (s, "ethernet");
if (mif->mode == MEMIF_INTERFACE_MODE_IP)
return format (s, "ip");
if (mif->mode == MEMIF_INTERFACE_MODE_PUNT_INJECT)
return format (s, "punt-inject");
return format (s, "unknown mode (%u)", mif->mode);;
}
static u8 *
format_memif_queue (u8 * s, va_list * args)
{
memif_if_t *mif = va_arg (*args, memif_if_t *);
memif_queue_t *mq = va_arg (*args, memif_queue_t *);
uword i = va_arg (*args, uword);
uword indent = format_get_indent (s);
s = format (s, "%U%s ring %u:\n",
format_white_space, indent,
(mif->flags & MEMIF_IF_FLAG_IS_SLAVE) ?
"slave-to-master" : "master-to-slave", i);
s = format (s, "%Uregion %u offset %u ring-size %u int-fd %d\n",
format_white_space, indent + 4,
mq->region, mq->offset, (1 << mq->log2_ring_size), mq->int_fd);
if (mq->ring)
s = format (s, "%Uhead %u tail %u flags 0x%04x interrupts %u\n",
format_white_space, indent + 4,
mq->ring->head, mq->ring->tail, mq->ring->flags,
mq->int_count);
return s;
}
static clib_error_t *
memif_show_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
@ -162,39 +217,43 @@ memif_show_command_fn (vlib_main_t * vm, unformat_input_t * input,
memif_main_t *mm = &memif_main;
memif_if_t *mif;
vnet_main_t *vnm = vnet_get_main ();
int i;
memif_queue_t *mq;
uword i;
/* *INDENT-OFF* */
pool_foreach (mif, mm->interfaces,
({
memif_socket_file_t * msf = vec_elt_at_index (mm->socket_files,
mif->socket_file_index);
vlib_cli_output (vm, "interface %U", format_vnet_sw_if_index_name,
vnm, mif->sw_if_index);
vlib_cli_output (vm, " key 0x%" PRIx64 " file %s", mif->key,
mif->socket_filename);
vlib_cli_output (vm, " listener %d conn-fd %d int-fd %d", mif->listener_index,
mif->connection.fd, mif->interrupt_line.fd);
vlib_cli_output (vm, " ring-size %u num-s2m-rings %u num-m2s-rings %u buffer_size %u",
(1 << mif->log2_ring_size),
mif->num_s2m_rings,
mif->num_m2s_rings,
mif->buffer_size);
for (i=0; i < mif->num_s2m_rings; i++)
if (mif->remote_name)
vlib_cli_output (vm, " remote-name \"%s\"", mif->remote_name);
if (mif->remote_if_name)
vlib_cli_output (vm, " remote-interface \"%s\"", mif->remote_if_name);
vlib_cli_output (vm, " id %d mode %U file %s", mif->id,
format_memif_if_mode, mif, msf->filename);
vlib_cli_output (vm, " flags%U", format_memif_if_flags, mif->flags);
vlib_cli_output (vm, " listener-fd %d conn-fd %d", msf->fd, mif->conn_fd);
vlib_cli_output (vm, " num-s2m-rings %u num-m2s-rings %u buffer-size %u",
mif->run.num_s2m_rings,
mif->run.num_m2s_rings,
mif->run.buffer_size);
if (mif->local_disc_string)
vlib_cli_output (vm, " local-disc-reason \"%s\"", mif->local_disc_string);
if (mif->remote_disc_string)
vlib_cli_output (vm, " remote-disc-reason \"%s\"", mif->remote_disc_string);
vec_foreach_index (i, mif->tx_queues)
{
memif_ring_t * ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
if (ring)
{
vlib_cli_output (vm, " slave-to-master ring %u:", i);
vlib_cli_output (vm, " head %u tail %u", ring->head, ring->tail);
}
mq = vec_elt_at_index (mif->tx_queues, i);
vlib_cli_output (vm, " %U", format_memif_queue, mif, mq, i);
}
for (i=0; i < mif->num_m2s_rings; i++)
vec_foreach_index (i, mif->rx_queues)
{
memif_ring_t * ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
if (ring)
{
vlib_cli_output (vm, " master-to-slave ring %u:", i);
vlib_cli_output (vm, " head %u tail %u", ring->head, ring->tail);
}
mq = vec_elt_at_index (mif->rx_queues, i);
vlib_cli_output (vm, " %U", format_memif_queue, mif, mq, i);
}
}));
/* *INDENT-ON* */

View File

@ -26,6 +26,7 @@
#include <vnet/ethernet/ethernet.h>
#include <memif/memif.h>
#include <memif/private.h>
#define foreach_memif_tx_func_error \
_(NO_FREE_SLOTS, "no free tx slots") \
@ -45,8 +46,7 @@ static char *memif_tx_func_error_strings[] = {
#undef _
};
static u8 *
u8 *
format_memif_device_name (u8 * s, va_list * args)
{
u32 i = va_arg (*args, u32);
@ -91,27 +91,30 @@ memif_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame, memif_if_t * mif,
memif_ring_type_t type)
{
u8 rid;
u8 qid;
memif_ring_t *ring;
u32 *buffers = vlib_frame_args (frame);
u32 n_left = frame->n_vectors;
u16 ring_size = 1 << mif->log2_ring_size;
u16 mask = ring_size - 1;
u16 ring_size, mask;
u16 head, tail;
u16 free_slots;
u32 thread_index = vlib_get_thread_index ();
u8 tx_queues = memif_get_tx_queues (mif);
u8 tx_queues = vec_len (mif->tx_queues);
memif_queue_t *mq;
if (tx_queues < vec_len (vlib_mains))
{
rid = thread_index % tx_queues;
qid = thread_index % tx_queues;
clib_spinlock_lock_if_init (&mif->lockp);
}
else
{
rid = thread_index;
qid = thread_index;
}
ring = memif_get_ring (mif, type, rid);
mq = vec_elt_at_index (mif->tx_queues, qid);
ring = mq->ring;
ring_size = 1 << mq->log2_ring_size;
mask = ring_size - 1;
/* free consumed buffers */
@ -214,10 +217,11 @@ memif_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
}
vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
if (mif->interrupt_line.fd > 0)
if ((ring->flags & MEMIF_RING_FLAG_MASK_INT) == 0 && mq->int_fd > -1)
{
u8 b = rid;
CLIB_UNUSED (int r) = write (mif->interrupt_line.fd, &b, sizeof (b));
u64 b = 1;
CLIB_UNUSED (int r) = write (mq->int_fd, &b, sizeof (b));
mq->int_count++;
}
return frame->n_vectors;
@ -262,35 +266,35 @@ memif_clear_hw_interface_counters (u32 instance)
/* Nothing for now */
}
static clib_error_t *
memif_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
vnet_hw_interface_rx_mode mode)
{
memif_main_t *mm = &memif_main;
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
memif_if_t *mif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, qid);
if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
mq->ring->flags |= MEMIF_RING_FLAG_MASK_INT;
else
mq->ring->flags &= ~MEMIF_RING_FLAG_MASK_INT;
return 0;
}
static clib_error_t *
memif_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
{
memif_main_t *apm = &memif_main;
vlib_main_t *vm = vlib_get_main ();
memif_msg_t msg = { 0 };
memif_main_t *mm = &memif_main;
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
memif_if_t *mif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
memif_if_t *mif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
static clib_error_t *error = 0;
if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
mif->flags |= MEMIF_IF_FLAG_ADMIN_UP;
else
{
mif->flags &= ~MEMIF_IF_FLAG_ADMIN_UP;
if (!(mif->flags & MEMIF_IF_FLAG_DELETING)
&& mif->connection.index != ~0)
{
msg.version = MEMIF_VERSION;
msg.type = MEMIF_MSG_TYPE_DISCONNECT;
if (send (mif->connection.fd, &msg, sizeof (msg), 0) < 0)
{
clib_unix_warning ("Failed to send disconnect request");
error = clib_error_return_unix (0, "send fd %d",
mif->connection.fd);
memif_disconnect (vm, mif);
}
}
}
mif->flags &= ~MEMIF_IF_FLAG_ADMIN_UP;
return error;
}
@ -317,6 +321,7 @@ VNET_DEVICE_CLASS (memif_device_class) = {
.clear_counters = memif_clear_hw_interface_counters,
.admin_up_down_function = memif_interface_admin_up_down,
.subif_add_del_function = memif_subif_add_del_function,
.rx_mode_change_function = memif_interface_rx_mode_change,
};
VLIB_DEVICE_TX_FUNCTION_MULTIARCH(memif_device_class,

View File

@ -17,9 +17,10 @@
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param role - role of the interface in the connection (master/slave)
@param mode - interface mode
@param rx_queues - number of rx queues (only valid for slave)
#param tx_queues - number of tx queues (only valid for slave)
@param key - 64bit integer used to authenticate and match opposite sides
@param id - 32bit integer used to authenticate and match opposite sides
of the connection
@param socket_filename - filename of the socket to be used for connection
establishment
@ -33,12 +34,12 @@ define memif_create
u32 context;
u8 role; /* 0 = master, 1 = slave */
u8 mode; /* 0 = ethernet, 1 = ip, 2 = punt/inject */
u8 rx_queues; /* optional, default is 1 */
u8 tx_queues; /* optional, default is 1 */
u64 key; /* optional, default is 0 */
u8 socket_filename[128]; /* optional, default is "/var/vpp/memif.sock"
and can be changed in VPP startup config */
u32 id; /* optional, default is 0 */
u8 socket_filename[128]; /* optional, default is "/var/vpp/memif.sock" */
u8 secret[24]; /* optional, default is "" */
u32 ring_size; /* optional, default is 1024 entries, must be power of 2 */
u16 buffer_size; /* optional, default is 2048 bytes */
u8 hw_addr[6]; /* optional, randomly generated if not defined */
@ -74,8 +75,9 @@ autoreply define memif_delete
@param sw_if_index - index of the interface
@param if_name - name of the interface
@param hw_addr - interface MAC address
@param key - key associated with the interface
@param id - id associated with the interface
@param role - role of the interface in the connection (master/slave)
@param mode - interface mode
@param socket_filename - name of the socket used by this interface
to establish new connections
@param ring_size - the number of entries of RX/TX rings
@ -93,8 +95,9 @@ define memif_details
u8 hw_addr[6];
/* memif specific parameters */
u64 key;
u32 id;
u8 role; /* 0 = master, 1 = slave */
u8 mode; /* 0 = ethernet, 1 = ip, 2 = punt/inject */
u8 socket_filename[128];
u32 ring_size;
u16 buffer_size; /* optional, default is 2048 bytes */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,9 @@
#include <vlib/vlib.h>
#include <vnet/ethernet/ethernet.h>
#include <vlib/unix/unix.h>
#include <memif/memif.h>
#include <memif/private.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
@ -107,8 +109,8 @@ vl_api_memif_create_t_handler (vl_api_memif_create_t * mp)
static const u8 empty_hw_addr[6];
int rv = 0;
/* key */
args.key = clib_net_to_host_u64 (mp->key);
/* id */
args.id = clib_net_to_host_u32 (mp->id);
/* socket filename */
mp->socket_filename[ARRAY_LEN (mp->socket_filename) - 1] = 0;
@ -120,6 +122,15 @@ vl_api_memif_create_t_handler (vl_api_memif_create_t * mp)
vec_len (args.socket_filename));
}
/* secret */
mp->secret[ARRAY_LEN (mp->secret) - 1] = 0;
if (strlen ((char *) mp->secret) > 0)
{
vec_validate (args.secret, strlen ((char *) mp->secret));
strncpy ((char *) args.secret, (char *) mp->secret,
vec_len (args.secret));
}
/* role */
args.is_master = (mp->role == 0);
if (args.is_master == 0)
@ -156,6 +167,9 @@ vl_api_memif_create_t_handler (vl_api_memif_create_t * mp)
rv = memif_create_if (vm, &args);
vec_free (args.socket_filename);
vec_free (args.secret);
reply:
/* *INDENT-OFF* */
REPLY_MACRO2 (VL_API_MEMIF_CREATE_REPLY,
@ -173,26 +187,19 @@ void
vl_api_memif_delete_t_handler (vl_api_memif_delete_t * mp)
{
memif_main_t *mm = &memif_main;
memif_if_t *mif;
vlib_main_t *vm = vlib_get_main ();
vnet_main_t *vnm = vnet_get_main ();
vl_api_memif_delete_reply_t *rmp;
u32 sw_if_index = ntohl (mp->sw_if_index);
vnet_hw_interface_t *hi =
vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index));
memif_if_t *mif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
int rv = 0;
/* *INDENT-OFF* */
pool_foreach (mif, mm->interfaces,
({
if (sw_if_index == mif->sw_if_index)
{
rv = memif_delete_if (vm, mif->key);
goto reply;
}
}));
/* *INDENT-ON* */
if (hi == NULL || memif_device_class.index != hi->dev_class_index)
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
else
rv = memif_delete_if (vm, mif);
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
reply:
REPLY_MACRO (VL_API_MEMIF_DELETE_REPLY);
}
@ -205,6 +212,8 @@ send_memif_details (unix_shared_memory_queue_t * q,
vl_api_memif_details_t *mp;
vnet_main_t *vnm = vnet_get_main ();
memif_main_t *mm = &memif_main;
memif_socket_file_t *msf = vec_elt_at_index (mm->socket_files,
mif->socket_file_index);
vnet_hw_interface_t *hwif;
hwif = vnet_get_sup_hw_interface (vnm, swif->sw_if_index);
@ -220,14 +229,13 @@ send_memif_details (unix_shared_memory_queue_t * q,
(char *) interface_name, ARRAY_LEN (mp->if_name) - 1);
memcpy (mp->hw_addr, hwif->hw_address, ARRAY_LEN (mp->hw_addr));
mp->key = clib_host_to_net_u64 (mif->key);
mp->id = clib_host_to_net_u32 (mif->id);
mp->role = (mif->flags & MEMIF_IF_FLAG_IS_SLAVE) ? 1 : 0;
strncpy ((char *) mp->socket_filename,
(char *) mif->socket_filename,
ARRAY_LEN (mp->socket_filename) - 1);
(char *) msf->filename, ARRAY_LEN (mp->socket_filename) - 1);
mp->ring_size = htonl (1 << mif->log2_ring_size);
mp->buffer_size = htons (mif->buffer_size);
mp->ring_size = htonl (1 << mif->run.log2_ring_size);
mp->buffer_size = htons (mif->run.buffer_size);
mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
mp->link_up_down = (hwif->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ? 1 : 0;

View File

@ -24,6 +24,7 @@
#include <vppinfra/error.h>
#include <vnet/ip/ip.h>
#include <memif/memif.h>
#include <memif/private.h>
#define __plugin_msg_base memif_test_main.msg_id_base
#include <vlibapi/vat_helper_macros.h>
@ -118,8 +119,9 @@ api_memif_create (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
vl_api_memif_create_t *mp;
u64 key = 0;
u32 id = 0;
u8 *socket_filename = 0;
u8 *secret = 0;
u8 role = 1;
u32 ring_size = 0;
u32 buffer_size = 0;
@ -131,10 +133,12 @@ api_memif_create (vat_main_t * vam)
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "key 0x%" PRIx64, &key))
if (unformat (i, "id %u", &id))
;
else if (unformat (i, "socket %s", &socket_filename))
;
else if (unformat (i, "secret %s", &secret))
;
else if (unformat (i, "ring_size %u", &ring_size))
;
else if (unformat (i, "buffer_size %u", &buffer_size))
@ -173,7 +177,7 @@ api_memif_create (vat_main_t * vam)
M (MEMIF_CREATE, mp);
mp->key = clib_host_to_net_u64 (key);
mp->id = clib_host_to_net_u32 (id);
mp->role = role;
mp->ring_size = clib_host_to_net_u32 (ring_size);
mp->buffer_size = clib_host_to_net_u16 (buffer_size & 0xffff);
@ -182,6 +186,11 @@ api_memif_create (vat_main_t * vam)
strncpy ((char *) mp->socket_filename, (char *) socket_filename, 127);
vec_free (socket_filename);
}
if (socket_filename != 0)
{
strncpy ((char *) mp->secret, (char *) secret, 16);
vec_free (socket_filename);
}
memcpy (mp->hw_addr, hw_addr, 6);
mp->rx_queues = rx_queues;
mp->tx_queues = tx_queues;
@ -282,11 +291,11 @@ static void vl_api_memif_details_t_handler (vl_api_memif_details_t * mp)
vat_main_t *vam = memif_test_main.vat_main;
fformat (vam->ofp, "%s: sw_if_index %u mac %U\n"
" key 0x%" PRIx64 " socket %s role %s\n"
" id %u socket %s role %s\n"
" ring_size %u buffer_size %u\n"
" state %s link %s\n",
mp->if_name, ntohl (mp->sw_if_index), format_ethernet_address,
mp->hw_addr, clib_net_to_host_u64 (mp->key), mp->socket_filename,
mp->hw_addr, clib_net_to_host_u32 (mp->id), mp->socket_filename,
mp->role ? "slave" : "master",
ntohl (mp->ring_size), ntohs (mp->buffer_size),
mp->admin_up_down ? "up" : "down",
@ -298,7 +307,7 @@ static void vl_api_memif_details_t_handler (vl_api_memif_details_t * mp)
* and that the data plane plugin processes
*/
#define foreach_vpe_api_msg \
_(memif_create, "[key <key>] [socket <path>] [ring_size <size>] " \
_(memif_create, "[id <id>] [socket <path>] [ring_size <size>] " \
"[buffer_size <size>] [hw_addr <mac_address>] " \
"<master|slave>") \
_(memif_delete, "<sw_if_index>") \

View File

@ -28,6 +28,7 @@
#include <vnet/feature/feature.h>
#include <memif/memif.h>
#include <memif/private.h>
#define foreach_memif_input_error
@ -78,11 +79,11 @@ memif_prefetch (vlib_main_t * vm, u32 bi)
static_always_inline uword
memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame, memif_if_t * mif,
memif_ring_type_t type, u16 rid)
memif_ring_type_t type, u16 qid)
{
vnet_main_t *vnm = vnet_get_main ();
memif_ring_t *ring = memif_get_ring (mif, type, rid);
memif_ring_data_t *rd;
memif_ring_t *ring;
memif_queue_t *mq;
u16 head;
u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
uword n_trace = vlib_get_trace_count (vm, node);
@ -94,12 +95,14 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 thread_index = vlib_get_thread_index ();
u32 bi0, bi1;
vlib_buffer_t *b0, *b1;
u16 ring_size = 1 << mif->log2_ring_size;
u16 mask = ring_size - 1;
u16 num_slots;
u16 ring_size, mask, num_slots;
void *mb0, *mb1;
rd = vec_elt_at_index (mif->ring_data, rid + type * mif->num_s2m_rings);
mq = vec_elt_at_index (mif->rx_queues, qid);
ring = mq->ring;
ring_size = 1 << mq->log2_ring_size;
mask = ring_size - 1;
if (mif->per_interface_next_index != ~0)
next_index = mif->per_interface_next_index;
@ -115,13 +118,13 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
}
head = ring->head;
if (head == rd->last_head)
if (head == mq->last_head)
return 0;
if (head > rd->last_head)
num_slots = head - rd->last_head;
if (head > mq->last_head)
num_slots = head - mq->last_head;
else
num_slots = ring_size - rd->last_head + head;
num_slots = ring_size - mq->last_head + head;
while (num_slots)
{
@ -132,28 +135,28 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
while (num_slots > 5 && n_left_to_next > 2)
{
if (PREDICT_TRUE (rd->last_head + 5 < ring_size))
if (PREDICT_TRUE (mq->last_head + 5 < ring_size))
{
CLIB_PREFETCH (memif_get_buffer (mif, ring, rd->last_head + 2),
CLIB_PREFETCH (memif_get_buffer (mif, ring, mq->last_head + 2),
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (memif_get_buffer (mif, ring, rd->last_head + 3),
CLIB_PREFETCH (memif_get_buffer (mif, ring, mq->last_head + 3),
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (&ring->desc[rd->last_head + 4],
CLIB_PREFETCH (&ring->desc[mq->last_head + 4],
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (&ring->desc[rd->last_head + 5],
CLIB_PREFETCH (&ring->desc[mq->last_head + 5],
CLIB_CACHE_LINE_BYTES, LOAD);
}
else
{
CLIB_PREFETCH (memif_get_buffer
(mif, ring, (rd->last_head + 2) % mask),
(mif, ring, (mq->last_head + 2) % mask),
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (memif_get_buffer
(mif, ring, (rd->last_head + 3) % mask),
(mif, ring, (mq->last_head + 3) % mask),
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (&ring->desc[(rd->last_head + 4) % mask],
CLIB_PREFETCH (&ring->desc[(mq->last_head + 4) % mask],
CLIB_CACHE_LINE_BYTES, LOAD);
CLIB_PREFETCH (&ring->desc[(rd->last_head + 5) % mask],
CLIB_PREFETCH (&ring->desc[(mq->last_head + 5) % mask],
CLIB_CACHE_LINE_BYTES, LOAD);
}
/* get empty buffer */
@ -185,17 +188,17 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
/* copy buffer */
mb0 = memif_get_buffer (mif, ring, rd->last_head);
mb0 = memif_get_buffer (mif, ring, mq->last_head);
clib_memcpy (vlib_buffer_get_current (b0), mb0,
CLIB_CACHE_LINE_BYTES);
b0->current_length = ring->desc[rd->last_head].length;
rd->last_head = (rd->last_head + 1) & mask;
b0->current_length = ring->desc[mq->last_head].length;
mq->last_head = (mq->last_head + 1) & mask;
mb1 = memif_get_buffer (mif, ring, rd->last_head);
mb1 = memif_get_buffer (mif, ring, mq->last_head);
clib_memcpy (vlib_buffer_get_current (b1), mb1,
CLIB_CACHE_LINE_BYTES);
b1->current_length = ring->desc[rd->last_head].length;
rd->last_head = (rd->last_head + 1) & mask;
b1->current_length = ring->desc[mq->last_head].length;
mq->last_head = (mq->last_head + 1) & mask;
if (b0->current_length > CLIB_CACHE_LINE_BYTES)
clib_memcpy (vlib_buffer_get_current (b0) + CLIB_CACHE_LINE_BYTES,
@ -221,7 +224,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->next_index = next0;
tr->hw_if_index = mif->hw_if_index;
tr->ring = rid;
tr->ring = qid;
if (n_trace)
{
@ -233,7 +236,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
tr = vlib_add_trace (vm, node, b1, sizeof (*tr));
tr->next_index = next1;
tr->hw_if_index = mif->hw_if_index;
tr->ring = rid;
tr->ring = qid;
}
}
@ -266,12 +269,12 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
/* fill buffer metadata */
b0 = vlib_get_buffer (vm, bi0);
b0->current_length = ring->desc[rd->last_head].length;
b0->current_length = ring->desc[mq->last_head].length;
vnet_buffer (b0)->sw_if_index[VLIB_RX] = mif->sw_if_index;
vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
/* copy buffer */
mb0 = memif_get_buffer (mif, ring, rd->last_head);
mb0 = memif_get_buffer (mif, ring, mq->last_head);
clib_memcpy (vlib_buffer_get_current (b0), mb0,
CLIB_CACHE_LINE_BYTES);
if (b0->current_length > CLIB_CACHE_LINE_BYTES)
@ -291,7 +294,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->next_index = next0;
tr->hw_if_index = mif->hw_if_index;
tr->ring = rid;
tr->ring = qid;
}
@ -303,7 +306,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
n_left_to_next, bi0, next0);
/* next packet */
rd->last_head = (rd->last_head + 1) & mask;
mq->last_head = (mq->last_head + 1) & mask;
num_slots--;
n_rx_packets++;
n_rx_bytes += b0->current_length;
@ -325,30 +328,28 @@ static uword
memif_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
u32 n_rx_packets = 0;
u32 n_rx = 0;
memif_main_t *nm = &memif_main;
memif_if_t *mif;
vnet_device_input_runtime_t *rt = (void *) node->runtime_data;
vnet_device_and_queue_t *dq;
memif_ring_type_t type;
foreach_device_and_queue (dq, rt->devices_and_queues)
{
memif_if_t *mif;
mif = vec_elt_at_index (nm->interfaces, dq->dev_instance);
if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) &&
(mif->flags & MEMIF_IF_FLAG_CONNECTED))
{
if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
type = MEMIF_RING_M2S;
n_rx += memif_device_input_inline (vm, node, frame, mif,
MEMIF_RING_M2S, dq->queue_id);
else
type = MEMIF_RING_S2M;
n_rx_packets +=
memif_device_input_inline (vm, node, frame, mif, type,
dq->queue_id);
n_rx += memif_device_input_inline (vm, node, frame, mif,
MEMIF_RING_S2M, dq->queue_id);
}
}
return n_rx_packets;
return n_rx;
}
/* *INDENT-OFF* */

296
src/plugins/memif/private.h Normal file
View File

@ -0,0 +1,296 @@
/*
*------------------------------------------------------------------
* Copyright (c) 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 <vppinfra/lock.h>
#define MEMIF_DEFAULT_SOCKET_DIR "/run/vpp"
#define MEMIF_DEFAULT_SOCKET_FILENAME "memif.sock"
#define MEMIF_DEFAULT_RING_SIZE 1024
#define MEMIF_DEFAULT_RX_QUEUES 1
#define MEMIF_DEFAULT_TX_QUEUES 1
#define MEMIF_DEFAULT_BUFFER_SIZE 2048
#define MEMIF_VERSION_MAJOR 0
#define MEMIF_VERSION_MINOR 1
#define MEMIF_VERSION ((MEMIF_VERSION_MAJOR << 8) | MEMIF_VERSION_MINOR)
#define MEMIF_COOKIE 0xdeadbeef
#define MEMIF_MAX_M2S_RING (vec_len (vlib_mains) - 1)
#define MEMIF_MAX_S2M_RING (vec_len (vlib_mains) - 1)
#define MEMIF_MAX_REGION 255
#define MEMIF_MAX_LOG2_RING_SIZE 14
#define MEMIF_DEBUG 0
#if MEMIF_DEBUG == 1
#define DBG(...) clib_warning(__VA_ARGS__)
#define DBG_UNIX_LOG(...) clib_unix_warning(__VA_ARGS__)
#else
#define DBG(...)
#define DBG_UNIX_LOG(...)
#endif
#if MEMIF_DEBUG == 1
#define memif_file_add(a, b) do { \
ASSERT (*a == ~0); \
*a = unix_file_add (&unix_main, b); \
clib_warning ("unix_file_add fd %d private_data %u idx %u", \
(b)->file_descriptor, (b)->private_data, *a); \
} while (0)
#define memif_file_del(a) do { \
clib_warning ("unix_file_del idx %u",a - unix_main.file_pool); \
unix_file_del (&unix_main, a); \
} while (0)
#define memif_file_del_by_index(a) do { \
clib_warning ("unix_file_del idx %u", a); \
unix_file_del_by_index (&unix_main, a); \
} while (0)
#else
#define memif_file_add(a, b) do { \
ASSERT (*a == ~0); \
*a = unix_file_add (&unix_main, b); \
} while (0)
#define memif_file_del(a) unix_file_del(&unix_main, a)
#define memif_file_del_by_index(a) unix_file_del_by_index(&unix_main, a)
#endif
typedef struct
{
u8 *filename;
int fd;
uword unix_file_index;
uword *pending_file_indices;
int ref_cnt;
int is_listener;
/* hash of all registered id */
mhash_t dev_instance_by_id;
/* hash of all registered fds */
uword *dev_instance_by_fd;
} memif_socket_file_t;
typedef struct
{
void *shm;
u32 region_size;
int fd;
} memif_region_t;
typedef struct
{
memif_msg_t msg;
int fd;
} memif_msg_fifo_elt_t;
typedef struct
{
/* ring data */
memif_ring_t *ring;
u8 log2_ring_size;
u8 region;
u32 offset;
u16 last_head;
u16 last_tail;
/* interrupts */
int int_fd;
uword int_unix_file_index;
u64 int_count;
} memif_queue_t;
#define foreach_memif_if_flag \
_(0, ADMIN_UP, "admin-up") \
_(1, IS_SLAVE, "slave") \
_(2, CONNECTING, "connecting") \
_(3, CONNECTED, "connected") \
_(4, DELETING, "deleting")
typedef enum
{
#define _(a, b, c) MEMIF_IF_FLAG_##b = (1 << a),
foreach_memif_if_flag
#undef _
} memif_if_flag_t;
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
clib_spinlock_t lockp;
u32 flags;
memif_interface_id_t id;
u32 hw_if_index;
u32 sw_if_index;
uword dev_instance;
memif_interface_mode_t mode:8;
u32 per_interface_next_index;
/* socket connection */
uword socket_file_index;
int conn_fd;
uword conn_unix_file_index;
memif_msg_fifo_elt_t *msg_queue;
u8 *secret;
memif_region_t *regions;
memif_queue_t *rx_queues;
memif_queue_t *tx_queues;
/* remote info */
pid_t remote_pid;
uid_t remote_uid;
gid_t remote_gid;
u8 *remote_name;
u8 *remote_if_name;
struct
{
u8 log2_ring_size;
u8 num_s2m_rings;
u8 num_m2s_rings;
u16 buffer_size;
} cfg;
struct
{
u8 log2_ring_size;
u8 num_s2m_rings;
u8 num_m2s_rings;
u16 buffer_size;
} run;
/* disconnect strings */
u8 *local_disc_string;
u8 *remote_disc_string;
} memif_if_t;
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
/** API message ID base */
u16 msg_id_base;
/* pool of all memory interfaces */
memif_if_t *interfaces;
/* pool of all unix socket files */
memif_socket_file_t *socket_files;
mhash_t socket_file_index_by_filename;
/* rx buffer cache */
u32 **rx_buffers;
} memif_main_t;
extern memif_main_t memif_main;
extern vnet_device_class_t memif_device_class;
extern vlib_node_registration_t memif_input_node;
enum
{
MEMIF_PROCESS_EVENT_START = 1,
MEMIF_PROCESS_EVENT_STOP = 2,
} memif_process_event_t;
typedef struct
{
memif_interface_id_t id;
u8 *socket_filename;
u8 *secret;
u8 is_master;
memif_interface_mode_t mode:8;
u8 log2_ring_size;
u16 buffer_size;
u8 hw_addr_set;
u8 hw_addr[6];
u8 rx_queues;
u8 tx_queues;
/* return */
u32 sw_if_index;
} memif_create_if_args_t;
int memif_create_if (vlib_main_t * vm, memif_create_if_args_t * args);
int memif_delete_if (vlib_main_t * vm, memif_if_t * mif);
clib_error_t *memif_plugin_api_hookup (vlib_main_t * vm);
#ifndef __NR_memfd_create
#if defined __x86_64__
#define __NR_memfd_create 319
#elif defined __arm__
#define __NR_memfd_create 385
#elif defined __aarch64__
#define __NR_memfd_create 279
#else
#error "__NR_memfd_create unknown for this architecture"
#endif
#endif
static inline int
memfd_create (const char *name, unsigned int flags)
{
return syscall (__NR_memfd_create, name, flags);
}
static_always_inline void *
memif_get_buffer (memif_if_t * mif, memif_ring_t * ring, u16 slot)
{
u16 region = ring->desc[slot].region;
return mif->regions[region].shm + ring->desc[slot].offset;
}
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
#endif
#define MFD_ALLOW_SEALING 0x0002U
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
#define F_SEAL_WRITE 0x0008 /* prevent writes */
/* memif.c */
clib_error_t *memif_init_regions_and_queues (memif_if_t * mif);
clib_error_t *memif_connect (memif_if_t * mif);
void memif_disconnect (memif_if_t * mif, clib_error_t * err);
/* socket.c */
clib_error_t *memif_conn_fd_accept_ready (unix_file_t * uf);
clib_error_t *memif_master_conn_fd_read_ready (unix_file_t * uf);
clib_error_t *memif_slave_conn_fd_read_ready (unix_file_t * uf);
clib_error_t *memif_master_conn_fd_write_ready (unix_file_t * uf);
clib_error_t *memif_slave_conn_fd_write_ready (unix_file_t * uf);
clib_error_t *memif_master_conn_fd_error (unix_file_t * uf);
clib_error_t *memif_slave_conn_fd_error (unix_file_t * uf);
clib_error_t *memif_msg_send_disconnect (memif_if_t * mif,
clib_error_t * err);
u8 *format_memif_device_name (u8 * s, va_list * args);
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

736
src/plugins/memif/socket.c Normal file

File diff suppressed because it is too large Load Diff