mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
11 KiB
C
365 lines
11 KiB
C
/* Copyright (C) 2007-2013 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* \author Anoop Saldanha <anoopsaldanha@gmail.com>
|
|
*/
|
|
|
|
/* compile in, only if we have a CUDA enabled device on the machine, with the
|
|
* toolkit and the driver installed */
|
|
|
|
#include "suricata-common.h"
|
|
|
|
#ifdef __SC_CUDA_SUPPORT__
|
|
|
|
#include "util-error.h"
|
|
#include "util-debug.h"
|
|
#include "conf.h"
|
|
#include "util-cuda.h"
|
|
#include "util-cuda-handlers.h"
|
|
|
|
/* file only exists if cuda is enabled */
|
|
#include "cuda-ptxdump.h"
|
|
|
|
/************************conf file profile section**********************/
|
|
|
|
typedef struct CudaHandlerConfProfile_ {
|
|
char *name;
|
|
void *ctx;
|
|
void (*Free)(void *);
|
|
|
|
struct CudaHandlerConfProfile_ *next;
|
|
} CudaHandlerConfProfile;
|
|
|
|
static CudaHandlerConfProfile *conf_profiles = NULL;
|
|
/* protects above var */
|
|
static SCMutex mutex = SCMUTEX_INITIALIZER;
|
|
|
|
void CudaHandlerAddCudaProfileFromConf(const char *name,
|
|
void *(*Callback)(ConfNode *node),
|
|
void (*Free)(void *))
|
|
{
|
|
/* we don't do data validation */
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerConfProfile *tmp_cp = conf_profiles;
|
|
while (tmp_cp != NULL && strcasecmp(name, tmp_cp->name) != 0)
|
|
tmp_cp = tmp_cp->next;
|
|
|
|
if (tmp_cp != NULL) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "We already have a cuda conf "
|
|
"profile by the name \"%s\" registered.", name);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char tmp[200];
|
|
int r = snprintf(tmp, sizeof(tmp), "%s%s", "cuda.", name);
|
|
if (r < 0) {
|
|
SCLogError(SC_ERR_FATAL, "snprintf failure.");
|
|
exit(EXIT_FAILURE);
|
|
} else if (r > (int)sizeof(tmp)) {
|
|
SCLogError(SC_ERR_FATAL, "buffer not big enough to write param.");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
void *ctx = Callback(ConfGetNode(tmp));
|
|
if (ctx == NULL) {
|
|
SCMutexUnlock(&mutex);
|
|
return;
|
|
}
|
|
|
|
CudaHandlerConfProfile *new_cp = SCMalloc(sizeof(CudaHandlerConfProfile));
|
|
if (unlikely(new_cp == NULL))
|
|
exit(EXIT_FAILURE);
|
|
memset(new_cp, 0, sizeof(CudaHandlerConfProfile));
|
|
new_cp->name = SCStrdup(name);
|
|
if (new_cp->name == NULL)
|
|
exit(EXIT_FAILURE);
|
|
new_cp->ctx = ctx;
|
|
new_cp->Free = Free;
|
|
|
|
if (conf_profiles == NULL) {
|
|
conf_profiles = new_cp;
|
|
} else {
|
|
new_cp->next = conf_profiles;
|
|
conf_profiles = new_cp;
|
|
}
|
|
|
|
SCMutexUnlock(&mutex);
|
|
return;
|
|
}
|
|
|
|
void *CudaHandlerGetCudaProfile(const char *name)
|
|
{
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerConfProfile *tmp_cp = conf_profiles;
|
|
while (tmp_cp != NULL && strcasecmp(name, tmp_cp->name) != 0)
|
|
tmp_cp = tmp_cp->next;
|
|
|
|
if (tmp_cp == NULL) {
|
|
SCMutexUnlock(&mutex);
|
|
return NULL;
|
|
}
|
|
|
|
SCMutexUnlock(&mutex);
|
|
return tmp_cp->ctx;
|
|
}
|
|
|
|
void CudaHandlerFreeProfiles(void)
|
|
{
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerConfProfile *tmp = conf_profiles;
|
|
while (tmp != NULL) {
|
|
CudaHandlerConfProfile *curr = tmp;
|
|
tmp = tmp->next;
|
|
SCFree(curr->name);
|
|
if (curr->Free != NULL)
|
|
curr->Free(curr->ctx);
|
|
SCFree(curr);
|
|
}
|
|
|
|
SCMutexUnlock(&mutex);
|
|
return;
|
|
}
|
|
|
|
/*******************cuda context related data section*******************/
|
|
|
|
/* we use a concept where every device on the gpu has only 1 context. If
|
|
* a section in the engine wants to use a device and tries to open a context
|
|
* on it, we first check if a context is already created for the device and if
|
|
* so we return it. If not we create a new one and update with the entry */
|
|
|
|
static CUcontext *cuda_contexts = NULL;
|
|
static int no_of_cuda_contexts = 0;
|
|
|
|
typedef struct CudaHandlerModuleData_ {
|
|
char *name;
|
|
void *data;
|
|
|
|
struct CudaHandlerModuleData_ *next;
|
|
} CudaHandlerModuleData;
|
|
|
|
typedef struct CudaHandlerModule_ {
|
|
char *name;
|
|
|
|
/* the context used by this module */
|
|
CUcontext context;
|
|
/* the device on which the above context was created */
|
|
int device_id;
|
|
CudaHandlerModuleData *module_data;
|
|
|
|
struct CudaHandlerModule_ *next;
|
|
} CudaHandlerModule;
|
|
|
|
static CudaHandlerModule *cudahl_modules = NULL;
|
|
|
|
CUcontext CudaHandlerModuleGetContext(const char *name, int device_id)
|
|
{
|
|
void *ptmp;
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerModule *module = cudahl_modules;
|
|
while (module != NULL && strcasecmp(module->name, name) != 0)
|
|
module = module->next;
|
|
if (module != NULL) {
|
|
if (module->device_id != device_id) {
|
|
SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Module already "
|
|
"registered, but the new device_id is different "
|
|
"from the already registered device_id.");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
SCMutexUnlock(&mutex);
|
|
return module->context;
|
|
}
|
|
|
|
CudaHandlerModule *new_module = SCMalloc(sizeof(CudaHandlerModule));
|
|
if (unlikely(new_module == NULL))
|
|
exit(EXIT_FAILURE);
|
|
memset(new_module, 0, sizeof(CudaHandlerModule));
|
|
new_module->device_id = device_id;
|
|
new_module->name = SCStrdup(name);
|
|
if (new_module->name == NULL)
|
|
exit(EXIT_FAILURE);
|
|
if (cudahl_modules == NULL) {
|
|
cudahl_modules = new_module;
|
|
} else {
|
|
new_module->next = cudahl_modules;
|
|
cudahl_modules = new_module;
|
|
}
|
|
|
|
if (no_of_cuda_contexts <= device_id) {
|
|
ptmp = SCRealloc(cuda_contexts, sizeof(CUcontext) * (device_id + 1));
|
|
if (unlikely(ptmp == NULL)) {
|
|
SCFree(cuda_contexts);
|
|
cuda_contexts = NULL;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
cuda_contexts = ptmp;
|
|
|
|
memset(cuda_contexts + no_of_cuda_contexts, 0,
|
|
sizeof(CUcontext) * ((device_id + 1) - no_of_cuda_contexts));
|
|
no_of_cuda_contexts = device_id + 1;
|
|
}
|
|
|
|
if (cuda_contexts[device_id] == 0) {
|
|
SCCudaDevices *devices = SCCudaGetDeviceList();
|
|
if (SCCudaCtxCreate(&cuda_contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC,
|
|
devices->devices[device_id]->device) == -1) {
|
|
SCLogDebug("ctxcreate failure.");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
new_module->context = cuda_contexts[device_id];
|
|
|
|
SCMutexUnlock(&mutex);
|
|
return cuda_contexts[device_id];
|
|
}
|
|
|
|
void CudaHandlerModuleStoreData(const char *module_name,
|
|
const char *data_name, void *data_ptr)
|
|
{
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerModule *module = cudahl_modules;
|
|
while (module != NULL && strcasecmp(module->name, module_name) != 0)
|
|
module = module->next;
|
|
if (module == NULL) {
|
|
SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Trying to retrieve data "
|
|
"\"%s\" from module \"%s\" that hasn't been registered "
|
|
"yet.", module_name, data_name);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
CudaHandlerModuleData *data = module->module_data;
|
|
while (data != NULL && (strcasecmp(data_name, data->name) != 0)) {
|
|
data = data->next;
|
|
}
|
|
if (data != NULL) {
|
|
SCLogWarning(SC_ERR_CUDA_HANDLER_ERROR, "Data \"%s\" already "
|
|
"registered for this module \"%s\".", data_name,
|
|
module_name);
|
|
SCMutexUnlock(&mutex);
|
|
goto end;
|
|
}
|
|
|
|
CudaHandlerModuleData *new_data = SCMalloc(sizeof(CudaHandlerModuleData));
|
|
if (unlikely(new_data == NULL))
|
|
exit(EXIT_FAILURE);
|
|
memset(new_data, 0, sizeof(CudaHandlerModuleData));
|
|
new_data->name = SCStrdup(data_name);
|
|
if (new_data->name == NULL)
|
|
exit(EXIT_FAILURE);
|
|
new_data->data = data_ptr;
|
|
|
|
if (module->module_data == NULL) {
|
|
module->module_data = new_data;
|
|
} else {
|
|
new_data->next = module->module_data;
|
|
module->module_data = new_data;
|
|
}
|
|
|
|
SCMutexUnlock(&mutex);
|
|
|
|
end:
|
|
return;
|
|
}
|
|
|
|
void *CudaHandlerModuleGetData(const char *module_name, const char *data_name)
|
|
{
|
|
SCMutexLock(&mutex);
|
|
|
|
CudaHandlerModule *module = cudahl_modules;
|
|
while (module != NULL && strcasecmp(module->name, module_name) != 0)
|
|
module = module->next;
|
|
if (module == NULL) {
|
|
SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Trying to retrieve data "
|
|
"\"%s\" from module \"%s\" that hasn't been registered "
|
|
"yet.", module_name, data_name);
|
|
SCMutexUnlock(&mutex);
|
|
return NULL;
|
|
}
|
|
|
|
CudaHandlerModuleData *data = module->module_data;
|
|
while (data != NULL && (strcasecmp(data_name, data->name) != 0)) {
|
|
data = data->next;
|
|
}
|
|
if (data == NULL) {
|
|
SCLogInfo("Data \"%s\" already registered for this module \"%s\". "
|
|
"Returning it.", data_name, module_name);
|
|
SCMutexUnlock(&mutex);
|
|
return NULL;
|
|
}
|
|
|
|
SCMutexUnlock(&mutex);
|
|
return data->data;
|
|
}
|
|
|
|
int CudaHandlerGetCudaModule(CUmodule *p_module, const char *ptx_image)
|
|
{
|
|
#define CUDA_HANDLER_GET_CUDA_MODULE_BUFFER_EXTRA_SPACE 15
|
|
|
|
int i = 0;
|
|
|
|
/* select the ptx image based on the compute capability supported by all
|
|
* devices (i.e. the lowest) */
|
|
char *image = SCMalloc(strlen(ptx_image) + CUDA_HANDLER_GET_CUDA_MODULE_BUFFER_EXTRA_SPACE);
|
|
if (unlikely(image == NULL)) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
memset(image, 0x00, strlen(ptx_image) + CUDA_HANDLER_GET_CUDA_MODULE_BUFFER_EXTRA_SPACE);
|
|
|
|
int major = INT_MAX;
|
|
int minor = INT_MAX;
|
|
SCCudaDevices *devices = SCCudaGetDeviceList();
|
|
for (i = 0; i < devices->count; i++){
|
|
if (devices->devices[i]->major_rev < major){
|
|
major = devices->devices[i]->major_rev;
|
|
minor = devices->devices[i]->minor_rev;
|
|
}
|
|
if (devices->devices[i]->major_rev == major &&
|
|
devices->devices[i]->minor_rev < minor){
|
|
minor = devices->devices[i]->minor_rev;
|
|
}
|
|
}
|
|
snprintf(image,
|
|
strlen(ptx_image) + CUDA_HANDLER_GET_CUDA_MODULE_BUFFER_EXTRA_SPACE,
|
|
"%s_sm_%u%u",
|
|
ptx_image, major, minor);
|
|
|
|
/* we don't have a cuda module associated with this module. Create a
|
|
* cuda module, update the module with this cuda module reference and
|
|
* then return the module refernce back to the calling function using
|
|
* the argument */
|
|
SCLogDebug("Loading kernel module: %s\n",image);
|
|
if (SCCudaModuleLoadData(p_module, (void *)SCCudaPtxDumpGetModule(image)) == -1)
|
|
goto error;
|
|
SCFree(image);
|
|
|
|
return 0;
|
|
error:
|
|
SCFree(image);
|
|
return -1;
|
|
|
|
#undef CUDA_HANDLER_GET_CUDA_MODULE_BUFFER_EXTRA_SPACE
|
|
}
|
|
|
|
|
|
#endif /* __SC_CUDA_SUPPORT__ */
|