multi-tenant: introduce device selector

Add device to tenant mapping support:

  mappings:
  - device: ens5f0
    tenant-id: 1
  - device: ens5f1
    tenant-id: 23

Implemented by assigning the tenant id to the 'livedev', which means
it's only supported for capture methods that use the livedev API.

It's also currently not supported for IPS. In a case like 'eth0 -> eth1'
it's unclear which tenant should be used for the return traffic in a
flow, where the incoming device is 'eth1'.
pull/3447/head
Victor Julien 9 years ago
parent a337908c78
commit 12fec46d13

@ -73,7 +73,7 @@
#include "util-magic.h"
#include "util-signal.h"
#include "util-spm.h"
#include "util-device.h"
#include "util-var-name.h"
#include "tm-threads.h"
@ -98,6 +98,7 @@ static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
static void TenantIdFree(void *d);
static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p);
static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p);
static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p);
@ -2168,6 +2169,10 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread
det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
SCLogDebug("TENANT_SELECTOR_VLAN");
break;
case TENANT_SELECTOR_LIVEDEV:
det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
SCLogDebug("TENANT_SELECTOR_LIVEDEV");
break;
case TENANT_SELECTOR_DIRECT:
det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
SCLogDebug("TENANT_SELECTOR_DIRECT");
@ -2932,6 +2937,122 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r
return 0;
}
static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
bool failure_fatal)
{
ConfNode *mapping_node = NULL;
int mapping_cnt = 0;
if (mappings_root_node != NULL) {
TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
if (tenant_id_node == NULL)
goto bad_mapping;
ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
if (device_node == NULL)
goto bad_mapping;
uint32_t tenant_id = 0;
if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
tenant_id_node->val) == -1)
{
SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
"of %s is invalid", tenant_id_node->val);
goto bad_mapping;
}
const char *dev = device_node->val;
LiveDevice *ld = LiveGetDevice(dev);
if (ld == NULL) {
SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
goto bad_mapping;
}
if (ld->tenant_id_set) {
SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
dev, ld->tenant_id);
goto bad_mapping;
}
ld->tenant_id = tenant_id;
ld->tenant_id_set = true;
if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
goto error;
}
SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
mapping_cnt++;
continue;
bad_mapping:
if (failure_fatal)
goto error;
}
}
SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
return mapping_cnt;
error:
return 0;
}
static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
bool failure_fatal)
{
ConfNode *mapping_node = NULL;
int mapping_cnt = 0;
if (mappings_root_node != NULL) {
TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
if (tenant_id_node == NULL)
goto bad_mapping;
ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
if (vlan_id_node == NULL)
goto bad_mapping;
uint32_t tenant_id = 0;
if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
tenant_id_node->val) == -1)
{
SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
"of %s is invalid", tenant_id_node->val);
goto bad_mapping;
}
uint16_t vlan_id = 0;
if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val),
vlan_id_node->val) == -1)
{
SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
"of %s is invalid", vlan_id_node->val);
goto bad_mapping;
}
if (vlan_id == 0 || vlan_id >= 4095) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
"of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
goto bad_mapping;
}
if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
goto error;
}
SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
mapping_cnt++;
continue;
bad_mapping:
if (failure_fatal)
goto error;
}
}
return mapping_cnt;
error:
return 0;
}
/**
* \brief setup multi-detect / multi-tenancy
*
@ -2977,6 +3098,15 @@ int DetectEngineMultiTenantSetup(void)
} else if (strcmp(handler, "direct") == 0) {
tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
} else if (strcmp(handler, "device") == 0) {
tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
if (EngineModeIsIPS()) {
SCLogWarning(SC_ERR_MT_NO_MAPPING,
"multi-tenant 'device' mode not supported for IPS");
SCMutexUnlock(&master->lock);
goto error;
}
} else {
SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
"multi-detect.selector", handler);
@ -2989,63 +3119,31 @@ int DetectEngineMultiTenantSetup(void)
/* traffic -- tenant mappings */
ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
ConfNode *mapping_node = NULL;
int mapping_cnt = 0;
if (mappings_root_node != NULL) {
TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
if (tenant_id_node == NULL)
goto bad_mapping;
ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
if (vlan_id_node == NULL)
goto bad_mapping;
uint32_t tenant_id = 0;
if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
tenant_id_node->val) == -1)
{
SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
"of %s is invalid", tenant_id_node->val);
goto bad_mapping;
}
uint16_t vlan_id = 0;
if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val),
vlan_id_node->val) == -1)
{
SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
"of %s is invalid", vlan_id_node->val);
goto bad_mapping;
}
if (vlan_id == 0 || vlan_id >= 4095) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
"of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
goto bad_mapping;
}
if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
goto error;
if (tenant_selector == TENANT_SELECTOR_VLAN) {
int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
failure_fatal);
if (mapping_cnt == 0) {
/* no mappings are valid when we're in unix socket mode,
* they can be added on the fly. Otherwise warn/error
* depending on failure_fatal */
if (unix_socket) {
SCLogNotice("no tenant traffic mappings defined, "
"tenants won't be used until mappings are added");
} else {
if (failure_fatal) {
SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
goto error;
} else {
SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
}
}
SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
mapping_cnt++;
continue;
bad_mapping:
if (failure_fatal)
goto error;
}
}
if (tenant_selector == TENANT_SELECTOR_VLAN && mapping_cnt == 0) {
/* no mappings are valid when we're in unix socket mode,
* they can be added on the fly. Otherwise warn/error
* depending on failure_fatal */
if (unix_socket) {
SCLogNotice("no tenant traffic mappings defined, "
"tenants won't be used until mappings are added");
} else {
} else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
failure_fatal);
if (mapping_cnt == 0) {
if (failure_fatal) {
SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
goto error;
@ -3141,6 +3239,18 @@ static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet
return 0;
}
static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
{
const DetectEngineThreadCtx *det_ctx = ctx;
const LiveDevice *ld = p->livedev;
if (ld == NULL || det_ctx == NULL)
return 0;
SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
return ld->tenant_id;
}
static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
uint32_t tenant_id, uint32_t traffic_id)
{
@ -3218,6 +3328,11 @@ static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelector
return -1;
}
int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
{
return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
}
int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
{
return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);

