Add memif - packet memory interface for intra-host communication

Change-Id: I94c06b07a39f07ceba87bf3e7fcfc70e43231e8a
Signed-off-by: Damjan Marion <damarion@cisco.com>
Co-Authored-By: Milan Lenco <Milan.Lenco@pantheon.tech>
This commit is contained in:
Damjan Marion
2017-03-22 10:18:13 +01:00
committed by Ole Trøan
parent 24d01367c8
commit eaabe07351
13 changed files with 2774 additions and 0 deletions
+1
View File
@@ -151,6 +151,7 @@ PLUGIN_ENABLED(ila)
PLUGIN_ENABLED(ioam)
PLUGIN_ENABLED(ixge)
PLUGIN_ENABLED(lb)
PLUGIN_ENABLED(memif)
PLUGIN_ENABLED(sixrd)
PLUGIN_ENABLED(snat)
PLUGIN_DISABLED(srv6sample)
+4
View File
@@ -57,6 +57,10 @@ if ENABLE_LB_PLUGIN
include lb.am
endif
if ENABLE_MEMIF_PLUGIN
include memif.am
endif
if ENABLE_SIXRD_PLUGIN
include sixrd.am
endif
+32
View File
@@ -0,0 +1,32 @@
# Copyright (c) 2017 Cisco Systems, Inc.
# 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.
vppplugins_LTLIBRARIES += memif_plugin.la
memif_plugin_la_SOURCES = memif/memif.c \
memif/memif_api.c \
memif/cli.c \
memif/node.c \
memif/device.c \
memif/memif_plugin.api.h
noinst_HEADERS += memif/memif.h
nobase_apiinclude_HEADERS += \
memif/memif_all_api_h.h \
memif/memif_msg_enum.h \
memif/memif.api.h
API_FILES += memif/memif.api
# vi:syntax=automake
+202
View File
@@ -0,0 +1,202 @@
/*
*------------------------------------------------------------------
* 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.
*------------------------------------------------------------------
*/
#include <stdint.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ethernet/ethernet.h>
#include <memif/memif.h>
static clib_error_t *
memif_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
int r;
u32 ring_size = MEMIF_DEFAULT_RING_SIZE;
memif_create_if_args_t args = { 0 };
args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "key 0x%" PRIx64, &args.key))
;
else if (unformat (line_input, "socket %s", &args.socket_filename))
;
else if (unformat (line_input, "ring-size %u", &ring_size))
;
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"))
args.is_master = 0;
else if (unformat (line_input, "hw-addr %U",
unformat_ethernet_address, args.hw_addr))
args.hw_addr_set = 1;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
unformat_free (line_input);
if (!is_pow2 (ring_size))
return clib_error_return (0, "ring size must be power of 2");
args.log2_ring_size = min_log2 (ring_size);
r = memif_create_if (vm, &args);
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);
if (r == VNET_API_ERROR_INVALID_INTERFACE)
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 0;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (memif_create_command, static) = {
.path = "create memif",
.short_help = "create memif [key <key>] [socket <path>] "
"[ring-size <size>] [buffer-size <size>] [hw-addr <mac-address>] "
"<master|slave>",
.function = memif_create_command_fn,
};
/* *INDENT-ON* */
static clib_error_t *
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;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "key 0x%" PRIx64, &key))
key_defined = 1;
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");
memif_delete_if (vm, key);
return 0;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (memif_delete_command, static) = {
.path = "delete memif",
.short_help = "delete memif key <key-value>",
.function = memif_delete_command_fn,
};
/* *INDENT-ON* */
static clib_error_t *
memif_show_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
memif_main_t *mm = &memif_main;
memif_if_t *mif;
vnet_main_t *vnm = vnet_get_main ();
int i;
/* *INDENT-OFF* */
pool_foreach (mif, mm->interfaces,
({
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-c2s-rings %u num-s2c-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++)
{
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);
}
}
for (i=0; i < mif->num_m2s_rings; i++)
{
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);
}
}
}));
/* *INDENT-ON* */
return 0;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (memif_show_command, static) = {
.path = "show memif",
.short_help = "show memif",
.function = memif_show_command_fn,
};
/* *INDENT-ON* */
clib_error_t *
memif_cli_init (vlib_main_t * vm)
{
return 0;
}
VLIB_INIT_FUNCTION (memif_cli_init);
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
/*
* 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.
*/
/** \brief Create memory interface
@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 key - 64bit integer used to authenticate and match opposite sides
of the connection
@param socket_filename - filename of the socket to be used for connection
establishment
@param ring_size - the number of entries of RX/TX rings
@param buffer_size - size of the buffer allocated for each ring entry
@param hw_addr - interface MAC address
*/
define memif_create
{
u32 client_index;
u32 context;
u8 role; /* 0 = master, 1 = slave */
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 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 */
};
/** \brief Create memory interface response
@param context - sender context, to match reply w/ request
@param retval - return value for request
@param sw_if_index - software index of the newly created interface
*/
define memif_create_reply
{
u32 context;
i32 retval;
u32 sw_if_index;
};
/** \brief Delete memory interface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - software index of the interface to delete
*/
define memif_delete
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
/** \brief Delete host-interface response
@param context - sender context, to match reply w/ request
@param retval - return value for request
*/
define memif_delete_reply
{
u32 context;
i32 retval;
};
/** \brief Memory interface details structure
@param context - sender context, to match reply w/ request (memif_dump)
@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 role - role of the interface in the connection (master/slave)
@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
@param buffer_size - size of the buffer allocated for each ring entry
@param admin_up_down - interface administrative status
@param link_up_down - interface link status
*/
define memif_details
{
u32 context;
u32 sw_if_index;
u8 if_name[64];
u8 hw_addr[6];
/* memif specific parameters */
u64 key;
u8 role; /* 0 = master, 1 = slave */
u8 socket_filename[128];
u32 ring_size;
u16 buffer_size; /* optional, default is 2048 bytes */
/* 1 = up, 0 = down */
u8 admin_up_down;
u8 link_up_down;
};
/** \brief Dump all memory interfaces
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
*/
define memif_dump
{
u32 client_index;
u32 context;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
+263
View File
@@ -0,0 +1,263 @@
/*
*------------------------------------------------------------------
* 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.
*------------------------------------------------------------------
*/
typedef struct
{
u16 version;
#define MEMIF_VERSION_MAJOR 0
#define MEMIF_VERSION_MINOR 1
#define MEMIF_VERSION ((MEMIF_VERSION_MAJOR << 8) | MEMIF_VERSION_MINOR)
u8 type;
#define MEMIF_MSG_TYPE_CONNECT_REQ 0
#define MEMIF_MSG_TYPE_CONNECT_RESP 1
#define MEMIF_MSG_TYPE_DISCONNECT 2
/* Connection-request parameters: */
u64 key;
u8 log2_ring_size;
#define MEMIF_DEFAULT_RING_SIZE 1024
u16 num_s2m_rings;
u16 num_m2s_rings;
u16 buffer_size;
#define MEMIF_DEFAULT_BUFFER_SIZE 2048
u32 shared_mem_size;
/* Connection-response parameters: */
u8 retval;
} memif_msg_t;
typedef struct __attribute__ ((packed))
{
u16 flags;
#define MEMIF_DESC_FLAG_NEXT (1 << 0)
u16 region;
u32 buffer_length;
u32 length;;
u8 reserved[4];
u64 offset;
u64 metadata;
} memif_desc_t;
STATIC_ASSERT_SIZEOF (memif_desc_t, 32);
typedef struct
{
u16 head __attribute__ ((aligned (128)));
u16 tail __attribute__ ((aligned (128)));
memif_desc_t desc[0] __attribute__ ((aligned (128)));
} memif_ring_t;
typedef struct
{
u32 cookie __attribute__ ((aligned (128)));
} memif_shm_t;
typedef struct
{
u16 last_head;
u16 last_tail;
} memif_ring_data_t;
typedef struct
{
int fd;
u32 index;
} memif_file_t;
typedef struct
{
uword index;
dev_t sock_dev;
ino_t sock_ino;
memif_file_t socket;
u16 usage_counter;
} memif_listener_t;
typedef struct
{
uword index;
memif_file_t connection;
uword listener_index;
} memif_pending_conn_t;
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
volatile u32 *lockp;
u32 flags;
#define MEMIF_IF_FLAG_ADMIN_UP (1 << 0)
#define MEMIF_IF_FLAG_IS_SLAVE (1 << 1)
#define MEMIF_IF_FLAG_CONNECTING (1 << 2)
#define MEMIF_IF_FLAG_CONNECTED (1 << 3)
#define MEMIF_IF_FLAG_DELETING (1 << 4)
u64 key;
uword if_index;
u32 hw_if_index;
u32 sw_if_index;
u32 per_interface_next_index;
uword listener_index;
memif_file_t connection;
memif_file_t interrupt_line;
u8 *socket_filename;
void **regions;
u8 log2_ring_size;
u8 num_s2m_rings;
u8 num_m2s_rings;
u16 buffer_size;
memif_ring_data_t *ring_data;
/* remote info */
pid_t remote_pid;
uid_t remote_uid;
} 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 listeners */
memif_listener_t *listeners;
/* pool of pending connections */
memif_pending_conn_t *pending_conns;
/* bitmap of pending rx interfaces */
uword *pending_input_bitmap;
/* rx buffer cache */
u32 **rx_buffers;
/* hash of all registered keys */
mhash_t if_index_by_key;
/* first cpu index */
u32 input_cpu_first_index;
/* total cpu count */
u32 input_cpu_count;
/* configuration */
u8 *default_socket_filename;
#define MEMIF_DEFAULT_SOCKET_FILENAME "/var/vpp/memif.sock"
} 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
{
u64 key;
u8 *socket_filename;
u8 is_master;
u8 log2_ring_size;
u16 buffer_size;
u8 hw_addr_set;
u8 hw_addr[6];
/* 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, u64 key);
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);
}
typedef enum
{
MEMIF_RING_S2M = 0,
MEMIF_RING_M2S = 1
} memif_ring_type_t;
static_always_inline memif_ring_t *
memif_get_ring (memif_if_t * mif, memif_ring_type_t type, u16 ring_num)
{
if (vec_len (mif->regions) == 0)
return NULL;
void *p = mif->regions[0];
int ring_size =
sizeof (memif_ring_t) +
sizeof (memif_desc_t) * (1 << mif->log2_ring_size);
p += sizeof (memif_shm_t);
p += (ring_num + type * mif->num_s2m_rings) * ring_size;
return (memif_ring_t *) p;
}
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] + 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 */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+18
View File
@@ -0,0 +1,18 @@
/*
* memif_all_api_h.h - plug-in api #include file
*
* Copyright (c) <current-year> <your-organization>
* 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 the generated file, see BUILT_SOURCES in Makefile.am */
#include <memif/memif.api.h>
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
/*
* memif_msg_enum.h - vpp engine plug-in message enumeration
*
* Copyright (c) <current-year> <your-organization>
* 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 included_memif_msg_enum_h
#define included_memif_msg_enum_h
#include <vppinfra/byte_order.h>
#define vl_msg_id(n,h) n,
typedef enum
{
#include <memif/memif_all_api_h.h>
/* We'll want to know how many messages IDs we need... */
VL_MSG_FIRST_AVAILABLE,
} vl_msg_id_t;
#undef vl_msg_id
#endif /* included_memif_msg_enum_h */
File diff suppressed because it is too large Load Diff
+6
View File
@@ -100,6 +100,12 @@
/* Full memory barrier (read and write). */
#define CLIB_MEMORY_BARRIER() __sync_synchronize ()
#if __x86_64__
#define CLIB_MEMORY_STORE_BARRIER() __builtin_ia32_sfence ()
#else
#define CLIB_MEMORY_STORE_BARRIER() __sync_synchronize ()
#endif
/* Arranges for function to be called before main. */
#define INIT_FUNCTION(decl) \
decl __attribute ((constructor)); \