From 45d5c3ca59cf0d8809aecdf61340e521da54963d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 30 Sep 2011 16:50:50 +0200 Subject: [PATCH] runmode: introduce configuration dereferencing. A devide configuration can be used by multiple threads. It is thus necessary to wait that all threads stop using the configuration before freeing it. This patch introduces an atomic counter and a free function which has to be called by each thread when it will not use anymore the structure. If the configuration is not used anymore, it is freed by the free function. --- src/runmode-af-packet.c | 16 ++++++++++++++++ src/runmode-pcap.c | 17 +++++++++++++++++ src/runmode-pfring.c | 21 +++++++++++++++++++++ src/source-af-packet.c | 9 ++++++--- src/source-af-packet.h | 2 ++ src/source-pcap.c | 34 ++++++++++++++++++++++++++++++---- src/source-pcap.h | 2 ++ src/source-pfring.c | 12 +++++++++++- src/source-pfring.h | 2 ++ 9 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 031d58846e..2a49acff97 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -78,6 +78,15 @@ void RunModeIdsAFPRegister(void) return; } +void AFPDerefConfig(void *conf) +{ + AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; + /* Pcap config is used only once but cost of this low. */ + if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { + SCFree(pfp); + } +} + /** * \brief extract information from config file * @@ -108,10 +117,13 @@ void *ParseAFPConfig(const char *iface) } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 1; + SC_ATOMIC_INIT(aconf->ref); + SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = PACKET_FANOUT_HASH; aconf->promisc = 1; + aconf->DerefFunc = AFPDerefConfig; /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); @@ -138,6 +150,10 @@ void *ParseAFPConfig(const char *iface) if (aconf->threads == 0) { aconf->threads = 1; } + + SC_ATOMIC_RESET(aconf->ref); + SC_ATOMIC_ADD(aconf->ref, aconf->threads); + if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 51c3d44b33..4f764acbfd 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -39,6 +39,7 @@ #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" +#include "util-atomic.h" static const char *default_mode = NULL; @@ -67,6 +68,18 @@ void RunModeIdsPcapRegister(void) return; } +void PcapDerefConfig(void *conf) +{ + PcapIfaceConfig *pfp = (PcapIfaceConfig *)conf; + /* Pcap config is used only once but cost of this low. */ + if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { + if (pfp->bpf_filter) { + SCFree(pfp->bpf_filter); + } + SCFree(pfp); + } +} + void *ParsePcapConfig(const char *iface) { @@ -96,6 +109,10 @@ void *ParsePcapConfig(const char *iface) aconf->bpf_filter = tmpbpf; } + SC_ATOMIC_INIT(aconf->ref); + SC_ATOMIC_ADD(aconf->ref, 1); + aconf->DerefFunc = PcapDerefConfig; + /* Find initial node */ pcap_node = ConfGetNode("pcap"); if (pcap_node == NULL) { diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index 4d02a3cea3..8204ccc4d4 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -75,6 +75,14 @@ void RunModeIdsPfringRegister(void) return; } +void PfringDerefConfig(void *conf) +{ + PfringIfaceConfig *pfp = (PfringIfaceConfig *)conf; + if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { + SCFree(pfp); + } +} + /** * \brief extract information from config file * @@ -111,6 +119,9 @@ void *OldParsePfringConfig(const char *iface) #ifdef HAVE_PFRING_CLUSTER_TYPE pfconf->ctype = (cluster_type)default_ctype; #endif + pfconf->DerefFunc = PfringDerefConfig; + SC_ATOMIC_INIT(pfconf->ref); + SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ if (ConfGet("pfring.threads", &threadsstr) != 1) { @@ -123,6 +134,10 @@ void *OldParsePfringConfig(const char *iface) if (pfconf->threads == 0) { pfconf->threads = 1; } + + SC_ATOMIC_RESET(pfconf->ref); + SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); + if (ConfGet("pfring.cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { @@ -190,6 +205,9 @@ void *ParsePfringConfig(const char *iface) #ifdef HAVE_PFRING_CLUSTER_TYPE pfconf->ctype = (cluster_type)default_ctype; #endif + pfconf->DerefFunc = PfringDerefConfig; + SC_ATOMIC_INIT(pfconf->ref); + SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ pf_ring_node = ConfGetNode("pfring"); @@ -220,6 +238,9 @@ void *ParsePfringConfig(const char *iface) pfconf->threads = 1; } + SC_ATOMIC_RESET(pfconf->ref); + SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); + /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index b6bae28ada..479cdbf27a 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -556,8 +556,10 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { } AFPThreadVars *ptv = SCMalloc(sizeof(AFPThreadVars)); - if (ptv == NULL) + if (ptv == NULL) { + afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_FAILED); + } memset(ptv, 0, sizeof(AFPThreadVars)); ptv->tv = tv; @@ -586,6 +588,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket"); SCFree(ptv); + afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_FAILED); } @@ -599,6 +602,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { #define T_DATA_SIZE 70000 ptv->data = SCMalloc(T_DATA_SIZE); if (ptv->data == NULL) { + afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_FAILED); } ptv->datalen = T_DATA_SIZE; @@ -607,8 +611,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { *data = (void *)ptv; - /* we've received a single use structure, we can free it */ - SCFree(initdata); + afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 78420a97c9..b43396dd83 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -51,6 +51,8 @@ typedef struct AFPIfaceConfig_ int cluster_type; /* promisc mode */ int promisc; + SC_ATOMIC_DECLARE(unsigned int, ref); + void (*DerefFunc)(void *); } AFPIfaceConfig; void TmModuleReceiveAFPRegister (void); diff --git a/src/source-pcap.c b/src/source-pcap.c index 0aba4b58b4..e53ca88854 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -295,8 +295,10 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { } PcapThreadVars *ptv = SCMalloc(sizeof(PcapThreadVars)); - if (ptv == NULL) + if (ptv == NULL) { + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); + } memset(ptv, 0, sizeof(PcapThreadVars)); ptv->tv = tv; @@ -308,6 +310,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (ptv->pcap_handle == NULL) { SCLogError(SC_ERR_PCAP_CREATE, "Coudn't create a new pcap handler, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } @@ -317,6 +320,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (pcap_set_snaplen_r != 0) { SCLogError(SC_ERR_PCAP_SET_SNAPLEN, "Couldn't set snaplen, error: %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } @@ -325,6 +329,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (pcap_set_promisc_r != 0) { SCLogError(SC_ERR_PCAP_SET_PROMISC, "Couldn't set promisc mode, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } @@ -333,6 +338,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (pcap_set_timeout_r != 0) { SCLogError(SC_ERR_PCAP_SET_TIMEOUT, "Problems setting timeout, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } #ifdef HAVE_PCAP_SET_BUFF @@ -345,6 +351,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (pcap_set_buffer_size_r != 0) { SCLogError(SC_ERR_PCAP_SET_BUFF_SIZE, "Problems setting pcap buffer size, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } } @@ -356,6 +363,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (pcap_activate_r != 0) { SCLogError(SC_ERR_PCAP_ACTIVATE_HANDLE, "Couldn't activate the pcap handler, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); ptv->pcap_state = PCAP_STATE_DOWN; } else { @@ -365,28 +373,34 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { /* set bpf filter if we have one */ if (pcapconfig->bpf_filter) { ptv->bpf_filter = SCStrdup(pcapconfig->bpf_filter); + /* free bpf as we are using a copy */ + SCFree(pcapconfig->bpf_filter); if(pcap_compile(ptv->pcap_handle,&ptv->filter,ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } } ptv->datalink = pcap_datalink(ptv->pcap_handle); + pcapconfig->DerefFunc(pcapconfig); + *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); } #else /* implied LIBPCAP_VERSION_MAJOR == 0 */ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); - + PcapIfaceConfig *pcapconfig = initdata; char *tmpbpfstring; if (initdata == NULL) { @@ -395,8 +409,11 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { } PcapThreadVars *ptv = SCMalloc(sizeof(PcapThreadVars)); - if (ptv == NULL) + if (ptv == NULL) { + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); + } memset(ptv, 0, sizeof(PcapThreadVars)); ptv->tv = tv; @@ -404,6 +421,8 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { SCLogInfo("using interface %s", (char *)initdata); if(strlen(initdata)>PCAP_IFACE_NAME_LENGTH) { SCFree(ptv); + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } strlcpy(ptv->iface, (char *)initdata, PCAP_IFACE_NAME_LENGTH); @@ -414,6 +433,8 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if (ptv->pcap_handle == NULL) { SCLogError(SC_ERR_PCAP_OPEN_LIVE, "Problem creating pcap handler for live mode, error %s", errbuf); SCFree(ptv); + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } @@ -425,20 +446,25 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { if(pcap_compile(ptv->pcap_handle,&ptv->filter, ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle)); SCFree(ptv); + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } } - ptv->datalink = pcap_datalink(ptv->pcap_handle); *data = (void *)ptv; + /* Dereference config */ + pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_OK); } #endif /* LIBPCAP_VERSION_MAJOR */ diff --git a/src/source-pcap.h b/src/source-pcap.h index 6af5f1716d..c312f02d28 100644 --- a/src/source-pcap.h +++ b/src/source-pcap.h @@ -51,6 +51,8 @@ typedef struct PcapIfaceConfig_ int buffer_size; /* BPF filter */ char *bpf_filter; + SC_ATOMIC_DECLARE(unsigned int, ref); + void (*DerefFunc)(void *); } PcapIfaceConfig; diff --git a/src/source-pfring.c b/src/source-pfring.c index dfd69b143b..78a8268fb1 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -275,9 +275,15 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { char *tmpctype; PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; + + if (pfconf == NULL) + return TM_ECODE_FAILED; + PfringThreadVars *ptv = SCMalloc(sizeof(PfringThreadVars)); - if (ptv == NULL) + if (ptv == NULL) { + pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; + } memset(ptv, 0, sizeof(PfringThreadVars)); ptv->tv = tv; @@ -289,6 +295,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { if (ptv->pd == NULL) { SCLogError(SC_ERR_PF_RING_OPEN,"opening %s failed: pfring_open error", ptv->interface); + pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } else { pfring_set_application_name(ptv->pd, PROG_NAME); @@ -311,6 +318,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { if (rc != 0) { SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " "returned %d for cluster-id: %d", rc, ptv->cluster_id); + pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", @@ -329,12 +337,14 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { if (rc != 0) { SCLogError(SC_ERR_PF_RING_OPEN, "pfring_enable failed returned %d ", rc); + pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } #endif /* HAVE_PFRING_ENABLE */ *data = (void *)ptv; + pfconf->DerefFunc(pfconf); return TM_ECODE_OK; } diff --git a/src/source-pfring.h b/src/source-pfring.h index cfe3335ef5..f39d8d8334 100644 --- a/src/source-pfring.h +++ b/src/source-pfring.h @@ -41,6 +41,8 @@ typedef struct PfringIfaceConfig_ char iface[PFRING_IFACE_NAME_LENGTH]; /* number of threads */ int threads; + SC_ATOMIC_DECLARE(unsigned int, ref); + void (*DerefFunc)(void *); } PfringIfaceConfig;