@ -102,6 +102,7 @@ int DetectEngineReloadIsIdle(void);
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml);
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt);
int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id);
int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id);
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id);
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id);

@ -1325,6 +1325,7 @@ enum DetectEngineTenantSelectors
TENANT_SELECTOR_UNKNOWN = 0, /**< not set */
TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */
TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */
TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */
};
typedef struct DetectEngineTenantMapping_ {

@ -133,6 +133,7 @@ int LiveRegisterDevice(const char *dev)
SC_ATOMIC_INIT(pd->drop);
SC_ATOMIC_INIT(pd->invalid_checksums);
pd->ignore_checksum = 0;
pd->id = LiveGetDeviceCount();
TAILQ_INSERT_TAIL(&live_devices, pd, next);
SCLogDebug("Device \"%s\" registered and created.", dev);

@ -40,13 +40,18 @@ int LiveGetOffload(void);
typedef struct LiveDevice_ {
char *dev; /**< the device (e.g. "eth0") */
char dev_short[MAX_DEVNAME + 1];
bool tenant_id_set;
int ignore_checksum;
int id;
SC_ATOMIC_DECLARE(uint64_t, pkts);
SC_ATOMIC_DECLARE(uint64_t, drop);
SC_ATOMIC_DECLARE(uint64_t, bypassed);
SC_ATOMIC_DECLARE(uint64_t, invalid_checksums);
TAILQ_ENTRY(LiveDevice_) next;
uint32_t tenant_id; /**< tenant id in multi-tenancy */
uint32_t offload_orig; /**< original offload settings to restore @exit */
} LiveDevice;

Loading…
Cancel
Save