snort: snort3 plugin and DAQ
Zero copy interface which exposes VPP buffers to snort instance(s). Includes VPP DAQ which is compiled only if libdaq 3 API headers are available. Type: feature Change-Id: I96611b43f94fbae091e7391589e0454ae66de88b Signed-off-by: Damjan Marion <damarion@cisco.com> Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
0ec7dad7a0
commit
839b1473e9
@@ -632,6 +632,11 @@ M: Florin Coras <fcoras@cisco.com>
|
||||
Y: src/plugins/quic/FEATURE.yaml
|
||||
F: src/plugins/quic/
|
||||
|
||||
Plugin - snort plugin
|
||||
I: snort
|
||||
M: Damjan Marion <damarion@cisco.com>
|
||||
F: src/plugins/snort/
|
||||
|
||||
libmemif
|
||||
I: libmemif
|
||||
M: Damjan Marion <damarion@cisco.com>
|
||||
|
52
src/plugins/snort/CMakeLists.txt
Normal file
52
src/plugins/snort/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright(c) 2021 Cisco Systems, Inc.
|
||||
|
||||
add_vpp_plugin(snort
|
||||
SOURCES
|
||||
enqueue.c
|
||||
dequeue.c
|
||||
main.c
|
||||
cli.c
|
||||
|
||||
MULTIARCH_SOURCES
|
||||
enqueue.c
|
||||
dequeue.c
|
||||
|
||||
COMPONENT
|
||||
vpp-plugin-snort
|
||||
)
|
||||
|
||||
# DAQ
|
||||
|
||||
find_path(LIBDAQ_INCLUDE_DIR NAMES daq_module_api.h daq_dlt.h daq_version.h)
|
||||
|
||||
if (NOT LIBDAQ_INCLUDE_DIR)
|
||||
message(WARNING "-- libdaq headers not found - snort3 DAQ disabled")
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(STRINGS ${LIBDAQ_INCLUDE_DIR}/daq_version.h daq_version)
|
||||
foreach(l ${daq_version})
|
||||
if (l MATCHES "^#define[\t ]*DAQ_")
|
||||
STRING(REGEX REPLACE "^#define[\t ]*([A-Z1-9_]+)[\t ]*(.+)" "\\1;\\2" v "${l}")
|
||||
list(GET v 0 name)
|
||||
list(GET v 1 value)
|
||||
set(${name} ${value})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(DAQ_VER "${DAQ_VERSION_MAJOR}.${DAQ_VERSION_MINOR}.${DAQ_VERSION_PATCH}")
|
||||
message(STATUS "libdaq ${DAQ_VER} include files found at ${LIBDAQ_INCLUDE_DIR}")
|
||||
|
||||
if (NOT DAQ_VERSION_MAJOR MATCHES 3)
|
||||
message(WARNING "-- libdaq version not supported - snort3 DAQ disabled")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(daq_vpp SHARED daq_vpp.c)
|
||||
set_target_properties(daq_vpp PROPERTIES SOVERSION ${VPP_LIB_VERSION})
|
||||
target_compile_options (daq_vpp PRIVATE "-fvisibility=hidden")
|
||||
target_compile_options (daq_vpp PRIVATE "-DHAVE_VISIBILITY")
|
||||
target_compile_options (daq_vpp PRIVATE "-I${LIBDAQ_INCLUDE_DIR}")
|
||||
install(TARGETS daq_vpp DESTINATION ${VPP_LIBRARY_DIR}/daq COMPONENT vpp-plugin-snort)
|
||||
|
282
src/plugins/snort/cli.c
Normal file
282
src/plugins/snort/cli.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright(c) 2021 Cisco Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <vlib/vlib.h>
|
||||
#include <vnet/vnet.h>
|
||||
#include <snort/snort.h>
|
||||
|
||||
static u8 *
|
||||
format_snort_instance (u8 *s, va_list *args)
|
||||
{
|
||||
snort_instance_t *i = va_arg (*args, snort_instance_t *);
|
||||
s = format (s, "%s [idx:%d sz:%d fd:%d]", i->name, i->index, i->shm_size,
|
||||
i->shm_fd);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
snort_create_instance_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
clib_error_t *err = 0;
|
||||
u8 *name = 0;
|
||||
u32 queue_size = 1024;
|
||||
u8 drop_on_diconnect = 1;
|
||||
|
||||
/* 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, "queue-size %u", &queue_size))
|
||||
;
|
||||
else if (unformat (line_input, "on-disconnect drop"))
|
||||
drop_on_diconnect = 1;
|
||||
else if (unformat (line_input, "on-disconnect pass"))
|
||||
drop_on_diconnect = 0;
|
||||
else if (unformat (line_input, "name %s", &name))
|
||||
;
|
||||
else
|
||||
{
|
||||
err = clib_error_return (0, "unknown input `%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_pow2 (queue_size))
|
||||
{
|
||||
err = clib_error_return (0, "Queue size must be a power of two");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!name)
|
||||
{
|
||||
err = clib_error_return (0, "please specify instance name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snort_instance_create (vm, (char *) name, min_log2 (queue_size),
|
||||
drop_on_diconnect);
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
unformat_free (line_input);
|
||||
return err;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_create_instance_command, static) = {
|
||||
.path = "snort create-instance",
|
||||
.short_help = "snort create-instaince name <name> [queue-size <size>] "
|
||||
"[on-disconnect drop|pass]",
|
||||
.function = snort_create_instance_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_attach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
clib_error_t *err = 0;
|
||||
u8 *name = 0;
|
||||
u32 sw_if_index = ~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, "interface %U", unformat_vnet_sw_interface,
|
||||
vnm, &sw_if_index))
|
||||
;
|
||||
else if (unformat (line_input, "instance %s", &name))
|
||||
;
|
||||
else
|
||||
{
|
||||
err = clib_error_return (0, "unknown input `%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
{
|
||||
err = clib_error_return (0, "please specify interface");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!name)
|
||||
{
|
||||
err = clib_error_return (0, "please specify instance name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snort_interface_enable_disable (vm, (char *) name, sw_if_index, 1);
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
unformat_free (line_input);
|
||||
return err;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_attach_command, static) = {
|
||||
.path = "snort attach",
|
||||
.short_help = "snort attach instance <name> interface <if-name>",
|
||||
.function = snort_attach_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_detach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
clib_error_t *err = 0;
|
||||
u32 sw_if_index = ~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, "interface %U", unformat_vnet_sw_interface,
|
||||
vnm, &sw_if_index))
|
||||
;
|
||||
else
|
||||
{
|
||||
err = clib_error_return (0, "unknown input `%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
{
|
||||
err = clib_error_return (0, "please specify interface");
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snort_interface_enable_disable (vm, 0, sw_if_index, 0);
|
||||
|
||||
done:
|
||||
unformat_free (line_input);
|
||||
return err;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_detach_command, static) = {
|
||||
.path = "snort detach",
|
||||
.short_help = "snort detach interface <if-name>",
|
||||
.function = snort_detach_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_show_instances_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
snort_instance_t *si;
|
||||
|
||||
pool_foreach (si, sm->instances)
|
||||
vlib_cli_output (vm, "%U", format_snort_instance, si);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_show_instances_command, static) = {
|
||||
.path = "show snort instances",
|
||||
.short_help = "show snort instances",
|
||||
.function = snort_show_instances_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_show_interfaces_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
snort_instance_t *si;
|
||||
u32 *index;
|
||||
|
||||
vlib_cli_output (vm, "interface\tsnort instance");
|
||||
vec_foreach (index, sm->instance_by_sw_if_index)
|
||||
{
|
||||
if (index[0] != ~0)
|
||||
{
|
||||
si = vec_elt_at_index (sm->instances, index[0]);
|
||||
vlib_cli_output (vm, "%U:\t%s", format_vnet_sw_if_index_name, vnm,
|
||||
index - sm->instance_by_sw_if_index, si->name);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_show_interfaces_command, static) = {
|
||||
.path = "show snort interfaces",
|
||||
.short_help = "show snort interfaces",
|
||||
.function = snort_show_interfaces_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_show_clients_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
vlib_cli_output (vm, "number of clients: %d", pool_elts (sm->clients));
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_show_clients_command, static) = {
|
||||
.path = "show snort clients",
|
||||
.short_help = "show snort clients",
|
||||
.function = snort_show_clients_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_mode_polling_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
return snort_set_node_mode (vm, VLIB_NODE_STATE_POLLING);
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
snort_mode_interrupt_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
return snort_set_node_mode (vm, VLIB_NODE_STATE_INTERRUPT);
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_mode_polling_command, static) = {
|
||||
.path = "snort mode polling",
|
||||
.short_help = "snort mode polling|interrupt",
|
||||
.function = snort_mode_polling_command_fn,
|
||||
};
|
||||
|
||||
VLIB_CLI_COMMAND (snort_mode_interrupt_command, static) = {
|
||||
.path = "snort mode interrupt",
|
||||
.short_help = "snort mode polling|interrupt",
|
||||
.function = snort_mode_interrupt_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_show_mode_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
char *mode =
|
||||
sm->input_mode == VLIB_NODE_STATE_POLLING ? "polling" : "interrupt";
|
||||
vlib_cli_output (vm, "input mode: %s", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_show_mode_command, static) = {
|
||||
.path = "show snort mode",
|
||||
.short_help = "show snort mode",
|
||||
.function = snort_show_mode_command_fn,
|
||||
};
|
693
src/plugins/snort/daq_vpp.c
Normal file
693
src/plugins/snort/daq_vpp.c
Normal file
File diff suppressed because it is too large
Load Diff
77
src/plugins/snort/daq_vpp.h
Normal file
77
src/plugins/snort/daq_vpp.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright(c) 2021 Cisco Systems, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __DAQ_VPP_H__
|
||||
#define __DAQ_VPP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DAQ_VPP_DEFAULT_SOCKET_FILE "snort.sock"
|
||||
#define DAQ_VPP_DEFAULT_SOCKET_PATH "/run/vpp/" DAQ_VPP_DEFAULT_SOCKET_FILE
|
||||
#define DAQ_VPP_INST_NAME_LEN 32
|
||||
|
||||
typedef enum memif_msg_type
|
||||
{
|
||||
DAQ_VPP_MSG_TYPE_NONE = 0,
|
||||
DAQ_VPP_MSG_TYPE_HELLO = 1,
|
||||
DAQ_VPP_MSG_TYPE_CONFIG = 2,
|
||||
DAQ_VPP_MSG_TYPE_BPOOL = 3,
|
||||
DAQ_VPP_MSG_TYPE_QPAIR = 4,
|
||||
} daq_vpp_msg_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char inst_name[DAQ_VPP_INST_NAME_LEN];
|
||||
} daq_vpp_msg_hello_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t shm_size;
|
||||
uint16_t num_bpools;
|
||||
uint16_t num_qpairs;
|
||||
} daq_vpp_msg_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t size;
|
||||
} daq_vpp_msg_bpool_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t log2_queue_size;
|
||||
uint32_t desc_table_offset;
|
||||
uint32_t enq_head_offset;
|
||||
uint32_t deq_head_offset;
|
||||
uint32_t enq_ring_offset;
|
||||
uint32_t deq_ring_offset;
|
||||
} daq_vpp_msg_qpair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
daq_vpp_msg_type_t type : 8;
|
||||
union
|
||||
{
|
||||
daq_vpp_msg_hello_t hello;
|
||||
daq_vpp_msg_config_t config;
|
||||
daq_vpp_msg_bpool_t bpool;
|
||||
daq_vpp_msg_qpair_t qpair;
|
||||
};
|
||||
} daq_vpp_msg_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DAQ_VPP_ACTION_DROP,
|
||||
DAQ_VPP_ACTION_FORWARD,
|
||||
} daq_vpp_action_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t offset;
|
||||
uint16_t length;
|
||||
uint16_t address_space_id;
|
||||
uint8_t buffer_pool;
|
||||
daq_vpp_action_t action : 8;
|
||||
} daq_vpp_desc_t;
|
||||
|
||||
#endif /* __DAQ_VPP_H__ */
|
366
src/plugins/snort/dequeue.c
Normal file
366
src/plugins/snort/dequeue.c
Normal file
File diff suppressed because it is too large
Load Diff
223
src/plugins/snort/enqueue.c
Normal file
223
src/plugins/snort/enqueue.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright(c) 2021 Cisco Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <vlib/vlib.h>
|
||||
#include <vnet/feature/feature.h>
|
||||
#include <snort/snort.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 next_index;
|
||||
u32 sw_if_index;
|
||||
u16 instance;
|
||||
u16 qpair;
|
||||
u32 enq_slot;
|
||||
u32 desc_index;
|
||||
daq_vpp_desc_t desc;
|
||||
} snort_enq_trace_t;
|
||||
|
||||
static u8 *
|
||||
format_snort_enq_trace (u8 *s, va_list *args)
|
||||
{
|
||||
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
|
||||
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
|
||||
snort_enq_trace_t *t = va_arg (*args, snort_enq_trace_t *);
|
||||
u32 indent = format_get_indent (s);
|
||||
|
||||
s = format (s,
|
||||
"sw-if-index %u next-index %u\n"
|
||||
"%Uinstance %u qpair %u desc-index %u slot %u\n"
|
||||
"%Udesc: buffer-pool %u offset %u len %u address-space-id %u\n",
|
||||
t->sw_if_index, t->next_index, format_white_space, indent,
|
||||
t->instance, t->qpair, t->desc_index, t->enq_slot,
|
||||
format_white_space, indent, t->desc.buffer_pool, t->desc.offset,
|
||||
t->desc.length, t->desc.address_space_id);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#define foreach_snort_enq_error \
|
||||
_ (SOCKET_ERROR, "write socket error") \
|
||||
_ (NO_INSTANCE, "no snort instance") \
|
||||
_ (NO_ENQ_SLOTS, "no enqueue slots (packet dropped)")
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#define _(sym, str) SNORT_ENQ_ERROR_##sym,
|
||||
foreach_snort_enq_error
|
||||
#undef _
|
||||
SNORT_ENQ_N_ERROR,
|
||||
} snort_enq_error_t;
|
||||
|
||||
static char *snort_enq_error_strings[] = {
|
||||
#define _(sym, string) string,
|
||||
foreach_snort_enq_error
|
||||
#undef _
|
||||
};
|
||||
|
||||
static_always_inline uword
|
||||
snort_enq_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
|
||||
vlib_frame_t *frame, int with_trace)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
snort_instance_t *si = 0;
|
||||
snort_qpair_t *qp = 0;
|
||||
u32 thread_index = vm->thread_index;
|
||||
u32 n_left = frame->n_vectors;
|
||||
u32 n_trace = 0;
|
||||
u32 total_enq = 0, n_processed = 0;
|
||||
u32 *from = vlib_frame_vector_args (frame);
|
||||
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
|
||||
u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
|
||||
|
||||
vlib_get_buffers (vm, from, bufs, n_left);
|
||||
|
||||
while (n_left)
|
||||
{
|
||||
u32 instance_index, next_index, n;
|
||||
instance_index =
|
||||
*(u32 *) vnet_feature_next_with_data (&next_index, b[0], sizeof (u32));
|
||||
si = vec_elt_at_index (sm->instances, instance_index);
|
||||
|
||||
/* if client isn't connected skip enqueue and take default action */
|
||||
if (PREDICT_FALSE (si->client_index == ~0))
|
||||
{
|
||||
if (si->drop_on_disconnect)
|
||||
next[0] = SNORT_ENQ_NEXT_DROP;
|
||||
else
|
||||
next[0] = next_index;
|
||||
next++;
|
||||
n_processed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
qp = vec_elt_at_index (si->qpairs, thread_index);
|
||||
n = qp->n_pending++;
|
||||
daq_vpp_desc_t *d = qp->pending_descs + n;
|
||||
|
||||
qp->pending_nexts[n] = next_index;
|
||||
qp->pending_buffers[n] = from[0];
|
||||
|
||||
vlib_buffer_chain_linearize (vm, b[0]);
|
||||
|
||||
/* If this pkt is traced, snapshoot the data */
|
||||
if (with_trace && b[0]->flags & VLIB_BUFFER_IS_TRACED)
|
||||
n_trace++;
|
||||
|
||||
/* fill descriptor */
|
||||
d->buffer_pool = b[0]->buffer_pool_index;
|
||||
d->length = b[0]->current_length;
|
||||
d->offset = (u8 *) b[0]->data + b[0]->current_data -
|
||||
sm->buffer_pool_base_addrs[d->buffer_pool];
|
||||
d->address_space_id = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
|
||||
}
|
||||
|
||||
n_left--;
|
||||
from++;
|
||||
b++;
|
||||
}
|
||||
|
||||
if (n_processed)
|
||||
{
|
||||
vlib_node_increment_counter (vm, snort_enq_node.index,
|
||||
SNORT_ENQ_ERROR_NO_INSTANCE, n_processed);
|
||||
vlib_buffer_enqueue_to_next (vm, node, vlib_frame_vector_args (frame),
|
||||
nexts, n_processed);
|
||||
}
|
||||
|
||||
vec_foreach (si, sm->instances)
|
||||
{
|
||||
u32 head, freelist_len, n_pending, n_enq, mask;
|
||||
u64 ctr = 1;
|
||||
qp = vec_elt_at_index (si->qpairs, thread_index);
|
||||
mask = pow2_mask (qp->log2_queue_size);
|
||||
n_pending = qp->n_pending;
|
||||
qp->n_pending = 0;
|
||||
|
||||
if (n_pending == 0)
|
||||
continue;
|
||||
|
||||
freelist_len = vec_len (qp->freelist);
|
||||
|
||||
if (freelist_len < n_pending)
|
||||
{
|
||||
n_enq = freelist_len;
|
||||
vlib_buffer_free (vm, qp->pending_buffers + n_enq,
|
||||
n_pending - n_enq);
|
||||
vlib_node_increment_counter (vm, snort_enq_node.index,
|
||||
SNORT_ENQ_ERROR_NO_ENQ_SLOTS,
|
||||
n_pending - n_enq);
|
||||
}
|
||||
else
|
||||
n_enq = n_pending;
|
||||
|
||||
if (n_enq == 0)
|
||||
continue;
|
||||
|
||||
total_enq += n_enq;
|
||||
head = *qp->enq_head;
|
||||
|
||||
for (u32 i = 0; i < n_enq; i++)
|
||||
{
|
||||
u32 desc_index = qp->freelist[--freelist_len];
|
||||
qp->next_indices[desc_index] = qp->pending_nexts[i];
|
||||
ASSERT (qp->buffer_indices[desc_index] == ~0);
|
||||
qp->buffer_indices[desc_index] = qp->pending_buffers[i];
|
||||
clib_memcpy_fast (qp->descriptors + desc_index,
|
||||
qp->pending_descs + i, sizeof (daq_vpp_desc_t));
|
||||
qp->enq_ring[head & mask] = desc_index;
|
||||
|
||||
/* trace */
|
||||
if (with_trace && n_trace)
|
||||
{
|
||||
vlib_buffer_t *tb = vlib_get_buffer (vm, qp->pending_buffers[i]);
|
||||
if (tb->flags & VLIB_BUFFER_IS_TRACED)
|
||||
{
|
||||
snort_enq_trace_t *t =
|
||||
vlib_add_trace (vm, node, tb, sizeof (*t));
|
||||
t->sw_if_index = vnet_buffer (tb)->sw_if_index[VLIB_RX];
|
||||
t->next_index = qp->pending_nexts[i];
|
||||
t->instance = si->index;
|
||||
t->qpair = qp - si->qpairs;
|
||||
t->enq_slot = head & mask;
|
||||
t->desc_index = desc_index;
|
||||
clib_memcpy_fast (&t->desc, qp->pending_descs + i,
|
||||
sizeof (daq_vpp_desc_t));
|
||||
}
|
||||
}
|
||||
head = head + 1;
|
||||
}
|
||||
|
||||
__atomic_store_n (qp->enq_head, head, __ATOMIC_RELEASE);
|
||||
_vec_len (qp->freelist) = freelist_len;
|
||||
if (sm->input_mode == VLIB_NODE_STATE_INTERRUPT)
|
||||
{
|
||||
if (write (qp->enq_fd, &ctr, sizeof (ctr)) < 0)
|
||||
vlib_node_increment_counter (vm, snort_enq_node.index,
|
||||
SNORT_ENQ_ERROR_SOCKET_ERROR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return total_enq;
|
||||
}
|
||||
|
||||
VLIB_NODE_FN (snort_enq_node)
|
||||
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
|
||||
{
|
||||
if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
|
||||
return snort_enq_node_inline (vm, node, frame, 1 /* is_trace*/);
|
||||
else
|
||||
return snort_enq_node_inline (vm, node, frame, 0 /* is_trace*/);
|
||||
}
|
||||
|
||||
VLIB_REGISTER_NODE (snort_enq_node) = {
|
||||
.name = "snort-enq",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_snort_enq_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
.n_next_nodes = SNORT_ENQ_N_NEXT_NODES,
|
||||
.next_nodes = SNORT_ENQ_NEXT_NODES,
|
||||
.n_errors = ARRAY_LEN (snort_enq_error_strings),
|
||||
.error_strings = snort_enq_error_strings,
|
||||
};
|
520
src/plugins/snort/main.c
Normal file
520
src/plugins/snort/main.c
Normal file
File diff suppressed because it is too large
Load Diff
113
src/plugins/snort/snort.h
Normal file
113
src/plugins/snort/snort.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright(c) 2021 Cisco Systems, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __snort_snort_h__
|
||||
#define __snort_snort_h__
|
||||
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/socket.h>
|
||||
#include <vlib/vlib.h>
|
||||
#include <snort/daq_vpp.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
|
||||
u8 log2_queue_size;
|
||||
daq_vpp_desc_t *descriptors;
|
||||
volatile u32 *enq_head;
|
||||
volatile u32 *deq_head;
|
||||
volatile u32 *enq_ring;
|
||||
volatile u32 *deq_ring;
|
||||
u32 next_desc;
|
||||
int enq_fd, deq_fd;
|
||||
u32 deq_fd_file_index;
|
||||
u32 *buffer_indices;
|
||||
u16 *next_indices;
|
||||
u32 *freelist;
|
||||
u32 ready;
|
||||
|
||||
/* temporary storeage used by enqueue node */
|
||||
u32 n_pending;
|
||||
u16 pending_nexts[VLIB_FRAME_SIZE];
|
||||
u32 pending_buffers[VLIB_FRAME_SIZE];
|
||||
daq_vpp_desc_t pending_descs[VLIB_FRAME_SIZE];
|
||||
} snort_qpair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 index;
|
||||
u32 client_index;
|
||||
void *shm_base;
|
||||
u32 shm_size;
|
||||
int shm_fd;
|
||||
snort_qpair_t *qpairs;
|
||||
u8 *name;
|
||||
u8 drop_on_disconnect;
|
||||
} snort_instance_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
daq_vpp_msg_t msg;
|
||||
int fds[2];
|
||||
int n_fds;
|
||||
} snort_client_msg_queue_elt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
clib_socket_t socket;
|
||||
u32 instance_index;
|
||||
u32 file_index;
|
||||
snort_client_msg_queue_elt *msg_queue;
|
||||
} snort_client_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* per-instance dequeue interrupts */
|
||||
void *interrupts;
|
||||
} snort_per_thread_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
clib_socket_t *listener;
|
||||
snort_client_t *clients;
|
||||
snort_instance_t *instances;
|
||||
uword *instance_by_name;
|
||||
u32 *instance_by_sw_if_index;
|
||||
u8 **buffer_pool_base_addrs;
|
||||
snort_per_thread_data_t *per_thread_data;
|
||||
u32 input_mode;
|
||||
u8 *socket_name;
|
||||
} snort_main_t;
|
||||
|
||||
extern snort_main_t snort_main;
|
||||
extern vlib_node_registration_t snort_enq_node;
|
||||
extern vlib_node_registration_t snort_deq_node;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SNORT_ENQ_NEXT_DROP,
|
||||
SNORT_ENQ_N_NEXT_NODES,
|
||||
} snort_enq_next_t;
|
||||
|
||||
#define SNORT_ENQ_NEXT_NODES \
|
||||
{ \
|
||||
[SNORT_ENQ_NEXT_DROP] = "error-drop", \
|
||||
}
|
||||
|
||||
/* functions */
|
||||
clib_error_t *snort_instance_create (vlib_main_t *vm, char *name,
|
||||
u8 log2_queue_sz, u8 drop_on_disconnect);
|
||||
clib_error_t *snort_interface_enable_disable (vlib_main_t *vm,
|
||||
char *instance_name,
|
||||
u32 sw_if_index, int is_enable);
|
||||
clib_error_t *snort_set_node_mode (vlib_main_t *vm, u32 mode);
|
||||
|
||||
always_inline void
|
||||
snort_freelist_init (u32 *fl)
|
||||
{
|
||||
for (int j = 0; j < vec_len (fl); j++)
|
||||
fl[j] = j;
|
||||
}
|
||||
|
||||
#endif /* __snort_snort_h__ */
|
Reference in New Issue
Block a user