snort: API functions for plugin
Also, made disconnect-instance and delete-instance functions available via cli. Type: feature Change-Id: I7939d27867959cb871b1cc7205b94410b53906fd Signed-off-by: Alexander Skorichenko <askorichenko@netgate.com>
This commit is contained in:
parent
d0e8bd75f6
commit
e3ad5aa68a
@ -7,6 +7,10 @@ add_vpp_plugin(snort
|
||||
dequeue.c
|
||||
main.c
|
||||
cli.c
|
||||
snort_api.c
|
||||
|
||||
API_FILES
|
||||
snort.api
|
||||
|
||||
MULTIARCH_SOURCES
|
||||
enqueue.c
|
||||
|
@ -25,6 +25,7 @@ snort_create_instance_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
u8 *name = 0;
|
||||
u32 queue_size = 1024;
|
||||
u8 drop_on_diconnect = 1;
|
||||
int rv = 0;
|
||||
|
||||
/* Get a line of input. */
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
@ -60,8 +61,30 @@ snort_create_instance_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snort_instance_create (vm, (char *) name, min_log2 (queue_size),
|
||||
drop_on_diconnect);
|
||||
rv = snort_instance_create (vm, (char *) name, min_log2 (queue_size),
|
||||
drop_on_diconnect);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
|
||||
err = clib_error_return (0, "instance '%s' already exists", name);
|
||||
break;
|
||||
case VNET_API_ERROR_SYSCALL_ERROR_1:
|
||||
err = clib_error_return (0, "memory fd failure: %U", format_clib_error,
|
||||
clib_mem_get_last_error ());
|
||||
break;
|
||||
case VNET_API_ERROR_SYSCALL_ERROR_2:
|
||||
err = clib_error_return (0, "ftruncate failure");
|
||||
break;
|
||||
case VNET_API_ERROR_SYSCALL_ERROR_3:
|
||||
err = clib_error_return (0, "mmap failure");
|
||||
break;
|
||||
default:
|
||||
err = clib_error_return (0, "snort_instance_create returned %d", rv);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
@ -76,6 +99,118 @@ VLIB_CLI_COMMAND (snort_create_instance_command, static) = {
|
||||
.function = snort_create_instance_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_disconnect_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;
|
||||
snort_instance_t *si;
|
||||
int rv = 0;
|
||||
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
return clib_error_return (0, "please specify instance name");
|
||||
|
||||
if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
|
||||
unformat (line_input, "%s", &name);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
err = clib_error_return (0, "please specify instance name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
si = snort_get_instance_by_name ((char *) name);
|
||||
if (!si)
|
||||
rv = VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
else
|
||||
rv = snort_instance_disconnect (vm, si->index);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case VNET_API_ERROR_NO_SUCH_ENTRY:
|
||||
err = clib_error_return (0, "unknown instance '%s'", name);
|
||||
break;
|
||||
case VNET_API_ERROR_FEATURE_DISABLED:
|
||||
err = clib_error_return (0, "instance '%s' is not connected", name);
|
||||
break;
|
||||
case VNET_API_ERROR_INVALID_VALUE:
|
||||
err = clib_error_return (0, "failed to disconnect a broken client");
|
||||
break;
|
||||
default:
|
||||
err = clib_error_return (0, "snort_instance_disconnect returned %d", rv);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
unformat_free (line_input);
|
||||
return err;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_disconnect_instance_command, static) = {
|
||||
.path = "snort disconnect instance",
|
||||
.short_help = "snort disconnect instance <name>",
|
||||
.function = snort_disconnect_instance_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_delete_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;
|
||||
int rv = 0;
|
||||
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
return clib_error_return (0, "please specify instance name");
|
||||
|
||||
if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
|
||||
unformat (line_input, "%s", &name);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
err = clib_error_return (0, "please specify instance name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
snort_instance_t *si = snort_get_instance_by_name ((char *) name);
|
||||
if (!si)
|
||||
err = clib_error_return (0, "unknown instance '%s' requested", name);
|
||||
else
|
||||
rv = snort_instance_delete (vm, si->index);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case VNET_API_ERROR_NO_SUCH_ENTRY:
|
||||
err = clib_error_return (0, "instance '%s' deletion failure", name);
|
||||
break;
|
||||
case VNET_API_ERROR_INSTANCE_IN_USE:
|
||||
err = clib_error_return (0, "instance '%s' has connected client", name);
|
||||
break;
|
||||
default:
|
||||
err = clib_error_return (0, "snort_instance_delete returned %d", rv);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
unformat_free (line_input);
|
||||
return err;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_delete_instance_command, static) = {
|
||||
.path = "snort delete instance",
|
||||
.short_help = "snort delete instance <name>",
|
||||
.function = snort_delete_instance_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
snort_attach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
@ -86,6 +221,7 @@ snort_attach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
u8 *name = 0;
|
||||
u32 sw_if_index = ~0;
|
||||
snort_attach_dir_t dir = SNORT_INOUT;
|
||||
int rv = 0;
|
||||
|
||||
/* Get a line of input. */
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
@ -124,8 +260,29 @@ snort_attach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
goto done;
|
||||
}
|
||||
|
||||
err =
|
||||
snort_interface_enable_disable (vm, (char *) name, sw_if_index, 1, dir);
|
||||
rv = snort_interface_enable_disable (vm, (char *) name, sw_if_index, 1, dir);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case VNET_API_ERROR_FEATURE_ALREADY_ENABLED:
|
||||
/* already attached to same instance */
|
||||
break;
|
||||
case VNET_API_ERROR_INSTANCE_IN_USE:
|
||||
err = clib_error_return (0,
|
||||
"interface %U already assigned to "
|
||||
"an instance",
|
||||
format_vnet_sw_if_index_name, vnm, sw_if_index);
|
||||
break;
|
||||
case VNET_API_ERROR_NO_SUCH_ENTRY:
|
||||
err = clib_error_return (0, "unknown instance '%s'", name);
|
||||
break;
|
||||
default:
|
||||
err = clib_error_return (0, "snort_interface_enable_disable returned %d",
|
||||
rv);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
vec_free (name);
|
||||
@ -148,6 +305,7 @@ snort_detach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
clib_error_t *err = 0;
|
||||
u32 sw_if_index = ~0;
|
||||
int rv = 0;
|
||||
|
||||
/* Get a line of input. */
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
@ -172,7 +330,23 @@ snort_detach_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = snort_interface_enable_disable (vm, 0, sw_if_index, 0, SNORT_INOUT);
|
||||
rv = snort_interface_enable_disable (vm, 0, sw_if_index, 0, SNORT_INOUT);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case VNET_API_ERROR_INVALID_INTERFACE:
|
||||
err = clib_error_return (0,
|
||||
"interface %U is not assigned to snort "
|
||||
"instance!",
|
||||
format_vnet_sw_if_index_name, vnm, sw_if_index);
|
||||
break;
|
||||
default:
|
||||
err = clib_error_return (0, "snort_interface_enable_disable returned %d",
|
||||
rv);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
unformat_free (line_input);
|
||||
@ -213,7 +387,7 @@ snort_show_interfaces_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
snort_instance_t *si;
|
||||
u32 *index;
|
||||
|
||||
vlib_cli_output (vm, "interface\tsnort instance");
|
||||
vlib_cli_output (vm, "interface\t\tsnort instance");
|
||||
vec_foreach (index, sm->instance_by_sw_if_index)
|
||||
{
|
||||
if (index[0] != ~0)
|
||||
@ -237,7 +411,18 @@ 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));
|
||||
u32 n_clients = pool_elts (sm->clients);
|
||||
snort_client_t *c;
|
||||
snort_instance_t *si;
|
||||
|
||||
vlib_cli_output (vm, "number of clients: %d", n_clients);
|
||||
if (n_clients)
|
||||
vlib_cli_output (vm, "client snort instance");
|
||||
pool_foreach (c, sm->clients)
|
||||
{
|
||||
si = vec_elt_at_index (sm->instances, c->instance_index);
|
||||
vlib_cli_output (vm, "%6d %s", c - sm->clients, si->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -251,14 +436,16 @@ 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);
|
||||
snort_set_node_mode (vm, VLIB_NODE_STATE_POLLING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
snort_set_node_mode (vm, VLIB_NODE_STATE_INTERRUPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (snort_mode_polling_command, static) = {
|
||||
|
@ -307,7 +307,7 @@ snort_deq_node_polling (vlib_main_t *vm, vlib_node_runtime_t *node,
|
||||
snort_qpair_t *qp;
|
||||
snort_instance_t *si;
|
||||
|
||||
vec_foreach (si, sm->instances)
|
||||
pool_foreach (si, sm->instances)
|
||||
{
|
||||
qp = vec_elt_at_index (si->qpairs, vm->thread_index);
|
||||
u32 ready = __atomic_load_n (&qp->ready, __ATOMIC_ACQUIRE);
|
||||
|
@ -133,7 +133,7 @@ snort_enq_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
|
||||
nexts, n_processed);
|
||||
}
|
||||
|
||||
vec_foreach (si, sm->instances)
|
||||
pool_foreach (si, sm->instances)
|
||||
{
|
||||
u32 head, freelist_len, n_pending, n_enq, mask;
|
||||
u64 ctr = 1;
|
||||
|
@ -3,10 +3,24 @@
|
||||
*/
|
||||
|
||||
#include <vlib/vlib.h>
|
||||
#include <vlibapi/api_types.h>
|
||||
#include <vnet/plugin/plugin.h>
|
||||
#include <vpp/app/version.h>
|
||||
#include <snort/snort.h>
|
||||
|
||||
#include <snort/snort.api_enum.h>
|
||||
#include <snort/snort.api_types.h>
|
||||
|
||||
#include <vnet/ip/ip_types_api.h>
|
||||
#include <vnet/format_fns.h>
|
||||
|
||||
#include <vlibapi/api_helper_macros.h>
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
snort_main_t snort_main;
|
||||
@ -18,6 +32,12 @@ VLIB_REGISTER_LOG_CLASS (snort_log, static) = {
|
||||
#define log_debug(fmt, ...) vlib_log_debug (snort_log.class, fmt, __VA_ARGS__)
|
||||
#define log_err(fmt, ...) vlib_log_err (snort_log.class, fmt, __VA_ARGS__)
|
||||
|
||||
snort_main_t *
|
||||
snort_get_main ()
|
||||
{
|
||||
return &snort_main;
|
||||
}
|
||||
|
||||
static void
|
||||
snort_client_disconnect (clib_file_t *uf)
|
||||
{
|
||||
@ -45,7 +65,38 @@ snort_client_disconnect (clib_file_t *uf)
|
||||
pool_put (sm->clients, c);
|
||||
}
|
||||
|
||||
static snort_instance_t *
|
||||
int
|
||||
snort_instance_disconnect (vlib_main_t *vm, u32 instance_index)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
snort_instance_t *si;
|
||||
snort_client_t *client;
|
||||
clib_file_main_t *fm = &file_main;
|
||||
clib_file_t *uf = 0;
|
||||
int rv = 0;
|
||||
|
||||
si = snort_get_instance_by_index (instance_index);
|
||||
if (!si)
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
if (si->client_index == ~0)
|
||||
return VNET_API_ERROR_FEATURE_DISABLED;
|
||||
|
||||
client = pool_elt_at_index (sm->clients, si->client_index);
|
||||
uf = clib_file_get (fm, client->file_index);
|
||||
if (uf)
|
||||
snort_client_disconnect (uf);
|
||||
else
|
||||
{
|
||||
log_err ("failed to disconnect a broken client from"
|
||||
"instance '%s'",
|
||||
si->name);
|
||||
rv = VNET_API_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
snort_instance_t *
|
||||
snort_get_instance_by_name (char *name)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
@ -54,7 +105,16 @@ snort_get_instance_by_name (char *name)
|
||||
return 0;
|
||||
|
||||
return vec_elt_at_index (sm->instances, p[0]);
|
||||
;
|
||||
}
|
||||
|
||||
snort_instance_t *
|
||||
snort_get_instance_by_index (u32 instance_index)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
|
||||
if (pool_is_free_index (sm->instances, instance_index))
|
||||
return 0;
|
||||
return pool_elt_at_index (sm->instances, instance_index);
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
@ -110,6 +170,8 @@ snort_conn_fd_read_ready (clib_file_t *uf)
|
||||
snort_client_disconnect (uf);
|
||||
return 0;
|
||||
}
|
||||
snort_freelist_init (qp->freelist);
|
||||
*qp->enq_head = *qp->deq_head = qp->next_desc = 0;
|
||||
}
|
||||
|
||||
base = (u8 *) si->shm_base;
|
||||
@ -281,14 +343,13 @@ snort_listener_init (vlib_main_t *vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
clib_error_t *
|
||||
int
|
||||
snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
u8 drop_on_disconnect)
|
||||
{
|
||||
vlib_thread_main_t *tm = vlib_get_thread_main ();
|
||||
snort_main_t *sm = &snort_main;
|
||||
snort_instance_t *si;
|
||||
clib_error_t *err = 0;
|
||||
u32 index, i;
|
||||
u8 *base = CLIB_MEM_VM_MAP_FAILED;
|
||||
u32 size;
|
||||
@ -296,9 +357,10 @@ snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
u32 qpair_mem_sz = 0;
|
||||
u32 qsz = 1 << log2_queue_sz;
|
||||
u8 align = CLIB_CACHE_LINE_BYTES;
|
||||
int rv = 0;
|
||||
|
||||
if (snort_get_instance_by_name (name))
|
||||
return clib_error_return (0, "instance already exists");
|
||||
return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
|
||||
|
||||
/* descriptor table */
|
||||
qpair_mem_sz += round_pow2 (qsz * sizeof (daq_vpp_desc_t), align);
|
||||
@ -316,14 +378,13 @@ snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
err = clib_error_return (0, "memory fd failure: %U", format_clib_error,
|
||||
clib_mem_get_last_error ());
|
||||
rv = VNET_API_ERROR_SYSCALL_ERROR_1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ftruncate (fd, size)) == -1)
|
||||
{
|
||||
err = clib_error_return (0, "ftruncate failure");
|
||||
rv = VNET_API_ERROR_SYSCALL_ERROR_2;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -331,7 +392,7 @@ snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
|
||||
if (base == CLIB_MEM_VM_MAP_FAILED)
|
||||
{
|
||||
err = clib_error_return (0, "mmap failure");
|
||||
rv = VNET_API_ERROR_SYSCALL_ERROR_3;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -399,17 +460,17 @@ snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
sm->input_mode);
|
||||
|
||||
done:
|
||||
if (err)
|
||||
if (rv)
|
||||
{
|
||||
if (base != CLIB_MEM_VM_MAP_FAILED)
|
||||
clib_mem_vm_unmap (base);
|
||||
if (fd != -1)
|
||||
close (fd);
|
||||
}
|
||||
return err;
|
||||
return rv;
|
||||
}
|
||||
|
||||
clib_error_t *
|
||||
int
|
||||
snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
u32 sw_if_index, int is_enable,
|
||||
snort_attach_dir_t snort_dir)
|
||||
@ -417,16 +478,16 @@ snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
snort_main_t *sm = &snort_main;
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
snort_instance_t *si;
|
||||
clib_error_t *err = 0;
|
||||
u64 fa_data;
|
||||
u32 index;
|
||||
int rv = 0;
|
||||
|
||||
if (is_enable)
|
||||
{
|
||||
if ((si = snort_get_instance_by_name (instance_name)) == 0)
|
||||
{
|
||||
err = clib_error_return (0, "unknown instance '%s'", instance_name);
|
||||
goto done;
|
||||
log_err ("unknown instance '%s'", instance_name);
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
}
|
||||
|
||||
vec_validate_init_empty (sm->instance_by_sw_if_index, sw_if_index, ~0);
|
||||
@ -434,12 +495,13 @@ snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
index = sm->instance_by_sw_if_index[sw_if_index];
|
||||
if (index != ~0)
|
||||
{
|
||||
if (index == si->index)
|
||||
rv = VNET_API_ERROR_FEATURE_ALREADY_ENABLED;
|
||||
else
|
||||
rv = VNET_API_ERROR_INSTANCE_IN_USE;
|
||||
si = vec_elt_at_index (sm->instances, index);
|
||||
err = clib_error_return (0,
|
||||
"interface %U already assgined to "
|
||||
"instance '%s'",
|
||||
format_vnet_sw_if_index_name, vnm,
|
||||
sw_if_index, si->name);
|
||||
log_err ("interface %U already assgined to instance '%s'",
|
||||
format_vnet_sw_if_index_name, vnm, sw_if_index, si->name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -462,11 +524,9 @@ snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
if (sw_if_index >= vec_len (sm->instance_by_sw_if_index) ||
|
||||
sm->instance_by_sw_if_index[sw_if_index] == ~0)
|
||||
{
|
||||
err =
|
||||
clib_error_return (0,
|
||||
"interface %U is not assigned to snort "
|
||||
"instance!",
|
||||
format_vnet_sw_if_index_name, vnm, sw_if_index);
|
||||
rv = VNET_API_ERROR_INVALID_INTERFACE;
|
||||
log_err ("interface %U is not assigned to snort instance!",
|
||||
format_vnet_sw_if_index_name, vnm, sw_if_index);
|
||||
goto done;
|
||||
}
|
||||
index = sm->instance_by_sw_if_index[sw_if_index];
|
||||
@ -488,12 +548,66 @@ snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
}
|
||||
|
||||
done:
|
||||
if (err)
|
||||
log_err ("%U", format_clib_error, err);
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
clib_error_t *
|
||||
static int
|
||||
snort_strip_instance_interfaces (vlib_main_t *vm, u32 instance_index)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
u32 *index;
|
||||
int rv = 0;
|
||||
|
||||
vec_foreach (index, sm->instance_by_sw_if_index)
|
||||
{
|
||||
if (*index == instance_index)
|
||||
rv = snort_interface_enable_disable (
|
||||
vm, NULL, index - sm->instance_by_sw_if_index, 0, 0);
|
||||
if (rv)
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
snort_instance_delete (vlib_main_t *vm, u32 instance_index)
|
||||
{
|
||||
snort_main_t *sm = &snort_main;
|
||||
snort_instance_t *si;
|
||||
snort_qpair_t *qp;
|
||||
int rv = 0;
|
||||
|
||||
si = snort_get_instance_by_index (instance_index);
|
||||
if (!si)
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
|
||||
if (si->client_index != ~0)
|
||||
return VNET_API_ERROR_INSTANCE_IN_USE;
|
||||
|
||||
if ((rv = snort_strip_instance_interfaces (vm, si->index)))
|
||||
return rv;
|
||||
|
||||
hash_unset_mem (sm->instance_by_name, si->name);
|
||||
|
||||
clib_mem_vm_unmap (si->shm_base);
|
||||
close (si->shm_fd);
|
||||
|
||||
vec_foreach (qp, si->qpairs)
|
||||
{
|
||||
clib_file_del_by_index (&file_main, qp->deq_fd_file_index);
|
||||
}
|
||||
|
||||
log_debug ("deleting instance '%s'", si->name);
|
||||
|
||||
vec_free (si->qpairs);
|
||||
vec_free (si->name);
|
||||
pool_put (sm->instances, si);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
snort_set_node_mode (vlib_main_t *vm, u32 mode)
|
||||
{
|
||||
int i;
|
||||
|
226
src/plugins/snort/snort.api
Normal file
226
src/plugins/snort/snort.api
Normal file
@ -0,0 +1,226 @@
|
||||
option version = "1.0.0";
|
||||
|
||||
import "vnet/interface_types.api";
|
||||
import "vnet/ip/ip_types.api";
|
||||
|
||||
define snort_instance_create {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 queue_size;
|
||||
u8 drop_on_disconnect;
|
||||
string name[];
|
||||
};
|
||||
|
||||
define snort_instance_create_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 instance_index;
|
||||
};
|
||||
|
||||
define snort_instance_delete {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 instance_index;
|
||||
};
|
||||
|
||||
define snort_instance_delete_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
define snort_client_disconnect {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 snort_client_index;
|
||||
};
|
||||
|
||||
define snort_client_disconnect_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
define snort_instance_disconnect {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 instance_index;
|
||||
};
|
||||
|
||||
define snort_instance_disconnect_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
define snort_interface_attach {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 instance_index;
|
||||
u32 sw_if_index;
|
||||
u8 snort_dir;
|
||||
};
|
||||
|
||||
define snort_interface_attach_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
define snort_interface_detach {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
define snort_interface_detach_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
define snort_input_mode_get {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
};
|
||||
|
||||
define snort_input_mode_get_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 snort_mode;
|
||||
};
|
||||
|
||||
define snort_input_mode_set {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u8 input_mode;
|
||||
};
|
||||
|
||||
define snort_input_mode_set_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
service {
|
||||
rpc snort_instance_get returns snort_instance_get_reply
|
||||
stream snort_instance_details;
|
||||
};
|
||||
|
||||
/** \brief Get snort instance(s).
|
||||
@param client_index - opaque cookie to identify the sender.
|
||||
@param context - sender context
|
||||
@param cursor - current iterator value (all requested).
|
||||
@param instance_index - instance index (~0 for all).
|
||||
*/
|
||||
define snort_instance_get
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 cursor;
|
||||
u32 instance_index;
|
||||
};
|
||||
|
||||
/** \brief Reply for snort instance(s).
|
||||
@param context - sender context
|
||||
@param retval - return code for the request.
|
||||
@param cursor - iterator value to continue with (if there is more).
|
||||
*/
|
||||
define snort_instance_get_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 cursor;
|
||||
};
|
||||
|
||||
/** \brief Details of a snort instance.
|
||||
@param context - sender context
|
||||
@param instance - snort instance info.
|
||||
*/
|
||||
define snort_instance_details {
|
||||
u32 context;
|
||||
u32 instance_index;
|
||||
u32 shm_size;
|
||||
u32 shm_fd;
|
||||
u8 drop_on_disconnect;
|
||||
u32 snort_client_index;
|
||||
string name[];
|
||||
};
|
||||
|
||||
service {
|
||||
rpc snort_interface_get returns snort_interface_get_reply
|
||||
stream snort_interface_details;
|
||||
};
|
||||
|
||||
/** \brief Get snort interface(s).
|
||||
@param client_index - opaque cookie to identify the sender.
|
||||
@param context - sender context
|
||||
@param cursor - current iterator value (all requested).
|
||||
@param sw_if_index - sw if index (~0 for all).
|
||||
*/
|
||||
define snort_interface_get
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 cursor;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Reply for snort interface(s).
|
||||
@param context - sender context
|
||||
@param retval - return code for the request.
|
||||
@param cursor - iterator value to continue with (if there is more).
|
||||
*/
|
||||
define snort_interface_get_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 cursor;
|
||||
};
|
||||
|
||||
/** \brief Details of a snort interface.
|
||||
@param context - sender context
|
||||
@param sw_if_index - interface index
|
||||
@param instance_index - snort instance the interface is attached to.
|
||||
*/
|
||||
define snort_interface_details {
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
u32 instance_index;
|
||||
};
|
||||
|
||||
service {
|
||||
rpc snort_client_get returns snort_client_get_reply
|
||||
stream snort_client_details;
|
||||
};
|
||||
|
||||
/** \brief Get snort clients.
|
||||
@param client_index - opaque cookie to identify the sender.
|
||||
@param context - sender context
|
||||
@param cursor - current iterator value (all requested).
|
||||
@param client_index (~0 for all).
|
||||
*/
|
||||
define snort_client_get
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 cursor;
|
||||
u32 snort_client_index;
|
||||
};
|
||||
|
||||
/** \brief Reply for snort clients.
|
||||
@param context - sender context
|
||||
@param retval - return code for the request.
|
||||
@param cursor - iterator value to continue with (if there is more).
|
||||
*/
|
||||
define snort_client_get_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 cursor;
|
||||
};
|
||||
|
||||
/** \brief Details of a snort client.
|
||||
@param context - sender context
|
||||
@param client index
|
||||
@param instance_index - snort instance of the client.
|
||||
*/
|
||||
define snort_client_details {
|
||||
u32 context;
|
||||
u32 client_index;
|
||||
u32 instance_index;
|
||||
};
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/socket.h>
|
||||
#include <vppinfra/file.h>
|
||||
#include <vlib/vlib.h>
|
||||
#include <snort/daq_vpp.h>
|
||||
|
||||
@ -78,8 +79,11 @@ typedef struct
|
||||
snort_per_thread_data_t *per_thread_data;
|
||||
u32 input_mode;
|
||||
u8 *socket_name;
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
} snort_main_t;
|
||||
|
||||
extern clib_file_main_t file_main;
|
||||
extern snort_main_t snort_main;
|
||||
extern vlib_node_registration_t snort_enq_node;
|
||||
extern vlib_node_registration_t snort_deq_node;
|
||||
@ -103,13 +107,17 @@ typedef enum
|
||||
}
|
||||
|
||||
/* 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,
|
||||
snort_attach_dir_t dir);
|
||||
clib_error_t *snort_set_node_mode (vlib_main_t *vm, u32 mode);
|
||||
snort_main_t *snort_get_main ();
|
||||
snort_instance_t *snort_get_instance_by_index (u32 instance_index);
|
||||
snort_instance_t *snort_get_instance_by_name (char *name);
|
||||
int snort_instance_create (vlib_main_t *vm, char *name, u8 log2_queue_sz,
|
||||
u8 drop_on_disconnect);
|
||||
int snort_interface_enable_disable (vlib_main_t *vm, char *instance_name,
|
||||
u32 sw_if_index, int is_enable,
|
||||
snort_attach_dir_t dir);
|
||||
int snort_set_node_mode (vlib_main_t *vm, u32 mode);
|
||||
int snort_instance_delete (vlib_main_t *vm, u32 instance_index);
|
||||
int snort_instance_disconnect (vlib_main_t *vm, u32 instance_index);
|
||||
|
||||
always_inline void
|
||||
snort_freelist_init (u32 *fl)
|
||||
|
398
src/plugins/snort/snort_api.c
Normal file
398
src/plugins/snort/snort_api.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@ class TestSnort(VppTestCase):
|
||||
def test_snort_cli(self):
|
||||
# TODO: add a test with packets
|
||||
# { cli command : part of the expected reply }
|
||||
print("TEST SNORT CLI")
|
||||
commands_replies = {
|
||||
"snort create-instance name snortTest queue-size 16 on-disconnect drop": "",
|
||||
"snort create-instance name snortTest2 queue-size 16 on-disconnect pass": "",
|
||||
@ -43,6 +44,7 @@ class TestSnort(VppTestCase):
|
||||
"snort mode interrupt": "",
|
||||
"snort detach interface pg0": "",
|
||||
"snort detach interface pg1": "",
|
||||
"snort delete instance snortTest": "",
|
||||
}
|
||||
|
||||
for command, reply in commands_replies.items():
|
||||
@ -50,5 +52,101 @@ class TestSnort(VppTestCase):
|
||||
self.assertIn(reply, actual_reply)
|
||||
|
||||
|
||||
@unittest.skipIf("snort" in config.excluded_plugins, "Exclude snort plugin test")
|
||||
class TestSnortVapi(VppTestCase):
|
||||
"""Snort plugin test [VAPI]"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestSnortVapi, cls).setUpClass()
|
||||
try:
|
||||
cls.create_pg_interfaces(range(2))
|
||||
for i in cls.pg_interfaces:
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
i.admin_up()
|
||||
except Exception:
|
||||
cls.tearDownClass()
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
for i in cls.pg_interfaces:
|
||||
i.unconfig_ip4()
|
||||
i.admin_down()
|
||||
super(TestSnortVapi, cls).tearDownClass()
|
||||
|
||||
def test_snort_01_modes_set_interrupt(self):
|
||||
"""Set mode to interrupt"""
|
||||
self.vapi.snort_input_mode_set(input_mode=1)
|
||||
reply = self.vapi.snort_input_mode_get()
|
||||
self.assertEqual(reply.snort_mode, 1)
|
||||
reply = self.vapi.cli("show snort mode")
|
||||
self.assertIn("interrupt", reply)
|
||||
|
||||
def test_snort_02_modes_set_polling(self):
|
||||
"""Set mode to polling"""
|
||||
self.vapi.snort_input_mode_set(input_mode=0)
|
||||
reply = self.vapi.snort_input_mode_get()
|
||||
self.assertEqual(reply.snort_mode, 0)
|
||||
|
||||
def test_snort_03_create(self):
|
||||
"""Create two snort instances"""
|
||||
reply = self.vapi.snort_instance_create(
|
||||
queue_size=8, drop_on_disconnect=0, name="snortTest0"
|
||||
)
|
||||
self.assertEqual(reply.instance_index, 0)
|
||||
reply = self.vapi.snort_instance_create(
|
||||
queue_size=32, drop_on_disconnect=1, name="snortTest1"
|
||||
)
|
||||
self.assertEqual(reply.instance_index, 1)
|
||||
reply = self.vapi.cli("show snort instances")
|
||||
self.assertIn("snortTest0", reply)
|
||||
self.assertIn("snortTest1", reply)
|
||||
|
||||
def test_snort_04_attach_if(self):
|
||||
"""Interfaces can be attached"""
|
||||
reply = self.vapi.snort_interface_attach(
|
||||
instance_index=0, sw_if_index=1, snort_dir=1
|
||||
)
|
||||
try:
|
||||
reply = self.vapi.snort_interface_attach(
|
||||
instance_index=1, sw_if_index=1, snort_dir=1
|
||||
)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.assertNotEqual(reply.retval, 0)
|
||||
|
||||
reply = self.vapi.snort_interface_attach(
|
||||
instance_index=1, sw_if_index=2, snort_dir=3
|
||||
)
|
||||
reply = self.vapi.cli("show snort interfaces")
|
||||
self.assertIn("snortTest0", reply)
|
||||
self.assertIn("snortTest1", reply)
|
||||
|
||||
def test_snort_05_delete_instance(self):
|
||||
"""Instances can be deleted"""
|
||||
reply = self.vapi.snort_instance_delete(instance_index=0)
|
||||
reply = self.vapi.cli("show snort interfaces")
|
||||
self.assertNotIn("snortTest0", reply)
|
||||
self.assertIn("snortTest1", reply)
|
||||
reply = self.vapi.cli("show snort interfaces")
|
||||
self.assertNotIn("pg0", reply)
|
||||
self.assertIn("pg1", reply)
|
||||
|
||||
def test_snort_06_detach_if(self):
|
||||
"""Interfaces can be detached"""
|
||||
try:
|
||||
reply = self.vapi.snort_interface_detach(sw_if_index=1)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.assertNotEqual(reply.retval, 0)
|
||||
reply = self.vapi.snort_interface_detach(sw_if_index=2)
|
||||
reply = self.vapi.cli("show snort interfaces")
|
||||
self.assertNotIn("pg1", reply)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
Loading…
x
Reference in New Issue
Block a user