diff mbox

[APPS/PATCH] odp snort support initial version

Message ID 1400594170-32523-1-git-send-email-maxim.uvarov@linaro.org
State Accepted
Headers show

Commit Message

Maxim Uvarov May 20, 2014, 1:56 p.m. UTC
From: Maxim Uvarov <maxim.uvarov@linaro.org>

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 Looke like it's not easy to understand and review this patch in mailing list.
 I filtered our original apps from patch. And merged it to the repo:
	https://git.linaro.org/lng/odp-apps.git/commit/4da44db4b18d8f2d4ada64727088333ff045df83
 If there will suggestions and comments I will renew this commit.

 Initial work with smaller commits was done here:
	https://git.linaro.org/people/maxim.uvarov/odp-snort.git
 maybe my public tree is more clean for review then odp-apps.git.

 Best regards,
 Maxim.


 Makefile                                           |    7 +-
 snort/Makefile                                     |   65 +
 snort/README                                       |   37 +
 .../0001-implement-odp-daq-module.patch            |  477 ++
 snort/download/daq-2.0.2.tar.gz                    |  Bin 0 -> 474447 bytes
 snort/download/daq-2.0.2.tar.gz.md5                |    1 +
 snort/download/libdnet-1.11.tar.gz                 |  Bin 0 -> 446233 bytes
 snort/download/snort-2.9.6.0.tar.gz                |  Bin 0 -> 5189146 bytes
 .../0001-Compile-Snort-as-static-library.patch     |  114 +
 .../0002-remove-static-from-needed-functions.patch |   73 +
 .../0001-implement-odp_timer_disarm_all.patch      |   63 +
 snort/odpsnort/Makefile                            |   47 +
 snort/odpsnort/odp_pktio.c                         |  673 +++
 snort/odpsnort/odp_pktio.h                         |    1 +
 snort/odpsnort/snort.c                             | 5095 ++++++++++++++++++++
 .../0001-add-dependancy-for-lrt.patch              |   30 +
 16 files changed, 6682 insertions(+), 1 deletion(-)
 create mode 100644 snort/Makefile
 create mode 100644 snort/README
 create mode 100644 snort/daq-patches/0001-implement-odp-daq-module.patch
 create mode 100644 snort/download/daq-2.0.2.tar.gz
 create mode 100644 snort/download/daq-2.0.2.tar.gz.md5
 create mode 100644 snort/download/libdnet-1.11.tar.gz
 create mode 100644 snort/download/snort-2.9.6.0.tar.gz
 create mode 100644 snort/lib-patches/0001-Compile-Snort-as-static-library.patch
 create mode 100644 snort/lib-patches/0002-remove-static-from-needed-functions.patch
 create mode 100644 snort/odp-patches/0001-implement-odp_timer_disarm_all.patch
 create mode 100644 snort/odpsnort/Makefile
 create mode 100644 snort/odpsnort/odp_pktio.c
 create mode 100644 snort/odpsnort/odp_pktio.h
 create mode 100644 snort/odpsnort/snort.c
 create mode 100644 snort/snort-patches/0001-add-dependancy-for-lrt.patch

Comments

Stuart Haslam June 6, 2014, 5:20 p.m. UTC | #1
On Tue, May 20, 2014 at 02:56:10PM +0100, root wrote:
> From: Maxim Uvarov <maxim.uvarov@linaro.org>
> 
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>  Looke like it's not easy to understand and review this patch in mailing list.
>
>  I filtered our original apps from patch. And merged it to the repo:
>         https://git.linaro.org/lng/odp-apps.git/commit/4da44db4b18d8f2d4ada64727088333ff045df83
>  If there will suggestions and comments I will renew this commit.
> 
>  Initial work with smaller commits was done here:
>         https://git.linaro.org/people/maxim.uvarov/odp-snort.git
>  maybe my public tree is more clean for review then odp-apps.git.

It was pretty difficult to follow this patch. It would be good if you
gave a bit of an intro stating what you have done and the status of the
work, what testing has been done and any open issues.

I assumed that both the daq and odpsnort versions were usable so have
attempted to build and test them, but actually I couldn't get either
working at all without some fixes.

The ODP DAQ wouldn't receive any packets, sometimes one or two packets
would be received but usually nothing at all. Turns out this is a bug
in the socket MMAP implementation as changing daq_odp.c to use BASIC
sockets resolved the problem. It then managed a few hundred packets
before stopping, which turned out to be due to packets being leaked in
the DAQ, after fixing this it now runs pretty well.

I'll send a patch for the MMAP bug shortly.

I had other issues with odpsnort (details below) which I spent a bit of
time starting to work through, but then it became clear that it wasn't
going to work as intended (with multiple threads) without a lot of work
in snort to make it thread safe. I don't think it's viable to start
making those changes so as I see it there are a couple of options,
either start from the snort 3.0 code base that is already multi-threaded
(in places, at least the analysis engines are) or stick with using
multiple instances of snort (with the ODP DAQ) and distribute the
flows across them.

[..]

> @@ -8,10 +8,15 @@ libpcap: odp
>  openvpn: odp
>         make -C openvpn
> 
> +snort: odp
> +       make -C snort
> +
>  odp:
>         if [ ! -d odp.git ]; \
>                 then git clone http://git.linaro.org/git/lng/odp.git odp.git; \
>         fi
> +       cd odp.git; git reset --hard HEAD
> +       cd odp.git; patch -N -p1 < ../snort/odp-patches/0001-implement-odp_timer_disarm_all.patch

HEAD seems a bad idea if you want to ensure the patch applies, is there
some plan to resolve the need for this patch? I remember it was
discussed on the list but I don't remember the outcome.

>         cd odp.git; make libs_install  CFLAGS="-fPIC"
> 
>  distclean:
> --- /dev/null
> +++ b/snort/Makefile
> @@ -0,0 +1,65 @@
> +.PHONY: all odp daq snort odpsnort
> +all: snort
> +
> +DAQ="daq-2.0.2"
> +daqprep:
> +       rm -rf ${DAQ}
> +       tar xpvfz ./download/daq-2.0.2.tar.gz
> +       cd ${DAQ}; patch -p1 < ../daq-patches/0001-implement-odp-daq-module.patch
> +

Dependencies aren't used throughout this makefile, so the whole
extract-patch-configure-build process is re-done every time you run make.
This is pretty painful especially when you're going through a first time
build to resolve issues. I would've done the above like;

DAQ=daq-2.0.2
DAQ_TGZ=./download/$(DAQ).tar.gz
DAQ_PATCH=../daq-patches/0001-implement-odp-daq-module.patch

daqprep: $(DAQ)/.patched

$(DAQ)/.patched: $(DAQ_TGZ) $(DAQ_PATCH)
	rm -rf $(DAQ)
	tar ..
	patch ..
	@touch $@

> +
> +daq: daqprep libdnet
> +       cd ${DAQ}; autoreconf

This fails for me with automake version 1.14.1 (ubuntu trusty), it seems
to expect automake 1.11.1. I did pursue it a little but got further
errors so moved to an older release.

> +       cd ${DAQ}; ./configure CFLAGS="-I${PWD}/../odp.git/build/include -g -O0" LDFLAGS="-g -L${PWD}/../odp.git/build/lib"

It would be good to be able to avoid needing to have another copy of the
odp source tree.. how about;

ODP_SOURCE_DIR?=$(PWD)/../odp/

> +       cd ${DAQ}; make
> +       cd ${DAQ}; make install

I shouldn't need to be root to build this, installs should go into a
local directory (i.e. use ./configure --prefix=DIR).

> +
> +
> +snortprep:
> +       rm -rf snort-2.9.6.0
> +       tar xpfz download/snort-2.9.6.0.tar.gz
> +
> +SNORT="snort-2.9.6.1-odp"

Should be 2.9.6.0

[..]

> +SNORT-lib="snort-2.9.6.0-lib"
> +snortlib: snortprep daq
> +       rm -rf ${SNORT-lib}
> +       cp -a snort-2.9.6.0 ${SNORT-lib}
> +       cd ${SNORT-lib}; patch -p2 <  ../snort-patches/0001-add-dependancy-for-lrt.patch
> +       cd ${SNORT-lib}; patch -p1 <  ../lib-patches/0001-Compile-Snort-as-static-library.patch
> +       cd ${SNORT-lib}; patch -p1 <  ../lib-patches/0002-remove-static-from-needed-functions.patch
> +       cd ${SNORT-lib}; autoreconf

My attempts at building this almost always stopped here with autoreconf
(actually m4) apparently stuck in a memory-leaking-loop which kept going
until either killed by the OOM killer or it hung my machine. Did you see
the same? any ideas how to avoid it?

I did manage to build it in on Ubuntu raring 32-bit x86, autoconf version
2.69, m4 version 1.4.16... but various other attempts (arm raring,
x86_64 trusty) failed every time.

[..]

> --- /dev/null
> +++ b/snort/README
> @@ -0,0 +1,37 @@
> +--- Snort on Open Data Plane ---
> +
> +Directory has 2 different demos:
> +
> +1. Data Acquisition Module (DAQ) with ODP support.
> +
> +All magic happens inside shared library daq-odp.so which provides packet I/O to Snort application. DAQ module loaded as plug-in so no snort modification is needed.
> +(Because of odp uses lib rt I added librt to dependencies.).

nit - need to wrap long lines

> +
> +Compile:
> +make
> +Run:
> +make run
> +
> +Make run will execute following command (odp daq module, interface eth0, and 10 packets to capture):
> +snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i eth0 -n 10
> +
> +2. Snort analyze function used in Open Data Plane applications.
> +
> +This example is opposite to the first one. I.e. it adds snort functionality to odp apps. For that Snort was built as static library with exported needed functions.
> +As base test/packet_io example was taken. Main thread does snort initialization then it starts several odp threads which do packet processing and feed Snort.
> +So this test has to scale across number of cpus and have some performance benefits according to regular single threaded snort.

What are the performance benefits? personally I'm not convinced this
approach will give any better performance than static load balancing
across multiple instances of snort.

> +
> +Compile:
> +make odpsnort
> +Run:
> +odpsnort/odp-snort
> +
> +Configuration:
> +Selection of number of threads and interfaces can be done in source code:
> +odpsnort/odp_pktio.c
> +    args->appl.core_count = 1;
> +    args->appl.if_count = 1;
> +    args->appl.if_names = calloc(args->appl.if_count, sizeof(char *));
> +    args->appl.if_names[0] = strdup("eth0");

Is fixing this on the TODO list? it's especially awkward because you can
pass an interface name to snort and it appears to accept it but
obviously isn't really using the one specified.

> +
> +
> --- /dev/null
> +++ b/snort/daq-patches/0001-implement-odp-daq-module.patch
> @@ -0,0 +1,477 @@
> +From 98f7d2a6eb53a17c855a40573300437ec8a3fe83 Mon Sep 17 00:00:00 2001
> +From: root <maxim.uvarov@linaro.org>
> +Date: Mon, 19 May 2014 18:04:58 +0400
> +Subject: [PATCH] implement odp daq module
> +
> +Signed-off-by: root <maxim.uvarov@linaro.org>

root?

[..]

> +diff --git a/os-daq-modules/daq_odp.c b/os-daq-modules/daq_odp.c

[..]

> ++
> ++typedef struct _odp_context
> ++{
> ++    volatile int break_loop;
> ++    DAQ_Stats_t stats;
> ++    DAQ_State state;
> ++    odp_queue_t inq_def;
> ++    odp_pktio_t pktio;
> ++    int snaplen;
> ++    char *device;
> ++    char errbuf[256];
> ++} ODP_Context_t;
> ++
> ++static int odp_daq_initialize(const DAQ_Config_t *config, void **ctxt_ptr, char *errbuf, size_t errlen)
> ++{
> ++      ODP_Context_t *odpc;
> ++      int rval = DAQ_ERROR;
> ++      int thr_id;
> ++      int i;
> ++
> ++      odp_buffer_pool_t pkt_pool;
> ++      odp_buffer_pool_t pool;
> ++      odp_pktio_t pktio;
> ++      odp_pktio_params_t params;
> ++      socket_params_t *sock_params = &params.sock_params;
> ++      odp_queue_param_t qparam;
> ++      char inq_name[ODP_QUEUE_NAME_LEN];
> ++      odp_packet_t pkt;
> ++      odp_buffer_t buf;

Quite a few unused variables here (buf, pkt, etc.)

> ++      int ret;
> ++      void *pool_base;
> ++
> ++      rval = DAQ_ERROR;
> ++
> ++      printf("%s()\n", __func__);
> ++      odpc = calloc(1, sizeof(ODP_Context_t));
> ++      if (!odpc)
> ++      {
> ++              snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the new ODP context!", __FUNCTION__);
> ++              rval = DAQ_ERROR_NOMEM;
> ++              goto err;
> ++      }
> ++
> ++      odpc->device = strdup(config->name);
> ++      if (!odpc->device)
> ++      {
> ++              snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the device string!", __FUNCTION__);
> ++              rval = DAQ_ERROR_NOMEM;
> ++              goto err;
> ++      }
> ++
> ++      *ctxt_ptr = odpc;
> ++
> ++      /* Init ODP before calling anything else */
> ++      if (odp_init_global()) {
> ++              ODP_ERR("Error: ODP global init failed.\n");

Shouldn't this write into errbuf as is done above?

> ++              goto err;
> ++      }
> ++
> ++      /* Init this thread */
> ++      thr_id = odp_thread_create(0);
> ++      odp_init_local(thr_id);
> ++
> ++      /* Create packet pool */
> ++      pool_base = odp_shm_reserve("shm_packet_pool",
> ++                                  SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE);
> ++      if (pool_base == NULL) {
> ++              ODP_ERR("Error: packet pool mem alloc failed.\n");

DAQ_ERROR_NOMEM

> ++              goto err;
> ++      }
> ++
> ++      pool = odp_buffer_pool_create("packet_pool", pool_base,
> ++                                    SHM_PKT_POOL_SIZE,
> ++                                    SHM_PKT_POOL_BUF_SIZE,
> ++                                    ODP_CACHE_LINE_SIZE,
> ++                                    ODP_BUFFER_TYPE_PACKET);
> ++      if (pool == ODP_BUFFER_POOL_INVALID) {
> ++              ODP_ERR("Error: packet pool create failed.\n");
> ++              exit(EXIT_FAILURE);

Why exit here when all other failures are just returning an error?

> ++      }
> ++      odpc->snaplen = SHM_PKT_POOL_BUF_SIZE;
> ++      odp_buffer_pool_print(pool);
> ++
> ++      /* Open a packet IO instance for this thread */
> ++      sock_params->type = ODP_PKTIO_TYPE_SOCKET_MMAP;
> ++      sock_params->fanout = 0;
> ++
> ++      odpc->pktio = odp_pktio_open(odpc->device, pool, &params);
> ++      if (odpc->pktio == ODP_PKTIO_INVALID) {
> ++              ODP_ERR("  [%02i] Error: pktio create failed\n", 1 /*thr*/);
> ++              goto err;
> ++      }
> ++
> ++      /*
> ++       * Create and set the default INPUT queue associated with the 'pktio'
> ++       * resource
> ++       */
> ++      qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
> ++      qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
> ++      qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
> ++      snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)odpc->pktio);
> ++      inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
> ++
> ++      odpc->inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam);
> ++      if (odpc->inq_def == ODP_QUEUE_INVALID) {
> ++              ODP_ERR("  [%02i] Error: pktio queue creation failed\n", 1 /*thr*/);
> ++              goto err;
> ++      }
> ++
> ++      ret = odp_pktio_inq_setdef(odpc->pktio, odpc->inq_def);
> ++      if (ret != 0) {
> ++              ODP_ERR("  [%02i] Error: default input-Q setup\n", 1 /*thr*/);
> ++              goto err;
> ++      }
> ++
> ++        odpc->state = DAQ_STATE_INITIALIZED;
> ++
> ++      printf("%s() DAQ_SUCCESS.\n\n", __func__);
> ++      return DAQ_SUCCESS;
> ++err:
> ++

Everything that was successfully allocated (odpc, pool_base, etc.) is
leaked here.

Also ctxt_ptr should probably be NULLed, or better not initialised until
you know init has succeeded.

> ++      return rval;
> ++}
> ++
> ++static int odp_daq_set_filter(void *handle, const char *filter)
> ++{
> ++      printf("%s()\n", __func__);
> ++      return DAQ_SUCCESS;
> ++}
> ++
> ++static int odp_daq_start(void *handle)
> ++{
> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++    if (!odpc)
> ++          return DAQ_ERROR_NOCTX;
> ++
> ++    odpc->state = DAQ_STATE_STARTED;
> ++    return DAQ_SUCCESS;
> ++}
> ++
> ++static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = {
> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_PASS */
> ++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLOCK */
> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_REPLACE */
> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_WHITELIST */
> ++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLACKLIST */
> ++    DAQ_VERDICT_PASS        /* DAQ_VERDICT_IGNORE */
> ++};
> ++
> ++static int odp_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user)
> ++{
> ++      ODP_Context_t *odpc;
> ++      DAQ_PktHdr_t daqhdr;
> ++      DAQ_Verdict verdict;
> ++      const uint8_t *data;
> ++
> ++      int thr_id;
> ++      odp_packet_t pkt;
> ++      odp_buffer_t buf;
> ++      int ret;
> ++      odp_buffer_pool_t pkt_pool;
> ++      odp_pktio_params_t params;
> ++      odp_pktio_t pktio;
> ++
> ++      int i;
> ++      odp_packet_t pkt_tbl[MAX_PKT_BURST];
> ++      int pkts;
> ++

Some unused variables here again (params, pktio, etc)

> ++      odpc = (ODP_Context_t *) handle;
> ++      if (!odpc)
> ++              return 0;

Should be DAQ_ERROR.. same for a few other 0 (DAQ_SUCCESS) returns below.

> ++
> ++      if (odpc->state != DAQ_STATE_STARTED)
> ++              return 0;
> ++
> ++      while (1)
> ++      {
> ++              /* Has breakloop() been called? */
> ++              if (odpc->break_loop)
> ++              {
> ++                      odpc->break_loop = 0;
> ++                      printf("%s() BREAK LOOP\n", __func__);
> ++                      return 0;
> ++              }
> ++
> ++              pkts = odp_pktio_recv(odpc->pktio, pkt_tbl, MAX_PKT_BURST);

Need to take into account the cnt parameter.

> ++              if (pkts <= 0) {
> ++                      return;
> ++              }
> ++
> ++              printf("got %d packets\n", pkts);
> ++
> ++              for (i = 0; i < pkts; ++i) {
> ++                      pkt = pkt_tbl[i];
> ++
> ++                      data = odp_packet_l2(pkt);
> ++                      if (!data) {
> ++                              printf("no l2 offset, packet dropped\n");
> ++                              continue;

pkt is leaked here. Actually pkt isn't freed anywhere even on the
success path.

> ++                      }
> ++
> ++                      verdict = DAQ_VERDICT_PASS;
> ++
> ++                      gettimeofday(&daqhdr.ts, NULL);
> ++                      daqhdr.caplen = odp_buffer_size(pkt);
> ++
> ++                      printf("%s() odp recieved packet len %d.\n", __func__, odp_packet_get_len(pkt));
> ++
> ++                      daqhdr.pktlen = odp_packet_get_len(pkt);
> ++                      daqhdr.ingress_index = 0;
> ++                      daqhdr.egress_index =  DAQ_PKTHDR_UNKNOWN;
> ++                      daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
> ++                      daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
> ++                      daqhdr.flags = 0;
> ++                      daqhdr.opaque = 0;
> ++                      daqhdr.priv_ptr = NULL;
> ++                      daqhdr.address_space_id = 0;
> ++
> ++                      if (callback)
> ++                      {
> ++                              verdict = callback(user, &daqhdr, data); // call back with pointer to data and daqhdr
> ++                              if (verdict >= MAX_DAQ_VERDICT)
> ++                                      verdict = DAQ_VERDICT_PASS;
> ++                              odpc->stats.verdicts[verdict]++;
> ++                              verdict = verdict_translation_table[verdict];
> ++                              printf("opd processed packet %ld\n", odpc->stats.verdicts[verdict]);
> ++                      }
> ++              }
> ++
> ++              if (pkts > 0) {
> ++                      printf("pkts > 0, return\n");
> ++                     return 0;
> ++              }
> ++      }
> ++      return 0;
> ++}
> ++
> ++static int odp_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, const uint8_t *packet_data, uint32_t len, int reverse)
> ++{
> ++    return DAQ_SUCCESS;
> ++}

Does this mean it doesn't work in IPS/inline mode?.. OK but that should
be documented in the README.

> ++
> ++static int odp_daq_breakloop(void *handle)
> ++{
> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++
> ++    odpc->break_loop = 1;
> ++    return DAQ_SUCCESS;
> ++}
> ++
> ++static int odp_daq_stop(void *handle)
> ++{
> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++
> ++    odpc->break_loop = 1;
> ++    odp_timer_disarm_all();

odpc->state = DAQ_STATE_STOPPED; ?

> ++
> ++    return DAQ_SUCCESS;
> ++}
> ++
> ++static void odp_daq_shutdown(void *handle)
> ++{
> ++      odp_timer_disarm_all();

Don't you need to free some resources here?.. the handle and the ODP
queues, shm, etc.

> ++}
> ++
> ++static DAQ_State odp_daq_check_status(void *handle)
> ++{
> ++      ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++
> ++      if (!odpc) {
> ++              printf("%s() odpc is not allocated\n");
> ++              return DAQ_STATE_UNINITIALIZED;
> ++      }
> ++
> ++      //printf("%s()\n", __func__);
> ++      return odpc->state;
> ++}
> ++
> ++static int odp_daq_get_stats(void *handle, DAQ_Stats_t *stats)
> ++{
> ++      ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++
> ++      memcpy(stats, &odpc->stats, sizeof(DAQ_Stats_t));
> ++      return DAQ_SUCCESS;
> ++}
> ++
> ++static void odp_daq_reset_stats(void *handle)
> ++{
> ++    //ODP_Context_t *odpc = (ODP_Context_t *) handle;

TODO?

> ++}
> ++
> ++static int odp_daq_get_snaplen(void *handle)
> ++{
> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
> ++
> ++    if (odpc)
> ++      return odpc->snaplen;
> ++
> ++    return 1500;
> ++}
> ++
> ++static uint32_t odp_daq_get_capabilities(void *handle)
> ++{
> ++    return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | /*DAQ_CAPA_UNPRIV_START |*/ DAQ_CAPA_BREAKLOOP | DAQ_CAPA_BPF | DAQ_CAPA_DEVICE_INDEX;

Assuming this means what it looks like, I guess you should remove
_INJECT and maybe _BPF?

[..]

> ++
> ++#ifdef BUILDING_SO
> ++DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA =
> ++#else
> ++const DAQ_Module_t afpacket_daq_module_data =
> ++#endif
> ++{
> ++    .api_version = DAQ_API_VERSION,
> ++    .module_version = 1,
> ++    .name = "odp",
> ++    .type = DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,

I've only looked at the comments in the header..

#define DAQ_TYPE_INTF_CAPABLE   0x02    /* can open live interfaces */
#define DAQ_TYPE_INLINE_CAPABLE 0x04    /* can form an inline bridge */
#define DAQ_TYPE_MULTI_INSTANCE 0x08    /* can be instantiated multiple times */

But I don't think this DAQ can be used INLINE (no inject) or as
MULTI_INSTANCE (odp_daq_initialise can't be called multiple times).

[..]

> --- /dev/null
> +++ b/snort/odpsnort/odp_pktio.c
> @@ -0,0 +1,673 @@

[..]

> +static void analyze_packet_in_snort(odp_packet_t pkt, int thr)
> +{
> +       DAQ_PktHdr_t daqhdr;
> +       const uint8_t *data;
> +       DAQ_Verdict verd;
> +
> +       data = odp_packet_l2(pkt);
> +       if (!data) {
> +               printf("no l2 offset, packet dropped\n");
> +               return;
> +       }
> +
> +       gettimeofday(&daqhdr.ts, NULL);
> +       daqhdr.caplen = odp_buffer_size(pkt);
> +       printf("%s() odp recieved packet len %d. thread %d\n", __func__, odp_packet_get_len(pkt), thr);
> +       daqhdr.pktlen = odp_packet_get_len(pkt);
> +       daqhdr.ingress_index = 0;
> +       daqhdr.egress_index =  DAQ_PKTHDR_UNKNOWN;
> +       daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
> +       daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
> +       daqhdr.flags = 0;
> +       daqhdr.opaque = 0;
> +       daqhdr.priv_ptr = NULL;
> +       daqhdr.address_space_id = 0;
> +
> +       /* Pass packet to Snort */
> +       verd = PacketCallback( "NULL", daqhdr, data);

Should be passing &daqhdr as PacketCallback expects a pointer to the
DAQ_PktHdr_t. This caused stack corruption and an immediate crash every
time I ran odp-snort.

> +       return;
> +}
> +
> +/**
> + * Packet IO loopback worker thread using ODP queues
> + *
> + * @param arg  thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_queue_thread(void *arg)
> +{
> +       int thr;
> +       odp_buffer_pool_t pkt_pool;
> +       odp_pktio_t pktio;
> +       thread_args_t *thr_args;
> +       odp_queue_t outq_def;
> +       odp_queue_t inq_def;
> +       char inq_name[ODP_QUEUE_NAME_LEN];
> +       odp_queue_param_t qparam;
> +       odp_packet_t pkt;
> +       odp_buffer_t buf;
> +       int ret;
> +       unsigned long pkt_cnt = 0;
> +       unsigned long err_cnt = 0;
> +       odp_pktio_params_t params;
> +       socket_params_t *sock_params = &params.sock_params;
> +
> +       thr = odp_thread_id();
> +       thr_args = arg;
> +
> +       printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
> +              thr_args->pktio_dev);
> +
> +       /* Lookup the packet pool */
> +       pkt_pool = odp_buffer_pool_lookup("packet_pool");
> +       if (pkt_pool == ODP_BUFFER_POOL_INVALID) {
> +               ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
> +               return NULL;
> +       }
> +
> +       /* Open a packet IO instance for this thread */
> +       sock_params->type = ODP_PKTIO_TYPE_SOCKET_BASIC;
> +       sock_params->fanout = 0;
> +       pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               ODP_ERR("  [%02i] Error: pktio create failed\n", thr);
> +               return NULL;
> +       }
> +
> +       /*
> +        * Create and set the default INPUT queue associated with the 'pktio'
> +        * resource
> +        */
> +       qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
> +       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
> +       qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
> +       snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio);
> +       inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
> +
> +       inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam);
> +       if (inq_def == ODP_QUEUE_INVALID) {
> +               ODP_ERR("  [%02i] Error: pktio queue creation failed\n", thr);
> +               return NULL;
> +       }
> +
> +       ret = odp_pktio_inq_setdef(pktio, inq_def);
> +       if (ret != 0) {
> +               ODP_ERR("  [%02i] Error: default input-Q setup\n", thr);
> +               return NULL;
> +       }
> +
> +       printf("  [%02i] created pktio:%02i, queue mode (ATOMIC queues)\n"
> +              "          default pktio%02i-INPUT queue:%u\n",
> +               thr, pktio, pktio, inq_def);
> +
> +       /* Loop packets */
> +       for (;;) {
> +               odp_pktio_t pktio_tmp;
> +
> +#if 1
> +               /* Use schedule to get buf from any input queue */
> +               buf = odp_schedule(NULL, ODP_SCHED_WAIT);
> +#else
> +               /* Always dequeue from the same input queue */
> +               buf = odp_queue_deq(inq_def);
> +#endif
> +
> +               if (!odp_buffer_is_valid(buf))
> +                       continue;
> +
> +               pkt = odp_packet_from_buffer(buf);
> +
> +               analyze_packet_in_snort(pkt, thr);

pkt is never freed!

> +
> +#if 0
> +               /* Print packet counts every once in a while */
> +               if (odp_unlikely(pkt_cnt++ % 100000 == 0)) {
> +                       printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
> +                       fflush(NULL);
> +               }
> +#endif
> +       }
> +
> +/* unreachable */
> +}
> +
> +/**
> + * Packet IO loopback worker thread using bursts from/to IO resources
> + *
> + * @param arg  thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_ifburst_thread(void *arg)
> +{
> +       int thr;
> +       odp_buffer_pool_t pkt_pool;
> +       odp_pktio_t pktio;
> +       thread_args_t *thr_args;
> +       int pkts, pkts_ok;
> +       odp_packet_t pkt_tbl[MAX_PKT_BURST];
> +       unsigned long pkt_cnt = 0;
> +       unsigned long err_cnt = 0;
> +       unsigned long tmp = 0;
> +       odp_pktio_params_t params;
> +       socket_params_t *sock_params = &params.sock_params;
> +
> +       thr = odp_thread_id();
> +       thr_args = arg;
> +
> +       printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
> +              thr_args->pktio_dev);
> +
> +       /* Lookup the packet pool */
> +       pkt_pool = odp_buffer_pool_lookup("packet_pool");
> +       if (pkt_pool == ODP_BUFFER_POOL_INVALID || pkt_pool != thr_args->pool) {
> +               ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
> +               return NULL;
> +       }
> +
> +       /* Open a packet IO instance for this thread */
> +       sock_params->type = thr_args->type;
> +       sock_params->fanout = thr_args->fanout;
> +       pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               ODP_ERR("  [%02i] Error: pktio create failed.\n", thr);
> +               return NULL;
> +       }
> +
> +       printf("  [%02i] created pktio:%02i, burst mode\n",
> +              thr, pktio);
> +
> +       /* Loop packets */
> +       for (;;) {
> +               pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST);
> +               if (pkts > 0) {
> +                       /* Drop packets with errors */
> +                       pkts_ok = drop_err_pkts(pkt_tbl, pkts);
> +                       if (pkts_ok > 0) {
> +                               /* Swap Eth MACs and IP-addrs */
> +                               swap_pkt_addrs(pkt_tbl, pkts_ok);
> +                               odp_pktio_send(pktio, pkt_tbl, pkts_ok);

So this isn't actually passing the packets to snort at all. I see the
mode is hard coded to use pktio_queue_thread so can this entire function
be removed?

> +                       }
> +
> +                       if (odp_unlikely(pkts_ok != pkts))
> +                               ODP_ERR("Dropped frames:%u - err_cnt:%lu\n",
> +                                       pkts-pkts_ok, ++err_cnt);
> +
> +                       /* Print packet counts every once in a while */
> +                       tmp += pkts_ok;
> +                       if (odp_unlikely((tmp >= 100000) || /* OR first print:*/
> +                           ((pkt_cnt == 0) && ((tmp-1) < MAX_PKT_BURST)))) {
> +                               pkt_cnt += tmp;
> +                               printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
> +                               fflush(NULL);
> +                               tmp = 0;
> +                       }
> +               }
> +       }
> +
> +/* unreachable */
> +}
> +
> +/**
> + * ODP packet example main function
> + */
> +int do_odp_init(int argc, char *argv[])
> +{
> +
> +       odp_buffer_pool_t pool;
> +       int thr_id;
> +       void *pool_base;
> +       int i;
> +       int first_core;
> +
> +
> +       /* Init ODP before calling anything else */
> +       if (odp_init_global()) {
> +               ODP_ERR("Error: ODP global init failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Reserve memory for args from shared mem */
> +       args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE);
> +       if (args == NULL) {
> +               ODP_ERR("Error: shared mem alloc failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +       memset(args, 0, sizeof(*args));
> +
> +       /* Parse and store the application arguments */
> +       //parse_args(argc, argv, &args->appl);
> +       args->appl.core_count = 1;

Isn't the point of this (odp-snort) to support running snort on multiple
cores? As I said above I saw plenty of crashes after changing core_count
to anything > 1.

[..]

> +/**
> + * Drop packets which input parsing marked as containing errors.
> + *
> + * Frees packets with error and modifies pkt_tbl[] to only contain packets with
> + * no detected errors.
> + *
> + * @param pkt_tbl  Array of packet
> + * @param len      Length of pkt_tbl[]
> + *
> + * @return Number of packets with no detected error
> + */
> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
> +{
> +       odp_packet_t pkt;
> +       unsigned pkt_cnt = len;
> +       unsigned i, j;
> +
> +       for (i = 0, j = 0; i < len; ++i) {
> +               pkt = pkt_tbl[i];
> +
> +               if (odp_unlikely(odp_packet_error(pkt))) {
> +                       odp_packet_free(pkt); /* Drop */
> +                       pkt_cnt--;
> +               } else if (odp_unlikely(i != j++)) {
> +                       pkt_tbl[j] = pkt;

pkt_tbl[j-1]

> +               }
> +       }
> +
> +       return pkt_cnt;
> +}
> +

[..]

> --- /dev/null
> +++ b/snort/odpsnort/odp_pktio.h
> @@ -0,0 +1 @@

Obviously needs standard header etc.

> +int do_odp_init(int argc, char *argv[]);

> --- /dev/null
> +++ b/snort/odpsnort/snort.c
> @@ -0,0 +1,5095 @@

[..]

> +/*
> + *
> + * Function: SnortMain(int, char *)
> + *
> + * Purpose:  The real place that the program handles entry and exit.  Called
> + *           called by main(), or by SnortServiceMain().
> + *
> + * Arguments: See command line args in README file
> + *
> + * Returns: 0 => normal exit, 1 => exit on error
> + *
> + */
> +int ODP_SnortMain(int argc, char *argv[])
> +{
> +    char* tmp_ptr = NULL;
> +    const char* intf;
> +    int daqInit;
> +
> +
> +    do_odp_init(argc, argv);

The command line arguments passed here will also go to SnortInit below,
which would cause problems if there are clashes (which there are).
Actually I see do_odp_init ignores the arguments anyway.

> +
> +#ifndef WIN32
> +    // must be done now in case of fatal error
> +    // and again after daemonization
> +    snort_main_thread_id = pthread_self();
> +#endif
> +
> +    SnortInit(argc, argv);
> +

[..]

> +// non-local for easy access from core
> +static Packet s_packet;
> +static DAQ_PktHdr_t s_pkth;
> +static uint8_t s_data[65536];
> +
> +static DAQ_Verdict PacketCallback(
> +    void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
> +{

With odp-snort running multi-core this will be called by multiple
threads simultaneously. There's clearly a whole lot of stuff here that
is not intended to be thread safe, such as non-atomic counters and
global state variables.

> +    int inject = 0;
> +    DAQ_Verdict verdict = DAQ_VERDICT_PASS;
> +    PROFILE_VARS;
> +
> +    PREPROC_PROFILE_START(totalPerfStats);
> +
> +#ifdef SIDE_CHANNEL
> +    if (ScSideChannelEnabled() && !snort_process_lock_held)
> +    {
> +        pthread_mutex_lock(&snort_process_lock);
> +        snort_process_lock_held = true;
> +    }
> +#endif
> +
> +#ifdef EXIT_CHECK
> +    if (snort_conf->exit_check && (pc.total_from_daq >= snort_conf->exit_check))
> +        ExitCheckStart();
> +#endif
> +
> +    /* First thing we do is process a Usr signal that we caught */
> +    if (SignalCheck())
> +    {
> +#ifndef SNORT_RELOAD
> +        /* Got SIGNAL_SNORT_RELOAD */
> +        PREPROC_PROFILE_END(totalPerfStats);
> +        Restart();
> +#endif
> +    }
> +
> +    pc.total_from_daq++;
> +
> +    /* Increment counter that we're evaling rules for caching results */
> +    rule_eval_pkt_count++;
> +
> +#ifdef TARGET_BASED
> +    /* Load in a new attribute table if we need to... */
> +    AttributeTableReloadCheck();
> +#endif
> +
> +    CheckForReload();
> +
> +    /* Save off the time of each and every packet */
> +    packet_time_update(&pkthdr->ts);
> +
> +#ifdef REG_TEST
> +    if ( snort_conf->pkt_skip && pc.total_from_daq <= snort_conf->pkt_skip )
> +    {
> +        PREPROC_PROFILE_END(totalPerfStats);
> +        return verdict;
> +    }
> +#endif
> +
> +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
> +    if (ScTerminateService() || ScPauseService())
> +    {
> +        PREPROC_PROFILE_END(totalPerfStats);
> +        return verdict;  // time to go
> +    }
> +#endif
> +
> +    /* reset the thresholding subsystem checks for this packet */
> +    sfthreshold_reset();
> +
> +    PREPROC_PROFILE_START(eventqPerfStats);
> +    SnortEventqReset();
> +    Replace_ResetQueue();
> +#ifdef ACTIVE_RESPONSE
> +    Active_ResetQueue();
> +#endif
> +    PREPROC_PROFILE_END(eventqPerfStats);
> +
> +    verdict = ProcessPacket(&s_packet, pkthdr, pkt, NULL);

The same global s_packet ptr is be passed from multiple threads. This is
what caused all of the crashes I saw.
Maxim Uvarov June 11, 2014, 6:37 p.m. UTC | #2
Hello Stuart,

thank you for spending your time on reviewing and running this. Please 
find my comments bellow.

After reviewing all notes I think that current odp-snort solution is not 
thread safe. And odpsnort needs
to be rewrote to thread safe snort3 or to multi process variant. For 
that needed odp IPC API to support
multi processing.

On 06/06/2014 09:20 PM, Stuart Haslam wrote:
 > On Tue, May 20, 2014 at 02:56:10PM +0100, root wrote:
 >> From: Maxim Uvarov <maxim.uvarov@linaro.org>
 >>
 >> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
 >> ---
 >>  Looke like it's not easy to understand and review this patch in 
mailing list.
 >>
 >>  I filtered our original apps from patch. And merged it to the repo:
 >> 
https://git.linaro.org/lng/odp-apps.git/commit/4da44db4b18d8f2d4ada64727088333ff045df83
 >>  If there will suggestions and comments I will renew this commit.
 >>
 >>  Initial work with smaller commits was done here:
 >> https://git.linaro.org/people/maxim.uvarov/odp-snort.git
 >>  maybe my public tree is more clean for review then odp-apps.git.
 >
 > It was pretty difficult to follow this patch. It would be good if you
 > gave a bit of an intro stating what you have done and the status of the
 > work, what testing has been done and any open issues.
 >
 > I assumed that both the daq and odpsnort versions were usable so have
 > attempted to build and test them, but actually I couldn't get either
 > working at all without some fixes.
Yes, there are 2 versions of apps.
1. ODP-DAQ module for snort which is loaded as standard dynamic plug-in
to provide packets I/O to non modified snort.

2. odpsnort - modified odp_packet test to capture packets in several threads
and then provide them to snort to analyse them.

Everything in odp-apps.git can be build with simple 'make' after git 
checkout.
Then I planned to embed builds to CI loop. But unfortunately x86 box in 
LAVA can
not compile all apps due to out of memory issue. I'm not sure if it's 
related that
everything in LAVA stored in ram disk or it's simple low memory machine. 
So that
once I found that I decided to build everything on host and to be part 
of Open Embedded
image. I send oe recipes for review to be included to our image. So I 
think compilation
check will not be a problem and also it will allow to run this examples 
in LAVA.

Before sending patches to the list I did very simple testing that: 1. 
odp-daq module accepts
packets and snort prints their internals. 2. the same for odpsnort. I 
did not do any performance check
due to this needs environment and it might be reasonable to do 
everything in test framework to have
reproducible results.

 >
 > The ODP DAQ wouldn't receive any packets, sometimes one or two packets
 > would be received but usually nothing at all. Turns out this is a bug
 > in the socket MMAP implementation as changing daq_odp.c to use BASIC
 > sockets resolved the problem. It then managed a few hundred packets
 > before stopping, which turned out to be due to packets being leaked in
 > the DAQ, after fixing this it now runs pretty well.
 >
 > I'll send a patch for the MMAP bug shortly.

In late versions we have MMAP as more preferred I/O type for most fresh 
kernel.
(code with ifdefs). There were always questions due to it required some 
set up
things like IP unset and removing arg. If you have patch to not do such 
hacks
that is nice.

 >
 > I had other issues with odpsnort (details below) which I spent a bit of
 > time starting to work through, but then it became clear that it wasn't
 > going to work as intended (with multiple threads) without a lot of work
 > in snort to make it thread safe.

That is good question. Me, Mike and Petri discussed that on previous Connect
that it might be worth to call snort analyze function from different odp 
thread.
None from us did not know snort internals. So it was a try. When I sent 
packets
from my local network I did not see segfaults or any errors. So I 
believed that snort
might be thread safe, but it's good question why nobody uses snort as 
multi-threaded application.
Might be on serious load there will be errors, or snort works wrongly. 
But I did not see that
yet. I'm not snort expert.

 > I don't think it's viable to start
 > making those changes so as I see it there are a couple of options,
 > either start from the snort 3.0 code base that is already multi-threaded
 > (in places, at least the analysis engines are) or stick with using
 > multiple instances of snort (with the ODP DAQ) and distribute the
 > flows across them.

You are second man who talks me about snort 3. But download page of 
snort has only 2.9.6 version.
Where I can find snort 3 sources?

Plan if multi-threaded version will not work was to switch to 
multiprocess scheme. And reuse ODP IPC
API which was in development plan but not yet ready.

But your suggestion is also interesting. For now I don't have idea how 
to slit incoming traffic for different
odp processes. Might be implement iptable module (nf-queque) which will 
get packets from iptables and set flow
rule there. I think we can not do that with raw sockets or mmap. Do you 
have some hint how that can be implemented?

To support different hardware more preference way is to accept traffic 
as is, split it on flows and send to others processes.

 >
 > [..]
 >
 >> @@ -8,10 +8,15 @@ libpcap: odp
 >>  openvpn: odp
 >>         make -C openvpn
 >>
 >> +snort: odp
 >> +       make -C snort
 >> +
 >>  odp:
 >>         if [ ! -d odp.git ]; \
 >>                 then git clone http://git.linaro.org/git/lng/odp.git 
odp.git; \
 >>         fi
 >> +       cd odp.git; git reset --hard HEAD
 >> +       cd odp.git; patch -N -p1 < 
../snort/odp-patches/0001-implement-odp_timer_disarm_all.patch
 >
 > HEAD seems a bad idea if you want to ensure the patch applies, is there
 > some plan to resolve the need for this patch? I remember it was
 > discussed on the list but I don't remember the outcome.
 >

HEAD was bad idea for OE. Fathi don't want accept HEAD and for that we 
have to update oe odp scenario almost each week.
For this patch idea was to keep it always fresh. I.e. we have to know 
when core API will change and it will not be applicable
any more. And for that particular patch - it's temporary workaround 
while Petri works on new timer API implementation.


 >>         cd odp.git; make libs_install  CFLAGS="-fPIC"
 >>
 >>  distclean:
 >> --- /dev/null
 >> +++ b/snort/Makefile
 >> @@ -0,0 +1,65 @@
 >> +.PHONY: all odp daq snort odpsnort
 >> +all: snort
 >> +
 >> +DAQ="daq-2.0.2"
 >> +daqprep:
 >> +       rm -rf ${DAQ}
 >> +       tar xpvfz ./download/daq-2.0.2.tar.gz
 >> +       cd ${DAQ}; patch -p1 < 
../daq-patches/0001-implement-odp-daq-module.patch
 >> +
 >
 > Dependencies aren't used throughout this makefile, so the whole
 > extract-patch-configure-build process is re-done every time you run make.
 > This is pretty painful especially when you're going through a first time
 > build to resolve issues. I would've done the above like;
 >
 > DAQ=daq-2.0.2
 > DAQ_TGZ=./download/$(DAQ).tar.gz
 > DAQ_PATCH=../daq-patches/0001-implement-odp-daq-module.patch
 >
 > daqprep: $(DAQ)/.patched
 >
 > $(DAQ)/.patched: $(DAQ_TGZ) $(DAQ_PATCH)
 >     rm -rf $(DAQ)
 >     tar ..
 >     patch ..
 >     @touch $@
 >

Thanks.

 >> +
 >> +daq: daqprep libdnet
 >> +       cd ${DAQ}; autoreconf
 >
 > This fails for me with automake version 1.14.1 (ubuntu trusty), it seems
 > to expect automake 1.11.1. I did pursue it a little but got further
 > errors so moved to an older release.
 >

OK. Autoreconf for OE armv7 was fine.

 >> +       cd ${DAQ}; ./configure 
CFLAGS="-I${PWD}/../odp.git/build/include -g -O0" LDFLAGS="-g 
-L${PWD}/../odp.git/build/lib"
 >
 > It would be good to be able to avoid needing to have another copy of the
 > odp source tree.. how about;
 >
 > ODP_SOURCE_DIR?=$(PWD)/../odp/
 >

I do fetch odp and build only once in top level directory. It needs 
timer patch and -fPIC. So I think it's ok.

 >> +       cd ${DAQ}; make
 >> +       cd ${DAQ}; make install
 >
 > I shouldn't need to be root to build this, installs should go into a
 > local directory (i.e. use ./configure --prefix=DIR).
 >
ok. but then on execution you will need to specify where is daq.

 >> +
 >> +
 >> +snortprep:
 >> +       rm -rf snort-2.9.6.0
 >> +       tar xpfz download/snort-2.9.6.0.tar.gz
 >> +
 >> +SNORT="snort-2.9.6.1-odp"
 >
 > Should be 2.9.6.0
 >

Agree.

 > [..]
 >
 >> +SNORT-lib="snort-2.9.6.0-lib"
 >> +snortlib: snortprep daq
 >> +       rm -rf ${SNORT-lib}
 >> +       cp -a snort-2.9.6.0 ${SNORT-lib}
 >> +       cd ${SNORT-lib}; patch -p2 < 
../snort-patches/0001-add-dependancy-for-lrt.patch
 >> +       cd ${SNORT-lib}; patch -p1 < 
../lib-patches/0001-Compile-Snort-as-static-library.patch
 >> +       cd ${SNORT-lib}; patch -p1 < 
../lib-patches/0002-remove-static-from-needed-functions.patch
 >> +       cd ${SNORT-lib}; autoreconf
 >
 > My attempts at building this almost always stopped here with autoreconf
 > (actually m4) apparently stuck in a memory-leaking-loop which kept going
 > until either killed by the OOM killer or it hung my machine. Did you see
 > the same? any ideas how to avoid it?

O! You might be see something the similar what I got on LAVA x86 
machine. I was totaly unable to
compile it there. I think it's autireconf bug which appeared after 2.68 
and fixed later. I can compile
it on my Ubuntu 12.04.3 LTS and in OE.

 >
 > I did manage to build it in on Ubuntu raring 32-bit x86, autoconf version
 > 2.69, m4 version 1.4.16... but various other attempts (arm raring,
 > x86_64 trusty) failed every time.

Maybe it's better to drop out this Makefiles completely and build only 
with OE recopies. It might be difficult to
support different versions of autotools but OE somehow avoids issues.

 >
 > [..]
 >
 >> --- /dev/null
 >> +++ b/snort/README
 >> @@ -0,0 +1,37 @@
 >> +--- Snort on Open Data Plane ---
 >> +
 >> +Directory has 2 different demos:
 >> +
 >> +1. Data Acquisition Module (DAQ) with ODP support.
 >> +
 >> +All magic happens inside shared library daq-odp.so which provides 
packet I/O to Snort application. DAQ module loaded as plug-in so no 
snort modification is needed.
 >> +(Because of odp uses lib rt I added librt to dependencies.).
 >
 > nit - need to wrap long lines
 >

OK.

 >> +
 >> +Compile:
 >> +make
 >> +Run:
 >> +make run
 >> +
 >> +Make run will execute following command (odp daq module, interface 
eth0, and 10 packets to capture):
 >> +snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i 
eth0 -n 10
 >> +
 >> +2. Snort analyze function used in Open Data Plane applications.
 >> +
 >> +This example is opposite to the first one. I.e. it adds snort 
functionality to odp apps. For that Snort was built as static library 
with exported needed functions.
 >> +As base test/packet_io example was taken. Main thread does snort 
initialization then it starts several odp threads which do packet 
processing and feed Snort.
 >> +So this test has to scale across number of cpus and have some 
performance benefits according to regular single threaded snort.
 >
 > What are the performance benefits? personally I'm not convinced this
 > approach will give any better performance than static load balancing
 > across multiple instances of snort.
 >

General benefit was to have odp supported by snort. It will bring some 
publicity of the project and hardware optimization for some specific boards.
Load balancing needs API to support multipline processes to run it as 
different processes. Most likely threads will have the same performance 
but we need to check that.


 >> +
 >> +Compile:
 >> +make odpsnort
 >> +Run:
 >> +odpsnort/odp-snort
 >> +
 >> +Configuration:
 >> +Selection of number of threads and interfaces can be done in source 
code:
 >> +odpsnort/odp_pktio.c
 >> +    args->appl.core_count = 1;
 >> +    args->appl.if_count = 1;
 >> +    args->appl.if_names = calloc(args->appl.if_count, sizeof(char *));
 >> +    args->appl.if_names[0] = strdup("eth0");
 >
 > Is fixing this on the TODO list? it's especially awkward because you can
 > pass an interface name to snort and it appears to accept it but
 > obviously isn't really using the one specified.
 >

Ah, yes, this need to be removed.

 >> +
 >> +
 >> --- /dev/null
 >> +++ b/snort/daq-patches/0001-implement-odp-daq-module.patch
 >> @@ -0,0 +1,477 @@
 >> +From 98f7d2a6eb53a17c855a40573300437ec8a3fe83 Mon Sep 17 00:00:00 2001
 >> +From: root <maxim.uvarov@linaro.org>
 >> +Date: Mon, 19 May 2014 18:04:58 +0400
 >> +Subject: [PATCH] implement odp daq module
 >> +
 >> +Signed-off-by: root <maxim.uvarov@linaro.org>
 >
 > root?
 >

Already fixed that in git.

 > [..]
 >
 >> +diff --git a/os-daq-modules/daq_odp.c b/os-daq-modules/daq_odp.c
 >
 > [..]
 >
 >> ++
 >> ++typedef struct _odp_context
 >> ++{
 >> ++    volatile int break_loop;
 >> ++    DAQ_Stats_t stats;
 >> ++    DAQ_State state;
 >> ++    odp_queue_t inq_def;
 >> ++    odp_pktio_t pktio;
 >> ++    int snaplen;
 >> ++    char *device;
 >> ++    char errbuf[256];
 >> ++} ODP_Context_t;
 >> ++
 >> ++static int odp_daq_initialize(const DAQ_Config_t *config, void 
**ctxt_ptr, char *errbuf, size_t errlen)
 >> ++{
 >> ++      ODP_Context_t *odpc;
 >> ++      int rval = DAQ_ERROR;
 >> ++      int thr_id;
 >> ++      int i;
 >> ++
 >> ++      odp_buffer_pool_t pkt_pool;
 >> ++      odp_buffer_pool_t pool;
 >> ++      odp_pktio_t pktio;
 >> ++      odp_pktio_params_t params;
 >> ++      socket_params_t *sock_params = &params.sock_params;
 >> ++      odp_queue_param_t qparam;
 >> ++      char inq_name[ODP_QUEUE_NAME_LEN];
 >> ++      odp_packet_t pkt;
 >> ++      odp_buffer_t buf;
 >
 > Quite a few unused variables here (buf, pkt, etc.)
 >

Yes, I saw that. Wanted to run it under OE/LAVA and make it work that do 
additional clean up.

 >> ++      int ret;
 >> ++      void *pool_base;
 >> ++
 >> ++      rval = DAQ_ERROR;
 >> ++
 >> ++      printf("%s()\n", __func__);
 >> ++      odpc = calloc(1, sizeof(ODP_Context_t));
 >> ++      if (!odpc)
 >> ++      {
 >> ++              snprintf(errbuf, errlen, "%s: Couldn't allocate 
memory for the new ODP context!", __FUNCTION__);
 >> ++              rval = DAQ_ERROR_NOMEM;
 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      odpc->device = strdup(config->name);
 >> ++      if (!odpc->device)
 >> ++      {
 >> ++              snprintf(errbuf, errlen, "%s: Couldn't allocate 
memory for the device string!", __FUNCTION__);
 >> ++              rval = DAQ_ERROR_NOMEM;
 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      *ctxt_ptr = odpc;
 >> ++
 >> ++      /* Init ODP before calling anything else */
 >> ++      if (odp_init_global()) {
 >> ++              ODP_ERR("Error: ODP global init failed.\n");
 >
 > Shouldn't this write into errbuf as is done above?
 >

yes, thanks.

 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      /* Init this thread */
 >> ++      thr_id = odp_thread_create(0);
 >> ++      odp_init_local(thr_id);
 >> ++
 >> ++      /* Create packet pool */
 >> ++      pool_base = odp_shm_reserve("shm_packet_pool",
 >> ++                                  SHM_PKT_POOL_SIZE, 
ODP_CACHE_LINE_SIZE);
 >> ++      if (pool_base == NULL) {
 >> ++              ODP_ERR("Error: packet pool mem alloc failed.\n");
 >
 > DAQ_ERROR_NOMEM
 >

ok.

 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      pool = odp_buffer_pool_create("packet_pool", pool_base,
 >> ++                                    SHM_PKT_POOL_SIZE,
 >> ++ SHM_PKT_POOL_BUF_SIZE,
 >> ++                                    ODP_CACHE_LINE_SIZE,
 >> ++ ODP_BUFFER_TYPE_PACKET);
 >> ++      if (pool == ODP_BUFFER_POOL_INVALID) {
 >> ++              ODP_ERR("Error: packet pool create failed.\n");
 >> ++              exit(EXIT_FAILURE);
 >
 > Why exit here when all other failures are just returning an error?
 >

ok.

 >> ++      }
 >> ++      odpc->snaplen = SHM_PKT_POOL_BUF_SIZE;
 >> ++      odp_buffer_pool_print(pool);
 >> ++
 >> ++      /* Open a packet IO instance for this thread */
 >> ++      sock_params->type = ODP_PKTIO_TYPE_SOCKET_MMAP;
 >> ++      sock_params->fanout = 0;
 >> ++
 >> ++      odpc->pktio = odp_pktio_open(odpc->device, pool, &params);
 >> ++      if (odpc->pktio == ODP_PKTIO_INVALID) {
 >> ++              ODP_ERR("  [%02i] Error: pktio create failed\n", 1 
/*thr*/);
 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      /*
 >> ++       * Create and set the default INPUT queue associated with 
the 'pktio'
 >> ++       * resource
 >> ++       */
 >> ++      qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
 >> ++      qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
 >> ++      qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
 >> ++      snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", 
(int)odpc->pktio);
 >> ++      inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
 >> ++
 >> ++      odpc->inq_def = odp_queue_create(inq_name, 
ODP_QUEUE_TYPE_PKTIN, &qparam);
 >> ++      if (odpc->inq_def == ODP_QUEUE_INVALID) {
 >> ++              ODP_ERR("  [%02i] Error: pktio queue creation 
failed\n", 1 /*thr*/);
 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++      ret = odp_pktio_inq_setdef(odpc->pktio, odpc->inq_def);
 >> ++      if (ret != 0) {
 >> ++              ODP_ERR("  [%02i] Error: default input-Q setup\n", 1 
/*thr*/);
 >> ++              goto err;
 >> ++      }
 >> ++
 >> ++        odpc->state = DAQ_STATE_INITIALIZED;
 >> ++
 >> ++      printf("%s() DAQ_SUCCESS.\n\n", __func__);
 >> ++      return DAQ_SUCCESS;
 >> ++err:
 >> ++
 >
 > Everything that was successfully allocated (odpc, pool_base, etc.) is
 > leaked here.
 >
 > Also ctxt_ptr should probably be NULLed, or better not initialised until
 > you know init has succeeded.


odpc is freed on exit. pool and others - yes, they are leaked. But we 
are missing clean up API in ODP.
Which I said some time later. One it will be written I will add that. 
For now it's not really critical
because you allocate all this things only once on running.

 >
 >> ++      return rval;
 >> ++}
 >> ++
 >> ++static int odp_daq_set_filter(void *handle, const char *filter)
 >> ++{
 >> ++      printf("%s()\n", __func__);
 >> ++      return DAQ_SUCCESS;
 >> ++}
 >> ++
 >> ++static int odp_daq_start(void *handle)
 >> ++{
 >> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++    if (!odpc)
 >> ++          return DAQ_ERROR_NOCTX;
 >> ++
 >> ++    odpc->state = DAQ_STATE_STARTED;
 >> ++    return DAQ_SUCCESS;
 >> ++}
 >> ++
 >> ++static const DAQ_Verdict 
verdict_translation_table[MAX_DAQ_VERDICT] = {
 >> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_PASS */
 >> ++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLOCK */
 >> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_REPLACE */
 >> ++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_WHITELIST */
 >> ++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLACKLIST */
 >> ++    DAQ_VERDICT_PASS        /* DAQ_VERDICT_IGNORE */
 >> ++};
 >> ++
 >> ++static int odp_daq_acquire(void *handle, int cnt, 
DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user)
 >> ++{
 >> ++      ODP_Context_t *odpc;
 >> ++      DAQ_PktHdr_t daqhdr;
 >> ++      DAQ_Verdict verdict;
 >> ++      const uint8_t *data;
 >> ++
 >> ++      int thr_id;
 >> ++      odp_packet_t pkt;
 >> ++      odp_buffer_t buf;
 >> ++      int ret;
 >> ++      odp_buffer_pool_t pkt_pool;
 >> ++      odp_pktio_params_t params;
 >> ++      odp_pktio_t pktio;
 >> ++
 >> ++      int i;
 >> ++      odp_packet_t pkt_tbl[MAX_PKT_BURST];
 >> ++      int pkts;
 >> ++
 >
 > Some unused variables here again (params, pktio, etc)
 >

ok.

 >> ++      odpc = (ODP_Context_t *) handle;
 >> ++      if (!odpc)
 >> ++              return 0;
 >
 > Should be DAQ_ERROR.. same for a few other 0 (DAQ_SUCCESS) returns below.
 >

0 is how many packets were captured. I copied that from some other module :)

 >> ++
 >> ++      if (odpc->state != DAQ_STATE_STARTED)
 >> ++              return 0;
 >> ++
 >> ++      while (1)
 >> ++      {
 >> ++              /* Has breakloop() been called? */
 >> ++              if (odpc->break_loop)
 >> ++              {
 >> ++                      odpc->break_loop = 0;
 >> ++                      printf("%s() BREAK LOOP\n", __func__);
 >> ++                      return 0;
 >> ++              }
 >> ++
 >> ++              pkts = odp_pktio_recv(odpc->pktio, pkt_tbl, 
MAX_PKT_BURST);
 >
 > Need to take into account the cnt parameter.
 >

ok, good catch.

 >> ++              if (pkts <= 0) {
 >> ++                      return;
 >> ++              }
 >> ++
 >> ++              printf("got %d packets\n", pkts);
 >> ++
 >> ++              for (i = 0; i < pkts; ++i) {
 >> ++                      pkt = pkt_tbl[i];
 >> ++
 >> ++                      data = odp_packet_l2(pkt);
 >> ++                      if (!data) {
 >> ++                              printf("no l2 offset, packet 
dropped\n");
 >> ++                              continue;
 >
 > pkt is leaked here. Actually pkt isn't freed anywhere even on the
 > success path.
 >

ok.

 >> ++                      }
 >> ++
 >> ++                      verdict = DAQ_VERDICT_PASS;
 >> ++
 >> ++                      gettimeofday(&daqhdr.ts, NULL);
 >> ++                      daqhdr.caplen = odp_buffer_size(pkt);
 >> ++
 >> ++                      printf("%s() odp recieved packet len %d.\n", 
__func__, odp_packet_get_len(pkt));
 >> ++
 >> ++                      daqhdr.pktlen = odp_packet_get_len(pkt);
 >> ++                      daqhdr.ingress_index = 0;
 >> ++                      daqhdr.egress_index = DAQ_PKTHDR_UNKNOWN;
 >> ++                      daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
 >> ++                      daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
 >> ++                      daqhdr.flags = 0;
 >> ++                      daqhdr.opaque = 0;
 >> ++                      daqhdr.priv_ptr = NULL;
 >> ++                      daqhdr.address_space_id = 0;
 >> ++
 >> ++                      if (callback)
 >> ++                      {
 >> ++                              verdict = callback(user, &daqhdr, 
data); // call back with pointer to data and daqhdr
 >> ++                              if (verdict >= MAX_DAQ_VERDICT)
 >> ++                                      verdict = DAQ_VERDICT_PASS;
 >> ++ odpc->stats.verdicts[verdict]++;
 >> ++                              verdict = 
verdict_translation_table[verdict];
 >> ++                              printf("opd processed packet %ld\n", 
odpc->stats.verdicts[verdict]);
 >> ++                      }
 >> ++              }
 >> ++
 >> ++              if (pkts > 0) {
 >> ++                      printf("pkts > 0, return\n");
 >> ++                     return 0;
 >> ++              }
 >> ++      }
 >> ++      return 0;
 >> ++}
 >> ++
 >> ++static int odp_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, 
const uint8_t *packet_data, uint32_t len, int reverse)
 >> ++{
 >> ++    return DAQ_SUCCESS;
 >> ++}
 >
 > Does this mean it doesn't work in IPS/inline mode?.. OK but that should
 > be documented in the README.
 >

Yes, I did not implement this function but it's not really hard. Will 
implement it.

 >> ++
 >> ++static int odp_daq_breakloop(void *handle)
 >> ++{
 >> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++
 >> ++    odpc->break_loop = 1;
 >> ++    return DAQ_SUCCESS;
 >> ++}
 >> ++
 >> ++static int odp_daq_stop(void *handle)
 >> ++{
 >> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++
 >> ++    odpc->break_loop = 1;
 >> ++    odp_timer_disarm_all();
 >
 > odpc->state = DAQ_STATE_STOPPED; ?
 >

Will check.


 >> ++
 >> ++    return DAQ_SUCCESS;
 >> ++}
 >> ++
 >> ++static void odp_daq_shutdown(void *handle)
 >> ++{
 >> ++      odp_timer_disarm_all();
 >
 > Don't you need to free some resources here?.. the handle and the ODP
 > queues, shm, etc.
 >

yes, once that api will exist.

 >> ++}
 >> ++
 >> ++static DAQ_State odp_daq_check_status(void *handle)
 >> ++{
 >> ++      ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++
 >> ++      if (!odpc) {
 >> ++              printf("%s() odpc is not allocated\n");
 >> ++              return DAQ_STATE_UNINITIALIZED;
 >> ++      }
 >> ++
 >> ++      //printf("%s()\n", __func__);
 >> ++      return odpc->state;
 >> ++}
 >> ++
 >> ++static int odp_daq_get_stats(void *handle, DAQ_Stats_t *stats)
 >> ++{
 >> ++      ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++
 >> ++      memcpy(stats, &odpc->stats, sizeof(DAQ_Stats_t));
 >> ++      return DAQ_SUCCESS;
 >> ++}
 >> ++
 >> ++static void odp_daq_reset_stats(void *handle)
 >> ++{
 >> ++    //ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >
 > TODO?
 >

yes, we definately need some stats.

 >> ++}
 >> ++
 >> ++static int odp_daq_get_snaplen(void *handle)
 >> ++{
 >> ++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
 >> ++
 >> ++    if (odpc)
 >> ++      return odpc->snaplen;
 >> ++
 >> ++    return 1500;
 >> ++}
 >> ++
 >> ++static uint32_t odp_daq_get_capabilities(void *handle)
 >> ++{
 >> ++    return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | 
/*DAQ_CAPA_UNPRIV_START |*/ DAQ_CAPA_BREAKLOOP | DAQ_CAPA_BPF | 
DAQ_CAPA_DEVICE_INDEX;
 >
 > Assuming this means what it looks like, I guess you should remove
 > _INJECT and maybe _BPF?
 >

ok.

 > [..]
 >
 >> ++
 >> ++#ifdef BUILDING_SO
 >> ++DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA =
 >> ++#else
 >> ++const DAQ_Module_t afpacket_daq_module_data =
 >> ++#endif
 >> ++{
 >> ++    .api_version = DAQ_API_VERSION,
 >> ++    .module_version = 1,
 >> ++    .name = "odp",
 >> ++    .type = DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | 
DAQ_TYPE_MULTI_INSTANCE,
 >
 > I've only looked at the comments in the header..
 >
 > #define DAQ_TYPE_INTF_CAPABLE   0x02    /* can open live interfaces */
 > #define DAQ_TYPE_INLINE_CAPABLE 0x04    /* can form an inline bridge */
 > #define DAQ_TYPE_MULTI_INSTANCE 0x08    /* can be instantiated 
multiple times */
 >
 > But I don't think this DAQ can be used INLINE (no inject) or as
 > MULTI_INSTANCE (odp_daq_initialise can't be called multiple times).
 >

yes, it can't.

 > [..]
 >
 >> --- /dev/null
 >> +++ b/snort/odpsnort/odp_pktio.c
 >> @@ -0,0 +1,673 @@
 >
 > [..]
 >
 >> +static void analyze_packet_in_snort(odp_packet_t pkt, int thr)
 >> +{
 >> +       DAQ_PktHdr_t daqhdr;
 >> +       const uint8_t *data;
 >> +       DAQ_Verdict verd;
 >> +
 >> +       data = odp_packet_l2(pkt);
 >> +       if (!data) {
 >> +               printf("no l2 offset, packet dropped\n");
 >> +               return;
 >> +       }
 >> +
 >> +       gettimeofday(&daqhdr.ts, NULL);
 >> +       daqhdr.caplen = odp_buffer_size(pkt);
 >> +       printf("%s() odp recieved packet len %d. thread %d\n", 
__func__, odp_packet_get_len(pkt), thr);
 >> +       daqhdr.pktlen = odp_packet_get_len(pkt);
 >> +       daqhdr.ingress_index = 0;
 >> +       daqhdr.egress_index =  DAQ_PKTHDR_UNKNOWN;
 >> +       daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
 >> +       daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
 >> +       daqhdr.flags = 0;
 >> +       daqhdr.opaque = 0;
 >> +       daqhdr.priv_ptr = NULL;
 >> +       daqhdr.address_space_id = 0;
 >> +
 >> +       /* Pass packet to Snort */
 >> +       verd =y( "NULL", daqhdr, data);
 >
 > Should be passing &daqhdr as PacketCallback expects a pointer to the
 > DAQ_PktHdr_t. This caused stack corruption and an immediate crash every
 > time I ran odp-snort.
 >

yes.
typedef DAQ_Verdict (*DAQ_Analysis_Func_t)(void *user, const 
DAQ_PktHdr_t *hdr, const uint8_t *data);


 >> +       return;
 >> +}
 >> +
 >> +/**
 >> + * Packet IO loopback worker thread using ODP queues
 >> + *
 >> + * @param arg  thread arguments of type 'thread_args_t *'
 >> + */
 >> +static void *pktio_queue_thread(void *arg)
 >> +{
 >> +       int thr;
 >> +       odp_buffer_pool_t pkt_pool;
 >> +       odp_pktio_t pktio;
 >> +       thread_args_t *thr_args;
 >> +       odp_queue_t outq_def;
 >> +       odp_queue_t inq_def;
 >> +       char inq_name[ODP_QUEUE_NAME_LEN];
 >> +       odp_queue_param_t qparam;
 >> +       odp_packet_t pkt;
 >> +       odp_buffer_t buf;
 >> +       int ret;
 >> +       unsigned long pkt_cnt = 0;
 >> +       unsigned long err_cnt = 0;
 >> +       odp_pktio_params_t params;
 >> +       socket_params_t *sock_params = &params.sock_params;
 >> +
 >> +       thr = odp_thread_id();
 >> +       thr_args = arg;
 >> +
 >> +       printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
 >> +              thr_args->pktio_dev);
 >> +
 >> +       /* Lookup the packet pool */
 >> +       pkt_pool = odp_buffer_pool_lookup("packet_pool");
 >> +       if (pkt_pool == ODP_BUFFER_POOL_INVALID) {
 >> +               ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       /* Open a packet IO instance for this thread */
 >> +       sock_params->type = ODP_PKTIO_TYPE_SOCKET_BASIC;
 >> +       sock_params->fanout = 0;
 >> +       pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
 >> +       if (pktio == ODP_PKTIO_INVALID) {
 >> +               ODP_ERR("  [%02i] Error: pktio create failed\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       /*
 >> +        * Create and set the default INPUT queue associated with 
the 'pktio'
 >> +        * resource
 >> +        */
 >> +       qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
 >> +       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
 >> +       qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
 >> +       snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", 
(int)pktio);
 >> +       inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
 >> +
 >> +       inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, 
&qparam);
 >> +       if (inq_def == ODP_QUEUE_INVALID) {
 >> +               ODP_ERR("  [%02i] Error: pktio queue creation 
failed\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       ret = odp_pktio_inq_setdef(pktio, inq_def);
 >> +       if (ret != 0) {
 >> +               ODP_ERR("  [%02i] Error: default input-Q setup\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       printf("  [%02i] created pktio:%02i, queue mode (ATOMIC 
queues)\n"
 >> +              "          default pktio%02i-INPUT queue:%u\n",
 >> +               thr, pktio, pktio, inq_def);
 >> +
 >> +       /* Loop packets */
 >> +       for (;;) {
 >> +               odp_pktio_t pktio_tmp;
 >> +
 >> +#if 1
 >> +               /* Use schedule to get buf from any input queue */
 >> +               buf = odp_schedule(NULL, ODP_SCHED_WAIT);
 >> +#else
 >> +               /* Always dequeue from the same input queue */
 >> +               buf = odp_queue_deq(inq_def);
 >> +#endif
 >> +
 >> +               if (!odp_buffer_is_valid(buf))
 >> +                       continue;
 >> +
 >> +               pkt = odp_packet_from_buffer(buf);
 >> +
 >> +               analyze_packet_in_snort(pkt, thr);
 >
 > pkt is never freed!
 >

ok.

 >> +
 >> +#if 0
 >> +               /* Print packet counts every once in a while */
 >> +               if (odp_unlikely(pkt_cnt++ % 100000 == 0)) {
 >> +                       printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
 >> +                       fflush(NULL);
 >> +               }
 >> +#endif
 >> +       }
 >> +
 >> +/* unreachable */
 >> +}
 >> +
 >> +/**
 >> + * Packet IO loopback worker thread using bursts from/to IO resources
 >> + *
 >> + * @param arg  thread arguments of type 'thread_args_t *'
 >> + */
 >> +static void *pktio_ifburst_thread(void *arg)
 >> +{
 >> +       int thr;
 >> +       odp_buffer_pool_t pkt_pool;
 >> +       odp_pktio_t pktio;
 >> +       thread_args_t *thr_args;
 >> +       int pkts, pkts_ok;
 >> +       odp_packet_t pkt_tbl[MAX_PKT_BURST];
 >> +       unsigned long pkt_cnt = 0;
 >> +       unsigned long err_cnt = 0;
 >> +       unsigned long tmp = 0;
 >> +       odp_pktio_params_t params;
 >> +       socket_params_t *sock_params = &params.sock_params;
 >> +
 >> +       thr = odp_thread_id();
 >> +       thr_args = arg;
 >> +
 >> +       printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
 >> +              thr_args->pktio_dev);
 >> +
 >> +       /* Lookup the packet pool */
 >> +       pkt_pool = odp_buffer_pool_lookup("packet_pool");
 >> +       if (pkt_pool == ODP_BUFFER_POOL_INVALID || pkt_pool != 
thr_args->pool) {
 >> +               ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       /* Open a packet IO instance for this thread */
 >> +       sock_params->type = thr_args->type;
 >> +       sock_params->fanout = thr_args->fanout;
 >> +       pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
 >> +       if (pktio == ODP_PKTIO_INVALID) {
 >> +               ODP_ERR("  [%02i] Error: pktio create failed.\n", thr);
 >> +               return NULL;
 >> +       }
 >> +
 >> +       printf("  [%02i] created pktio:%02i, burst mode\n",
 >> +              thr, pktio);
 >> +
 >> +       /* Loop packets */
 >> +       for (;;) {
 >> +               pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST);
 >> +               if (pkts > 0) {
 >> +                       /* Drop packets with errors */
 >> +                       pkts_ok = drop_err_pkts(pkt_tbl, pkts);
 >> +                       if (pkts_ok > 0) {
 >> +                               /* Swap Eth MACs and IP-addrs */
 >> +                               swap_pkt_addrs(pkt_tbl, pkts_ok);
 >> +                               odp_pktio_send(pktio, pkt_tbl, pkts_ok);
 >
 > So this isn't actually passing the packets to snort at all. I see the
 > mode is hard coded to use pktio_queue_thread so can this entire function
 > be removed?
 >

this function needs to be converted to queque type packet aquisition.


 >> +                       }
 >> +
 >> +                       if (odp_unlikely(pkts_ok != pkts))
 >> +                               ODP_ERR("Dropped frames:%u - 
err_cnt:%lu\n",
 >> +                                       pkts-pkts_ok, ++err_cnt);
 >> +
 >> +                       /* Print packet counts every once in a while */
 >> +                       tmp += pkts_ok;
 >> +                       if (odp_unlikely((tmp >= 100000) || /* OR 
first print:*/
 >> +                           ((pkt_cnt == 0) && ((tmp-1) < 
MAX_PKT_BURST)))) {
 >> +                               pkt_cnt += tmp;
 >> +                               printf("  [%02i] pkt_cnt:%lu\n", 
thr, pkt_cnt);
 >> +                               fflush(NULL);
 >> +                               tmp = 0;
 >> +                       }
 >> +               }
 >> +       }
 >> +
 >> +/* unreachable */
 >> +}
 >> +
 >> +/**
 >> + * ODP packet example main function
 >> + */
 >> +int do_odp_init(int argc, char *argv[])
 >> +{
 >> +
 >> +       odp_buffer_pool_t pool;
 >> +       int thr_id;
 >> +       void *pool_base;
 >> +       int i;
 >> +       int first_core;
 >> +
 >> +
 >> +       /* Init ODP before calling anything else */
 >> +       if (odp_init_global()) {
 >> +               ODP_ERR("Error: ODP global init failed.\n");
 >> +               exit(EXIT_FAILURE);
 >> +       }
 >> +
 >> +       /* Reserve memory for args from shared mem */
 >> +       args = odp_shm_reserve("shm_args", sizeof(args_t), 
ODP_CACHE_LINE_SIZE);
 >> +       if (args == NULL) {
 >> +               ODP_ERR("Error: shared mem alloc failed.\n");
 >> +               exit(EXIT_FAILURE);
 >> +       }
 >> +       memset(args, 0, sizeof(*args));
 >> +
 >> +       /* Parse and store the application arguments */
 >> +       //parse_args(argc, argv, &args->appl);
 >> +       args->appl.core_count = 1;
 >
 > Isn't the point of this (odp-snort) to support running snort on multiple
 > cores? As I said above I saw plenty of crashes after changing core_count
 > to anything > 1.
 >

yes, in my case it crashed only on exit. I.e. when I pressed ctrl+c. Due to
needed accurate complete odp threads when closing snort.

 > [..]
 >
 >> +/**
 >> + * Drop packets which input parsing marked as containing errors.
 >> + *
 >> + * Frees packets with error and modifies pkt_tbl[] to only contain 
packets with
 >> + * no detected errors.
 >> + *
 >> + * @param pkt_tbl  Array of packet
 >> + * @param len      Length of pkt_tbl[]
 >> + *
 >> + * @return Number of packets with no detected error
 >> + */
 >> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
 >> +{
 >> +       odp_packet_t pkt;
 >> +       unsigned pkt_cnt = len;
 >> +       unsigned i, j;
 >> +
 >> +       for (i = 0, j = 0; i < len; ++i) {
 >> +               pkt = pkt_tbl[i];
 >> +
 >> +               if (odp_unlikely(odp_packet_error(pkt))) {
 >> +                       odp_packet_free(pkt); /* Drop */
 >> +                       pkt_cnt--;
 >> +               } else if (odp_unlikely(i != j++)) {
 >> +                       pkt_tbl[j] = pkt;
 >
 > pkt_tbl[j-1]
 >

ok.

 >> +               }
 >> +       }
 >> +
 >> +       return pkt_cnt;
 >> +}
 >> +
 >
 > [..]
 >
 >> --- /dev/null
 >> +++ b/snort/odpsnort/odp_pktio.h
 >> @@ -0,0 +1 @@
 >
 > Obviously needs standard header etc.
 >

ok.

 >> +int do_odp_init(int argc, char *argv[]);
 >
 >> --- /dev/null
 >> +++ b/snort/odpsnort/snort.c
 >> @@ -0,0 +1,5095 @@
 >
 > [..]
 >
 >> +/*
 >> + *
 >> + * Function: SnortMain(int, char *)
 >> + *
 >> + * Purpose:  The real place that the program handles entry and 
exit.  Called
 >> + *           called by main(), or by SnortServiceMain().
 >> + *
 >> + * Arguments: See command line args in README file
 >> + *
 >> + * Returns: 0 => normal exit, 1 => exit on error
 >> + *
 >> + */
 >> +int ODP_SnortMain(int argc, char *argv[])
 >> +{
 >> +    char* tmp_ptr = NULL;
 >> +    const char* intf;
 >> +    int daqInit;
 >> +
 >> +
 >> +    do_odp_init(argc, argv);
 >
 > The command line arguments passed here will also go to SnortInit below,
 > which would cause problems if there are clashes (which there are).
 > Actually I see do_odp_init ignores the arguments anyway.
 >

Ok. I think snort has more complex args and it's better to provide them. 
And for odp use some config file.
Will update it.


 >> +
 >> +#ifndef WIN32
 >> +    // must be done now in case of fatal error
 >> +    // and again after daemonization
 >> +    snort_main_thread_id = pthread_self();
 >> +#endif
 >> +
 >> +    SnortInit(argc, argv);
 >> +
 >
 > [..]
 >
 >> +// non-local for easy access from core
 >> +static Packet s_packet;
 >> +static DAQ_PktHdr_t s_pkth;
 >> +static uint8_t s_data[65536];
 >> +
 >> +static DAQ_Verdict PacketCallback(
 >> +    void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
 >> +{
 >
 > With odp-snort running multi-core this will be called by multiple
 > threads simultaneously. There's clearly a whole lot of stuff here that
 > is not intended to be thread safe, such as non-atomic counters and
 > global state variables.
 >

If you are sure about this than this hole solution will not work. And it's
better try to go with several different processes or thread safe snort 3.

 >> +    int inject = 0;
 >> +    DAQ_Verdict verdict = DAQ_VERDICT_PASS;
 >> +    PROFILE_VARS;
 >> +
 >> +    PREPROC_PROFILE_START(totalPerfStats);
 >> +
 >> +#ifdef SIDE_CHANNEL
 >> +    if (ScSideChannelEnabled() && !snort_process_lock_held)
 >> +    {
 >> +        pthread_mutex_lock(&snort_process_lock);
 >> +        snort_process_lock_held = true;
 >> +    }
 >> +#endif
 >> +
 >> +#ifdef EXIT_CHECK
 >> +    if (snort_conf->exit_check && (pc.total_from_daq >= 
snort_conf->exit_check))
 >> +        ExitCheckStart();
 >> +#endif
 >> +
 >> +    /* First thing we do is process a Usr signal that we caught */
 >> +    if (SignalCheck())
 >> +    {
 >> +#ifndef SNORT_RELOAD
 >> +        /* Got SIGNAL_SNORT_RELOAD */
 >> +        PREPROC_PROFILE_END(totalPerfStats);
 >> +        Restart();
 >> +#endif
 >> +    }
 >> +
 >> +    pc.total_from_daq++;
 >> +
 >> +    /* Increment counter that we're evaling rules for caching 
results */
 >> +    rule_eval_pkt_count++;
 >> +
 >> +#ifdef TARGET_BASED
 >> +    /* Load in a new attribute table if we need to... */
 >> +    AttributeTableReloadCheck();
 >> +#endif
 >> +
 >> +    CheckForReload();
 >> +
 >> +    /* Save off the time of each and every packet */
 >> +    packet_time_update(&pkthdr->ts);
 >> +
 >> +#ifdef REG_TEST
 >> +    if ( snort_conf->pkt_skip && pc.total_from_daq <= 
snort_conf->pkt_skip )
 >> +    {
 >> +        PREPROC_PROFILE_END(totalPerfStats);
 >> +        return verdict;
 >> +    }
 >> +#endif
 >> +
 >> +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
 >> +    if (ScTerminateService() || ScPauseService())
 >> +    {
 >> +        PREPROC_PROFILE_END(totalPerfStats);
 >> +        return verdict;  // time to go
 >> +    }
 >> +#endif
 >> +
 >> +    /* reset the thresholding subsystem checks for this packet */
 >> +    sfthreshold_reset();
 >> +
 >> +    PREPROC_PROFILE_START(eventqPerfStats);
 >> +    SnortEventqReset();
 >> +    Replace_ResetQueue();
 >> +#ifdef ACTIVE_RESPONSE
 >> +    Active_ResetQueue();
 >> +#endif
 >> +    PREPROC_PROFILE_END(eventqPerfStats);
 >> +
 >> +    verdict = ProcessPacket(&s_packet, pkthdr, pkt, NULL);
 >
 > The same global s_packet ptr is be passed from multiple threads. This is
 > what caused all of the crashes I saw.
 >

Yes, snort has bunch of static variables and to convert them to per 
thread variable
might be too complex or complete app rewrite. So again it's better then 
to switch to
something thread safe.

Best regards,
Maxim.
diff mbox

Patch

--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@ 
 .PHONY: libpcap openvpn
 
-all: openvpn libpcap
+all: openvpn libpcap snort
 
 libpcap: odp
 	make -C libpcap ODP_DIR=$(PWD)/odp.git
@@ -8,10 +8,15 @@  libpcap: odp
 openvpn: odp
 	make -C openvpn
 
+snort: odp
+	make -C snort
+
 odp:
 	if [ ! -d odp.git ]; \
 		then git clone http://git.linaro.org/git/lng/odp.git odp.git; \
 	fi
+	cd odp.git; git reset --hard HEAD
+	cd odp.git; patch -N -p1 < ../snort/odp-patches/0001-implement-odp_timer_disarm_all.patch
 	cd odp.git; make libs_install  CFLAGS="-fPIC"
 
 distclean:
--- /dev/null
+++ b/snort/Makefile
@@ -0,0 +1,65 @@ 
+.PHONY: all odp daq snort odpsnort
+all: snort
+
+DAQ="daq-2.0.2"
+daqprep:
+	rm -rf ${DAQ}
+	tar xpvfz ./download/daq-2.0.2.tar.gz
+	cd ${DAQ}; patch -p1 < ../daq-patches/0001-implement-odp-daq-module.patch
+
+
+daq: daqprep libdnet
+	cd ${DAQ}; autoreconf
+	cd ${DAQ}; ./configure CFLAGS="-I${PWD}/../odp.git/build/include -g -O0" LDFLAGS="-g -L${PWD}/../odp.git/build/lib"
+	cd ${DAQ}; make
+	cd ${DAQ}; make install
+
+
+snortprep:
+	rm -rf snort-2.9.6.0
+	tar xpfz download/snort-2.9.6.0.tar.gz
+
+SNORT="snort-2.9.6.1-odp"
+snort: snortprep daq
+	rm -rf $(SNORT)
+	cp -a snort-2.9.6.0 $(SNORT)
+	cd ${SNORT}; patch -p2 < ../snort-patches/0001-add-dependancy-for-lrt.patch
+	cd ${SNORT}; ./configure --disable-static-daq LDFLAGS="-lrt"
+	cd ${SNORT}; make
+	cd ${SNORT}; make install
+
+LIBDNET="libdnet-1.11"
+libdnet:
+	#wget http://prdownloads.sourceforge.net/libdnet/libdnet-1.11.tar.gz
+	tar xpfz ./download/libdnet-1.11.tar.gz
+	cd ${LIBDNET}; ./configure
+	cd ${LIBDNET}; make
+	cd ${LIBDNET}; make install
+
+run:
+	export LD_LIBRARY_PATH="/usr/local/lib"; snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i eth0 -n 10
+
+SNORT-lib="snort-2.9.6.0-lib"
+snortlib: snortprep daq
+	rm -rf ${SNORT-lib}
+	cp -a snort-2.9.6.0 ${SNORT-lib}
+	cd ${SNORT-lib}; patch -p2 <  ../snort-patches/0001-add-dependancy-for-lrt.patch
+	cd ${SNORT-lib}; patch -p1 <  ../lib-patches/0001-Compile-Snort-as-static-library.patch
+	cd ${SNORT-lib}; patch -p1 <  ../lib-patches/0002-remove-static-from-needed-functions.patch
+	cd ${SNORT-lib}; autoreconf
+	cd ${SNORT-lib}; ./configure --disable-static-daq LDFLAGS="-lrt"
+	cd ${SNORT-lib}; make
+
+odpsnort: snortlib
+	cd odpsnort; make
+
+all: libdnet daq snort odpsnort
+
+distclean:
+	rm -rf ${DAQ}
+	rm -rf ${SNORT}
+	rm -rf ${SNORT-lib}
+	rm -rf snort-2.9.6.1
+	rm -rf snort-2.9.6.0
+	rm -rf libdnet-1.11
+	make -C odpsnort clean
--- /dev/null
+++ b/snort/README
@@ -0,0 +1,37 @@ 
+--- Snort on Open Data Plane ---
+
+Directory has 2 different demos:
+
+1. Data Acquisition Module (DAQ) with ODP support.
+
+All magic happens inside shared library daq-odp.so which provides packet I/O to Snort application. DAQ module loaded as plug-in so no snort modification is needed.
+(Because of odp uses lib rt I added librt to dependencies.).
+
+Compile:
+make
+Run:
+make run
+
+Make run will execute following command (odp daq module, interface eth0, and 10 packets to capture):
+snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i eth0 -n 10
+
+2. Snort analyze function used in Open Data Plane applications.
+
+This example is opposite to the first one. I.e. it adds snort functionality to odp apps. For that Snort was built as static library with exported needed functions.
+As base test/packet_io example was taken. Main thread does snort initialization then it starts several odp threads which do packet processing and feed Snort.
+So this test has to scale across number of cpus and have some performance benefits according to regular single threaded snort.
+
+Compile:
+make odpsnort
+Run:
+odpsnort/odp-snort
+
+Configuration:
+Selection of number of threads and interfaces can be done in source code:
+odpsnort/odp_pktio.c
+    args->appl.core_count = 1;
+    args->appl.if_count = 1;
+    args->appl.if_names = calloc(args->appl.if_count, sizeof(char *));
+    args->appl.if_names[0] = strdup("eth0");
+
+
--- /dev/null
+++ b/snort/daq-patches/0001-implement-odp-daq-module.patch
@@ -0,0 +1,477 @@ 
+From 98f7d2a6eb53a17c855a40573300437ec8a3fe83 Mon Sep 17 00:00:00 2001
+From: root <maxim.uvarov@linaro.org>
+Date: Mon, 19 May 2014 18:04:58 +0400
+Subject: [PATCH] implement odp daq module
+
+Signed-off-by: root <maxim.uvarov@linaro.org>
+---
+ configure.ac               |   7 +
+ os-daq-modules/Makefile.am |  12 ++
+ os-daq-modules/daq_odp.c   | 409 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 428 insertions(+)
+ create mode 100644 os-daq-modules/daq_odp.c
+
+diff --git a/configure.ac b/configure.ac
+index ae4f77f..5689dd3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -107,6 +107,12 @@ else
+     DEFAULT_ENABLE=no
+ fi
+ 
++# OpenDataPlane
++AC_ARG_ENABLE(odp-module,
++              AC_HELP_STRING([--disable-odp-module],[don't build the bundled OpenDataPlane module]),
++              [enable_odp_module="$enableval"], [enable_odp_module="$DEFAULT_ENABLE"])
++AM_CONDITIONAL([BUILD_ODP_MODULE], [test "$enable_odp_module" = yes])
++
+ # AFPacket Module
+ AC_ARG_ENABLE(afpacket-module,
+               AC_HELP_STRING([--disable-afpacket-module],[don't build the bundled AFPacket module]),
+@@ -276,4 +282,5 @@ echo "Build IPFW DAQ module...... : $enable_ipfw_module"
+ echo "Build IPQ DAQ module....... : $enable_ipq_module"
+ echo "Build NFQ DAQ module....... : $enable_nfq_module"
+ echo "Build PCAP DAQ module...... : $enable_pcap_module"
++echo "Build ODP DAQ module......  : $enable_odp_module"
+ echo
+diff --git a/os-daq-modules/Makefile.am b/os-daq-modules/Makefile.am
+index 37d6df3..cc61354 100644
+--- a/os-daq-modules/Makefile.am
++++ b/os-daq-modules/Makefile.am
+@@ -14,6 +14,18 @@ libdaq_static_modules_la_CFLAGS =
+ libdaq_static_modules_la_LDFLAGS = -static -avoid-version
+ libdaq_static_modules_la_LIBADD =
+ 
++if BUILD_ODP_MODULE
++if BUILD_SHARED_MODULES
++    pkglib_LTLIBRARIES += daq_odp.la
++    daq_odp_la_SOURCES = daq_odp.c
++    daq_odp_la_CFLAGS = -DBUILDING_SO
++    daq_odp_la_LDFLAGS = -module -export-dynamic -avoid-version -lrt -lodp -shared @XCCFLAGS@
++    daq_odp_la_LIBADD = $(top_builddir)/sfbpf/libsfbpf.la
++endif
++    libdaq_static_modules_la_SOURCES += daq_odp.c
++    libdaq_static_modules_la_CFLAGS += -DBUILD_ODP_MODULE
++endif
++
+ if BUILD_AFPACKET_MODULE
+ if BUILD_SHARED_MODULES
+     pkglib_LTLIBRARIES += daq_afpacket.la
+diff --git a/os-daq-modules/daq_odp.c b/os-daq-modules/daq_odp.c
+new file mode 100644
+index 0000000..aa6639e
+--- /dev/null
++++ b/os-daq-modules/daq_odp.c
+@@ -0,0 +1,409 @@
++/*
++ ** Copyright (c) 2014, Linaro Limited
++ ** All rights reserved.
++ **
++ ** SPDX-License-Identifier:      BSD-3-Clause
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <errno.h>
++#include <linux/if_ether.h>
++#include <linux/if_packet.h>
++#include <net/if.h>
++#include <net/if_arp.h>
++#include <netinet/in.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++#include <sys/poll.h>
++#include <sys/socket.h>
++#include <unistd.h>
++
++#include "daq_api.h"
++#include "sfbpf.h"
++
++#include <odp.h>
++#include <helper/odp_linux.h>
++#include <helper/odp_packet_helper.h>
++#include <helper/odp_eth.h>
++#include <helper/odp_ip.h>
++
++#define MAX_WORKERS            1
++#define SHM_PKT_POOL_SIZE      (512*2048)
++#define SHM_PKT_POOL_BUF_SIZE  1856
++#define MAX_PKT_BURST          16
++#define ODP_DEBUG		1
++
++static unsigned long debug_cnt = 0;
++
++typedef struct _odp_context
++{
++    volatile int break_loop;
++    DAQ_Stats_t stats;
++    DAQ_State state;
++    odp_queue_t inq_def;
++    odp_pktio_t pktio;
++    int snaplen;
++    char *device;
++    char errbuf[256];
++} ODP_Context_t;
++
++static int odp_daq_initialize(const DAQ_Config_t *config, void **ctxt_ptr, char *errbuf, size_t errlen)
++{
++	ODP_Context_t *odpc;
++	int rval = DAQ_ERROR;
++	int thr_id;
++	int i;
++
++	odp_buffer_pool_t pkt_pool;
++	odp_buffer_pool_t pool;
++	odp_pktio_t pktio;
++	odp_pktio_params_t params;
++	socket_params_t *sock_params = &params.sock_params;
++	odp_queue_param_t qparam;
++	char inq_name[ODP_QUEUE_NAME_LEN];
++	odp_packet_t pkt;
++	odp_buffer_t buf;
++	int ret;
++	void *pool_base;
++
++	rval = DAQ_ERROR;
++
++	printf("%s()\n", __func__);
++	odpc = calloc(1, sizeof(ODP_Context_t));
++	if (!odpc)
++	{
++		snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the new ODP context!", __FUNCTION__);
++		rval = DAQ_ERROR_NOMEM;
++		goto err;
++	}
++
++	odpc->device = strdup(config->name);
++	if (!odpc->device)
++	{
++		snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the device string!", __FUNCTION__);
++		rval = DAQ_ERROR_NOMEM;
++		goto err;
++	}
++
++	*ctxt_ptr = odpc;
++
++	/* Init ODP before calling anything else */
++	if (odp_init_global()) {
++		ODP_ERR("Error: ODP global init failed.\n");
++		goto err;
++	}
++
++	/* Init this thread */
++	thr_id = odp_thread_create(0);
++	odp_init_local(thr_id);
++
++	/* Create packet pool */
++	pool_base = odp_shm_reserve("shm_packet_pool",
++				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE);
++	if (pool_base == NULL) {
++		ODP_ERR("Error: packet pool mem alloc failed.\n");
++		goto err;
++	}
++
++	pool = odp_buffer_pool_create("packet_pool", pool_base,
++				      SHM_PKT_POOL_SIZE,
++				      SHM_PKT_POOL_BUF_SIZE,
++				      ODP_CACHE_LINE_SIZE,
++				      ODP_BUFFER_TYPE_PACKET);
++	if (pool == ODP_BUFFER_POOL_INVALID) {
++		ODP_ERR("Error: packet pool create failed.\n");
++		exit(EXIT_FAILURE);
++	}
++	odpc->snaplen = SHM_PKT_POOL_BUF_SIZE;
++	odp_buffer_pool_print(pool);
++
++	/* Open a packet IO instance for this thread */
++	sock_params->type = ODP_PKTIO_TYPE_SOCKET_MMAP;
++	sock_params->fanout = 0;
++
++	odpc->pktio = odp_pktio_open(odpc->device, pool, &params);
++	if (odpc->pktio == ODP_PKTIO_INVALID) {
++		ODP_ERR("  [%02i] Error: pktio create failed\n", 1 /*thr*/);
++		goto err;
++	}
++
++	/*
++	 * Create and set the default INPUT queue associated with the 'pktio'
++	 * resource
++	 */
++	qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
++	qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
++	qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
++	snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)odpc->pktio);
++	inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
++
++	odpc->inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam);
++	if (odpc->inq_def == ODP_QUEUE_INVALID) {
++		ODP_ERR("  [%02i] Error: pktio queue creation failed\n", 1 /*thr*/);
++		goto err;
++	}
++
++	ret = odp_pktio_inq_setdef(odpc->pktio, odpc->inq_def);
++	if (ret != 0) {
++		ODP_ERR("  [%02i] Error: default input-Q setup\n", 1 /*thr*/);
++		goto err;
++	}
++
++        odpc->state = DAQ_STATE_INITIALIZED;
++
++	printf("%s() DAQ_SUCCESS.\n\n", __func__);
++	return DAQ_SUCCESS;
++err:
++
++	return rval;
++}
++
++static int odp_daq_set_filter(void *handle, const char *filter)
++{
++	printf("%s()\n", __func__);
++	return DAQ_SUCCESS;
++}
++
++static int odp_daq_start(void *handle)
++{
++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
++    if (!odpc)
++	    return DAQ_ERROR_NOCTX;
++
++    odpc->state = DAQ_STATE_STARTED;
++    return DAQ_SUCCESS;
++}
++
++static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = {
++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_PASS */
++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLOCK */
++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_REPLACE */
++    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_WHITELIST */
++    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLACKLIST */
++    DAQ_VERDICT_PASS        /* DAQ_VERDICT_IGNORE */
++};
++
++static int odp_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user)
++{
++    	ODP_Context_t *odpc;
++	DAQ_PktHdr_t daqhdr;
++	DAQ_Verdict verdict;
++	const uint8_t *data;
++
++	int thr_id;
++	odp_packet_t pkt;
++	odp_buffer_t buf;
++	int ret;
++	odp_buffer_pool_t pkt_pool;
++	odp_pktio_params_t params;
++	odp_pktio_t pktio;
++
++	int i;
++	odp_packet_t pkt_tbl[MAX_PKT_BURST];
++	int pkts;
++
++	odpc = (ODP_Context_t *) handle;
++	if (!odpc)
++		return 0;
++
++	if (odpc->state != DAQ_STATE_STARTED)
++		return 0;
++
++	while (1)
++	{
++		/* Has breakloop() been called? */
++		if (odpc->break_loop)
++		{
++			odpc->break_loop = 0;
++			printf("%s() BREAK LOOP\n", __func__);
++			return 0;
++		}
++
++		pkts = odp_pktio_recv(odpc->pktio, pkt_tbl, MAX_PKT_BURST);
++		if (pkts <= 0) {
++			return;
++		}
++
++		printf("got %d packets\n", pkts);
++
++		for (i = 0; i < pkts; ++i) {
++			pkt = pkt_tbl[i];
++
++			data = odp_packet_l2(pkt);
++			if (!data) {
++				printf("no l2 offset, packet dropped\n");
++				continue;
++			}
++
++			verdict = DAQ_VERDICT_PASS;
++
++			gettimeofday(&daqhdr.ts, NULL);
++			daqhdr.caplen = odp_buffer_size(pkt);
++
++			printf("%s() odp recieved packet len %d.\n", __func__, odp_packet_get_len(pkt));
++
++			daqhdr.pktlen = odp_packet_get_len(pkt);
++			daqhdr.ingress_index = 0;
++			daqhdr.egress_index =  DAQ_PKTHDR_UNKNOWN;
++			daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
++			daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
++			daqhdr.flags = 0;
++			daqhdr.opaque = 0;
++			daqhdr.priv_ptr = NULL;
++			daqhdr.address_space_id = 0;
++
++			if (callback)
++			{
++				verdict = callback(user, &daqhdr, data); // call back with pointer to data and daqhdr
++				if (verdict >= MAX_DAQ_VERDICT)
++					verdict = DAQ_VERDICT_PASS;
++				odpc->stats.verdicts[verdict]++;
++				verdict = verdict_translation_table[verdict];
++				printf("opd processed packet %ld\n", odpc->stats.verdicts[verdict]);
++			}
++		}
++
++		if (pkts > 0) {
++			printf("pkts > 0, return\n");
++		       return 0;
++		}
++	}
++	return 0;
++}
++
++static int odp_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, const uint8_t *packet_data, uint32_t len, int reverse)
++{
++    return DAQ_SUCCESS;
++}
++
++static int odp_daq_breakloop(void *handle)
++{
++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++    odpc->break_loop = 1;
++    return DAQ_SUCCESS;
++}
++
++static int odp_daq_stop(void *handle)
++{
++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++    odpc->break_loop = 1;
++    odp_timer_disarm_all();
++
++    return DAQ_SUCCESS;
++}
++
++static void odp_daq_shutdown(void *handle)
++{
++	odp_timer_disarm_all();
++}
++
++static DAQ_State odp_daq_check_status(void *handle)
++{
++	ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++	if (!odpc) {
++		printf("%s() odpc is not allocated\n");
++		return DAQ_STATE_UNINITIALIZED;
++	}
++
++    	//printf("%s()\n", __func__);
++	return odpc->state;
++}
++
++static int odp_daq_get_stats(void *handle, DAQ_Stats_t *stats)
++{
++	ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++	memcpy(stats, &odpc->stats, sizeof(DAQ_Stats_t));
++	return DAQ_SUCCESS;
++}
++
++static void odp_daq_reset_stats(void *handle)
++{
++    //ODP_Context_t *odpc = (ODP_Context_t *) handle;
++}
++
++static int odp_daq_get_snaplen(void *handle)
++{
++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++    if (odpc)
++	return odpc->snaplen;
++
++    return 1500;
++}
++
++static uint32_t odp_daq_get_capabilities(void *handle)
++{
++    return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | /*DAQ_CAPA_UNPRIV_START |*/ DAQ_CAPA_BREAKLOOP | DAQ_CAPA_BPF | DAQ_CAPA_DEVICE_INDEX;
++}
++
++static int odp_daq_get_datalink_type(void *handle)
++{
++    return DLT_EN10MB;
++}
++
++static const char *odp_daq_get_errbuf(void *handle)
++{
++	ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++	return odpc->errbuf;
++}
++
++static void odp_daq_set_errbuf(void *handle, const char *string)
++{
++    ODP_Context_t *odpc = (ODP_Context_t *) handle;
++
++    if (!string)
++        return;
++
++    DPE(odpc->errbuf, "%s", string);
++    return;
++}
++
++static int odp_daq_get_device_index(void *handle, const char *string)
++{
++    return DAQ_ERROR_NOTSUP;
++}
++
++#ifdef BUILDING_SO
++DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA =
++#else
++const DAQ_Module_t afpacket_daq_module_data =
++#endif
++{
++    .api_version = DAQ_API_VERSION,
++    .module_version = 1,
++    .name = "odp",
++    .type = DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
++    .initialize = odp_daq_initialize,
++    .set_filter = odp_daq_set_filter,
++    .start = odp_daq_start,
++    .acquire = odp_daq_acquire,
++    .inject = odp_daq_inject,
++    .breakloop = odp_daq_breakloop,
++    .stop = odp_daq_stop,
++    .shutdown = odp_daq_shutdown,
++    .check_status = odp_daq_check_status,
++    .get_stats = odp_daq_get_stats,
++    .reset_stats = odp_daq_reset_stats,
++    .get_snaplen = odp_daq_get_snaplen,
++    .get_capabilities = odp_daq_get_capabilities,
++    .get_datalink_type = odp_daq_get_datalink_type,
++    .get_errbuf = odp_daq_get_errbuf,
++    .set_errbuf = odp_daq_set_errbuf,
++    .get_device_index = odp_daq_get_device_index,
++    .modify_flow = NULL,
++    .hup_prep = NULL,
++    .hup_apply = NULL,
++    .hup_post = NULL,
++};
+-- 
+1.8.5.1.163.gd7aced9
+
--- /dev/null
+++ b/snort/download/daq-2.0.2.tar.gz.md5
@@ -0,0 +1 @@ 
+865bf9b750a2a2ca632591a3c70b0ea0
\ No newline at end of file
--- /dev/null
+++ b/snort/lib-patches/0001-Compile-Snort-as-static-library.patch
@@ -0,0 +1,114 @@ 
+From 3e23b5c31acc1759b1ed2aabd518964390f16c89 Mon Sep 17 00:00:00 2001
+From: Maxim Uvarov <maxim.uvarov@linaro.org>
+Date: Wed, 16 Apr 2014 18:15:29 +0400
+Subject: [PATCH 1/2] Compile Snort as static library
+
+Compile Snort as static library to use it's analyze functions
+in other applications.
+Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
+---
+ src/Makefile.am |   40 +++++++++++++++++++++-------------------
+ src/snort.c     |    8 ++------
+ 2 files changed, 23 insertions(+), 25 deletions(-)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 1c1f826..f683dee 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,13 +1,13 @@
+ ## $Id$
+ AUTOMAKE_OPTIONS=foreign no-dependencies
+ 
+-bin_PROGRAMS = snort
++noinst_LIBRARIES = libsnort.a
+ 
+ if BUILD_SNPRINTF
+ SNPRINTF_SOURCES = snprintf.c snprintf.h
+ endif
+ 
+-snort_SOURCES = cdefs.h \
++libsnort_a_SOURCES = cdefs.h \
+ event.h \
+ generators.h \
+ sf_protocols.h \
+@@ -62,20 +62,6 @@ rule_option_types.h \
+ sfdaq.c sfdaq.h \
+ idle_processing.c idle_processing.h idle_processing_funcs.h
+ 
+-snort_LDADD = output-plugins/libspo.a \
+-detection-plugins/libspd.a            \
+-dynamic-plugins/libdynamic.a            \
+-dynamic-output/plugins/liboutput.a      \
+-preprocessors/libspp.a                \
+-parser/libparser.a \
+-target-based/libtarget_based.a \
+-preprocessors/HttpInspect/libhttp_inspect.a \
+-preprocessors/Stream5/libstream5.a \
+-sfutil/libsfutil.a \
+-control/libsfcontrol.a \
+-file-process/libfileAPI.a \
+-file-process/libs/libfile.a
+-
+ if BUILD_DYNAMIC_EXAMPLES
+ EXAMPLES_DIR = dynamic-examples
+ endif
+@@ -85,9 +71,25 @@ SUBDIRS = sfutil win32 output-plugins detection-plugins dynamic-plugins preproce
+ 
+ INCLUDES = @INCLUDES@
+ 
++libsnort_a_LIBADD = $(wildcard output-plugins/*.o) \
++$(wildcard detection-plugins/*.o)            \
++$(wildcard dynamic-plugins/*.o)            \
++$(wildcard dynamic-output/plugins/*.o)      \
++$(wildcard dynamic-output/*/*.o)      \
++$(wildcard preprocessors/*.o)                \
++$(wildcard parser/*.o) \
++$(wildcard target-based/*.o) \
++$(wildcard preprocessors/HttpInspect/*/*.o) \
++$(wildcard preprocessors/Stream5/*.o) \
++$(wildcard sfutil/*.o) \
++$(wildcard control/*.o) \
++$(wildcard file-process/*.o) \
++$(wildcard file-process/libs/*.o)
++
++
+ if BUILD_SIDE_CHANNEL
+-snort_LDADD += \
+-side-channel/libsidechannel.a \
+-side-channel/plugins/libsscm.a
++libsnort_a_LIBADD += \
++$(wildcard side-channel/*.o) \
++$(wildcard side-channel/plugins/*.o)
+ SUBDIRS += side-channel
+ endif
+diff --git a/src/snort.c b/src/snort.c
+index 0280107..ce5c52e 100644
+--- a/src/snort.c
++++ b/src/snort.c
+@@ -775,14 +775,9 @@ static int InlineFailOpen (void)
+  * Returns: 0 => normal exit, 1 => exit on error
+  *
+  */
++#if 0
+ int main(int argc, char *argv[])
+ {
+-	/* hack to add deps to -lrt for timer_create() and friends from odp */
+-	static volatile int link_rt = 0;
+-	timer_t timerid = 0;
+-	if (link_rt)
+-		timer_settime(timerid, 0, NULL, NULL);
+-
+ #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+     /* Do some sanity checking, because some people seem to forget to
+      * put spaces between their parameters
+@@ -808,6 +803,7 @@ int main(int argc, char *argv[])
+ 
+     return SnortMain(argc, argv);
+ }
++#endif
+ 
+ /*
+  *
+-- 
+1.7.9.5
+
--- /dev/null
+++ b/snort/lib-patches/0002-remove-static-from-needed-functions.patch
@@ -0,0 +1,73 @@ 
+From 71aeb1a6bbda6464b717565aa4a1e3126cb59f1c Mon Sep 17 00:00:00 2001
+From: Maxim Uvarov <maxim.uvarov@linaro.org>
+Date: Wed, 16 Apr 2014 18:16:57 +0400
+Subject: [PATCH 2/2] remove static from needed functions
+
+Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
+---
+ src/snort.c |   14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/src/snort.c b/src/snort.c
+index ce5c52e..5e5060a 100644
+--- a/src/snort.c
++++ b/src/snort.c
+@@ -485,7 +485,7 @@ static void InitProtoNames(void);
+ static const char* GetPacketSource(char**);
+ 
+ static void CleanExit(int);
+-static void SnortInit(int, char **);
++void SnortInit(int, char **);
+ static void InitPidChrootAndPrivs(pid_t);
+ static void ParseCmdLine(int, char **);
+ static int ShowUsage(char *);
+@@ -515,8 +515,8 @@ static void FreeReferences(ReferenceSystemNode *);
+ static void FreePlugins(SnortConfig *);
+ static void FreePreprocessors(SnortConfig *);
+ 
+-static void SnortUnprivilegedInit(void);
+-static int SetPktProcessor(void);
++void SnortUnprivilegedInit(void);
++int SetPktProcessor(void);
+ static void PacketLoop(void);
+ #if 0
+ static char * ConfigFileSearch(void);
+@@ -1618,7 +1618,7 @@ static Packet s_packet;
+ static DAQ_PktHdr_t s_pkth;
+ static uint8_t s_data[65536];
+ 
+-static DAQ_Verdict PacketCallback(
++/*static*/ DAQ_Verdict PacketCallback(
+     void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
+ {
+     int inject = 0;
+@@ -1779,7 +1779,7 @@ static DAQ_Verdict PacketCallback(
+     return verdict;
+ }
+ 
+-static void PrintPacket(Packet *p)
++void PrintPacket(Packet *p)
+ {
+     if (p->iph != NULL)
+     {
+@@ -2989,7 +2989,7 @@ static void ParseCmdLine(int argc, char **argv)
+  */
+ // TBD add GetDecoder(dlt) to decode module and hide all
+ // protocol decoder functions.
+-static int SetPktProcessor(void)
++int SetPktProcessor(void)
+ {
+     const char* slink = NULL;
+     const char* extra = NULL;
+@@ -5162,7 +5162,7 @@ static DAQ_Verdict IgnoreCallback (
+ // packet passing is done by the driver/hardware.  the goal then is to put as
+ // much initialization stuff in SnortInit() as possible and to restrict this
+ // function to those things that depend on DAQ startup or non-root user/group.
+-static void SnortUnprivilegedInit(void)
++void SnortUnprivilegedInit(void)
+ {
+ #ifdef ACTIVE_RESPONSE
+     // this depends on instantiated daq capabilities
+-- 
+1.7.9.5
+
--- /dev/null
+++ b/snort/odp-patches/0001-implement-odp_timer_disarm_all.patch
@@ -0,0 +1,63 @@ 
+From 943e815797f886580354f050e7316306c032335c Mon Sep 17 00:00:00 2001
+From: Maxim Uvarov <maxim.uvarov@linaro.org>
+Date: Wed, 9 Apr 2014 20:38:13 +0400
+Subject: [ODP/PATCH] implement odp_timer_disarm_all()
+
+Implement function to disarm all timers. Needed in case of
+normal exit from application.
+Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
+---
+ platform/linux-generic/include/odp_internal.h |  1 +
+ platform/linux-generic/source/odp_timer.c     | 24 ++++++++++++++++++++++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h
+index fb3be79..9b0769e 100644
+--- a/platform/linux-generic/include/odp_internal.h
++++ b/platform/linux-generic/include/odp_internal.h
+@@ -38,6 +38,7 @@ int odp_schedule_init_global(void);
+ int odp_schedule_init_local(void);
+ 
+ int odp_timer_init_global(void);
++int odp_timer_disarm_all(void);
+ 
+ #ifdef __cplusplus
+ }
+diff --git a/platform/linux-generic/source/odp_timer.c b/platform/linux-generic/source/odp_timer.c
+index 6fb5025..98ffde3 100644
+--- a/platform/linux-generic/source/odp_timer.c
++++ b/platform/linux-generic/source/odp_timer.c
+@@ -217,6 +217,30 @@ int odp_timer_init_global(void)
+ 	return 0;
+ }
+ 
++int odp_timer_disarm_all(void)
++{
++	int timers;
++	struct itimerspec ispec;
++
++	timers = odp_atomic_load_int(&odp_timer.num_timers);
++
++	ispec.it_interval.tv_sec  = 0;
++	ispec.it_interval.tv_nsec = 0;
++	ispec.it_value.tv_sec     = 0;
++	ispec.it_value.tv_nsec    = 0;
++
++	for (; timers >= 0; timers--) {
++		if (timer_settime(odp_timer.timer[timers].timerid,
++				  0, &ispec, NULL)) {
++			ODP_DBG("Timer reset failed\n");
++			return -1;
++		}
++		odp_atomic_fetch_sub_int(&odp_timer.num_timers, 1);
++	}
++
++	return 0;
++}
++
+ odp_timer_t odp_timer_create(const char *name, odp_buffer_pool_t pool,
+ 			     uint64_t resolution, uint64_t min_tmo,
+ 			     uint64_t max_tmo)
+-- 
+1.8.5.1.163.gd7aced9
+
--- /dev/null
+++ b/snort/odpsnort/Makefile
@@ -0,0 +1,47 @@ 
+SNORT=$(PWD)/../snort-2.9.6.0-lib
+CFLAGS += -I/$(SNORT)/src
+LDFLAGS += -L/$(SNORT)/src
+LDFLAGS += -L/$(SNORT)/src/dynamic-plugins
+
+DAQ=$(PWD)/../daq-2.0.2
+DAQ_LIB_DIR = "$(DAQ)/api/.libs"
+LDFLAGS += "-L$(DAQ_LIB_DIR)"
+
+DAQ_LIB = "$(DAQ)/api/.libs/libdaq.a"
+
+DNET_LIB_DIR = "/usr/local/lib"
+LDFLAGS += "-L$(DNET_LIB_DIR)"
+
+INC = "-I$(SNORT)/src/sfutil"
+INC += "-I$(SNORT)/src/preprocessors"
+INC += "-I$(SNORT)/src/dynamic-preprocessors/include"
+INC += "-I$(SNORT)/src/detection-plugins"
+INC += "-I$(SNORT)/src/target-based"
+INC += "-I$(SNORT)/src/control"
+INC += "-I$(SNORT)/src/file-process"
+INC += "-I$(SNORT)/src/file-process/libs"
+INC += "-I$(SNORT)/src/preprocessors/Stream5"
+INC += "-I$(SNORT)"
+
+ODP_DIR = $(PWD)/../../odp.git
+ODP_LIB = $(ODP_DIR)/build/lib/libodp.a
+ODP_CFLAGS += -I$(ODP_DIR)/include
+ODP_CFLAGS += -I$(ODP_DIR)/platform/linux-generic/include
+ODP_CFLAGS += -I$(ODP_DIR)/platform/linux-generic/include/api
+
+LDFLAGS += $(ODP_LIB)
+
+DAQ = $(PWD)/../daq-2.0.2
+ODP_CFLAGS += -I$(DAQ)
+
+all:
+	gcc -c -O0 -g snort.c ${CFLAGS} ${LDFLAGS} $(INC) -o snort.o
+	gcc -c -O0 -g -pthread $(ODP_CFLAGS)  odp_pktio.c -o odp_pktio.o
+	gcc snort.o odp_pktio.o ${CFLAGS} ${LDFLAGS} $(INC) -g -O0 -lsnort -lz -lpcap -pthread -lpcre -lssl -lcrypto -lm -ldnet ${DAQ_LIB} -lrt -o odp-snort
+
+clean:
+	rm -rf odp-snort *.o
+run:
+	export LD_LIBRARY_PATH="/usr/local/lib";./odp-snort -i eth0
+
+
--- /dev/null
+++ b/snort/odpsnort/odp_pktio.c
@@ -0,0 +1,673 @@ 
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example odp_example_pktio.c  ODP basic packet IO loopback test application
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <odp.h>
+#include <helper/odp_linux.h>
+#include <helper/odp_packet_helper.h>
+#include <helper/odp_eth.h>
+#include <helper/odp_ip.h>
+
+/* Snort */
+#include <api/daq_common.h>
+
+#define MAX_WORKERS            32
+#define SHM_PKT_POOL_SIZE      (512*2048)
+#define SHM_PKT_POOL_BUF_SIZE  1856
+#define MAX_PKT_BURST          16
+
+#define APPL_MODE_PKT_BURST    0
+#define APPL_MODE_PKT_QUEUE    1
+
+#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x))
+
+/** Get rid of path in filename - only for unix-type paths using '/' */
+#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
+			    strrchr((file_name), '/') + 1 : (file_name))
+/**
+ * Parsed command line application arguments
+ */
+typedef struct {
+	int core_count;
+	int if_count;		/**< Number of interfaces to be used */
+	char **if_names;	/**< Array of pointers to interface names */
+	int mode;		/**< Packet IO mode */
+	int type;		/**< Packet IO type */
+	int fanout;		/**< Packet IO fanout */
+	odp_buffer_pool_t pool;	/**< Buffer pool for packet IO */
+} appl_args_t;
+
+/**
+ * Thread specific arguments
+ */
+typedef struct {
+	char *pktio_dev;	/**< Interface name to use */
+	odp_buffer_pool_t pool;	/**< Buffer pool for packet IO */
+	int mode;		/**< Thread mode */
+	int type;		/**< Thread i/o type */
+	int fanout;		/**< Thread i/o fanout */
+} thread_args_t;
+
+/**
+ * Grouping of both parsed CL args and thread specific args - alloc together
+ */
+typedef struct {
+	/** Application (parsed) arguments */
+	appl_args_t appl;
+	/** Thread specific arguments */
+	thread_args_t thread[MAX_WORKERS];
+} args_t;
+
+/** Global pointer to args */
+static args_t *args;
+
+/* helper funcs */
+static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
+static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len);
+static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
+static void print_info(char *progname, appl_args_t *appl_args);
+static void usage(char *progname);
+
+static void analyze_packet_in_snort(odp_packet_t pkt, int thr)
+{
+	DAQ_PktHdr_t daqhdr;
+	const uint8_t *data;
+	DAQ_Verdict verd;
+
+	data = odp_packet_l2(pkt);
+	if (!data) {
+		printf("no l2 offset, packet dropped\n");
+		return;
+	}
+
+	gettimeofday(&daqhdr.ts, NULL);
+	daqhdr.caplen = odp_buffer_size(pkt);
+	printf("%s() odp recieved packet len %d. thread %d\n", __func__, odp_packet_get_len(pkt), thr);
+	daqhdr.pktlen = odp_packet_get_len(pkt);
+	daqhdr.ingress_index = 0;
+	daqhdr.egress_index =  DAQ_PKTHDR_UNKNOWN;
+	daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
+	daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
+	daqhdr.flags = 0;
+	daqhdr.opaque = 0;
+	daqhdr.priv_ptr = NULL;
+	daqhdr.address_space_id = 0;
+
+	/* Pass packet to Snort */
+	verd = PacketCallback( "NULL", daqhdr, data);
+	return;
+}
+
+/**
+ * Packet IO loopback worker thread using ODP queues
+ *
+ * @param arg  thread arguments of type 'thread_args_t *'
+ */
+static void *pktio_queue_thread(void *arg)
+{
+	int thr;
+	odp_buffer_pool_t pkt_pool;
+	odp_pktio_t pktio;
+	thread_args_t *thr_args;
+	odp_queue_t outq_def;
+	odp_queue_t inq_def;
+	char inq_name[ODP_QUEUE_NAME_LEN];
+	odp_queue_param_t qparam;
+	odp_packet_t pkt;
+	odp_buffer_t buf;
+	int ret;
+	unsigned long pkt_cnt = 0;
+	unsigned long err_cnt = 0;
+	odp_pktio_params_t params;
+	socket_params_t *sock_params = &params.sock_params;
+
+	thr = odp_thread_id();
+	thr_args = arg;
+
+	printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
+	       thr_args->pktio_dev);
+
+	/* Lookup the packet pool */
+	pkt_pool = odp_buffer_pool_lookup("packet_pool");
+	if (pkt_pool == ODP_BUFFER_POOL_INVALID) {
+		ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
+		return NULL;
+	}
+
+	/* Open a packet IO instance for this thread */
+	sock_params->type = ODP_PKTIO_TYPE_SOCKET_BASIC;
+	sock_params->fanout = 0;
+	pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
+	if (pktio == ODP_PKTIO_INVALID) {
+		ODP_ERR("  [%02i] Error: pktio create failed\n", thr);
+		return NULL;
+	}
+
+	/*
+	 * Create and set the default INPUT queue associated with the 'pktio'
+	 * resource
+	 */
+	qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
+	qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
+	qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
+	snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio);
+	inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
+
+	inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam);
+	if (inq_def == ODP_QUEUE_INVALID) {
+		ODP_ERR("  [%02i] Error: pktio queue creation failed\n", thr);
+		return NULL;
+	}
+
+	ret = odp_pktio_inq_setdef(pktio, inq_def);
+	if (ret != 0) {
+		ODP_ERR("  [%02i] Error: default input-Q setup\n", thr);
+		return NULL;
+	}
+
+	printf("  [%02i] created pktio:%02i, queue mode (ATOMIC queues)\n"
+	       "          default pktio%02i-INPUT queue:%u\n",
+		thr, pktio, pktio, inq_def);
+
+	/* Loop packets */
+	for (;;) {
+		odp_pktio_t pktio_tmp;
+
+#if 1
+		/* Use schedule to get buf from any input queue */
+		buf = odp_schedule(NULL, ODP_SCHED_WAIT);
+#else
+		/* Always dequeue from the same input queue */
+		buf = odp_queue_deq(inq_def);
+#endif
+
+		if (!odp_buffer_is_valid(buf))
+			continue;
+
+		pkt = odp_packet_from_buffer(buf);
+
+		analyze_packet_in_snort(pkt, thr);
+
+#if 0
+		/* Print packet counts every once in a while */
+		if (odp_unlikely(pkt_cnt++ % 100000 == 0)) {
+			printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
+			fflush(NULL);
+		}
+#endif
+	}
+
+/* unreachable */
+}
+
+/**
+ * Packet IO loopback worker thread using bursts from/to IO resources
+ *
+ * @param arg  thread arguments of type 'thread_args_t *'
+ */
+static void *pktio_ifburst_thread(void *arg)
+{
+	int thr;
+	odp_buffer_pool_t pkt_pool;
+	odp_pktio_t pktio;
+	thread_args_t *thr_args;
+	int pkts, pkts_ok;
+	odp_packet_t pkt_tbl[MAX_PKT_BURST];
+	unsigned long pkt_cnt = 0;
+	unsigned long err_cnt = 0;
+	unsigned long tmp = 0;
+	odp_pktio_params_t params;
+	socket_params_t *sock_params = &params.sock_params;
+
+	thr = odp_thread_id();
+	thr_args = arg;
+
+	printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr,
+	       thr_args->pktio_dev);
+
+	/* Lookup the packet pool */
+	pkt_pool = odp_buffer_pool_lookup("packet_pool");
+	if (pkt_pool == ODP_BUFFER_POOL_INVALID || pkt_pool != thr_args->pool) {
+		ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
+		return NULL;
+	}
+
+	/* Open a packet IO instance for this thread */
+	sock_params->type = thr_args->type;
+	sock_params->fanout = thr_args->fanout;
+	pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, &params);
+	if (pktio == ODP_PKTIO_INVALID) {
+		ODP_ERR("  [%02i] Error: pktio create failed.\n", thr);
+		return NULL;
+	}
+
+	printf("  [%02i] created pktio:%02i, burst mode\n",
+	       thr, pktio);
+
+	/* Loop packets */
+	for (;;) {
+		pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST);
+		if (pkts > 0) {
+			/* Drop packets with errors */
+			pkts_ok = drop_err_pkts(pkt_tbl, pkts);
+			if (pkts_ok > 0) {
+				/* Swap Eth MACs and IP-addrs */
+				swap_pkt_addrs(pkt_tbl, pkts_ok);
+				odp_pktio_send(pktio, pkt_tbl, pkts_ok);
+			}
+
+			if (odp_unlikely(pkts_ok != pkts))
+				ODP_ERR("Dropped frames:%u - err_cnt:%lu\n",
+					pkts-pkts_ok, ++err_cnt);
+
+			/* Print packet counts every once in a while */
+			tmp += pkts_ok;
+			if (odp_unlikely((tmp >= 100000) || /* OR first print:*/
+			    ((pkt_cnt == 0) && ((tmp-1) < MAX_PKT_BURST)))) {
+				pkt_cnt += tmp;
+				printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
+				fflush(NULL);
+				tmp = 0;
+			}
+		}
+	}
+
+/* unreachable */
+}
+
+/**
+ * ODP packet example main function
+ */
+int do_odp_init(int argc, char *argv[])
+{
+
+	odp_buffer_pool_t pool;
+	int thr_id;
+	void *pool_base;
+	int i;
+	int first_core;
+
+
+	/* Init ODP before calling anything else */
+	if (odp_init_global()) {
+		ODP_ERR("Error: ODP global init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Reserve memory for args from shared mem */
+	args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE);
+	if (args == NULL) {
+		ODP_ERR("Error: shared mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	memset(args, 0, sizeof(*args));
+
+	/* Parse and store the application arguments */
+	//parse_args(argc, argv, &args->appl);
+	args->appl.core_count = 1;
+	args->appl.if_count = 1;
+	args->appl.if_names = calloc(args->appl.if_count, sizeof(char *));
+	args->appl.if_names[0] = strdup("eth0");
+
+	args->appl.fanout = 0;
+	args->appl.mode = APPL_MODE_PKT_QUEUE; 
+
+	/* Print both system and application information */
+	print_info(NO_PATH(argv[0]), &args->appl);
+
+	/* Init this thread */
+	thr_id = odp_thread_create(0);
+	odp_init_local(thr_id);
+
+	/* Create packet pool */
+	pool_base = odp_shm_reserve("shm_packet_pool",
+				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE);
+	if (pool_base == NULL) {
+		ODP_ERR("Error: packet pool mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	pool = odp_buffer_pool_create("packet_pool", pool_base,
+				      SHM_PKT_POOL_SIZE,
+				      SHM_PKT_POOL_BUF_SIZE,
+				      ODP_CACHE_LINE_SIZE,
+				      ODP_BUFFER_TYPE_PACKET);
+	if (pool == ODP_BUFFER_POOL_INVALID) {
+		ODP_ERR("Error: packet pool create failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	odp_buffer_pool_print(pool);
+
+	return 0;
+}
+
+void odp_snort_run_threads(void)
+{
+	odp_linux_pthread_t thread_tbl[MAX_WORKERS];
+	int i;
+	int core_count;
+	int num_workers;
+	int first_core;
+
+	core_count  = odp_sys_core_count();
+	num_workers = core_count;
+
+	/*
+	 * By default core #0 runs Linux kernel background tasks.
+	 * Start mapping thread from core #1
+	 */
+	first_core = 1;
+
+	if (core_count == 1)
+		first_core = 0;
+
+	printf("First core:         %i\n\n", first_core);
+
+	if (args->appl.core_count)
+		num_workers = args->appl.core_count;
+
+	if (num_workers > MAX_WORKERS)
+		num_workers = MAX_WORKERS;
+
+	printf("Num worker threads: %i\n", num_workers);
+
+	/* Create and init worker threads */
+	memset(thread_tbl, 0, sizeof(thread_tbl));
+	for (i = 0; i < num_workers; ++i) {
+		void *(*thr_run_func) (void *);
+		int core;
+		int if_idx;
+
+		core = (first_core + i) % core_count;
+
+		if_idx = i % args->appl.if_count;
+
+		args->thread[i].pktio_dev = args->appl.if_names[if_idx];
+		args->thread[i].mode = args->appl.mode;
+		args->thread[i].type = args->appl.type;
+		args->thread[i].fanout = args->appl.fanout;
+
+		if (args->appl.mode == APPL_MODE_PKT_BURST)
+			thr_run_func = pktio_ifburst_thread;
+		else /* APPL_MODE_PKT_QUEUE */
+			thr_run_func = pktio_queue_thread;
+		/*
+		 * Create threads one-by-one instead of all-at-once,
+		 * because each thread might get different arguments.
+		 * Calls odp_thread_create(cpu) for each thread
+		 */
+		odp_linux_pthread_create(thread_tbl, 1, core, thr_run_func,
+					 &args->thread[i]);
+	}
+
+	/* Master thread waits for other threads to exit */
+	odp_linux_pthread_join(thread_tbl, num_workers);
+	printf("Exit\n\n");
+}
+
+
+/**
+ * Drop packets which input parsing marked as containing errors.
+ *
+ * Frees packets with error and modifies pkt_tbl[] to only contain packets with
+ * no detected errors.
+ *
+ * @param pkt_tbl  Array of packet
+ * @param len      Length of pkt_tbl[]
+ *
+ * @return Number of packets with no detected error
+ */
+static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
+{
+	odp_packet_t pkt;
+	unsigned pkt_cnt = len;
+	unsigned i, j;
+
+	for (i = 0, j = 0; i < len; ++i) {
+		pkt = pkt_tbl[i];
+
+		if (odp_unlikely(odp_packet_error(pkt))) {
+			odp_packet_free(pkt); /* Drop */
+			pkt_cnt--;
+		} else if (odp_unlikely(i != j++)) {
+			pkt_tbl[j] = pkt;
+		}
+	}
+
+	return pkt_cnt;
+}
+
+/**
+ * Swap eth src<->dst and IP src<->dst addresses
+ *
+ * @param pkt_tbl  Array of packets
+ * @param len      Length of pkt_tbl[]
+ */
+
+static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len)
+{
+	odp_packet_t pkt;
+	odp_ethhdr_t *eth;
+	odp_ethaddr_t tmp_addr;
+	odp_ipv4hdr_t *ip;
+	uint32be_t ip_tmp_addr; /* tmp ip addr */
+	unsigned i;
+
+	for (i = 0; i < len; ++i) {
+		pkt = pkt_tbl[i];
+		if (odp_packet_inflag_eth(pkt)) {
+			eth = (odp_ethhdr_t *)odp_packet_l2(pkt);
+
+			tmp_addr = eth->dst;
+			eth->dst = eth->src;
+			eth->src = tmp_addr;
+
+			if (odp_packet_inflag_ipv4(pkt)) {
+				/* IPv4 */
+				ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt);
+
+				ip_tmp_addr  = ip->src_addr;
+				ip->src_addr = ip->dst_addr;
+				ip->dst_addr = ip_tmp_addr;
+			}
+		}
+	}
+}
+
+/**
+ * Parse and store the command line arguments
+ *
+ * @param argc       argument count
+ * @param argv[]     argument vector
+ * @param appl_args  Store application arguments here
+ */
+static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
+{
+	int opt;
+	int long_index;
+	char *names, *str, *token, *save;
+	size_t len;
+	int i;
+	static struct option longopts[] = {
+		{"count", required_argument, NULL, 'c'},
+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */
+		{"mode", required_argument, NULL, 'm'},		/* return 'm' */
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	appl_args->mode = -1; /* Invalid, must be changed by parsing */
+	appl_args->type = 3;  /* 3: ODP_PKTIO_TYPE_SOCKET_MMAP */
+	appl_args->fanout = 1; /* turn off fanout by default for mmap */
+
+	for (i = 0; i < argc; i++)
+		printf("argv %s\n", argv[i]);
+
+	while (1) {
+		opt = getopt_long(argc, argv, "+c:i:m:t:f:h",
+				  longopts, &long_index);
+
+		printf("opt %d\n", opt);
+		if (opt == -1)
+			break;	/* No more options */
+
+		switch (opt) {
+		case 'c':
+			appl_args->core_count = atoi(optarg);
+			break;
+			/* parse packet-io interface names */
+		case 'i':
+			len = strlen(optarg);
+			if (len == 0) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+			len += 1;	/* add room for '\0' */
+
+			names = malloc(len);
+			if (names == NULL) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			/* count the number of tokens separated by ',' */
+			strcpy(names, optarg);
+			for (str = names, i = 0;; str = NULL, i++) {
+				token = strtok_r(str, ",", &save);
+				if (token == NULL)
+					break;
+			}
+			appl_args->if_count = i;
+
+			if (appl_args->if_count == 0) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			/* allocate storage for the if names */
+			appl_args->if_names =
+			    calloc(appl_args->if_count, sizeof(char *));
+
+			/* store the if names (reset names string) */
+			strcpy(names, optarg);
+			for (str = names, i = 0;; str = NULL, i++) {
+				token = strtok_r(str, ",", &save);
+				if (token == NULL)
+					break;
+				appl_args->if_names[i] = token;
+			}
+			break;
+
+		case 'm':
+			i = atoi(optarg);
+			if (i == 0)
+				appl_args->mode = APPL_MODE_PKT_BURST;
+			else
+				appl_args->mode = APPL_MODE_PKT_QUEUE;
+			break;
+
+		case 't':
+			appl_args->type = atoi(optarg);
+			break;
+
+		case 'f':
+			appl_args->fanout = atoi(optarg);
+			break;
+
+		case 'h':
+			usage(argv[0]);
+			exit(EXIT_SUCCESS);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (appl_args->if_count == 0 || appl_args->mode == -1) {
+		usage(argv[0]);
+		printf("unable to parse odp args if_count %d mode %d\n", 
+				appl_args->if_count, appl_args->mode);
+		exit(EXIT_FAILURE);
+	}
+
+	optind = 1;		/* reset 'extern optind' from the getopt lib */
+}
+
+/**
+ * Print system and application info
+ */
+static void print_info(char *progname, appl_args_t *appl_args)
+{
+	int i;
+
+	printf("\n"
+	       "ODP system info\n"
+	       "---------------\n"
+	       "ODP API version: %s\n"
+	       "CPU model:       %s\n"
+	       "CPU freq (hz):   %"PRIu64"\n"
+	       "Cache line size: %i\n"
+	       "Core count:      %i\n"
+	       "\n",
+	       odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
+	       odp_sys_cache_line_size(), odp_sys_core_count());
+
+	printf("Running ODP appl: \"%s\"\n"
+	       "-----------------\n"
+	       "IF-count:        %i\n"
+	       "Using IFs:      ",
+	       progname, appl_args->if_count);
+	for (i = 0; i < appl_args->if_count; ++i)
+		printf(" %s", appl_args->if_names[i]);
+	printf("\n"
+	       "Mode:            ");
+	if (appl_args->mode == APPL_MODE_PKT_BURST)
+		PRINT_APPL_MODE(APPL_MODE_PKT_BURST);
+	else
+		PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE);
+	printf("\n\n");
+	fflush(NULL);
+}
+
+/**
+ * Prinf usage information
+ */
+static void usage(char *progname)
+{
+	printf("\n"
+	       "Usage: %s OPTIONS\n"
+	       "  E.g. %s -i eth1,eth2,eth3 -m 0\n"
+	       "\n"
+	       "OpenDataPlane example application.\n"
+	       "\n"
+	       "Mandatory OPTIONS:\n"
+	       "  -i, --interface Eth interfaces (comma-separated, no spaces)\n"
+	       "  -m, --mode      0: Burst send&receive packets (no queues)\n"
+	       "                  1: Send&receive packets through ODP queues.\n"
+	       " -t, --type   1: ODP_PKTIO_TYPE_SOCKET_BASIC\n"
+	       "	      2: ODP_PKTIO_TYPE_SOCKET_MMSG\n"
+	       "	      3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
+	       "	      4: ODP_PKTIO_TYPE_NETMAP\n"
+	       "	 Default: 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
+	       " -f, --fanout 0: off 1: on (Default 1: on)\n"
+	       "\n"
+	       "Optional OPTIONS\n"
+	       "  -c, --count <number> Core count.\n"
+	       "  -h, --help           Display help and exit.\n"
+	       "\n", NO_PATH(progname), NO_PATH(progname)
+	    );
+}
--- /dev/null
+++ b/snort/odpsnort/odp_pktio.h
@@ -0,0 +1 @@ 
+int do_odp_init(int argc, char *argv[]);
--- /dev/null
+++ b/snort/odpsnort/snort.c
@@ -0,0 +1,5095 @@ 
+/* $Id$ */
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2002-2013 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation.  You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** 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
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+/*
+ *
+ * Program: Snort
+ *
+ * Purpose: Check out the README file for info on what you can do
+ *          with Snort.
+ *
+ * Author: Martin Roesch (roesch@clark.net)
+ *
+ * Comments: Ideas and code stolen liberally from Mike Borella's IP Grab
+ *           program. Check out his stuff at http://www.borella.net.  I
+ *           also have ripped some util functions from TCPdump, plus Mike's
+ *           prog is derived from it as well.  All hail TCPdump....
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <pcap.h>
+#ifdef HAVE_MALLOC_TRIM
+#include <malloc.h>
+#endif
+
+#ifndef WIN32
+#include <netdb.h>
+#else
+#include <Iphlpapi.h>
+#endif
+
+#ifdef HAVE_GETOPT_LONG
+//#define _GNU_SOURCE
+/* A GPL copy of getopt & getopt_long src code is now in sfutil */
+# undef HAVE_GETOPT_LONG
+#endif
+#include <getopt.h>
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifndef WIN32
+# include <grp.h>
+# include <pwd.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif  /* !WIN32 */
+
+#if !defined(CATCH_SEGV) && !defined(WIN32)
+# include <sys/resource.h>
+#endif
+#include <pthread.h>
+
+#include "decode.h"
+#include "encode.h"
+#include "sfdaq.h"
+#include "active.h"
+#include "snort.h"
+#include "rules.h"
+#include "treenodes.h"
+#include "plugbase.h"
+#include "snort_debug.h"
+#include "util.h"
+#include "parser.h"
+#include "tag.h"
+#include "log.h"
+#include "detect.h"
+#include "mstring.h"
+#include "fpcreate.h"
+#include "fpdetect.h"
+#include "sfthreshold.h"
+#include "rate_filter.h"
+#include "packet_time.h"
+#include "detection-plugins/sp_flowbits.h"
+#include "preprocessors/spp_perfmonitor.h"
+#include "preprocessors/perf-base.h"
+#include "preprocessors/perf.h"
+#include "mempool.h"
+#include "strlcpyu.h"
+#include "sflsq.h"
+#include "sp_replace.h"
+#include "output-plugins/spo_log_tcpdump.h"
+#include "event_queue.h"
+#include "asn1.h"
+#include "mpse.h"
+#include "generators.h"
+#include "ppm.h"
+#include "profiler.h"
+#include "dynamic-plugins/sp_dynamic.h"
+#include "dynamic-plugins/sf_dynamic_define.h"
+#include "dynamic-output/plugins/output.h"
+#include "sfutil/strvec.h"
+#include "detection_util.h"
+#include "sfcontrol_funcs.h"
+#include "idle_processing_funcs.h"
+#include "file_service.h"
+#ifdef SIDE_CHANNEL
+# include "sidechannel.h"
+#endif
+
+#include "dynamic-plugins/sf_dynamic_engine.h"
+#include "dynamic-plugins/sf_dynamic_detection.h"
+#define PROFILE_PREPROCS_NOREDEF
+#include "dynamic-plugins/sf_dynamic_preprocessor.h"
+#include "dynamic-plugins/sp_preprocopt.h"
+#ifdef SIDE_CHANNEL
+# include "dynamic-plugins/sf_dynamic_side_channel.h"
+#endif
+
+#ifdef TARGET_BASED
+# include "target-based/sftarget_reader.h"
+#endif
+
+#ifdef EXIT_CHECK
+# include "cpuclock.h"
+#endif
+#include "sfActionQueue.h"
+
+#ifdef INTEL_SOFT_CPM
+#include "sfutil/intel-soft-cpm.h"
+#endif
+
+#include "stream5_common.h"
+#include "stream5_ha.h"
+
+#include "odp_pktio.h"
+
+/* Macros *********************************************************************/
+#ifndef DLT_LANE8023
+/*
+ * Old OPEN BSD Log format is 17.
+ * Define DLT_OLDPFLOG unless DLT_LANE8023 (Suse 6.3) is already
+ * defined in bpf.h.
+ */
+# define DLT_OLDPFLOG 17
+#endif
+
+#define ALERT_MODE_OPT__NONE       "none"
+#define ALERT_MODE_OPT__PKT_CNT    "packet-count"
+#define ALERT_MODE_OPT__FULL       "full"
+#define ALERT_MODE_OPT__FAST       "fast"
+#define ALERT_MODE_OPT__CONSOLE    "console"
+#define ALERT_MODE_OPT__CMG        "cmg"
+#define ALERT_MODE_OPT__JH         "jh"
+#define ALERT_MODE_OPT__DJR        "djr"
+#define ALERT_MODE_OPT__AJK        "ajk"
+#define ALERT_MODE_OPT__UNIX_SOCK  "unsock"
+#define ALERT_MODE_OPT__TEST       "test"
+
+#define LOG_MODE_OPT__NONE    "none"
+#define LOG_MODE_OPT__PCAP    "pcap"
+#define LOG_MODE_OPT__ASCII   "ascii"
+
+#ifdef MPLS
+# define MPLS_PAYLOAD_OPT__IPV4      "ipv4"
+# define MPLS_PAYLOAD_OPT__IPV6      "ipv6"
+# define MPLS_PAYLOAD_OPT__ETHERNET  "ethernet"
+#endif
+
+#define DEFAULT_PAF_MAX  16384
+
+/* Data types *****************************************************************/
+
+typedef enum _GetOptArgType
+{
+    LONGOPT_ARG_NONE = 0,
+    LONGOPT_ARG_REQUIRED,
+    LONGOPT_ARG_OPTIONAL
+
+} GetOptArgType;
+
+/* Externs *******************************************************************/
+extern void PrintPacket(Packet *p);
+
+/* Undefine the one from sf_dynamic_preprocessor.h */
+#ifdef PERF_PROFILING
+extern PreprocStats detectPerfStats, decodePerfStats, metaPerfStats,
+       totalPerfStats, eventqPerfStats, rulePerfStats, mpsePerfStats;
+extern PreprocStats ruleCheckBitPerfStats, ruleSetBitPerfStats, ruleFailedFlowbitsPerfStats;
+extern PreprocStats ruleRTNEvalPerfStats, ruleOTNEvalPerfStats, ruleHeaderNoMatchPerfStats;
+extern PreprocStats ruleAddEventQPerfStats, ruleNQEventQPerfStats;
+extern PreprocStats preprocRuleOptionPerfStats;
+#endif
+
+/* for getopt */
+extern char *optarg;
+extern int optind;
+extern int opterr;
+extern int optopt;
+
+extern ListHead *head_tmp;
+
+/* Globals/Public *************************************************************/
+extern PacketCount pc;  /* packet count information */
+extern uint32_t *netmasks;   /* precalculated netmask array */
+extern char **protocol_names;
+extern char *snort_conf_file;   /* -c */
+extern char *snort_conf_dir;
+
+extern SnortConfig *snort_cmd_line_conf;
+extern SnortConfig *snort_conf;
+extern tSfPolicyId runtimePolicyId;
+extern tSfPolicyId parserPolicyId;
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+SnortConfig *snort_conf_new = NULL;
+SnortConfig *snort_conf_old = NULL;
+#endif
+
+extern tSfActionQueueId decoderActionQ;
+extern MemPool decoderAlertMemPool;
+
+extern VarNode *cmd_line_var_list;
+
+#ifdef TARGET_BASED
+pthread_t attribute_reload_thread_id;
+pid_t attribute_reload_thread_pid;
+volatile int attribute_reload_thread_running = 0;
+volatile int attribute_reload_thread_stop = 0;
+int reload_attribute_table_flags = 0;
+#endif
+
+extern volatile bool snort_initializing;
+static volatile int snort_exiting = 0;
+static pid_t snort_main_thread_pid = 0;
+#ifndef WIN32
+static pthread_t snort_main_thread_id = 0;
+#endif
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+static volatile int snort_reload = 0;
+static volatile int snort_swapped = 0;
+static volatile int snort_reload_thread_created = 0;
+static pthread_t snort_reload_thread_id;
+static pid_t snort_reload_thread_pid;
+#ifdef CONTROL_SOCKET
+static volatile int reloadInProgress = 0;
+#endif
+#endif
+
+extern const struct timespec thread_sleep;
+#ifdef OPENBSD
+const struct timespec packet_sleep = { 0, 1 };
+#endif
+
+#ifdef HAVE_PCAP_LEX_DESTROY
+extern void pcap_lex_destroy(void);
+#endif
+
+extern PreprocConfigFuncNode *preproc_config_funcs;
+extern OutputConfigFuncNode *output_config_funcs;
+extern RuleOptConfigFuncNode *rule_opt_config_funcs;
+extern RuleOptOverrideInitFuncNode *rule_opt_override_init_funcs;
+extern RuleOptParseCleanupNode *rule_opt_parse_cleanup_list;
+extern RuleOptByteOrderFuncNode *rule_opt_byte_order_funcs;
+
+extern PreprocSignalFuncNode *preproc_clean_exit_funcs;
+extern PreprocSignalFuncNode *preproc_shutdown_funcs;
+extern PreprocSignalFuncNode *preproc_reset_funcs;
+extern PreprocSignalFuncNode *preproc_reset_stats_funcs;
+extern PreprocStatsFuncNode *preproc_stats_funcs;
+
+extern PluginSignalFuncNode *plugin_shutdown_funcs;
+extern PluginSignalFuncNode *plugin_clean_exit_funcs;
+#ifdef SNORT_RELOAD
+PostConfigFuncNode *plugin_reload_funcs = NULL;
+#endif
+
+extern OutputFuncNode *AlertList;   /* Alert function list */
+extern OutputFuncNode *LogList;     /* Log function list */
+
+extern PeriodicCheckFuncNode *periodic_check_funcs;
+extern DynamicRuleNode *dynamic_rules;
+extern grinder_t grinder;
+
+#ifdef SIDE_CHANNEL
+pthread_mutex_t snort_process_lock;
+static bool snort_process_lock_held = false;
+#endif
+
+/* Locals/Private ************************************************************/
+static long int pcap_loop_count = 0;
+static SF_QUEUE *pcap_save_queue = NULL;
+
+#if defined(INLINE_FAILOPEN) && !defined(WIN32)
+static pthread_t inline_failopen_thread_id;
+static pid_t inline_failopen_thread_pid;
+static volatile int inline_failopen_thread_running = 0;
+static volatile int inline_failopen_initialized = 0;
+static int inline_failopen_pass_pkt_cnt = 0;
+static void * SnortPostInitThread(void *);
+static DAQ_Verdict IgnoreCallback (void*, const DAQ_PktHdr_t*, const uint8_t*);
+#endif
+
+static char signal_error_msg[STD_BUF];
+static int exit_signal = 0;
+static bool dump_stats_signal = false;
+static bool rotate_stats_signal = false;
+#ifdef TARGET_BASED
+static bool no_attr_table_signal = false;
+#endif
+
+#ifndef SNORT_RELOAD
+static volatile bool reload_signal = false;
+#else
+/* reload_signal is incremented in the signal handler for SIGNAL_SNORT_RELOAD
+ * which is handled in the main thread.  The reload thread compares the
+ * reload_signal count to reload_total which it increments after an equality
+ * test between reload_signal and reload_total fails (which means we got a new
+ *  SIGNAL_SNORT_RELOAD).  They need to be the same type and size to do this
+ *  comparison.  See ReloadConfigThread() */
+typedef uint32_t snort_reload_t;
+static volatile snort_reload_t reload_signal = 0;
+static snort_reload_t reload_total = 0;
+#endif
+
+static int done_processing = 0;
+static int exit_logged = 0;
+
+static SF_LIST *pcap_object_list = NULL;
+static SF_QUEUE *pcap_queue = NULL;
+static char* pcap_filter = NULL;
+
+static int snort_argc = 0;
+static char **snort_argv = NULL;
+
+/* command line options for getopt */
+static char *valid_options =
+    "?A:bB:c:CdDeEfF:"
+#ifndef WIN32
+    "g:"
+#endif
+    "G:h:Hi:Ik:K:l:L:"
+#ifndef WIN32
+    "m:"
+#endif
+    "Mn:NOpP:q"
+#ifndef WIN32
+    "Q"
+#endif
+    "r:R:sS:"
+#ifndef WIN32
+    "t:"
+#endif
+    "T"
+#ifndef WIN32
+    "u:"
+#endif
+    "UvVw:"
+#ifdef WIN32
+    "W"
+#endif
+    "XxyZ:"
+;
+
+static struct option long_options[] =
+{
+   {"logid", LONGOPT_ARG_REQUIRED, NULL, 'G'},
+   {"perfmon-file", LONGOPT_ARG_REQUIRED, NULL, 'Z'},
+   {"snaplen", LONGOPT_ARG_REQUIRED, NULL, 'P'},
+   {"version", LONGOPT_ARG_NONE, NULL, 'V'},
+   {"help", LONGOPT_ARG_NONE, NULL, '?'},
+   {"conf-error-out", LONGOPT_ARG_NONE, NULL,'x'},
+   {"dynamic-engine-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_ENGINE_FILE},
+   {"dynamic-engine-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_ENGINE_DIRECTORY},
+   {"dynamic-detection-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_LIBRARY_FILE},
+   {"dynamic-detection-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_LIBRARY_DIRECTORY},
+   {"dump-dynamic-rules", LONGOPT_ARG_REQUIRED, NULL, DUMP_DYNAMIC_RULES},
+   {"dynamic-preprocessor-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_PREPROC_FILE},
+   {"dynamic-preprocessor-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_PREPROC_DIRECTORY},
+   {"dynamic-output-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_OUTPUT_FILE},
+   {"dynamic-output-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_OUTPUT_DIRECTORY},
+   {"alert-before-pass", LONGOPT_ARG_NONE, NULL, ALERT_BEFORE_PASS},
+   {"treat-drop-as-alert", LONGOPT_ARG_NONE, NULL, TREAT_DROP_AS_ALERT},
+   {"treat-drop-as-ignore", LONGOPT_ARG_NONE, NULL, TREAT_DROP_AS_IGNORE},
+   {"process-all-events", LONGOPT_ARG_NONE, NULL, PROCESS_ALL_EVENTS},
+   {"pid-path", LONGOPT_ARG_REQUIRED, NULL, PID_PATH},
+   {"create-pidfile", LONGOPT_ARG_NONE, NULL, CREATE_PID_FILE},
+   {"nolock-pidfile", LONGOPT_ARG_NONE, NULL, NOLOCK_PID_FILE},
+   {"no-interface-pidfile", LONGOPT_ARG_NONE, NULL, NO_IFACE_PID_FILE},
+
+#ifdef INLINE_FAILOPEN
+   {"disable-inline-init-failopen", LONGOPT_ARG_NONE, NULL, DISABLE_INLINE_FAILOPEN},
+#endif
+
+   {"nostamps", LONGOPT_ARG_NONE, NULL, NO_LOGGING_TIMESTAMPS},
+
+#ifdef TARGET_BASED
+   {"disable-attribute-reload-thread", LONGOPT_ARG_NONE, NULL, DISABLE_ATTRIBUTE_RELOAD},
+#endif
+
+   {"pcap-single", LONGOPT_ARG_REQUIRED, NULL, PCAP_SINGLE},
+   {"pcap-file", LONGOPT_ARG_REQUIRED, NULL, PCAP_FILE_LIST},
+   {"pcap-list", LONGOPT_ARG_REQUIRED, NULL, PCAP_LIST},
+
+#ifndef WIN32
+   {"pcap-dir", LONGOPT_ARG_REQUIRED, NULL, PCAP_DIR},
+   {"pcap-filter", LONGOPT_ARG_REQUIRED, NULL, PCAP_FILTER},
+   {"pcap-no-filter", LONGOPT_ARG_NONE, NULL, PCAP_NO_FILTER},
+#endif
+
+   {"pcap-loop", LONGOPT_ARG_REQUIRED, NULL, PCAP_LOOP},
+   {"pcap-reload", LONGOPT_ARG_NONE, NULL, PCAP_RELOAD},
+   {"pcap-reset", LONGOPT_ARG_NONE, NULL, PCAP_RESET},
+   {"pcap-show", LONGOPT_ARG_NONE, NULL, PCAP_SHOW},
+
+#ifdef EXIT_CHECK
+   {"exit-check", LONGOPT_ARG_REQUIRED, NULL, ARG_EXIT_CHECK},
+#endif
+
+   {"search-method", LONGOPT_ARG_REQUIRED, NULL, DETECTION_SEARCH_METHOD},
+   {"man", LONGOPT_ARG_REQUIRED, NULL, DETECTION_SEARCH_METHOD},
+
+#ifdef MPLS
+   {"enable-mpls-multicast", LONGOPT_ARG_NONE, NULL, ENABLE_MPLS_MULTICAST},
+   {"enable-mpls-overlapping-ip", LONGOPT_ARG_NONE, NULL, ENABLE_OVERLAPPING_IP},
+   {"max-mpls-labelchain-len", LONGOPT_ARG_REQUIRED, NULL, MAX_MPLS_LABELCHAIN_LEN},
+   {"mpls-payload-type", LONGOPT_ARG_REQUIRED, NULL, MPLS_PAYLOAD_TYPE},
+#endif
+
+   {"require-rule-sid", LONGOPT_ARG_NONE, NULL, REQUIRE_RULE_SID},
+
+   {"daq", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_TYPE},
+   {"daq-mode", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_MODE},
+   {"daq-var", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_VAR},
+   {"daq-dir", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_DIR},
+   {"daq-list", LONGOPT_ARG_OPTIONAL, NULL, ARG_DAQ_LIST},
+   {"dirty-pig", LONGOPT_ARG_NONE, NULL, ARG_DIRTY_PIG},
+
+   {"enable-inline-test", LONGOPT_ARG_NONE, NULL, ENABLE_INLINE_TEST},
+
+   {"cs-dir", LONGOPT_ARG_REQUIRED, NULL, ARG_CS_DIR},
+   {"ha-peer", LONGOPT_ARG_NONE, NULL, ARG_HA_PEER},
+   {"ha-out", LONGOPT_ARG_REQUIRED, NULL, ARG_HA_OUT},
+   {"ha-in", LONGOPT_ARG_REQUIRED, NULL, ARG_HA_IN},
+
+   {0, 0, 0, 0}
+};
+
+typedef void (*log_func_t)(Packet*);
+static void LogPacket (Packet* p)
+{
+    pc.log_pkts++;
+    CallLogPlugins(p, NULL, NULL);
+}
+static void IgnorePacket (Packet* p) { }
+static log_func_t log_func = IgnorePacket;
+
+/* Private function prototypes ************************************************/
+static void InitNetmasks(void);
+static void InitProtoNames(void);
+static const char* GetPacketSource(char**);
+
+static void CleanExit(int);
+//static void SnortInit(int, char **);
+static void InitPidChrootAndPrivs(pid_t);
+static void ParseCmdLine(int, char **);
+static int ShowUsage(char *);
+static void PrintVersion(void);
+static void SetSnortConfDir(void);
+static void InitGlobals(void);
+static SnortConfig * MergeSnortConfs(SnortConfig *, SnortConfig *);
+static void InitSignals(void);
+#if defined(NOCOREFILE) && !defined(WIN32)
+static void SetNoCores(void);
+#endif
+static void SnortCleanup(int);
+
+static void ParseCmdLineDynamicLibInfo(SnortConfig *, int, char *);
+static DynamicLibInfo * DupDynamicLibInfo(DynamicLibInfo *);
+static void FreeDynamicLibInfo(DynamicLibInfo *);
+static void FreeDynamicLibInfos(SnortConfig *);
+
+static void FreeOutputConfigs(OutputConfig *);
+#ifdef SIDE_CHANNEL
+static void FreeSideChannelModuleConfigs(SideChannelModuleConfig *);
+#endif
+static void FreePreprocConfigs(SnortConfig *);
+static void FreeRuleStateList(RuleState *);
+static void FreeClassifications(ClassType *);
+static void FreeReferences(ReferenceSystemNode *);
+static void FreePlugins(SnortConfig *);
+static void FreePreprocessors(SnortConfig *);
+
+extern void SnortUnprivilegedInit(void);
+static int SetPktProcessor(void);
+static void PacketLoop(void);
+extern void odp_snort_run_threads(void);
+#if 0
+static char * ConfigFileSearch(void);
+#endif
+static void SnortReset(void);
+
+static void LoadDynamicPlugins(SnortConfig *);
+
+static void SnortIdle(void);
+#ifndef WIN32
+static void SnortStartThreads(void);
+#endif
+
+/* Signal handler declarations ************************************************/
+static void SigDumpStatsHandler(int);
+static void SigExitHandler(int);
+static void SigReloadHandler(int);
+static void SigRotateStatsHandler(int);
+#ifdef CONTROL_SOCKET
+static void SigPipeHandler(int);
+#endif
+static void SigOopsHandler(int);
+
+#ifdef TARGET_BASED
+static void SigNoAttributeTableHandler(int);
+#endif
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+static SnortConfig * ReloadConfig(void);
+static void * ReloadConfigThread(void *);
+static int VerifyReload(SnortConfig *);
+static int VerifyOutputs(SnortConfig *, SnortConfig *);
+static int VerifyLibInfos(DynamicLibInfo *, DynamicLibInfo *);
+#endif  /* SNORT_RELOAD */
+
+static int IsProcessingPackets(uint16_t type, const uint8_t *data, uint32_t length, void **new_config,
+                               char *statusBuf, int statusBuf_len)
+{
+    return (!snort_initializing && !snort_exiting && !exit_signal) ? 0 : -1;
+}
+
+#if defined(SNORT_RELOAD) && !defined(WIN32) && defined(CONTROL_SOCKET)
+
+static pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int ControlSocketReloadConfig(uint16_t type, const uint8_t *data, uint32_t length, void **new_config,
+                                     char *statusBuf, int statusBuf_len)
+{
+    SnortConfig *new_sc;
+
+    pthread_mutex_lock(&reload_mutex);
+    while (reloadInProgress)
+    {
+        sleep(1);
+    }
+    reloadInProgress = 1;
+    pthread_mutex_unlock(&reload_mutex);
+
+    LogMessage("\n");
+    LogMessage("        --== Reloading Snort ==--\n");
+    LogMessage("\n");
+
+    new_sc = ReloadConfig();
+    if (new_sc == NULL)
+    {
+        reloadInProgress = 0;
+        return -1;
+    }
+    *new_config = (void *)new_sc;
+    return 0;
+}
+
+static int ControlSocketReloadSwap(uint16_t type, void *new_config, void **old_config)
+{
+    PostConfigFuncNode *idxPlugin = NULL;
+
+    *old_config = (void *)snort_conf;
+    snort_conf = (SnortConfig *)new_config;
+    SwapPreprocConfigurations(snort_conf);
+
+    FreeSwappedPreprocConfigurations(snort_conf);
+
+#ifdef INTEL_SOFT_CPM
+    if (snort_conf->fast_pattern_config->search_method == MPSE_INTEL_CPM)
+        IntelPmActivate(snort_conf);
+#endif
+
+    /* Do any reload for plugin data */
+    idxPlugin = plugin_reload_funcs;
+    while(idxPlugin)
+    {
+        idxPlugin->func(snort_conf, SIGHUP, idxPlugin->arg);
+        idxPlugin = idxPlugin->next;
+    }
+    return 0;
+}
+
+static void ControlSocketReloadFree(uint16_t type, void *old_config, struct _THREAD_ELEMENT *te, ControlDataSendFunc f)
+{
+    SnortConfig *old_sc = (SnortConfig *)old_config;
+
+    SnortConfFree(old_sc);
+
+#ifdef INTEL_SOFT_CPM
+    if (snort_conf->fast_pattern_config->search_method != MPSE_INTEL_CPM)
+        IntelPmStopInstance();
+#endif
+
+    LogMessage("\n");
+    LogMessage("        --== Reload Complete ==--\n");
+    LogMessage("\n");
+
+    reloadInProgress = 0;
+}
+#endif
+
+static inline void CheckForReload(void)
+{
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+    /* Check for a new configuration */
+    if (snort_reload)
+    {
+        PostConfigFuncNode *idxPlugin = NULL;
+        snort_reload = 0;
+
+        /* There was an error reloading.  A non-reloadable configuration
+         * option changed */
+        if (snort_conf_new == NULL)
+        {
+#ifdef RELOAD_ERROR_FATAL
+            CleanExit(1);
+#else
+            Restart();
+#endif
+        }
+
+        snort_conf_old = snort_conf;
+        snort_conf = snort_conf_new;
+        snort_conf_new = NULL;
+        SwapPreprocConfigurations(snort_conf);
+
+        /* Need to do this here because there is potentially outstanding
+         * state data pointing to the previous configuration.  A race
+         * condition is created if these are free'd in the reload thread
+         * where a double free could occur. */
+        FreeSwappedPreprocConfigurations(snort_conf);
+
+#ifdef INTEL_SOFT_CPM
+        if (snort_conf->fast_pattern_config->search_method == MPSE_INTEL_CPM)
+            IntelPmActivate(snort_conf);
+#endif
+
+        snort_swapped = 1;
+
+        /* Do any reload for plugin data */
+        idxPlugin = plugin_reload_funcs;
+        while(idxPlugin)
+        {
+            idxPlugin->func(snort_conf, SIGHUP, idxPlugin->arg);
+            idxPlugin = idxPlugin->next;
+        }
+    }
+#endif
+}
+
+/*  F U N C T I O N   D E F I N I T I O N S  **********************************/
+
+static int InlineFailOpen (void)
+{
+#if defined(INLINE_FAILOPEN) && !defined(WIN32)
+    if (ScAdapterInlineMode() &&
+        !ScReadMode() && !ScDisableInlineFailopen())
+    {
+        /* If in inline mode, start a thread to handle the rest of snort
+         * initialization, then dispatch packets until that initialization
+         * is complete. */
+        LogMessage("Fail Open Thread starting..\n");
+
+	printf("%s()%d chreate new thread\n", __func__, __LINE__);
+        if (pthread_create(&inline_failopen_thread_id, NULL, SnortPostInitThread, NULL))
+        {
+            ErrorMessage("Failed to start Fail Open Thread.  "
+                         "Starting normally\n");
+        }
+        else
+        {
+            while (!inline_failopen_thread_running)
+                nanosleep(&thread_sleep, NULL);
+
+            LogMessage("Fail Open Thread started tid=%p (pid=%u)\n",
+                    (void*)inline_failopen_thread_id, inline_failopen_thread_pid);
+
+# ifdef DEBUG
+            {
+                FILE *tmp = fopen("/var/tmp/fo_threadid", "w");
+                if ( tmp )
+                {
+                    fprintf(tmp, "Fail Open Thread PID: %u\n", inline_failopen_thread_pid);
+                    fclose(tmp);
+                }
+            }
+# endif
+            DAQ_Start();
+            SetPktProcessor();
+            inline_failopen_initialized = 1;
+
+            /* Passing packets is in the main thread because some systems
+             * may have to refer to packet passing thread via process id
+             * (linuxthreads) */
+            while (snort_initializing)
+            {
+                int error = DAQ_Acquire(1, IgnoreCallback, NULL);
+
+                if (error)
+                    break;
+            }
+
+            pthread_join(inline_failopen_thread_id, NULL);
+            inline_failopen_thread_running = 0;
+
+            LogMessage("Fail Open Thread terminated, passed %d packets.\n",
+                       inline_failopen_pass_pkt_cnt);
+
+            return 1;
+        }
+    }
+#endif
+    return 0;
+}
+
+/*
+ *
+ * Function: main(int, char *)
+ *
+ * Purpose:  Handle program entry and exit, call main prog sections
+ *           This can handle both regular (command-line) style
+ *           startup, as well as Win32 Service style startup.
+ *
+ * Arguments: See command line args in README file
+ *
+ * Returns: 0 => normal exit, 1 => exit on error
+ *
+ */
+int main(int argc, char *argv[])
+{
+	/* hack to add deps to -lrt for timer_create() and friends from odp */
+	static volatile int link_rt = 0;
+	timer_t timerid = 0;
+	if (link_rt)
+		timer_settime(timerid, 0, NULL, NULL);
+
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+    /* Do some sanity checking, because some people seem to forget to
+     * put spaces between their parameters
+     */
+    if ((argc > 1) &&
+        ((_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_INSTALL_CMDLINE_PARAM)) == 0) ||
+         (_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_UNINSTALL_CMDLINE_PARAM)) == 0) ||
+         (_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_SHOW_CMDLINE_PARAM)) == 0)))
+    {
+        FatalError("You must have a space after the '%s' command-line parameter\n",
+                   SERVICE_CMDLINE_PARAM);
+    }
+
+    /* If the first parameter is "/SERVICE", then start Snort as a Win32 service */
+    if((argc > 1) && (_stricmp(argv[1],SERVICE_CMDLINE_PARAM) == 0))
+    {
+        return SnortServiceMain(argc, argv);
+    }
+#endif /* WIN32 && ENABLE_WIN32_SERVICE */
+
+    snort_argc = argc;
+    snort_argv = argv;
+
+    return ODP_SnortMain(argc, argv);
+}
+
+/*
+ *
+ * Function: SnortMain(int, char *)
+ *
+ * Purpose:  The real place that the program handles entry and exit.  Called
+ *           called by main(), or by SnortServiceMain().
+ *
+ * Arguments: See command line args in README file
+ *
+ * Returns: 0 => normal exit, 1 => exit on error
+ *
+ */
+int ODP_SnortMain(int argc, char *argv[])
+{
+    char* tmp_ptr = NULL;
+    const char* intf;
+    int daqInit;
+
+
+    do_odp_init(argc, argv);
+
+#ifndef WIN32
+    // must be done now in case of fatal error
+    // and again after daemonization
+    snort_main_thread_id = pthread_self();
+#endif
+
+    SnortInit(argc, argv);
+
+    intf = GetPacketSource(&tmp_ptr);
+    daqInit = intf || snort_conf->daq_type;
+
+    if ( daqInit )
+    {
+        //DAQ_Init(snort_conf);
+        //DAQ_New(snort_conf, intf);
+    }
+    if ( tmp_ptr )
+        free(tmp_ptr);
+
+    if ( ScDaemonMode() )
+    {
+        GoDaemon();
+    }
+
+    // this must follow daemonization
+    snort_main_thread_pid = gettid();
+#ifndef WIN32
+    snort_main_thread_id = pthread_self();
+#endif
+
+#ifndef WIN32
+    /* Change groups */
+    InitGroups(ScUid(), ScGid());
+#endif
+
+#if !defined(HAVE_LINUXTHREADS) && !defined(WIN32)
+    // this could be moved to linux threads location
+    // and only done there
+    SnortStartThreads();
+#endif
+
+#if defined(SNORT_RELOAD) && !defined(WIN32) && defined(CONTROL_SOCKET)
+    if (ControlSocketRegisterHandler(CS_TYPE_RELOAD, &ControlSocketReloadConfig, &ControlSocketReloadSwap, &ControlSocketReloadFree))
+    {
+        LogMessage("Failed to register the reload control handler.\n");
+    }
+#endif
+
+    if (ControlSocketRegisterHandler(CS_TYPE_IS_PROCESSING, &IsProcessingPackets, NULL, NULL))
+    {
+        LogMessage("Failed to register the is processing control handler.\n");
+    }
+
+    if ( ScTestMode() )
+    {
+        if ( daqInit && DAQ_UnprivilegedStart() )
+            SetPktProcessor();
+        SnortUnprivilegedInit();
+    }
+    else if ( DAQ_UnprivilegedStart() )
+    {
+        SnortUnprivilegedInit();
+        SetPktProcessor();
+        //DAQ_Start();
+    }
+    else if ( !InlineFailOpen() )
+    {
+        //DAQ_Start();
+        SetPktProcessor();
+        SnortUnprivilegedInit();
+    }
+
+    printf("going to packet loop\n");
+    odp_snort_run_threads();
+
+    //PacketLoop();
+
+    // DAQ is shutdown in CleanExit() since we don't always return here
+    CleanExit(0);
+
+    return 0;
+}
+
+#ifndef WIN32
+/* All threads need to be created after daemonizing.  If created in
+ * the parent thread, when it goes away, so will all of the threads.
+ * The child does not "inherit" threads created in the parent. */
+static void SnortStartThreads(void)
+{
+# ifdef SNORT_RELOAD
+    if (ScIdsMode())
+    {
+        LogMessage("Reload thread starting...\n");
+	printf("%s()%d chreate new thread\n", __func__, __LINE__);
+        if (pthread_create(&snort_reload_thread_id, NULL, ReloadConfigThread, NULL) != 0)
+        {
+            ErrorMessage("Could not create configuration reload thread.\n");
+            CleanExit(1);
+        }
+
+        while (!snort_reload_thread_created)
+            nanosleep(&thread_sleep, NULL);
+
+        LogMessage("Reload thread started, thread %p (%u)\n",
+                (void*)snort_reload_thread_id, snort_reload_thread_pid);
+    }
+# endif
+
+# ifdef TARGET_BASED
+    SFAT_StartReloadThread();
+# endif
+}
+#else   /* WIN32 */
+//------------------------------------------------------------------------------
+// interface stuff
+//------------------------------------------------------------------------------
+
+static void PrintAllInterfaces (void)
+{
+    char errorbuf[PCAP_ERRBUF_SIZE];
+    pcap_if_t *alldevs;
+    pcap_if_t *dev;
+    int j = 1;
+    MIB_IFTABLE *iftable = NULL;
+    unsigned int len = 0;
+    unsigned int ret, i;
+
+    if (pcap_findalldevs(&alldevs, errorbuf) == -1)
+        FatalError("Could not get device list: %s.", errorbuf);
+
+    /* max of two iterations here -- first to get the
+     * correct length if not big enough. Second to
+     * get the data. */
+    for (len = sizeof(iftable[0]); ; ) {
+        if (iftable)
+            free(iftable);
+        iftable = SnortAlloc(len);
+        ret = GetIfTable(iftable, &len, TRUE);
+        if (ret == NO_ERROR)
+            break;
+        else if (ret != ERROR_INSUFFICIENT_BUFFER)
+            FatalError("Could not get device list: %s.", errorbuf);;
+    }
+
+    printf("Index\tPhysical Address\tIP Address\tDevice Name\tDescription\n");
+    printf("-----\t----------------\t----------\t-----------\t-----------\n");
+
+    for (dev = alldevs; dev != NULL; dev = dev->next, j++)
+    {
+        uint8_t *mac_addr = NULL;
+        for (i = 0; i<iftable->dwNumEntries; i++)
+        {
+            if (strncmp(dev->description, iftable->table[i].bDescr, iftable->table[i].dwDescrLen) == 0)
+            {
+                mac_addr = iftable->table[i].bPhysAddr;
+                break;
+            }
+        }
+        printf("%5d\t", j);
+        if (mac_addr)
+        {
+            printf("%02X:%02X:%02X:%02X:%02X:%02X\t",
+                mac_addr[0], mac_addr[1], mac_addr[2],
+                mac_addr[3], mac_addr[4], mac_addr[5]);
+        }
+        else
+        {
+            printf("00:00:00:00:00:00\t");
+        }
+        if (dev->addresses)
+        {
+            struct sockaddr_in* saddr = (struct sockaddr_in*)dev->addresses->addr;
+            sfip_t dev_ip;
+            if ((saddr->sin_family == AF_INET) || (saddr->sin_family == AF_INET6))
+            {
+                sfip_set_raw(&dev_ip, &saddr->sin_addr, saddr->sin_family);
+                printf("%s\t", inet_ntoa(&dev_ip));
+            }
+            else
+            {
+                printf("disabled\t");
+            }
+            printf("%s\t%s\n", dev->name, dev->description);
+        }
+        else
+        {
+            printf("disabled\t%s\t%s\n", dev->name, dev->description);
+        }
+
+    }
+    pcap_freealldevs(alldevs);
+    free(iftable);
+}
+#endif  /* WIN32 */
+
+// pcap list stuff ...
+
+static void PQ_SetFilter (const char* f)
+{
+    if (pcap_filter != NULL)
+        free(pcap_filter);
+
+    pcap_filter = f ? SnortStrdup(f) : NULL;
+}
+
+static void PQ_Single (const char* pcap)
+{
+    PcapReadObject* pro;
+
+    if (pcap_object_list == NULL)
+    {
+        pcap_object_list = sflist_new();
+        if (pcap_object_list == NULL)
+            FatalError("Could not allocate list to store pcap\n");
+    }
+
+    pro = (PcapReadObject *)SnortAlloc(sizeof(PcapReadObject));
+    pro->type = PCAP_SINGLE;
+    pro->arg = SnortStrdup(pcap);
+    pro->filter = NULL;
+
+    if (sflist_add_tail(pcap_object_list, (NODE_DATA)pro) == -1)
+        FatalError("Could not add pcap object to list: %s\n", pcap);
+}
+
+static void PQ_Multi (char type, const char* list)
+{
+    PcapReadObject* pro;
+
+    if (pcap_object_list == NULL)
+    {
+        pcap_object_list = sflist_new();
+        if (pcap_object_list == NULL)
+            FatalError("Could not allocate list to store pcaps\n");
+    }
+
+    pro = (PcapReadObject *)SnortAlloc(sizeof(PcapReadObject));
+    pro->type = type;
+    pro->arg = SnortStrdup(list);
+    if (pcap_filter != NULL)
+        pro->filter = SnortStrdup(pcap_filter);
+    else
+        pro->filter = NULL;
+
+    if (sflist_add_tail(pcap_object_list, (NODE_DATA)pro) == -1)
+        FatalError("Could not add pcap object to list: %s\n", list);
+}
+
+static void PQ_SetUp (void)
+{
+    if (pcap_object_list != NULL)
+    {
+        if (sflist_count(pcap_object_list) == 0)
+        {
+            sflist_free_all(pcap_object_list, NULL);
+            FatalError("No pcaps specified.\n");
+        }
+
+        pcap_queue = sfqueue_new();
+        pcap_save_queue = sfqueue_new();
+        if ((pcap_queue == NULL) || (pcap_save_queue == NULL))
+            FatalError("Could not allocate pcap queues.\n");
+
+        if (GetPcaps(pcap_object_list, pcap_queue) == -1)
+            FatalError("Error getting pcaps.\n");
+
+        if (sfqueue_count(pcap_queue) == 0)
+            FatalError("No pcaps found.\n");
+
+        /* free pcap list used to get params */
+        while (sflist_count(pcap_object_list) > 0)
+        {
+            PcapReadObject *pro = (PcapReadObject *)sflist_remove_head(pcap_object_list);
+            if (pro == NULL)
+                FatalError("Failed to remove pcap item from list.\n");
+
+            if (pro->arg != NULL)
+                free(pro->arg);
+
+            if (pro->filter != NULL)
+                free(pro->filter);
+
+            free(pro);
+        }
+
+        sflist_free_all(pcap_object_list, NULL);
+        pcap_object_list = NULL;
+    }
+    if (pcap_filter != NULL)
+    {
+        free(pcap_filter);
+        pcap_filter = NULL;
+    }
+}
+
+static int PQ_CleanUp (void)
+{
+    /* clean up pcap queues */
+    if (pcap_queue != NULL)
+        sfqueue_free_all(pcap_queue, free);
+
+    if (pcap_save_queue != NULL)
+        sfqueue_free_all(pcap_save_queue, free);
+
+    return 0;
+}
+
+static void PQ_Show (const char* pcap)
+{
+    if ( !ScPcapShow() )
+        return;
+
+    if ( !strcmp(pcap, "-") ) pcap = "stdin";
+
+    fprintf(stdout,
+        "Reading network traffic from \"%s\" with snaplen = %d\n",
+        pcap, DAQ_GetSnapLen());
+}
+
+static const char* PQ_First (void)
+{
+    const char* pcap = (char*)sfqueue_remove(pcap_queue);
+
+    if ( !pcap )
+        return pcap;
+
+    if ( sfqueue_add(pcap_save_queue, (NODE_DATA)pcap) == -1 )
+        FatalError("Could not add pcap to saved list\n");
+
+    return pcap;
+}
+
+// this must follow 2nd or later start and not stop because we force a
+// reset when the dlt changes even if not enabled with --pcap-reset to
+// avoid eventually flushing stream packets through a different grinder
+// than the one they were queued with.
+static void PQ_Reset ()
+{
+    static int dlt = -1;
+    int new_dlt = DAQ_GetBaseProtocol();
+
+    if ( ScPcapReset() || ((dlt != new_dlt) && (dlt != -1)) )
+        SnortReset();
+
+    dlt = new_dlt;
+
+    /* open a new tcpdump file - necessary because the snaplen and
+     * datalink could be different between pcaps */
+    if (snort_conf->log_tcpdump)
+    {
+        /* this sleep is to ensure we get a new log file since it has a
+         * time stamp with resolution to the second */
+#ifdef WIN32
+        Sleep(1000);
+#else
+        sleep(1);
+#endif
+        LogTcpdumpReset();
+    }
+}
+
+static int PQ_Next (void)
+{
+    char reopen_pcap = 0;
+
+    if (sfqueue_count(pcap_queue) > 0)
+    {
+        reopen_pcap = 1;
+    }
+    else if (pcap_loop_count)
+    {
+        if (pcap_loop_count > 0)
+            pcap_loop_count--;
+
+        if (pcap_loop_count != 0)
+        {
+            SF_QUEUE *tmp;
+
+            /* switch pcap lists */
+            tmp = pcap_queue;
+            pcap_queue = pcap_save_queue;
+            pcap_save_queue = tmp;
+
+            reopen_pcap = 1;
+        }
+    }
+
+    if (reopen_pcap)
+    {
+        /* reinitialize pcap */
+        const char* pcap = PQ_First();
+
+        if ( !pcap )
+            FatalError("Could not get pcap from list\n");
+
+        DAQ_Stop();
+        DAQ_Delete();
+
+        DAQ_New(snort_conf, pcap);
+        DAQ_Start();
+
+        PQ_Reset();
+        PQ_Show(pcap);
+        SetPktProcessor();
+
+        SetSampleTime(perfmon_config, NULL);
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+        if ( snort_conf->run_flags & RUN_FLAG__PCAP_RELOAD && ScIdsMode())
+        {
+            /* Awaiting user confirmation */
+            printf("Hit return to continue.\n");
+            fflush(stdout);
+            while(getc(stdin) != '\n');
+
+            SigReloadHandler(SIGNAL_SNORT_RELOAD);
+
+            while (!snort_reload)
+                sleep(1);
+        }
+#endif
+
+        return 1;
+    }
+    return 0;
+}
+
+static char* GetFirstInterface (void)
+{
+    char *iface = NULL;
+    char errorbuf[PCAP_ERRBUF_SIZE];
+#ifdef WIN32
+    pcap_if_t *alldevs;
+
+    if ( (pcap_findalldevs(&alldevs, errorbuf) == -1) || !alldevs )
+    {
+        FatalError( "Failed to lookup interface: %s. "
+            "Please specify one with -i switch\n", errorbuf);
+    }
+
+    /* Pick first interface */
+    iface = SnortStrdup(alldevs->name);
+    pcap_freealldevs(alldevs);
+#else
+    DEBUG_WRAP(DebugMessage(
+        DEBUG_INIT, "interface is NULL, looking up interface...."););
+
+    /* look up the device and get the handle */
+    iface = pcap_lookupdev(errorbuf);
+
+    if ( !iface )
+    {
+        FatalError( "Failed to lookup interface: %s. "
+            "Please specify one with -i switch\n", errorbuf);
+    }
+
+    DEBUG_WRAP(DebugMessage(DEBUG_INIT, "found interface %s\n",
+                            PRINT_INTERFACE(iface)););
+
+    iface = SnortStrdup(iface);
+#endif
+    return iface;
+}
+
+static const char* GetPacketSource (char** sptr)
+{
+    const char* intf = "other";
+
+    if ( ScReadMode() )
+    {
+        intf = PQ_First();
+        PQ_Show(intf);
+    }
+    else if ( !ScVersionMode() && !ScRuleDumpMode() )
+    {
+        intf = snort_conf->interface;
+
+        // don't get interface if daq is explicitly configured
+        // since we can't assume that an interface is compatible
+        if ( !intf && !ScTestMode() &&
+            (!snort_conf->daq_type ||
+            // but we make execptions for these:
+            // TBD make selection based on DAQ_TYPE_XXX
+            !strcasecmp(snort_conf->daq_type, "afpacket") ||
+            !strcasecmp(snort_conf->daq_type, "pcap") ||
+            !strcasecmp(snort_conf->daq_type, "dump")) )
+        {
+            intf = GetFirstInterface();
+            *sptr = (char*)intf;
+        }
+    }
+    return intf;
+}
+
+static void InitPidChrootAndPrivs(pid_t pid)
+{
+    /* create the PID file */
+    if ( !ScReadMode() &&
+        (ScDaemonMode() || *snort_conf->pidfile_suffix || ScCreatePidFile()))
+    {
+        CreatePidFile(DAQ_GetInterfaceSpec(), pid);
+    }
+
+#ifndef WIN32
+    /* Drop the Chrooted Settings */
+    if (snort_conf->chroot_dir)
+        SetChroot(snort_conf->chroot_dir, &snort_conf->log_dir);
+#endif
+
+#ifndef WIN32
+    /* Drop privileges if requested, when initialization is done */
+    SetUidGid(ScUid(), ScGid());
+#endif
+}
+
+static void LoadDynamicPlugins(SnortConfig *sc)
+{
+    unsigned i;
+
+    if (sc == NULL)
+        return;
+
+    if (sc->dyn_engines != NULL)
+    {
+        /* Load the dynamic engines */
+        for (i = 0; i < sc->dyn_engines->count; i++)
+        {
+            switch (sc->dyn_engines->lib_paths[i]->ptype)
+            {
+                case PATH_TYPE__FILE:
+                    LoadDynamicEngineLib(sc->dyn_engines->lib_paths[i]->path, 0);
+                    break;
+
+                case PATH_TYPE__DIRECTORY:
+                    LoadAllDynamicEngineLibs(sc->dyn_engines->lib_paths[i]->path);
+                    break;
+            }
+        }
+    }
+
+    if (sc->dyn_rules != NULL)
+    {
+        /* Load the dynamic detection libs */
+        for (i = 0; i < sc->dyn_rules->count; i++)
+        {
+            switch (sc->dyn_rules->lib_paths[i]->ptype)
+            {
+                case PATH_TYPE__FILE:
+                    LoadDynamicDetectionLib(sc->dyn_rules->lib_paths[i]->path, 0);
+                    break;
+
+                case PATH_TYPE__DIRECTORY:
+                    LoadAllDynamicDetectionLibs(sc->dyn_rules->lib_paths[i]->path);
+                    break;
+            }
+        }
+    }
+
+    if (sc->dyn_preprocs != NULL)
+    {
+        /* Load the dynamic preprocessors */
+        for (i = 0; i < sc->dyn_preprocs->count; i++)
+        {
+            switch (sc->dyn_preprocs->lib_paths[i]->ptype)
+            {
+                case PATH_TYPE__FILE:
+                    LoadDynamicPreprocessor(sc->dyn_preprocs->lib_paths[i]->path, 0);
+                    break;
+
+                case PATH_TYPE__DIRECTORY:
+                    LoadAllDynamicPreprocessors(sc->dyn_preprocs->lib_paths[i]->path);
+                    break;
+            }
+        }
+    }
+
+# ifdef SIDE_CHANNEL
+    if (sc->dyn_side_channels != NULL)
+    {
+        /* Load the dynamic side channels */
+        for (i = 0; i < sc->dyn_side_channels->count; i++)
+        {
+            switch (sc->dyn_side_channels->lib_paths[i]->ptype)
+            {
+                case PATH_TYPE__FILE:
+                    LoadDynamicSideChannelLib(sc->dyn_side_channels->lib_paths[i]->path, 0);
+                    break;
+
+                case PATH_TYPE__DIRECTORY:
+                    LoadAllDynamicSideChannelLibs(sc->dyn_side_channels->lib_paths[i]->path);
+                    break;
+            }
+        }
+    }
+# endif /* SIDE_CHANNEL */
+
+    ValidateDynamicEngines();
+}
+
+static void DisplayDynamicPluginVersions(void)
+{
+    void *lib = NULL;
+    DynamicPluginMeta *meta;
+
+    RemoveDuplicateEngines();
+    RemoveDuplicateDetectionPlugins();
+    RemoveDuplicatePreprocessorPlugins();
+#ifdef SIDE_CHANNEL
+    RemoveDuplicateSideChannelPlugins();
+#endif /* SIDE_CHANNEL */
+
+    lib = GetNextEnginePluginVersion(NULL);
+    while ( lib != NULL )
+    {
+        meta = GetDetectionPluginMetaData(lib);
+
+        LogMessage("           Rules Engine: %s  Version %d.%d  <Build %d>\n",
+                   meta->uniqueName, meta->major, meta->minor, meta->build);
+        lib = GetNextEnginePluginVersion(lib);
+    }
+
+    lib = GetNextDetectionPluginVersion(NULL);
+    while ( lib != NULL )
+    {
+        meta = GetEnginePluginMetaData(lib);
+
+        LogMessage("           Rules Object: %s  Version %d.%d  <Build %d>\n",
+                   meta->uniqueName, meta->major, meta->minor, meta->build);
+        lib = GetNextDetectionPluginVersion(lib);
+    }
+
+    lib = GetNextPreprocessorPluginVersion(NULL);
+    while ( lib != NULL )
+    {
+        meta = GetPreprocessorPluginMetaData(lib);
+
+        LogMessage("           Preprocessor Object: %s  Version %d.%d  <Build %d>\n",
+                   meta->uniqueName, meta->major, meta->minor, meta->build);
+        lib = GetNextPreprocessorPluginVersion(lib);
+    }
+
+#ifdef SIDE_CHANNEL
+    lib = GetNextSideChannelPluginVersion(NULL);
+    while ( lib != NULL )
+    {
+        meta = GetSideChannelPluginMetaData(lib);
+
+        LogMessage("           Side Channel Object: %s  Version %d.%d  <Build %d>\n",
+                   meta->uniqueName, meta->major, meta->minor, meta->build);
+        lib = GetNextSideChannelPluginVersion(lib);
+    }
+#endif /* SIDE_CHANNEL */
+
+    lib = GetNextOutputModule(NULL);
+    while ( lib != NULL )
+    {
+        LogMessage("           Output Module: %s  Version %u\n",
+            GetOutputModuleName(lib), GetOutputModuleVersion(lib));
+        lib = GetNextOutputModule(lib);
+    }
+}
+
+/*
+ * This function will print versioning information regardless of whether or
+ * not the quiet flag is set.  If the quiet flag has been set and we want
+ * to honor it, check it before calling this function.
+ */
+static void PrintVersion(void)
+{
+    /* Unset quiet flag so LogMessage will print, then restore just
+     * in case anything other than exiting after this occurs */
+    int save_quiet_flag = snort_conf->logging_flags & LOGGING_FLAG__QUIET;
+
+    snort_conf->logging_flags &= ~LOGGING_FLAG__QUIET;
+    DisplayBanner();
+
+    //  Get and print out library versions
+    DisplayDynamicPluginVersions();
+
+    snort_conf->logging_flags |= save_quiet_flag;
+}
+
+static void PrintDaqModules (SnortConfig* sc, char* dir)
+{
+    if ( dir )
+        ConfigDaqDir(sc, dir);
+
+    DAQ_Load(snort_conf);
+    DAQ_PrintTypes(stdout);
+    DAQ_Unload();
+}
+
+#ifdef EXIT_CHECK
+static uint64_t exitTime = 0;
+
+static void ExitCheckStart (void)
+{
+    if ( exitTime )
+    {
+        return;
+    }
+    LogMessage("Exit Check: signaling at " STDu64 "callback\n", (long long unsigned int)pc.total_from_daq);
+    get_clockticks(exitTime);
+#ifndef WIN32
+    kill(0, SIGINT);  // send to all processes in my process group
+#else
+    raise(SIGINT);
+#endif
+}
+
+static void ExitCheckEnd (void)
+{
+    uint64_t now = 0;
+    double usecs = 0.0;
+
+    if ( !exitTime )
+    {
+        LogMessage(
+            "Exit Check: callbacks = " STDu64 "(limit not reached)\n",
+            (long long unsigned int)pc.total_from_daq
+        );
+        return;
+    }
+    get_clockticks(now);
+    exitTime = now - exitTime;
+    usecs = exitTime / get_ticks_per_usec();
+
+    LogMessage("Exit Check: usecs = %f\n", usecs);
+}
+#endif
+
+#ifdef HAVE_DAQ_ACQUIRE_WITH_META
+static int MetaCallback(
+    void* user, const DAQ_MetaHdr_t *metahdr, const uint8_t* data)
+{
+    tSfPolicyId policy_id = getDefaultPolicy();
+    SnortPolicy *policy;
+    PreprocMetaEvalFuncNode *idx;
+    PROFILE_VARS;
+
+#ifdef SIDE_CHANNEL
+    if (ScSideChannelEnabled() && !snort_process_lock_held)
+    {
+        pthread_mutex_lock(&snort_process_lock);
+        snort_process_lock_held = true;
+    }
+#endif
+
+    /* First thing we do is process a Usr signal that we caught */
+    if (SignalCheck())
+    {
+#ifndef SNORT_RELOAD
+        /* Got SIGNAL_SNORT_RELOAD */
+        Restart();
+#endif
+    }
+
+    CheckForReload();
+
+    PREPROC_PROFILE_START(metaPerfStats);
+
+    policy = snort_conf->targeted_policies[policy_id];
+    idx = policy->preproc_meta_eval_funcs;
+    while (idx != NULL)
+    {
+        idx->func(metahdr->type, data);
+        idx = idx->next;
+    }
+
+    PREPROC_PROFILE_END(metaPerfStats);
+
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+    if (ScTerminateService() || ScPauseService())
+    {
+        return 0;  // time to go
+    }
+#endif
+
+    ControlSocketDoWork(0);
+#ifdef SIDE_CHANNEL
+    SideChannelDrainRX(0);
+#endif
+
+    return 0;
+}
+#endif
+
+// non-local for easy access from core
+static Packet s_packet;
+static DAQ_PktHdr_t s_pkth;
+static uint8_t s_data[65536];
+
+static DAQ_Verdict PacketCallback(
+    void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
+{
+    int inject = 0;
+    DAQ_Verdict verdict = DAQ_VERDICT_PASS;
+    PROFILE_VARS;
+
+    PREPROC_PROFILE_START(totalPerfStats);
+
+#ifdef SIDE_CHANNEL
+    if (ScSideChannelEnabled() && !snort_process_lock_held)
+    {
+        pthread_mutex_lock(&snort_process_lock);
+        snort_process_lock_held = true;
+    }
+#endif
+
+#ifdef EXIT_CHECK
+    if (snort_conf->exit_check && (pc.total_from_daq >= snort_conf->exit_check))
+        ExitCheckStart();
+#endif
+
+    /* First thing we do is process a Usr signal that we caught */
+    if (SignalCheck())
+    {
+#ifndef SNORT_RELOAD
+        /* Got SIGNAL_SNORT_RELOAD */
+        PREPROC_PROFILE_END(totalPerfStats);
+        Restart();
+#endif
+    }
+
+    pc.total_from_daq++;
+
+    /* Increment counter that we're evaling rules for caching results */
+    rule_eval_pkt_count++;
+
+#ifdef TARGET_BASED
+    /* Load in a new attribute table if we need to... */
+    AttributeTableReloadCheck();
+#endif
+
+    CheckForReload();
+
+    /* Save off the time of each and every packet */
+    packet_time_update(&pkthdr->ts);
+
+#ifdef REG_TEST
+    if ( snort_conf->pkt_skip && pc.total_from_daq <= snort_conf->pkt_skip )
+    {
+        PREPROC_PROFILE_END(totalPerfStats);
+        return verdict;
+    }
+#endif
+
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+    if (ScTerminateService() || ScPauseService())
+    {
+        PREPROC_PROFILE_END(totalPerfStats);
+        return verdict;  // time to go
+    }
+#endif
+
+    /* reset the thresholding subsystem checks for this packet */
+    sfthreshold_reset();
+
+    PREPROC_PROFILE_START(eventqPerfStats);
+    SnortEventqReset();
+    Replace_ResetQueue();
+#ifdef ACTIVE_RESPONSE
+    Active_ResetQueue();
+#endif
+    PREPROC_PROFILE_END(eventqPerfStats);
+
+    verdict = ProcessPacket(&s_packet, pkthdr, pkt, NULL);
+
+#ifdef ACTIVE_RESPONSE
+    if ( Active_ResponseQueued() )
+    {
+        Active_SendResponses(&s_packet);
+    }
+#endif
+    if ( Active_PacketWasDropped() )
+    {
+        if ( verdict == DAQ_VERDICT_PASS )
+            verdict = DAQ_VERDICT_BLOCK;
+    }
+    else
+    {
+        Replace_ModifyPacket(&s_packet);
+
+        if ( s_packet.packet_flags & PKT_MODIFIED )
+        {
+            // this packet was normalized and/or has replacements
+            Encode_Update(&s_packet);
+            verdict = DAQ_VERDICT_REPLACE;
+        }
+#ifdef NORMALIZER
+        else if ( s_packet.packet_flags & PKT_RESIZED )
+        {
+            // we never increase, only trim, but
+            // daq doesn't support resizing wire packet
+            if ( !DAQ_Inject(s_packet.pkth, 0, s_packet.pkt, s_packet.pkth->pktlen) )
+            {
+                verdict = DAQ_VERDICT_BLOCK;
+                inject = 1;
+            }
+        }
+#endif
+        else
+        {
+            if ((s_packet.packet_flags & PKT_IGNORE) ||
+                (stream_api && (stream_api->get_ignore_direction(s_packet.ssnptr) == SSN_DIR_BOTH)))
+            {
+                if ( !Active_GetTunnelBypass() )
+                {
+                    verdict = DAQ_VERDICT_WHITELIST;
+                }
+                else
+                {
+                    verdict = DAQ_VERDICT_PASS;
+                    pc.internal_whitelist++;
+                }
+            }
+            else if ( s_packet.packet_flags & PKT_TRUST )
+            {
+                if (stream_api)
+                    stream_api->set_ignore_direction(s_packet.ssnptr, SSN_DIR_BOTH);
+
+                verdict = DAQ_VERDICT_WHITELIST;
+            }
+            else
+            {
+                verdict = DAQ_VERDICT_PASS;
+            }
+        }
+    }
+#ifdef ENABLE_HA
+    // This needs to be called here since the session could
+    // have been updated anywhere up to this point. :( 
+    if (stream_api)
+        stream_api->process_ha(s_packet.ssnptr);
+#endif
+
+    /* Collect some "on the wire" stats about packet size, etc */
+    UpdateWireStats(&sfBase, pkthdr->caplen, Active_PacketWasDropped(), inject);
+    Active_Reset();
+    Encode_Reset();
+
+    checkLWSessionTimeout(4, pkthdr->ts.tv_sec);
+    ControlSocketDoWork(0);
+#ifdef SIDE_CHANNEL
+    SideChannelDrainRX(0);
+#endif
+
+    s_packet.pkth = NULL;  // no longer avail on segv
+
+    PREPROC_PROFILE_END(totalPerfStats);
+    return verdict;
+}
+
+/*
+ * Function: ShowUsage(char *)
+ *
+ * Purpose:  Display the program options and exit
+ *
+ * Arguments: argv[0] => name of the program (argv[0])
+ *
+ * Returns: 0 => success
+ */
+static int ShowUsage(char *program_name)
+{
+    fprintf(stdout, "USAGE: %s [-options] <filter options>\n", program_name);
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+    fprintf(stdout, "       %s %s %s [-options] <filter options>\n", program_name
+                                                                   , SERVICE_CMDLINE_PARAM
+                                                                   , SERVICE_INSTALL_CMDLINE_PARAM);
+    fprintf(stdout, "       %s %s %s\n", program_name
+                                       , SERVICE_CMDLINE_PARAM
+                                       , SERVICE_UNINSTALL_CMDLINE_PARAM);
+    fprintf(stdout, "       %s %s %s\n", program_name
+                                       , SERVICE_CMDLINE_PARAM
+                                       , SERVICE_SHOW_CMDLINE_PARAM);
+#endif
+
+#ifdef WIN32
+# define FPUTS_WIN32(msg) fputs(msg,stdout)
+# define FPUTS_UNIX(msg)  NULL
+# define FPUTS_BOTH(msg)  fputs(msg,stdout)
+#else
+# define FPUTS_WIN32(msg)
+# define FPUTS_UNIX(msg)  fputs(msg,stdout)
+# define FPUTS_BOTH(msg)  fputs(msg,stdout)
+#endif
+
+    FPUTS_BOTH ("Options:\n");
+    FPUTS_BOTH ("        -A         Set alert mode: fast, full, console, test or none "
+                                  " (alert file alerts only)\n");
+    FPUTS_UNIX ("                   \"unsock\" enables UNIX socket logging (experimental).\n");
+    FPUTS_BOTH ("        -b         Log packets in tcpdump format (much faster!)\n");
+    FPUTS_BOTH ("        -B <mask>  Obfuscated IP addresses in alerts and packet dumps using CIDR mask\n");
+    FPUTS_BOTH ("        -c <rules> Use Rules File <rules>\n");
+    FPUTS_BOTH ("        -C         Print out payloads with character data only (no hex)\n");
+    FPUTS_BOTH ("        -d         Dump the Application Layer\n");
+    FPUTS_UNIX ("        -D         Run Snort in background (daemon) mode\n");
+    FPUTS_BOTH ("        -e         Display the second layer header info\n");
+    FPUTS_WIN32("        -E         Log alert messages to NT Eventlog. (Win32 only)\n");
+    FPUTS_BOTH ("        -f         Turn off fflush() calls after binary log writes\n");
+    FPUTS_BOTH ("        -F <bpf>   Read BPF filters from file <bpf>\n");
+    FPUTS_UNIX ("        -g <gname> Run snort gid as <gname> group (or gid) after initialization\n");
+    FPUTS_BOTH ("        -G <0xid>  Log Identifier (to uniquely id events for multiple snorts)\n");
+    FPUTS_BOTH ("        -h <hn>    Set home network = <hn>\n"
+                "                   (for use with -l or -B, does NOT change $HOME_NET in IDS mode)\n");
+    FPUTS_BOTH ("        -H         Make hash tables deterministic.\n");
+    FPUTS_BOTH ("        -i <if>    Listen on interface <if>\n");
+    FPUTS_BOTH ("        -I         Add Interface name to alert output\n");
+    FPUTS_BOTH ("        -k <mode>  Checksum mode (all,noip,notcp,noudp,noicmp,none)\n");
+    FPUTS_BOTH ("        -K <mode>  Logging mode (pcap[default],ascii,none)\n");
+    FPUTS_BOTH ("        -l <ld>    Log to directory <ld>\n");
+    FPUTS_BOTH ("        -L <file>  Log to this tcpdump file\n");
+    FPUTS_UNIX ("        -M         Log messages to syslog (not alerts)\n");
+    FPUTS_UNIX ("        -m <umask> Set umask = <umask>\n");
+    FPUTS_BOTH ("        -n <cnt>   Exit after receiving <cnt> packets\n");
+    FPUTS_BOTH ("        -N         Turn off logging (alerts still work)\n");
+    FPUTS_BOTH ("        -O         Obfuscate the logged IP addresses\n");
+    FPUTS_BOTH ("        -p         Disable promiscuous mode sniffing\n");
+    printf     ("        -P <snap>  Set explicit snaplen of packet (default: %d)\n",
+                                    DAQ_GetSnapLen());
+    FPUTS_BOTH ("        -q         Quiet. Don't show banner and status report\n");
+#ifndef WIN32
+    FPUTS_BOTH ("        -Q         Enable inline mode operation.\n");
+#endif
+    FPUTS_BOTH ("        -r <tf>    Read and process tcpdump file <tf>\n");
+    FPUTS_BOTH ("        -R <id>    Include 'id' in snort_intf<id>.pid file name\n");
+    FPUTS_BOTH ("        -s         Log alert messages to syslog\n");
+    FPUTS_BOTH ("        -S <n=v>   Set rules file variable n equal to value v\n");
+    FPUTS_UNIX ("        -t <dir>   Chroots process to <dir> after initialization\n");
+    FPUTS_BOTH ("        -T         Test and report on the current Snort configuration\n");
+    FPUTS_UNIX ("        -u <uname> Run snort uid as <uname> user (or uid) after initialization\n");
+    FPUTS_BOTH ("        -U         Use UTC for timestamps\n");
+    FPUTS_BOTH ("        -v         Be verbose\n");
+    FPUTS_BOTH ("        -V         Show version number\n");
+    FPUTS_WIN32("        -W         Lists available interfaces. (Win32 only)\n");
+#if defined(NON_ETHER_DECODER) && defined(DLT_IEEE802_11)
+    FPUTS_BOTH ("        -w         Dump 802.11 management and control frames\n");
+#endif
+    FPUTS_BOTH ("        -X         Dump the raw packet data starting at the link layer\n");
+    FPUTS_BOTH ("        -x         Exit if Snort configuration problems occur\n");
+    FPUTS_BOTH ("        -y         Include year in timestamp in the alert and log files\n");
+    FPUTS_BOTH ("        -Z <file>  Set the performonitor preprocessor file path and name\n");
+    FPUTS_BOTH ("        -?         Show this information\n");
+    FPUTS_BOTH ("<Filter Options> are standard BPF options, as seen in TCPDump\n");
+
+    FPUTS_BOTH ("Longname options and their corresponding single char version\n");
+    FPUTS_BOTH ("   --logid <0xid>                  Same as -G\n");
+    FPUTS_BOTH ("   --perfmon-file <file>           Same as -Z\n");
+    FPUTS_BOTH ("   --pid-path <dir>                Specify the directory for the Snort PID file\n");
+    FPUTS_BOTH ("   --snaplen <snap>                Same as -P\n");
+    FPUTS_BOTH ("   --help                          Same as -?\n");
+    FPUTS_BOTH ("   --version                       Same as -V\n");
+    FPUTS_BOTH ("   --alert-before-pass             Process alert, drop, sdrop, or reject before pass, default is pass before alert, drop,...\n");
+    FPUTS_BOTH ("   --treat-drop-as-alert           Converts drop, sdrop, and reject rules into alert rules during startup\n");
+    FPUTS_BOTH ("   --treat-drop-as-ignore          Use drop, sdrop, and reject rules to ignore session traffic when not inline.\n");
+    FPUTS_BOTH ("   --process-all-events            Process all queued events (drop, alert,...), default stops after 1st action group\n");
+    FPUTS_BOTH ("   --enable-inline-test            Enable Inline-Test Mode Operation\n");
+    FPUTS_BOTH ("   --dynamic-engine-lib <file>     Load a dynamic detection engine\n");
+    FPUTS_BOTH ("   --dynamic-engine-lib-dir <path> Load all dynamic engines from directory\n");
+    FPUTS_BOTH ("   --dynamic-detection-lib <file>  Load a dynamic rules library\n");
+    FPUTS_BOTH ("   --dynamic-detection-lib-dir <path> Load all dynamic rules libraries from directory\n");
+    FPUTS_BOTH ("   --dump-dynamic-rules <path>     Creates stub rule files of all loaded rules libraries\n");
+    FPUTS_BOTH ("   --dynamic-preprocessor-lib <file>  Load a dynamic preprocessor library\n");
+    FPUTS_BOTH ("   --dynamic-preprocessor-lib-dir <path> Load all dynamic preprocessor libraries from directory\n");
+    FPUTS_BOTH ("   --dynamic-output-lib <file>  Load a dynamic output library\n");
+    FPUTS_BOTH ("   --dynamic-output-lib-dir <path> Load all dynamic output libraries from directory\n");
+    FPUTS_UNIX ("   --create-pidfile                Create PID file, even when not in Daemon mode\n");
+    FPUTS_UNIX ("   --nolock-pidfile                Do not try to lock Snort PID file\n");
+    FPUTS_UNIX ("   --no-interface-pidfile          Do not include the interface name in Snort PID file\n");
+#ifdef INLINE_FAILOPEN
+    FPUTS_UNIX ("   --disable-inline-init-failopen  Do not fail open and pass packets while initializing with inline mode.\n");
+#endif
+#ifdef TARGET_BASED
+    FPUTS_UNIX ("   --disable-attribute-reload-thread Do not create a thread to reload the attribute table\n");
+#endif
+    FPUTS_BOTH ("   --pcap-single <tf>              Same as -r.\n");
+    FPUTS_BOTH ("   --pcap-file <file>              file that contains a list of pcaps to read - read mode is implied.\n");
+    FPUTS_BOTH ("   --pcap-list \"<list>\"            a space separated list of pcaps to read - read mode is implied.\n");
+    FPUTS_UNIX ("   --pcap-dir <dir>                a directory to recurse to look for pcaps - read mode is implied.\n");
+    FPUTS_UNIX ("   --pcap-filter <filter>          filter to apply when getting pcaps from file or directory.\n");
+    FPUTS_UNIX ("   --pcap-no-filter                reset to use no filter when getting pcaps from file or directory.\n");
+    FPUTS_BOTH ("   --pcap-loop <count>             this option will read the pcaps specified on command line continuously.\n"
+                "                                   for <count> times.  A value of 0 will read until Snort is terminated.\n");
+    FPUTS_BOTH ("   --pcap-reset                    if reading multiple pcaps, reset snort to post-configuration state before reading next pcap.\n");
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+    FPUTS_BOTH ("   --pcap-reload                   if reading multiple pcaps, reload snort config between pcaps.\n");
+#endif
+    FPUTS_BOTH ("   --pcap-show                     print a line saying what pcap is currently being read.\n");
+    FPUTS_BOTH ("   --exit-check <count>            Signal termination after <count> callbacks from DAQ_Acquire(), showing the time it\n"
+                "                                   takes from signaling until DAQ_Stop() is called.\n");
+    FPUTS_BOTH ("   --conf-error-out                Same as -x\n");
+#ifdef MPLS
+    FPUTS_BOTH ("   --enable-mpls-multicast         Allow multicast MPLS\n");
+    FPUTS_BOTH ("   --enable-mpls-overlapping-ip    Handle overlapping IPs within MPLS clouds\n");
+    FPUTS_BOTH ("   --max-mpls-labelchain-len       Specify the max MPLS label chain\n");
+    FPUTS_BOTH ("   --mpls-payload-type             Specify the protocol (ipv4, ipv6, ethernet) that is encapsulated by MPLS\n");
+#endif
+    FPUTS_BOTH ("   --require-rule-sid              Require that all snort rules have SID specified.\n");
+    FPUTS_BOTH ("   --daq <type>                    Select packet acquisition module (default is pcap).\n");
+    FPUTS_BOTH ("   --daq-mode <mode>               Select the DAQ operating mode.\n");
+    FPUTS_BOTH ("   --daq-var <name=value>          Specify extra DAQ configuration variable.\n");
+    FPUTS_BOTH ("   --daq-dir <dir>                 Tell snort where to find desired DAQ.\n");
+    FPUTS_BOTH ("   --daq-list[=<dir>]              List packet acquisition modules available in dir.  Default is static modules only.\n");
+    FPUTS_BOTH ("   --dirty-pig                     Don't flush packets and release memory on shutdown.\n");
+    FPUTS_BOTH ("   --cs-dir <dir>                  Directory to use for control socket.\n");
+    FPUTS_BOTH ("   --ha-peer                       Activate live high-availability state sharing with peer.\n");
+    FPUTS_BOTH ("   --ha-out <file>                 Write high-availability events to this file.\n");
+    FPUTS_BOTH ("   --ha-in <file>                  Read high-availability events from this file on startup (warm-start).\n");
+#undef FPUTS_WIN32
+#undef FPUTS_UNIX
+#undef FPUTS_BOTH
+    return 0;
+}
+
+static void ParseCmdLineDynamicLibInfo(SnortConfig *sc, int type, char *path)
+{
+    DynamicLibInfo *dli = NULL;
+    DynamicLibPath *dlp = NULL;
+
+    if ((sc == NULL) || (path == NULL))
+        FatalError("%s(%d) NULL arguments.\n", __FILE__, __LINE__);
+
+    switch (type)
+    {
+        case DYNAMIC_PREPROC_FILE:
+        case DYNAMIC_PREPROC_DIRECTORY:
+            DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic preprocessor specifier\n"););
+            if (sc->dyn_preprocs == NULL)
+            {
+                sc->dyn_preprocs = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
+                sc->dyn_preprocs->type = DYNAMIC_TYPE__PREPROCESSOR;
+            }
+            else if (sc->dyn_preprocs->count >= MAX_DYNAMIC_LIBS)
+            {
+                FatalError("Maximum number of loaded Dynamic Preprocessor Libs "
+                           "(%d) exceeded.\n", MAX_DYNAMIC_LIBS);
+            }
+
+            dli = sc->dyn_preprocs;
+            break;
+
+        case DYNAMIC_LIBRARY_FILE:
+        case DYNAMIC_LIBRARY_DIRECTORY:
+            DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic detection specifier\n"););
+            if (sc->dyn_rules == NULL)
+            {
+                sc->dyn_rules = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
+                sc->dyn_rules->type = DYNAMIC_TYPE__DETECTION;
+            }
+            else if (sc->dyn_rules->count >= MAX_DYNAMIC_LIBS)
+            {
+                FatalError("Maximum number of loaded Dynamic Detection Libs "
+                           "(%d) exceeded.\n", MAX_DYNAMIC_LIBS);
+            }
+
+            dli = sc->dyn_rules;
+            break;
+
+        case DYNAMIC_ENGINE_FILE:
+        case DYNAMIC_ENGINE_DIRECTORY:
+            DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic engine specifier\n"););
+            if (sc->dyn_engines == NULL)
+            {
+                sc->dyn_engines = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
+                sc->dyn_engines->type = DYNAMIC_TYPE__ENGINE;
+            }
+            else if (sc->dyn_engines->count >= MAX_DYNAMIC_LIBS)
+            {
+                FatalError("Maximum number of loaded Dynamic Engine Libs "
+                           "(%d) exceeded.\n", MAX_DYNAMIC_LIBS);
+            }
+
+            dli = sc->dyn_engines;
+            break;
+        case DYNAMIC_OUTPUT_FILE:
+            output_load_module(path);
+            return;
+            break;
+        case DYNAMIC_OUTPUT_DIRECTORY:
+            output_load(path);
+            return;
+            break;
+
+
+        default:
+            FatalError("%s(%d) Invalid dynamic type: %d\n", __FILE__, __LINE__, type);
+            break;
+    }
+
+    dlp = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath));
+    switch (type)
+    {
+        case DYNAMIC_PREPROC_FILE:
+        case DYNAMIC_LIBRARY_FILE:
+        case DYNAMIC_ENGINE_FILE:
+        case DYNAMIC_OUTPUT_FILE:
+            dlp->ptype = PATH_TYPE__FILE;
+            break;
+
+        case DYNAMIC_PREPROC_DIRECTORY:
+        case DYNAMIC_LIBRARY_DIRECTORY:
+        case DYNAMIC_ENGINE_DIRECTORY:
+        case DYNAMIC_OUTPUT_DIRECTORY:
+            dlp->ptype = PATH_TYPE__DIRECTORY;
+            break;
+
+        default:
+            FatalError("%s(%d) Invalid dynamic type: %d\n", __FILE__, __LINE__, type);
+            break;
+    }
+
+    dlp->path = SnortStrdup(path);
+    dli->lib_paths[dli->count] = dlp;
+    dli->count++;
+}
+
+/*
+ * Function: ParseCmdLine(int, char **)
+ *
+ * Parses command line arguments
+ *
+ * Arguments:
+ *  int
+ *      count of arguments passed to the routine
+ *  char **
+ *      2-D character array, contains list of command line args
+ *
+ * Returns: None
+ *
+ */
+
+static void ParseCmdLine(int argc, char **argv)
+{
+    int ch;
+    int option_index = -1;
+    char *endptr;   /* for SnortStrtol calls */
+    SnortConfig *sc;
+    int output_logging = 0;
+    int output_alerting = 0;
+    int syslog_configured = 0;
+#ifndef WIN32
+    int daemon_configured = 0;
+#endif
+
+    DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Parsing command line...\n"););
+
+    if (snort_cmd_line_conf != NULL)
+    {
+        FatalError("%s(%d) Trying to parse the command line again.\n",
+                   __FILE__, __LINE__);
+    }
+
+    snort_cmd_line_conf = SnortConfNew();
+    snort_conf = snort_cmd_line_conf;     /* Set the global for log messages */
+    sc = snort_cmd_line_conf;
+
+    optind = 1;
+
+    /* Look for a -D and/or -M switch so we can start logging to syslog
+     * with "snort" tag right away */
+    while ((ch = getopt_long(argc, argv, valid_options, long_options, &option_index)) != -1)
+    {
+        switch (ch)
+        {
+            case 'M':
+                if (syslog_configured)
+                    break;
+
+                /* If daemon or logging to syslog use "snort" as identifier and
+                 * start logging there now */
+                openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
+
+                sc->logging_flags |= LOGGING_FLAG__SYSLOG;
+                syslog_configured = 1;
+                break;
+
+#ifndef WIN32
+            case 'E':
+                sc->run_flags |= RUN_FLAG__DAEMON_RESTART;
+                /* Fall through */
+            case 'D':
+                if (daemon_configured)
+                    break;
+
+                /* If daemon or logging to syslog use "snort" as identifier and
+                 * start logging there now */
+                openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
+
+                ConfigDaemon(sc, optarg);
+                daemon_configured = 1;
+                break;
+#endif
+
+            case 'q':
+                /* Turn on quiet mode if configured so any log messages that may
+                 * be printed while parsing the command line before the quiet option
+                 * is read won't be printed */
+                ConfigQuiet(sc, NULL);
+                break;
+
+            case '?':  /* show help and exit with 1 */
+                PrintVersion();
+                ShowUsage(argv[0]);
+                exit(1);
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    /*
+    **  Set this so we know whether to return 1 on invalid input.
+    **  Snort uses '?' for help and getopt uses '?' for telling us there
+    **  was an invalid option, so we can't use that to tell invalid input.
+    **  Instead, we check optopt and it will tell us.
+    */
+    optopt = 0;
+    optind = 1;
+
+    /* loop through each command line var and process it */
+    while ((ch = getopt_long(argc, argv, valid_options, long_options, &option_index)) != -1)
+    {
+        DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Processing cmd line switch: %c\n", ch););
+
+        switch (ch)
+        {
+            case DYNAMIC_ENGINE_FILE:       /* Load dynamic engine specified */
+            case DYNAMIC_ENGINE_DIRECTORY:  /* Load dynamic engine specified */
+            case DYNAMIC_PREPROC_FILE:      /* Load dynamic preprocessor lib specified */
+            case DYNAMIC_PREPROC_DIRECTORY:
+            case DYNAMIC_LIBRARY_FILE:      /* Load dynamic detection lib specified */
+            case DYNAMIC_LIBRARY_DIRECTORY:
+            case DYNAMIC_OUTPUT_FILE:      /* Load dynamic output lib specified */
+            case DYNAMIC_OUTPUT_DIRECTORY:
+                ParseCmdLineDynamicLibInfo(sc, ch, optarg);
+                break;
+
+            case DUMP_DYNAMIC_RULES:
+                ConfigDumpDynamicRulesPath(sc, optarg);
+                break;
+
+            case ALERT_BEFORE_PASS:
+                ConfigAlertBeforePass(sc, NULL);
+                break;
+
+            case PROCESS_ALL_EVENTS:
+                ConfigProcessAllEvents(sc, NULL);
+                break;
+
+            case TREAT_DROP_AS_ALERT:
+                ConfigTreatDropAsAlert(sc, NULL);
+                break;
+
+            case TREAT_DROP_AS_IGNORE:
+                ConfigTreatDropAsIgnore(sc, NULL);
+                break;
+
+            case PID_PATH:
+                ConfigPidPath(sc, optarg);
+                break;
+
+            case CREATE_PID_FILE:
+                ConfigCreatePidFile(sc, NULL);
+                break;
+
+            case NOLOCK_PID_FILE:
+                sc->run_flags |= RUN_FLAG__NO_LOCK_PID_FILE;
+                break;
+
+            case NO_IFACE_PID_FILE:
+                sc->run_flags |= RUN_FLAG__NO_IFACE_PID_FILE;
+                break;
+
+#ifdef INLINE_FAILOPEN
+            case DISABLE_INLINE_FAILOPEN:
+                ConfigDisableInlineFailopen(sc, NULL);
+                break;
+#endif
+            case NO_LOGGING_TIMESTAMPS:
+                ConfigNoLoggingTimestamps(sc, NULL);
+                break;
+
+#ifdef EXIT_CHECK
+            case ARG_EXIT_CHECK:
+                {
+                    char* endPtr;
+
+                    sc->exit_check = SnortStrtoul(optarg, &endPtr, 0);
+                    if ((errno == ERANGE) || (*endPtr != '\0'))
+                        FatalError("--exit-check value must be non-negative integer\n");
+
+                    LogMessage("Exit Check: limit = "STDu64" callbacks\n", (long long unsigned int)sc->exit_check);
+                }
+
+                break;
+#endif
+
+#ifdef TARGET_BASED
+            case DISABLE_ATTRIBUTE_RELOAD:
+                ConfigDisableAttributeReload(sc, NULL);
+                break;
+#endif
+            case DETECTION_SEARCH_METHOD:
+                if (sc->fast_pattern_config != NULL)
+                    FatalError("Can only configure search method once.\n");
+
+                sc->fast_pattern_config = FastPatternConfigNew();
+
+                if (fpSetDetectSearchMethod(sc->fast_pattern_config, optarg) == -1)
+                    FatalError("Invalid search method: %s.\n", optarg);
+
+                break;
+
+            case ARG_DAQ_TYPE:
+                ConfigDaqType(sc, optarg);
+                break;
+
+            case ARG_DAQ_MODE:
+                ConfigDaqMode(sc, optarg);
+                break;
+
+            case ARG_DAQ_VAR:
+                ConfigDaqVar(sc, optarg);
+                break;
+
+            case ARG_DAQ_DIR:
+                ConfigDaqDir(sc, optarg);
+                break;
+
+            case ARG_DAQ_LIST:
+                PrintDaqModules(sc, optarg);
+                exit(0);
+                break;
+
+            case ARG_DIRTY_PIG:
+                ConfigDirtyPig(sc, optarg);
+                break;
+
+            case 'A':  /* alert mode */
+                output_alerting = 1;
+
+                if (strcasecmp(optarg, ALERT_MODE_OPT__NONE) == 0)
+                {
+                    sc->no_alert = 1;
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__PKT_CNT) == 0)
+                {
+                    /* print packet count at start of alert */
+                    sc->output_flags |= OUTPUT_FLAG__ALERT_PKT_CNT;
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__FULL) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_full");
+                }
+                else if (strcasecmp(optarg, "console:" ALERT_MODE_OPT__FULL) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_full: stdout");
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__FAST) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_fast");
+                }
+                else if (
+                    strcasecmp(optarg, "console:" ALERT_MODE_OPT__FAST) == 0 ||
+                    strcasecmp(optarg, ALERT_MODE_OPT__CONSOLE) == 0 )
+                {
+                    ParseOutput(sc, NULL, "alert_fast: stdout");
+                }
+                else if ((strcasecmp(optarg, ALERT_MODE_OPT__CMG) == 0) ||
+                         (strcasecmp(optarg, ALERT_MODE_OPT__JH) == 0) ||
+                         (strcasecmp(optarg, ALERT_MODE_OPT__DJR) == 0))
+                {
+                    ParseOutput(sc, NULL, "alert_fast: stdout packet");
+                    sc->no_log = 1;
+                    /* turn on layer2 headers */
+                    sc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK;
+                    /* turn on data dump */
+                    sc->output_flags |= OUTPUT_FLAG__APP_DATA;
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__AJK) == 0)
+                {
+                    ParseOutput(sc, NULL, "unified2");
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__UNIX_SOCK) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_unixsock");
+                }
+                else if (strcasecmp(optarg, ALERT_MODE_OPT__TEST) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_test");
+                    sc->no_log = 1;
+                }
+                else if (strcasecmp(optarg, "console:" ALERT_MODE_OPT__TEST) == 0)
+                {
+                    ParseOutput(sc, NULL, "alert_test: stdout");
+                    sc->no_log = 1;
+                }
+                else
+                {
+                    FatalError("Unknown command line alert option: %s\n", optarg);
+                }
+
+                break;
+
+            case 'b':  /* log packets in binary format for post-processing */
+                ParseOutput(sc, NULL, "log_tcpdump");
+                output_logging = 1;
+                break;
+
+            case 'B':  /* obfuscate with a substitution mask */
+                ConfigObfuscationMask(sc, optarg);
+                break;
+
+            case 'c':  /* use configuration file x */
+                sc->run_mode_flags |= RUN_MODE_FLAG__IDS;
+                snort_conf_file = SnortStrdup(optarg);
+                break;
+
+            case 'C':  /* dump the application layer as text only */
+                ConfigDumpCharsOnly(sc, NULL);
+                break;
+
+            case 'd':  /* dump the application layer data */
+                ConfigDumpPayload(sc, NULL);
+                break;
+
+#ifndef WIN32
+            case 'E':  /* Restarting from daemon mode */
+            case 'D':  /* daemon mode */
+                /* These are parsed at the beginning so as to start logging
+                 * to syslog right away */
+                break;
+#endif
+
+            case 'e':  /* show second level header info */
+                ConfigDecodeDataLink(sc, NULL);
+                break;
+#ifdef WIN32
+            case 'E':  /* log alerts to Event Log */
+                ParseOutput(sc, NULL, "alert_syslog");
+                sc->logging_flags &= ~LOGGING_FLAG__SYSLOG_REMOTE;
+                output_alerting = 1;
+                break;
+#endif
+            case 'f':
+                sc->output_flags |= OUTPUT_FLAG__LINE_BUFFER;
+                break;
+
+            case 'F':   /* read BPF filter in from a file */
+                ConfigBpfFile(sc, optarg);
+                break;
+
+#ifndef WIN32
+            case 'g':   /* setgid */
+                ConfigSetGid(sc, optarg);
+                break;
+#endif
+
+            case 'G':  /* snort loG identifier */
+                sc->event_log_id = SnortStrtoul(optarg, &endptr, 0);
+                if ((errno == ERANGE) || (*endptr != '\0') ||
+                    (sc->event_log_id > UINT16_MAX))
+                {
+                    FatalError("Snort log identifier invalid: %s.  It must "
+                               "be between 0 and %u.\n", optarg, UINT16_MAX);
+                }
+
+                /* Forms upper 2 bytes.  Lower two bytes are the event id */
+                sc->event_log_id <<= 16;
+
+                break;
+
+            case 'h':
+                /* set home network to x, this will help determine what to set
+                 * logging diectories to */
+                ConfigReferenceNet(sc, optarg);
+                break;
+
+            case 'H':
+                sc->run_flags |= RUN_FLAG__STATIC_HASH;
+                break;
+
+            case 'i':
+                ConfigInterface(sc, optarg);
+                break;
+
+            case 'I':  /* add interface name to alert string */
+                ConfigAlertWithInterfaceName(sc, NULL);
+                break;
+
+            case 'k':  /* set checksum mode */
+                ConfigChecksumMode(sc, optarg);
+                break;
+
+            case 'K':  /* log mode */
+                if (strcasecmp(optarg, LOG_MODE_OPT__NONE) == 0)
+                {
+                    sc->no_log = 1;
+                }
+                else if (strcasecmp(optarg, LOG_MODE_OPT__PCAP) == 0)
+                {
+                    ParseOutput(sc, NULL, "log_tcpdump");
+                }
+                else if (strcasecmp(optarg, LOG_MODE_OPT__ASCII) == 0)
+                {
+                    ParseOutput(sc, NULL, "log_ascii");
+                }
+                else
+                {
+                    FatalError("Unknown command line log option: %s\n", optarg);
+                }
+
+                output_logging = 1;
+                break;
+
+            case 'l':  /* use log dir <X> */
+                ConfigLogDir(sc, optarg);
+                break;
+
+            case 'L':  /* set BinLogFile name */
+                /* implies tcpdump format logging
+                 * 256 is kind of arbitrary but should be more than enough */
+                if (strlen(optarg) < 256)
+                {
+                    ParseOutput(sc, NULL, "log_tcpdump");
+                    sc->pcap_log_file = SnortStrdup(optarg);
+                }
+                else
+                {
+                    FatalError("log_tcpdump file name \"%s\" has to be less "
+                               "than or equal to 256 characters.\n", optarg);
+                }
+
+                output_logging = 1;
+                break;
+
+            case 'M':
+                /* This is parsed at the beginning so as to start logging
+                 * to syslog right away */
+                break;
+
+#ifndef WIN32
+            case 'm':  /* set the umask for the output files */
+                ConfigUmask(sc, optarg);
+                break;
+#endif
+
+            case 'n':  /* grab x packets and exit */
+                ConfigPacketCount(sc, optarg);
+                break;
+
+            case 'N':  /* no logging mode */
+                ConfigNoLog(sc, NULL);
+                break;
+
+            case 'O':  /* obfuscate the logged IP addresses for privacy */
+                ConfigObfuscate(sc, NULL);
+                break;
+
+            case 'p':  /* disable explicit promiscuous mode */
+                ConfigNoPromiscuous(sc, NULL);
+                break;
+
+            case 'P':  /* explicitly define snaplength of packets */
+                ConfigPacketSnaplen(sc, optarg);
+                break;
+
+            case 'q':  /* no stdout output mode */
+                /* This is parsed at the beginning so as to start logging
+                 * in quiet mode right away */
+                break;
+
+#ifndef WIN32
+            case 'Q':
+                LogMessage("Enabling inline operation\n");
+                sc->run_flags |= RUN_FLAG__INLINE;
+                break;
+#endif
+            case ENABLE_INLINE_TEST:
+                LogMessage("Enable Inline Test Mode\n");
+                sc->run_flags |= RUN_FLAG__INLINE_TEST;
+                break;
+
+
+            case 'r':  /* read packets from a TCPdump file instead of the net */
+            case PCAP_SINGLE:
+                PQ_Single(optarg);
+                sc->run_flags |= RUN_FLAG__READ;
+                break;
+
+            case 'R': /* augment pid file name suffix */
+                if ((strlen(optarg) >= MAX_PIDFILE_SUFFIX) || (strlen(optarg) <= 0) ||
+                    (strstr(optarg, "..") != NULL) || (strstr(optarg, "/") != NULL))
+                {
+                        FatalError("Invalid pidfile suffix: %s.  Suffix must "
+                                   "less than %u characters and not have "
+                                   "\"..\" or \"/\" in the name.\n", optarg,
+                                   MAX_PIDFILE_SUFFIX);
+                }
+
+                SnortStrncpy(sc->pidfile_suffix, optarg, sizeof(sc->pidfile_suffix));
+                break;
+
+            case 's':  /* log alerts to syslog */
+#ifndef WIN32
+                ParseOutput(sc, NULL, "alert_syslog");
+#else
+                sc->logging_flags |= LOGGING_FLAG__SYSLOG_REMOTE;
+#endif
+                output_alerting = 1;
+                break;
+
+            case 'S':  /* set a rules file variable */
+                {
+                    char *equal_ptr = strchr(optarg, '=');
+                    VarNode *node;
+
+                    if (equal_ptr == NULL)
+                    {
+                        FatalError("Format for command line variable definitions "
+                                   "is:\n -S var=value\n");
+                    }
+
+                    /* Save these and parse when snort conf is parsed so
+                     * they can be added to the snort conf configuration */
+                    node = (VarNode *)SnortAlloc(sizeof(VarNode));
+                    node->name = SnortStrndup(optarg, equal_ptr - optarg);
+
+                    /* Make sure it's not already in the list */
+                    if (cmd_line_var_list != NULL)
+                    {
+                        VarNode *tmp = cmd_line_var_list;
+
+                        while (tmp != NULL)
+                        {
+                            if (strcasecmp(tmp->name, node->name) == 0)
+                            {
+                                FreeVarList(cmd_line_var_list);
+                                FatalError("Duplicate variable name: %s.\n",
+                                           tmp->name);
+                            }
+
+                            tmp = tmp->next;
+                        }
+                    }
+
+                    node->value = SnortStrdup(equal_ptr + 1);
+                    node->line = SnortStrdup(optarg);
+                    node->next = cmd_line_var_list;
+                    cmd_line_var_list = node;
+
+                    /* Put line in a parser parsable form - we know the
+                     * equals is already there */
+                    equal_ptr = strchr(node->line, '=');
+                    *equal_ptr = ' ';
+                }
+
+                break;
+
+#ifndef WIN32
+            case 't':  /* chroot to the user specified directory */
+                ConfigChrootDir(sc, optarg);
+                break;
+#endif
+
+            case 'T':  /* test mode, verify that the rules load properly */
+                sc->run_mode_flags |= RUN_MODE_FLAG__TEST;
+                break;
+
+#ifndef WIN32
+            case 'u':  /* setuid */
+                ConfigSetUid(sc, optarg);
+                break;
+#endif
+
+            case 'U':  /* use UTC */
+                ConfigUtc(sc, NULL);
+                break;
+
+            case 'v':  /* be verbose */
+                ConfigVerbose(sc, NULL);
+                break;
+
+            case 'V':  /* prog ver already gets printed out, so we just exit */
+                sc->run_mode_flags |= RUN_MODE_FLAG__VERSION;
+                sc->logging_flags |= LOGGING_FLAG__QUIET;
+                break;
+
+#ifdef WIN32
+            case 'W':
+                PrintVersion();
+                PrintAllInterfaces();
+                exit(0);  /* XXX Should maybe use CleanExit here? */
+                break;
+#endif
+
+#if !defined(NO_NON_ETHER_DECODER) && defined(DLT_IEEE802_11)
+            case 'w':  /* show 802.11 all frames info */
+                sc->output_flags |= OUTPUT_FLAG__SHOW_WIFI_MGMT;
+                break;
+#endif
+            case 'X':  /* display verbose packet bytecode dumps */
+                ConfigDumpPayloadVerbose(sc, NULL);
+                break;
+
+            case 'x':
+                sc->run_flags |= RUN_FLAG__CONF_ERROR_OUT;
+                break;
+
+            case 'y':  /* Add year to timestamp in alert and log files */
+                ConfigShowYear(sc, NULL);
+                break;
+
+            case 'Z':  /* Set preprocessor perfmon file path/filename */
+                ConfigPerfFile(sc, optarg);
+                break;
+
+            case PCAP_FILE_LIST:
+            case PCAP_LIST:
+#ifndef WIN32
+            case PCAP_DIR:
+#endif
+                PQ_Multi((char)ch, optarg);
+                sc->run_flags |= RUN_FLAG__READ;
+                break;
+
+            case PCAP_LOOP:
+                {
+                    long int loop_count = SnortStrtol(optarg, &endptr, 0);
+
+                    if ((errno == ERANGE) || (*endptr != '\0') ||
+                        (loop_count < 0) || (loop_count > 2147483647))
+                    {
+                        FatalError("Valid values for --pcap-loop are between 0 and 2147483647\n");
+                    }
+
+                    if (loop_count == 0)
+                        pcap_loop_count = -1;
+                    else
+                        pcap_loop_count = loop_count;
+                }
+
+                break;
+
+            case PCAP_RESET:
+                sc->run_flags |= RUN_FLAG__PCAP_RESET;
+                break;
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+            case PCAP_RELOAD:
+                sc->run_flags |= RUN_FLAG__PCAP_RELOAD;
+                break;
+#endif
+
+#ifndef WIN32
+            case PCAP_FILTER:
+                PQ_SetFilter(optarg);
+                break;
+
+            case PCAP_NO_FILTER:
+                PQ_SetFilter(NULL);
+                break;
+#endif
+
+            case PCAP_SHOW:
+                sc->run_flags |= RUN_FLAG__PCAP_SHOW;
+                break;
+#ifdef MPLS
+            case ENABLE_MPLS_MULTICAST:
+                ConfigEnableMplsMulticast(sc, NULL);
+                break;
+
+            case ENABLE_OVERLAPPING_IP:
+                ConfigEnableMplsOverlappingIp(sc, NULL);
+                break;
+
+            case MAX_MPLS_LABELCHAIN_LEN:
+                ConfigMaxMplsLabelChain(sc, optarg);
+                break;
+
+            case MPLS_PAYLOAD_TYPE:
+                ConfigMplsPayloadType(sc, optarg);
+                break;
+#endif
+            case REQUIRE_RULE_SID:
+                sc->run_flags |= RUN_FLAG__REQUIRE_RULE_SID;
+                break;
+
+            case ARG_CS_DIR:
+                if ( optarg != NULL )
+                    sc->cs_dir = SnortStrdup(optarg);
+                break;
+#ifdef REG_TEST
+            case ARG_HA_PEER:
+                sc->ha_peer = true;
+                break;
+
+            case ARG_HA_OUT:
+                sc->ha_out = SnortStrdup(optarg);
+                break;
+
+            case ARG_HA_IN:
+                sc->ha_in = SnortStrdup(optarg);
+                break;
+#endif
+
+            case '?':  /* show help and exit with 1 */
+                PrintVersion();
+                ShowUsage(argv[0]);
+                /* XXX Should do a clean exit */
+                exit(1);
+                break;
+
+            default:
+                FatalError("Invalid option: %c.\n", ch);
+                break;
+        }
+    }
+
+    sc->bpf_filter = copy_argv(&argv[optind]);
+
+    if ((sc->run_mode_flags & RUN_MODE_FLAG__TEST) &&
+        (sc->run_flags & RUN_FLAG__DAEMON))
+    {
+        FatalError("Cannot use test mode and daemon mode together.\n"
+                   "To verify configuration, run first in test "
+                   "mode and then restart in daemon mode.\n");
+    }
+
+    if ((sc->run_flags & RUN_FLAG__INLINE) &&
+            (sc->run_flags & RUN_FLAG__INLINE_TEST))
+    {
+        FatalError("Cannot use inline adapter mode and inline test "
+                "mode together. \n");
+    }
+
+    // TBD no reason why command line args only can't be checked
+    // marginally useful, perhaps, but why do we go out of our way
+    // to make things hard on the user?
+    if ((sc->run_mode_flags & RUN_MODE_FLAG__TEST) &&
+        (snort_conf_file == NULL))
+    {
+        FatalError("Test mode must be run with a snort configuration "
+                   "file.  Use the '-c' option on the command line to "
+                   "specify a configuration file.\n");
+    }
+    if (pcap_loop_count && !(sc->run_flags & RUN_FLAG__READ))
+    {
+        FatalError("--pcap-loop can only be used in combination with pcaps "
+                   "on the command line.\n");
+    }
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+    if ((sc->run_flags & RUN_FLAG__PCAP_RELOAD) &&
+        !(sc->run_flags & RUN_FLAG__READ))
+    {
+        FatalError("--pcap-reload can only be used in combination with pcaps "
+                   "on the command line.\n");
+    }
+#endif
+
+    /* Set the run mode based on what we've got from command line */
+
+    /* Version overrides all */
+    if (sc->run_mode_flags & RUN_MODE_FLAG__VERSION)
+    {
+        sc->run_mode = RUN_MODE__VERSION;
+    }
+    /* Next dumping so rule stubs */
+    else if (sc->run_mode_flags & RUN_MODE_FLAG__RULE_DUMP)
+    {
+        sc->run_mode = RUN_MODE__RULE_DUMP;
+    }
+    /* Next if we want to test a snort conf */
+    else if (sc->run_mode_flags & RUN_MODE_FLAG__TEST)
+    {
+        sc->run_mode = RUN_MODE__TEST;
+    }
+    /* Now if there is a snort conf.  If a snort conf wasn't given on the
+     * command line, we'll look in a default place if the next ones
+     * don't match */
+    else if ((sc->run_mode_flags & RUN_MODE_FLAG__IDS) && (snort_conf_file != NULL))
+    {
+        sc->run_mode = RUN_MODE__IDS;
+    }
+    /* If logging but not alerting or log directory is set */
+    else if ((output_logging && !output_alerting) || (sc->log_dir != NULL))
+    {
+        sc->no_alert = 1;
+        sc->run_mode = RUN_MODE__PACKET_LOG;
+    }
+    /* If none of the above and not logging or alerting and verbose */
+    else if ((!output_logging && !output_alerting) &&
+             (sc->logging_flags & LOGGING_FLAG__VERBOSE))
+    {
+        sc->no_alert = 1;
+        sc->no_log = 1;
+        sc->run_mode = RUN_MODE__PACKET_DUMP;
+    }
+
+#if 1
+    if (!sc->run_mode)
+    {
+        sc->no_alert = 1;
+        sc->no_log = 1;
+        sc->run_mode = RUN_MODE__PACKET_DUMP;
+    }
+#else
+    if (!sc->run_mode)
+        sc->run_mode = RUN_MODE__IDS;
+
+    /* If mode mandates a conf and we don't have one,  check for default. */
+    if (((sc->run_mode == RUN_MODE__IDS) || (sc->run_mode == RUN_MODE__TEST)) &&
+        (snort_conf_file == NULL))
+    {
+        snort_conf_file = ConfigFileSearch();
+        if (snort_conf_file == NULL)
+        {
+            DisplayBanner();
+            ShowUsage(argv[0]);
+            FatalError("\n\nUh, you need to tell me to do something...");
+        }
+    }
+#endif
+
+    if ((sc->run_mode == RUN_MODE__PACKET_LOG) &&
+        (sc->output_configs == NULL))
+    {
+        ParseOutput(sc, NULL, "log_tcpdump");
+    }
+
+    switch ( snort_conf->run_mode )
+    {
+        case RUN_MODE__IDS:
+            if (ScLogVerbose())
+                log_func = PrintPacket;
+            break;
+
+        case RUN_MODE__PACKET_LOG:
+            log_func = LogPacket;
+            break;
+
+        case RUN_MODE__PACKET_DUMP:
+            log_func = PrintPacket;
+            break;
+
+        default:
+            break;
+    }
+    SetSnortConfDir();
+}
+
+/*
+ * Function: SetPktProcessor()
+ *
+ * Purpose:  Set root decoder based on datalink
+ */
+// TBD add GetDecoder(dlt) to decode module and hide all
+// protocol decoder functions.
+static int SetPktProcessor(void)
+{
+	const char* slink = NULL;
+	const char* extra = NULL;
+	int dlt = DLT_EN10MB;
+
+	switch ( dlt )
+	{
+		case DLT_EN10MB:
+			slink = "Ethernet";
+			grinder = DecodeEthPkt;
+			break;
+		default:
+			/* oops, don't know how to handle this one */
+			FatalError("Cannot decode data link type %d\n", dlt);
+			break;
+	}
+	if ( !ScReadMode() || ScPcapShow() )
+	{
+		LogMessage("Decoding %s\n", slink);
+	}
+	if (extra && ScOutputDataLink())
+	{
+		LogMessage("%s\n", extra);
+		snort_conf->output_flags &= ~OUTPUT_FLAG__SHOW_DATA_LINK;
+	}
+#ifdef ACTIVE_RESPONSE
+	Encode_Init();
+#endif
+	return 0;
+}
+/*
+ *  Handle idle time checks in snort packet processing loop
+ */
+static void SnortIdle(void)
+{
+    /* Rollover of performance log */
+    if (IsSetRotatePerfFileFlag())
+    {
+        sfRotateBaseStatsFile(perfmon_config);
+        sfRotateFlowStatsFile(perfmon_config);
+        ClearRotatePerfFileFlag();
+    }
+#ifdef OPENBSD
+    else if (reload_signal != reload_total)
+        nanosleep(&packet_sleep, NULL);
+#endif
+
+    checkLWSessionTimeout(16384, time(NULL));
+    ControlSocketDoWork(1);
+#ifdef SIDE_CHANNEL
+    SideChannelDrainRX(0);
+#endif
+    IdleProcessingExecute();
+}
+
+void PacketLoop (void)
+{
+    int error;
+    int pkts_to_read = (int)snort_conf->pkt_cnt;
+
+    TimeStart();
+
+    while ( !exit_logged )
+    {
+        error = DAQ_Acquire(pkts_to_read, PacketCallback, NULL);
+
+#ifdef SIDE_CHANNEL
+        /* If we didn't manage to lock the process lock in a DAQ acquire callback, lock it now. */
+        if (ScSideChannelEnabled() && !snort_process_lock_held)
+        {
+            pthread_mutex_lock(&snort_process_lock);
+            snort_process_lock_held = true;
+        }
+#endif
+
+        if ( error )
+        {
+            if ( !ScReadMode() || !PQ_Next() )
+            {
+                /* If not read-mode or no next pcap, we're done */
+                break;
+            }
+        }
+        /* Check for any pending signals when no packets are read*/
+        else
+        {
+            // TBD SnortIdle() only checks for perf file rotation
+            // and that can only be done after calling SignalCheck()
+            // so either move SnortIdle() to SignalCheck() or directly
+            // set the flag in the signal handler (and then clear it
+            // in SnortIdle()).
+
+            // check for signals
+            if ( SignalCheck() )
+            {
+#ifndef SNORT_RELOAD
+                // Got SIGNAL_SNORT_RELOAD
+                Restart();
+#endif
+            }
+            CheckForReload();
+        }
+        if ( pkts_to_read > 0 )
+        {
+            if ( snort_conf->pkt_cnt <= pc.total_from_daq )
+                break;
+            else
+                pkts_to_read = (int)(snort_conf->pkt_cnt - pc.total_from_daq);
+        }
+        // idle time processing..quick things to check or do ...
+        // TBD fix this per above ... and if it stays here, should
+        // prolly change the name if acquire breaks due to a signal
+        // (since in that case we aren't idle here)
+        SnortIdle();
+
+#ifdef SIDE_CHANNEL
+        /* Unlock the Snort process lock once we've hit the DAQ acquire timeout. */
+        if (snort_process_lock_held)
+        {
+            snort_process_lock_held = false;
+            pthread_mutex_unlock(&snort_process_lock);
+        }
+#endif
+    }
+
+#ifdef SIDE_CHANNEL
+    /* Error conditions can lead to exiting the packet loop prior to unlocking the process lock.  */
+    if (snort_process_lock_held)
+    {
+        snort_process_lock_held = false;
+        pthread_mutex_unlock(&snort_process_lock);
+    }
+#endif
+
+    if ( !exit_logged && error )
+    {
+        if ( error == DAQ_READFILE_EOF )
+            error = 0;
+        else if ( error > 0 )
+        {
+            DAQ_Abort();
+            exit(1);
+        }
+        CleanExit(error);
+    }
+    done_processing = 1;
+}
+
+/* Resets Snort to a post-configuration state */
+static void SnortReset(void)
+{
+    PreprocSignalFuncNode *idxPreprocReset;
+    PreprocSignalFuncNode *idxPreprocResetStats;
+
+    /* reset preprocessors */
+    idxPreprocReset = preproc_reset_funcs;
+    while (idxPreprocReset != NULL)
+    {
+        idxPreprocReset->func(-1, idxPreprocReset->arg);
+        idxPreprocReset = idxPreprocReset->next;
+    }
+
+    SnortEventqReset();
+    Replace_ResetQueue();
+#ifdef ACTIVE_RESPONSE
+    Active_ResetQueue();
+#endif
+
+    sfthreshold_reset_active();
+    RateFilter_ResetActive();
+    TagCacheReset();
+
+#ifdef PERF_PROFILING
+    ShowPreprocProfiles();
+    ShowRuleProfiles();
+#endif
+
+    DropStats(0);
+
+    /* zero out packet count */
+    memset(&pc, 0, sizeof(pc));
+
+#ifdef PERF_PROFILING
+    ResetRuleProfiling();
+    ResetPreprocProfiling();
+#endif
+
+    /* reset preprocessor stats */
+    idxPreprocResetStats = preproc_reset_stats_funcs;
+    while (idxPreprocResetStats != NULL)
+    {
+        idxPreprocResetStats->func(-1, idxPreprocResetStats->arg);
+        idxPreprocResetStats = idxPreprocResetStats->next;
+    }
+}
+
+
+#if 0
+/* locate one of the possible default config files */
+/* allocates memory to hold filename */
+static char *ConfigFileSearch(void)
+{
+    struct stat st;
+    int i;
+    char *conf_files[]={"/etc/snort.conf", "./snort.conf", NULL};
+    char *fname = NULL;
+    char *rval = NULL;
+
+    i = 0;
+
+    /* search the default set of config files */
+    while(conf_files[i])
+    {
+        fname = conf_files[i];
+
+        if(stat(fname, &st) != -1)
+        {
+            rval = SnortStrdup(fname);
+            break;
+        }
+        i++;
+    }
+
+    /* search for .snortrc in the HOMEDIR */
+    if(!rval)
+    {
+        char *home_dir = NULL;
+
+        if((home_dir = getenv("HOME")) != NULL)
+        {
+            char *snortrc = "/.snortrc";
+            int path_len;
+
+            path_len = strlen(home_dir) + strlen(snortrc) + 1;
+
+            /* create the full path */
+            fname = (char *)SnortAlloc(path_len);
+
+            SnortSnprintf(fname, path_len, "%s%s", home_dir, snortrc);
+
+            if(stat(fname, &st) != -1)
+                rval = fname;
+            else
+                free(fname);
+        }
+    }
+
+    return rval;
+}
+#endif
+
+/* Signal Handlers ************************************************************/
+static void SigExitHandler(int signal)
+{
+    if (exit_signal != 0)
+        return;
+
+    /* Don't want to have to wait to start processing packets before
+     * getting out of dodge */
+    if (snort_initializing)
+        _exit(0);
+
+    exit_signal = signal;
+}
+
+static void SigDumpStatsHandler(int signal)
+{
+    dump_stats_signal = true;
+}
+
+static void SigRotateStatsHandler(int signal)
+{
+    rotate_stats_signal = true;
+}
+
+static void SigReloadHandler(int signal)
+{
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+    reload_signal++;
+#else
+    reload_signal = true;
+#endif
+}
+
+#ifdef CONTROL_SOCKET
+static void SigPipeHandler(int signal)
+{
+}
+#endif
+
+#ifdef TARGET_BASED
+static void SigNoAttributeTableHandler(int signal)
+{
+   no_attr_table_signal = true;
+}
+#endif
+
+static void SigOopsHandler(int signal)
+{
+    if ( s_packet.pkth )
+    {
+        s_pkth = *s_packet.pkth;
+
+        if ( s_packet.pkt )
+            memcpy(s_data, s_packet.pkt, 0xFFFF & s_packet.pkth->caplen);
+    }
+    SnortAddSignal(signal, SIG_DFL, 0);
+
+    raise(signal);
+}
+
+
+static void PrintStatistics (void)
+{
+    if ( ScTestMode() || ScVersionMode() || ScRuleDumpMode() )
+        return;
+
+    fpShowEventStats(snort_conf);
+
+#ifdef PERF_PROFILING
+    {
+        int save_quiet_flag = snort_conf->logging_flags & LOGGING_FLAG__QUIET;
+
+        snort_conf->logging_flags &= ~LOGGING_FLAG__QUIET;
+
+        ShowPreprocProfiles();
+        ShowRuleProfiles();
+
+        snort_conf->logging_flags |= save_quiet_flag;
+    }
+#endif
+
+    DropStats(2);
+    print_thresholding(snort_conf->threshold_config, 1);
+}
+
+/****************************************************************************
+ *
+ * Function: CleanExit()
+ *
+ * Purpose:  Clean up misc file handles and such and exit
+ *
+ * Arguments: exit value;
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+static void CleanExit(int exit_val)
+{
+    SnortConfig tmp;
+
+#ifdef TARGET_BASED
+#ifdef DEBUG
+#if 0
+    SFLAT_dump();
+#endif
+#endif
+#endif
+
+    /* Have to trick LogMessage to log correctly after snort_conf
+     * is freed */
+    memset(&tmp, 0, sizeof(tmp));
+
+    if (snort_conf != NULL)
+    {
+        tmp.logging_flags |=
+            (snort_conf->logging_flags & LOGGING_FLAG__QUIET);
+
+        tmp.run_flags |= (snort_conf->run_flags & RUN_FLAG__DAEMON);
+
+        tmp.logging_flags |=
+            (snort_conf->logging_flags & LOGGING_FLAG__SYSLOG);
+    }
+
+    SnortCleanup(exit_val);
+    snort_conf = &tmp;
+
+    LogMessage("Snort exiting\n");
+#ifndef WIN32
+    closelog();
+#endif
+    if ( !done_processing )
+        exit(exit_val);
+}
+
+static void SnortCleanup(int exit_val)
+{
+    PreprocSignalFuncNode *idxPreproc = NULL;
+    PluginSignalFuncNode *idxPlugin = NULL;
+
+    /* This function can be called more than once.  For example,
+     * once from the SIGINT signal handler, and once recursively
+     * as a result of calling pcap_close() below.  We only need
+     * to perform the cleanup once, however.  So the static
+     * variable already_exiting will act as a flag to prevent
+     * double-freeing any memory.  Not guaranteed to be
+     * thread-safe, but it will prevent the simple cases.
+     */
+    static int already_exiting = 0;
+    if( already_exiting != 0 )
+    {
+        return;
+    }
+    already_exiting = 1;
+    snort_exiting = 1;
+    snort_initializing = false;  /* just in case we cut out early */
+
+    Active_Suspend();  // rules that fire now can't actually block
+
+#if 0
+    if ( DAQ_WasStarted() )
+    {
+#ifdef EXIT_CHECK
+        if (snort_conf->exit_check)
+            ExitCheckEnd();
+#endif
+        DAQ_Stop();
+    }
+#endif
+
+    ControlSocketCleanUp();
+#ifdef SIDE_CHANNEL
+    SideChannelStopTXThread();
+    SideChannelCleanUp();
+#endif
+    IdleProcessingCleanUp();
+
+    if ( snort_conf->dirty_pig )
+    {
+        //DAQ_Delete();
+        //DAQ_Term();
+        //PrintStatistics();
+        return;
+    }
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+    /* Setting snort_exiting will cause the thread to break out
+     * of it's loop and exit */
+    if (snort_reload_thread_created)
+        pthread_join(snort_reload_thread_id, NULL);
+#endif
+
+#if defined(INLINE_FAILOPEN) && !defined(WIN32)
+    if (inline_failopen_thread_running)
+        pthread_kill(inline_failopen_thread_id, SIGKILL);
+#endif
+
+#if defined(TARGET_BASED) && !defined(WIN32)
+    if (attribute_reload_thread_running)
+    {
+        /* Set the flag to stop the attribute reload thread and
+         * send VTALRM signal to pull it out of the idle sleep.
+         * Thread exits normally on next iteration through its
+         * loop.
+         *
+         * If its doing other processing, that continues post
+         * interrupt and thread exits normally.
+         */
+        attribute_reload_thread_stop = 1;
+        pthread_kill(attribute_reload_thread_id, SIGVTALRM);
+        while (attribute_reload_thread_running)
+            nanosleep(&thread_sleep, NULL);
+        pthread_join(attribute_reload_thread_id, NULL);
+    }
+#endif
+
+    /* Do some post processing on any incomplete Preprocessor Data */
+    idxPreproc = preproc_shutdown_funcs;
+    while (idxPreproc)
+    {
+        idxPreproc->func(SIGQUIT, idxPreproc->arg);
+        idxPreproc = idxPreproc->next;
+    }
+
+    /* Do some post processing on any incomplete Plugin Data */
+    idxPlugin = plugin_shutdown_funcs;
+    while(idxPlugin)
+    {
+        idxPlugin->func(SIGQUIT, idxPlugin->arg);
+        idxPlugin = idxPlugin->next;
+    }
+
+    if (!ScTestMode() && !ScVersionMode() && !ScRuleDumpMode() )
+    {
+        if ( !exit_val )
+            TimeStop();
+    }
+
+    /* Exit preprocessors */
+    idxPreproc = preproc_clean_exit_funcs;
+    while(idxPreproc)
+    {
+        idxPreproc->func(SIGQUIT, idxPreproc->arg);
+        idxPreproc = idxPreproc->next;
+    }
+
+    /* Do some post processing on any incomplete Plugin Data */
+    idxPlugin = plugin_clean_exit_funcs;
+    while(idxPlugin)
+    {
+        idxPlugin->func(SIGQUIT, idxPlugin->arg);
+        idxPlugin = idxPlugin->next;
+    }
+
+    if (decoderActionQ != NULL)
+    {
+        sfActionQueueDestroy (decoderActionQ);
+        mempool_destroy (&decoderAlertMemPool);
+        decoderActionQ = NULL;
+        memset(&decoderAlertMemPool, 0, sizeof(decoderAlertMemPool));
+    }
+
+    //DAQ_Delete();
+    //DAQ_Term();
+    //PrintStatistics();
+
+#ifdef ACTIVE_RESPONSE
+    Active_Term();
+    Encode_Term();
+#endif
+
+
+    CleanupProtoNames();
+
+#ifdef TARGET_BASED
+    SFAT_Cleanup();
+#endif
+
+    PQ_CleanUp();
+
+    ClosePidFile();
+
+    /* remove pid file */
+    if (SnortStrnlen(snort_conf->pid_filename, sizeof(snort_conf->pid_filename)) > 0)
+    {
+        int ret;
+
+        ret = unlink(snort_conf->pid_filename);
+
+        if (ret != 0)
+        {
+            ErrorMessage("Could not remove pid file %s: %s\n",
+                         snort_conf->pid_filename, strerror(errno));
+        }
+    }
+
+#ifdef INTEL_SOFT_CPM
+    //IntelPmPrintBufferStats();
+#endif
+
+    /* free allocated memory */
+    if (snort_conf == snort_cmd_line_conf)
+    {
+        SnortConfFree(snort_cmd_line_conf);
+        snort_cmd_line_conf = NULL;
+        snort_conf = NULL;
+    }
+    else
+    {
+        SnortConfFree(snort_cmd_line_conf);
+        snort_cmd_line_conf = NULL;
+        SnortConfFree(snort_conf);
+        snort_conf = NULL;
+    }
+
+#ifdef SNORT_RELOAD
+    if (snort_conf_new != NULL)
+    {
+        /* If main thread is exiting, it won't swap in the new configuration,
+         * so free it here, really just to quiet valgrind.  Note this needs to
+         * be done here since some preprocessors, will potentially need access
+         * to the data here since stream5 flushes out its cache and potentially
+         * sends reassembled packets back through Preprocess */
+        SnortConfFree(snort_conf_new);
+        snort_conf_new = NULL;
+    }
+#endif
+
+    EventTrace_Term();
+
+    detection_filter_cleanup();
+    sfthreshold_free();
+    RateFilter_Cleanup();
+    asn1_free_mem();
+    FreeOutputConfigFuncs();
+    FreePreprocConfigFuncs();
+
+    FreeRuleOptConfigFuncs(rule_opt_config_funcs);
+    rule_opt_config_funcs = NULL;
+
+    FreeRuleOptOverrideInitFuncs(rule_opt_override_init_funcs);
+    rule_opt_override_init_funcs = NULL;
+
+    FreeRuleOptByteOrderFuncs(rule_opt_byte_order_funcs);
+    rule_opt_byte_order_funcs = NULL;
+
+    FreeRuleOptParseCleanupList(rule_opt_parse_cleanup_list);
+    rule_opt_parse_cleanup_list = NULL;
+
+    FreeOutputList(AlertList);
+    AlertList = NULL;
+
+    FreeOutputList(LogList);
+    LogList = NULL;
+
+    /* Global lists */
+    FreePreprocStatsFuncs(preproc_stats_funcs);
+    preproc_stats_funcs = NULL;
+
+    FreePreprocSigFuncs(preproc_shutdown_funcs);
+    preproc_shutdown_funcs = NULL;
+
+    FreePreprocSigFuncs(preproc_clean_exit_funcs);
+    preproc_clean_exit_funcs = NULL;
+
+    FreePreprocSigFuncs(preproc_reset_funcs);
+    preproc_reset_funcs = NULL;
+
+    FreePreprocSigFuncs(preproc_reset_stats_funcs);
+    preproc_reset_stats_funcs = NULL;
+
+    FreePluginSigFuncs(plugin_shutdown_funcs);
+    plugin_shutdown_funcs = NULL;
+
+    FreePluginSigFuncs(plugin_clean_exit_funcs);
+    plugin_clean_exit_funcs = NULL;
+
+#ifdef SNORT_RELOAD
+    FreePluginPostConfigFuncs(plugin_reload_funcs);
+    plugin_reload_funcs = NULL;
+#endif
+
+    FreePeriodicFuncs(periodic_check_funcs);
+    periodic_check_funcs = NULL;
+
+    ParserCleanup();
+
+    /* Stuff from plugbase */
+    DynamicRuleListFree(dynamic_rules);
+    dynamic_rules = NULL;
+
+    CloseDynamicPreprocessorLibs();
+    CloseDynamicDetectionLibs();
+    CloseDynamicEngineLibs();
+#ifdef SIDE_CHANNEL
+    CloseDynamicSideChannelLibs();
+#endif
+    output_unload();
+
+    CleanupTag();
+    ClearDumpBuf();
+
+#ifdef PERF_PROFILING
+    CleanupPreprocStatsNodeList();
+#endif
+
+    if (netmasks != NULL)
+    {
+        free(netmasks);
+        netmasks = NULL;
+    }
+
+    if (protocol_names != NULL)
+    {
+        int i;
+
+        for (i = 0; i < NUM_IP_PROTOS; i++)
+        {
+            if (protocol_names[i] != NULL)
+                free(protocol_names[i]);
+        }
+
+        free(protocol_names);
+        protocol_names = NULL;
+    }
+
+#ifdef INTEL_SOFT_CPM
+    IntelPmStopInstance();
+#endif
+
+    SynToMulticastDstIpDestroy();
+
+    FreeVarList(cmd_line_var_list);
+
+    if (snort_conf_file != NULL)
+        free(snort_conf_file);
+
+    if (snort_conf_dir != NULL)
+        free(snort_conf_dir);
+
+    close_fileAPI();
+}
+
+static void InitGlobals(void)
+{
+    memset(&pc, 0, sizeof(pc));
+
+    InitNetmasks();
+    InitProtoNames();
+#ifdef SIDE_CHANNEL
+    pthread_mutex_init(&snort_process_lock, NULL);
+#endif
+}
+
+/****************************************************************************
+ *
+ * Function: InitNetMasks()
+ *
+ * Purpose: Loads the netmask struct in network order.  Yes, I know I could
+ *          just load the array when I define it, but this is what occurred
+ *          to me when I wrote this at 3:00 AM.
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+static void InitNetmasks(void)
+{
+    if (netmasks == NULL)
+        netmasks = (uint32_t *)SnortAlloc(33 * sizeof(uint32_t));
+
+    netmasks[0]  = 0x00000000;
+    netmasks[1]  = 0x80000000;
+    netmasks[2]  = 0xC0000000;
+    netmasks[3]  = 0xE0000000;
+    netmasks[4]  = 0xF0000000;
+    netmasks[5]  = 0xF8000000;
+    netmasks[6]  = 0xFC000000;
+    netmasks[7]  = 0xFE000000;
+    netmasks[8]  = 0xFF000000;
+    netmasks[9]  = 0xFF800000;
+    netmasks[10] = 0xFFC00000;
+    netmasks[11] = 0xFFE00000;
+    netmasks[12] = 0xFFF00000;
+    netmasks[13] = 0xFFF80000;
+    netmasks[14] = 0xFFFC0000;
+    netmasks[15] = 0xFFFE0000;
+    netmasks[16] = 0xFFFF0000;
+    netmasks[17] = 0xFFFF8000;
+    netmasks[18] = 0xFFFFC000;
+    netmasks[19] = 0xFFFFE000;
+    netmasks[20] = 0xFFFFF000;
+    netmasks[21] = 0xFFFFF800;
+    netmasks[22] = 0xFFFFFC00;
+    netmasks[23] = 0xFFFFFE00;
+    netmasks[24] = 0xFFFFFF00;
+    netmasks[25] = 0xFFFFFF80;
+    netmasks[26] = 0xFFFFFFC0;
+    netmasks[27] = 0xFFFFFFE0;
+    netmasks[28] = 0xFFFFFFF0;
+    netmasks[29] = 0xFFFFFFF8;
+    netmasks[30] = 0xFFFFFFFC;
+    netmasks[31] = 0xFFFFFFFE;
+    netmasks[32] = 0xFFFFFFFF;
+}
+
+/****************************************************************************
+ *
+ * Function: InitProtoNames()
+ *
+ * Purpose: Initializes the protocol names
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+static void InitProtoNames(void)
+{
+    int i;
+
+    if (protocol_names == NULL)
+        protocol_names = (char **)SnortAlloc(sizeof(char *) * NUM_IP_PROTOS);
+
+    for (i = 0; i < NUM_IP_PROTOS; i++)
+    {
+        struct protoent *pt = getprotobynumber(i);
+
+        if (pt != NULL)
+        {
+            size_t j;
+
+            protocol_names[i] = SnortStrdup(pt->p_name);
+            for (j = 0; j < strlen(protocol_names[i]); j++)
+                protocol_names[i][j] = toupper(protocol_names[i][j]);
+        }
+        else
+        {
+            char protoname[10];
+
+            SnortSnprintf(protoname, sizeof(protoname), "PROTO:%03d", i);
+            protocol_names[i] = SnortStrdup(protoname);
+        }
+    }
+}
+
+
+static void SetSnortConfDir(void)
+{
+    /* extract the config directory from the config filename */
+    if (snort_conf_file != NULL)
+    {
+#ifndef WIN32
+        char *path_sep = strrchr(snort_conf_file, '/');
+#else
+        char *path_sep = strrchr(snort_conf_file, '\\');
+#endif
+
+        /* is there a directory seperator in the filename */
+        if (path_sep != NULL)
+        {
+            path_sep++;  /* include path separator */
+            snort_conf_dir = SnortStrndup(snort_conf_file, path_sep - snort_conf_file);
+        }
+        else
+        {
+            snort_conf_dir = SnortStrdup("./");
+        }
+
+        DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config file = %s, config dir = "
+                    "%s\n", snort_conf_file, snort_conf_dir););
+    }
+}
+
+static void FreePlugins(SnortConfig *sc)
+{
+    if (sc == NULL)
+        return;
+
+    FreePreprocessors(sc);
+
+    FreePluginPostConfigFuncs(sc->plugin_post_config_funcs);
+    sc->plugin_post_config_funcs = NULL;
+}
+
+static void FreePreprocessors(SnortConfig *sc)
+{
+    tSfPolicyId i;
+
+    if (sc == NULL)
+        return;
+
+    FreePreprocCheckConfigFuncs(sc->preproc_config_check_funcs);
+    sc->preproc_config_check_funcs = NULL;
+
+    for (i = 0; i < sc->num_policies_allocated; i++)
+    {
+        SnortPolicy *p = sc->targeted_policies[i];
+
+        if (p == NULL)
+            continue;
+
+        FreePreprocEvalFuncs(p->preproc_eval_funcs);
+        p->preproc_eval_funcs = NULL;
+        p->num_preprocs = 0;
+
+        FreePreprocEvalFuncs(p->unused_preproc_eval_funcs);
+        p->unused_preproc_eval_funcs = NULL;
+
+        FreePreprocMetaEvalFuncs(p->preproc_meta_eval_funcs);
+        p->preproc_meta_eval_funcs = NULL;
+        p->num_meta_preprocs = 0;
+
+        FreeDetectionEvalFuncs(p->detect_eval_funcs);
+        p->detect_eval_funcs = NULL;
+        p->num_detects = 0;
+    }
+
+    FreePreprocPostConfigFuncs(sc->preproc_post_config_funcs);
+    sc->preproc_post_config_funcs = NULL;
+}
+
+static SnortConfig * MergeSnortConfs(SnortConfig *cmd_line, SnortConfig *config_file)
+{
+    unsigned int i;
+
+    /* Move everything from the command line config over to the
+     * config_file config */
+
+    if (cmd_line == NULL)
+    {
+        FatalError("%s(%d) Merging snort configs: snort conf is NULL.\n",
+                   __FILE__, __LINE__);
+    }
+
+    ResolveOutputPlugins(cmd_line, config_file);
+
+    if (config_file == NULL)
+    {
+        if (cmd_line->log_dir == NULL)
+            cmd_line->log_dir = SnortStrdup(DEFAULT_LOG_DIR);
+    }
+    else if ((cmd_line->log_dir == NULL) && (config_file->log_dir == NULL))
+    {
+        config_file->log_dir = SnortStrdup(DEFAULT_LOG_DIR);
+    }
+    else if (cmd_line->log_dir != NULL)
+    {
+        if (config_file->log_dir != NULL)
+            free(config_file->log_dir);
+
+        config_file->log_dir = SnortStrdup(cmd_line->log_dir);
+    }
+
+    if (config_file == NULL)
+        return cmd_line;
+
+    /* Used because of a potential chroot */
+    config_file->orig_log_dir = SnortStrdup(config_file->log_dir);
+
+    config_file->run_mode = cmd_line->run_mode;
+    config_file->run_mode_flags |= cmd_line->run_mode_flags;
+
+    if ((cmd_line->run_mode == RUN_MODE__TEST) &&
+        (config_file->run_flags & RUN_FLAG__DAEMON))
+    {
+        /* Just ignore deamon setting in conf file */
+        config_file->run_flags &= ~RUN_FLAG__DAEMON;
+    }
+
+    config_file->run_flags |= cmd_line->run_flags;
+    config_file->output_flags |= cmd_line->output_flags;
+    config_file->logging_flags |= cmd_line->logging_flags;
+
+    /* Merge checksum flags.  If command line modified them, use from the
+     * command line, else just use from config_file. */
+    for (i = 0; i < config_file->num_policies_allocated; i++)
+    {
+        if (config_file->targeted_policies[i] != NULL)
+        {
+            if (cmd_line->checksum_flags_modified)
+                config_file->targeted_policies[i]->checksum_flags = cmd_line->checksum_flags;
+
+            if (cmd_line->checksum_drop_flags_modified)
+                config_file->targeted_policies[i]->checksum_drop_flags = cmd_line->checksum_drop_flags;
+        }
+    }
+
+    config_file->event_log_id = cmd_line->event_log_id;
+
+    if (cmd_line->dynamic_rules_path != NULL)
+    {
+        if(strcmp(cmd_line->dynamic_rules_path, "")  != 0)
+        {
+            if( config_file->dynamic_rules_path != NULL )
+                free(config_file->dynamic_rules_path);
+            config_file->dynamic_rules_path = SnortStrdup(cmd_line->dynamic_rules_path);
+        }
+    }
+
+    if (cmd_line->dyn_engines != NULL)
+    {
+        FreeDynamicLibInfo(config_file->dyn_engines);
+        config_file->dyn_engines = DupDynamicLibInfo(cmd_line->dyn_engines);
+    }
+
+    if (cmd_line->dyn_rules != NULL)
+    {
+        FreeDynamicLibInfo(config_file->dyn_rules);
+        config_file->dyn_rules = DupDynamicLibInfo(cmd_line->dyn_rules);
+    }
+
+    if (cmd_line->dyn_preprocs != NULL)
+    {
+        FreeDynamicLibInfo(config_file->dyn_preprocs);
+        config_file->dyn_preprocs = DupDynamicLibInfo(cmd_line->dyn_preprocs);
+    }
+
+    if (cmd_line->pid_path[0] != '\0')
+        ConfigPidPath(config_file, cmd_line->pid_path);
+
+    config_file->exit_check = cmd_line->exit_check;
+
+    /* Command line only configures search method */
+    if (cmd_line->fast_pattern_config != NULL)
+        config_file->fast_pattern_config->search_method = cmd_line->fast_pattern_config->search_method;
+
+    if (cmd_line->obfuscation_net.family != 0)
+        memcpy(&config_file->obfuscation_net, &cmd_line->obfuscation_net, sizeof(sfip_t));
+
+    if (cmd_line->homenet.family != 0)
+        memcpy(&config_file->homenet, &cmd_line->homenet, sizeof(sfip_t));
+
+    if (cmd_line->interface != NULL)
+    {
+        if (config_file->interface != NULL)
+            free(config_file->interface);
+        config_file->interface = SnortStrdup(cmd_line->interface);
+    }
+
+    if (cmd_line->bpf_file != NULL)
+    {
+        if (config_file->bpf_file != NULL)
+            free(config_file->bpf_file);
+        config_file->bpf_file = SnortStrdup(cmd_line->bpf_file);
+    }
+
+    if (cmd_line->bpf_filter != NULL)
+        config_file->bpf_filter = SnortStrdup(cmd_line->bpf_filter);
+
+    if (cmd_line->pkt_snaplen != -1)
+        config_file->pkt_snaplen = cmd_line->pkt_snaplen;
+
+    if (cmd_line->pkt_cnt != 0)
+        config_file->pkt_cnt = cmd_line->pkt_cnt;
+
+#ifdef REG_TEST
+    if (cmd_line->pkt_skip != 0)
+        config_file->pkt_skip = cmd_line->pkt_skip;
+#endif
+
+    if (cmd_line->group_id != -1)
+        config_file->group_id = cmd_line->group_id;
+
+    if (cmd_line->user_id != -1)
+        config_file->user_id = cmd_line->user_id;
+
+    /* Only configurable on command line */
+    if (cmd_line->pcap_log_file != NULL)
+        config_file->pcap_log_file = SnortStrdup(cmd_line->pcap_log_file);
+
+    if (cmd_line->file_mask != 0)
+        config_file->file_mask = cmd_line->file_mask;
+
+    if (cmd_line->pidfile_suffix[0] != '\0')
+    {
+        SnortStrncpy(config_file->pidfile_suffix, cmd_line->pidfile_suffix,
+                     sizeof(config_file->pidfile_suffix));
+    }
+
+    if (cmd_line->chroot_dir != NULL)
+    {
+        if (config_file->chroot_dir != NULL)
+            free(config_file->chroot_dir);
+        config_file->chroot_dir = SnortStrdup(cmd_line->chroot_dir);
+    }
+
+    if (cmd_line->perf_file != NULL)
+    {
+        if (config_file->perf_file != NULL)
+            free(config_file->perf_file);
+        config_file->perf_file = SnortStrdup(cmd_line->perf_file);
+    }
+
+    if ( cmd_line->daq_type )
+        config_file->daq_type = SnortStrdup(cmd_line->daq_type);
+
+    if ( cmd_line->daq_mode )
+        config_file->daq_mode = SnortStrdup(cmd_line->daq_mode);
+
+    if ( cmd_line->dirty_pig )
+        config_file->dirty_pig = cmd_line->dirty_pig;
+
+    if ( cmd_line->daq_vars )
+    {
+        /* Command line overwrites daq_vars */
+        if (config_file->daq_vars)
+            StringVector_Delete(config_file->daq_vars);
+
+        config_file->daq_vars = StringVector_New();
+        StringVector_AddVector(config_file->daq_vars, cmd_line->daq_vars);
+    }
+    if ( cmd_line->daq_dirs )
+    {
+        /* Command line overwrites daq_dirs */
+        if (config_file->daq_dirs)
+            StringVector_Delete(config_file->daq_dirs);
+
+        config_file->daq_dirs = StringVector_New();
+        StringVector_AddVector(config_file->daq_dirs, cmd_line->daq_dirs);
+    }
+#ifdef MPLS
+    if (cmd_line->mpls_stack_depth != DEFAULT_LABELCHAIN_LENGTH)
+        config_file->mpls_stack_depth = cmd_line->mpls_stack_depth;
+
+    /* Set MPLS payload type here if it hasn't been defined */
+    if ((cmd_line->mpls_payload_type == 0) &&
+        (config_file->mpls_payload_type == 0))
+    {
+        config_file->mpls_payload_type = DEFAULT_MPLS_PAYLOADTYPE;
+    }
+    else if (cmd_line->mpls_payload_type != 0)
+    {
+        config_file->mpls_payload_type = cmd_line->mpls_payload_type;
+    }
+#endif
+
+    if (cmd_line->run_flags & RUN_FLAG__PROCESS_ALL_EVENTS)
+        config_file->event_queue_config->process_all_events = 1;
+
+    if (cmd_line->cs_dir != NULL)
+    {
+        if (config_file->cs_dir != NULL)
+            free(config_file->cs_dir);
+        config_file->cs_dir = SnortStrdup(cmd_line->cs_dir);
+    }
+    if (config_file->cs_dir)
+    {
+
+#ifndef WIN32
+        /*
+         *  If an absolute path is specified, then use that.
+         *  otherwise, relative to pid path
+         */
+        if ((config_file->cs_dir[0] != '/') && config_file->pid_path[0])
+        {
+
+            char fullpath[PATH_MAX];
+
+            if (config_file->pid_path[strlen(config_file->pid_path) - 1] == '/')
+            {
+                SnortSnprintf(fullpath, sizeof(fullpath),
+                        "%s%s", config_file->pid_path, config_file->cs_dir);
+            }
+            else
+            {
+                SnortSnprintf(fullpath, sizeof(fullpath),
+                        "%s/%s", config_file->pid_path, config_file->cs_dir);
+            }
+            free (config_file->cs_dir);
+            config_file->cs_dir = SnortStrdup(fullpath);
+
+        }
+#else
+        /*Not supported in WINDOWS*/
+        free (config_file->cs_dir);
+        config_file->cs_dir = NULL;
+#endif
+        ControlSocketConfigureDirectory(config_file->cs_dir);
+    }
+
+#ifdef REG_TEST
+    config_file->ha_peer = cmd_line->ha_peer;
+
+    if ( cmd_line->ha_out )
+    {
+        if(config_file->ha_out != NULL)
+            free(config_file->ha_out);
+        config_file->ha_out = strdup(cmd_line->ha_out);
+    }
+
+    if ( cmd_line->ha_in )
+    {
+        if(config_file->ha_in != NULL)
+            free(config_file->ha_in);
+        config_file->ha_in = strdup(cmd_line->ha_in);
+    }
+#endif
+
+    return config_file;
+}
+
+static void FreeDynamicLibInfos(SnortConfig *sc)
+{
+    if (sc == NULL)
+        return;
+
+    if (sc->dyn_engines != NULL)
+    {
+        FreeDynamicLibInfo(sc->dyn_engines);
+        sc->dyn_engines = NULL;
+    }
+
+    if (sc->dyn_rules != NULL)
+    {
+        FreeDynamicLibInfo(sc->dyn_rules);
+        sc->dyn_rules = NULL;
+    }
+
+    if (sc->dyn_preprocs != NULL)
+    {
+        FreeDynamicLibInfo(sc->dyn_preprocs);
+        sc->dyn_preprocs = NULL;
+    }
+
+#ifdef SIDE_CHANNEL
+    if (sc->dyn_side_channels != NULL)
+    {
+        FreeDynamicLibInfo(sc->dyn_side_channels);
+        sc->dyn_side_channels = NULL;
+    }
+#endif
+}
+
+static void FreeDynamicLibInfo(DynamicLibInfo *lib_info)
+{
+    unsigned i;
+
+    if (lib_info == NULL)
+        return;
+
+    for (i = 0; i < lib_info->count; i++)
+    {
+        free(lib_info->lib_paths[i]->path);
+        free(lib_info->lib_paths[i]);
+    }
+
+    free(lib_info);
+}
+
+static DynamicLibInfo * DupDynamicLibInfo(DynamicLibInfo *src)
+{
+    DynamicLibInfo *dst;
+    unsigned i;
+
+    if (src == NULL)
+        return NULL;
+
+    dst = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
+    dst->type = src->type;
+    dst->count = src->count;
+
+    for (i = 0; i < src->count; i++)
+    {
+        DynamicLibPath *dylib_path = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath));
+
+        dylib_path->ptype = src->lib_paths[i]->ptype;
+        dylib_path->path = SnortStrdup(src->lib_paths[i]->path);
+
+        dst->lib_paths[i] = dylib_path;
+    }
+
+    return dst;
+}
+
+#if defined(INLINE_FAILOPEN) && !defined(WIN32)
+static void * SnortPostInitThread(void *data)
+{
+    sigset_t mtmask;
+
+    inline_failopen_thread_pid = gettid();
+    inline_failopen_thread_running = 1;
+
+    /* Don't handle any signals here */
+    sigfillset(&mtmask);
+    pthread_sigmask(SIG_BLOCK, &mtmask, NULL);
+
+    while (!inline_failopen_initialized)
+        nanosleep(&thread_sleep, NULL);
+
+    SnortUnprivilegedInit();
+
+    pthread_exit((void *)NULL);
+}
+
+static DAQ_Verdict IgnoreCallback (
+    void *user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
+{
+    /* Empty function -- do nothing with the packet we just read */
+    inline_failopen_pass_pkt_cnt++;
+
+#ifdef DEBUG
+    {
+        FILE *tmp = fopen("/var/tmp/fo_threadid", "a");
+        if ( tmp )
+        {
+            fprintf(tmp, "Packet Count %d\n", inline_failopen_pass_pkt_cnt);
+            fclose(tmp);
+        }
+    }
+#endif
+    return DAQ_VERDICT_PASS;
+}
+#endif /* defined(INLINE_FAILOPEN) && !defined(WIN32) */
+
+
+#if defined(NOCOREFILE) && !defined(WIN32)
+static void SetNoCores(void)
+{
+    struct rlimit rlim;
+
+    getrlimit(RLIMIT_CORE, &rlim);
+    rlim.rlim_max = 0;
+    setrlimit(RLIMIT_CORE, &rlim);
+}
+#endif
+
+static void InitSignals(void)
+{
+
+#ifndef WIN32
+# if defined(LINUX) || defined(FREEBSD) || defined(OPENBSD) || \
+     defined(SOLARIS) || defined(BSD) || defined(MACOS)
+    sigset_t set;
+
+    sigemptyset(&set);
+#  if defined(INLINE_FAILOPEN) || \
+      defined(TARGET_BASED) || defined(SNORT_RELOAD)
+    pthread_sigmask(SIG_SETMASK, &set, NULL);
+#  else
+    sigprocmask(SIG_SETMASK, &set, NULL);
+#  endif /* INLINE_FAILOPEN */
+# else
+    sigsetmask(0);
+# endif /* LINUX, BSD, SOLARIS */
+#endif  /* !WIN32 */
+
+    /* Make this prog behave nicely when signals come along.
+     * Windows doesn't like all of these signals, and will
+     * set errno for some.  Ignore/reset this error so it
+     * doesn't interfere with later checks of errno value.  */
+    signal_error_msg[0] = '\0';
+    SnortAddSignal(SIGTERM, SigExitHandler, 1);
+    SnortAddSignal(SIGINT, SigExitHandler, 1);
+#ifndef WIN32
+    SnortAddSignal(SIGQUIT, SigExitHandler, 1);
+    SnortAddSignal(SIGNAL_SNORT_DUMP_STATS, SigDumpStatsHandler, 1);
+    SnortAddSignal(SIGNAL_SNORT_RELOAD, SigReloadHandler, 1);
+    SnortAddSignal(SIGNAL_SNORT_ROTATE_STATS, SigRotateStatsHandler, 1);
+#endif
+
+#ifdef CONTROL_SOCKET
+    SnortAddSignal(SIGPIPE, SigPipeHandler, 1);
+#endif
+
+#ifdef TARGET_BASED
+#ifndef WIN32
+    /* Used to print warning if attribute table is not configured
+     * When it is, it will set new signal handler */
+    SnortAddSignal(SIGNAL_SNORT_READ_ATTR_TBL, SigNoAttributeTableHandler, 1);
+#endif
+#endif
+
+    SnortAddSignal(SIGABRT, SigOopsHandler, 1);
+    SnortAddSignal(SIGSEGV, SigOopsHandler, 1);
+#ifndef WIN32
+    SnortAddSignal(SIGBUS, SigOopsHandler, 1);
+#endif
+
+    errno = 0;
+}
+
+static void FreeOutputConfigs(OutputConfig *head)
+{
+    while (head != NULL)
+    {
+        OutputConfig *tmp = head;
+
+        head = head->next;
+
+        if (tmp->keyword != NULL)
+            free(tmp->keyword);
+
+        if (tmp->opts != NULL)
+            free(tmp->opts);
+
+        if (tmp->file_name != NULL)
+            free(tmp->file_name);
+
+        /* Don't free listhead as it's just a pointer to the user defined
+         * rule's rule list node's list head */
+
+        free(tmp);
+    }
+}
+
+#ifdef SIDE_CHANNEL
+static void FreeSideChannelModuleConfigs(SideChannelModuleConfig *head)
+{
+    while (head != NULL)
+    {
+        SideChannelModuleConfig *tmp = head;
+
+        head = head->next;
+
+        if (tmp->keyword != NULL)
+            free(tmp->keyword);
+
+        if (tmp->opts != NULL)
+            free(tmp->opts);
+
+        if (tmp->file_name != NULL)
+            free(tmp->file_name);
+
+        free(tmp);
+    }
+}
+#endif
+
+static void FreePreprocConfigs(SnortConfig *sc)
+{
+    tSfPolicyId i;
+
+    if (sc == NULL)
+        return;
+
+    for (i = 0; i < sc->num_policies_allocated; i++)
+    {
+        SnortPolicy *p = sc->targeted_policies[i];
+        PreprocConfig *head;
+
+        if (p == NULL)
+            continue;
+
+        head = p->preproc_configs;
+
+        while (head != NULL)
+        {
+            PreprocConfig *tmp = head;
+
+            head = head->next;
+
+            if (tmp->keyword != NULL)
+                free(tmp->keyword);
+
+            if (tmp->opts != NULL)
+                free(tmp->opts);
+
+            if (tmp->file_name != NULL)
+                free(tmp->file_name);
+
+            free(tmp);
+        }
+    }
+}
+
+static void FreeRuleStateList(RuleState *head)
+{
+    while (head != NULL)
+    {
+        RuleState *tmp = head;
+
+        head = head->next;
+
+        free(tmp);
+    }
+}
+
+static void FreeClassifications(ClassType *head)
+{
+    while (head != NULL)
+    {
+        ClassType *tmp = head;
+
+        head = head->next;
+
+        if (tmp->name != NULL)
+            free(tmp->name);
+
+        if (tmp->type != NULL)
+            free(tmp->type);
+
+        free(tmp);
+    }
+}
+
+static void FreeReferences(ReferenceSystemNode *head)
+{
+    while (head != NULL)
+    {
+        ReferenceSystemNode *tmp = head;
+
+        head = head->next;
+
+        if (tmp->name != NULL)
+            free(tmp->name);
+
+        if (tmp->url != NULL)
+            free(tmp->url);
+
+        free(tmp);
+    }
+}
+
+#if defined(SNORT_RELOAD) && !defined(WIN32)
+static void updatePeriodicCheck()
+{
+    PeriodicCheckFuncNode *checkFunc;
+
+    /* reset preprocessors */
+    checkFunc = periodic_check_funcs;
+    while (checkFunc != NULL)
+    {
+        if ( 0 == checkFunc->time_left )
+        {
+            checkFunc->func(-1, checkFunc->arg);
+            checkFunc->time_left = checkFunc->period;
+            //LogMessage("        --== Share Memory! ==--\n");
+        }
+        else
+            checkFunc->time_left--;
+
+        checkFunc = checkFunc->next;
+    }
+
+}
+
+static void * ReloadConfigThread(void *data)
+{
+    sigset_t mtmask;
+
+    /* Don't handle any signals here */
+    sigfillset(&mtmask);
+    pthread_sigmask(SIG_BLOCK, &mtmask, NULL);
+
+    snort_reload_thread_pid = gettid();
+    snort_reload_thread_created = 1;
+
+    while (snort_initializing)
+        nanosleep(&thread_sleep, NULL);
+
+    while (!snort_exiting)
+    {
+        if (reload_signal != reload_total)
+        {
+            int reload_failed = 0;
+
+#ifdef CONTROL_SOCKET
+            pthread_mutex_lock(&reload_mutex);
+            if (!reloadInProgress)
+            {
+                reloadInProgress = 1;
+                pthread_mutex_unlock(&reload_mutex);
+#endif
+                reload_total++;
+
+                LogMessage("\n");
+                LogMessage("        --== Reloading Snort ==--\n");
+                LogMessage("\n");
+
+                snort_conf_new = ReloadConfig();
+                if (snort_conf_new == NULL)
+                    reload_failed = 1;
+                snort_reload = 1;
+
+                while (!snort_swapped && !snort_exiting)
+                    nanosleep(&thread_sleep, NULL);
+
+                snort_swapped = 0;
+
+                SnortConfFree(snort_conf_old);
+                snort_conf_old = NULL;
+
+#ifdef INTEL_SOFT_CPM
+                if (snort_conf->fast_pattern_config->search_method != MPSE_INTEL_CPM)
+                    IntelPmStopInstance();
+#endif
+
+                if (snort_exiting && !reload_failed)
+                {
+                    /* This will load the new preprocessor configurations and
+                     * free the old ones, so any preprocessor cleanup that
+                     * requires a configuration will be using the new one
+                     * unless it relies on old configurations that are still
+                     * attached to existing sessions. */
+                    SwapPreprocConfigurations(snort_conf);
+                    FreeSwappedPreprocConfigurations(snort_conf);
+
+#ifdef CONTROL_SOCKET
+                    reloadInProgress = 0;
+#endif
+                    /* Get out of the loop and exit */
+                    break;
+                }
+
+                if (!reload_failed)
+                {
+                    LogMessage("\n");
+                    LogMessage("        --== Reload Complete ==--\n");
+                    LogMessage("\n");
+                }
+#ifdef CONTROL_SOCKET
+                reloadInProgress = 0;
+            }
+            else
+                pthread_mutex_unlock(&reload_mutex);
+#endif
+        }
+        /* Use the maintenance thread for periodic check*/
+        updatePeriodicCheck();
+
+        sleep(1);
+    }
+
+    pthread_exit((void *)0);
+}
+
+static SnortConfig * ReloadConfig(void)
+{
+    SnortConfig *sc;
+
+#ifdef HAVE_MALLOC_TRIM
+    malloc_trim(0);
+#endif
+
+    sc = ParseSnortConf();
+
+    sc = MergeSnortConfs(snort_cmd_line_conf, sc);
+
+    sc->reloadPolicyFlag = 1;
+
+#ifdef PERF_PROFILING
+    /* Parse profiling here because of file option and potential
+     * dependence on log directory */
+    {
+        char *opts = NULL;
+        int in_table;
+
+        in_table = sfghash_find2(sc->config_table,
+                                 CONFIG_OPT__PROFILE_PREPROCS, (void *)&opts);
+        if (in_table)
+            ConfigProfilePreprocs(sc, opts);
+
+        in_table = sfghash_find2(sc->config_table,
+                                 CONFIG_OPT__PROFILE_RULES, (void *)&opts);
+        if (in_table)
+            ConfigProfileRules(sc, opts);
+    }
+#endif
+
+    if (VerifyReload(sc) == -1)
+    {
+        SnortConfFree(sc);
+        return NULL;
+    }
+
+    if (sc->output_flags & OUTPUT_FLAG__USE_UTC)
+        sc->thiszone = 0;
+    else
+        sc->thiszone = gmt2local(0);
+
+    /* Preprocessors will have a reload callback */
+    ConfigurePreprocessors(sc, 1);
+
+    FlowbitResetCounts();
+    ParseRules(sc);
+    RuleOptParseCleanup();
+
+    ReloadDynamicRules(sc);
+
+    /* Handles Fatal Errors itself. */
+    SnortEventqNew(sc->event_queue_config, sc->event_queue);
+
+    detection_filter_print_config(sc->detection_filter_config);
+    RateFilter_PrintConfig(sc->rate_filter_config);
+    print_thresholding(sc->threshold_config, 0);
+    PrintRuleOrder(sc->rule_lists);
+
+    SetRuleStates(sc);
+
+    if (file_sevice_config_verify(snort_conf, sc) == -1)
+    {
+        SnortConfFree(sc);
+        return NULL;
+    }
+
+    if (VerifyReloadedPreprocessors(sc) == -1)
+    {
+        SnortConfFree(sc);
+        return NULL;
+    }
+
+    if (CheckPreprocessorsConfig(sc))
+    {
+        SnortConfFree(sc);
+        return NULL;
+    }
+
+    FilterConfigPreprocessors(sc);
+    PostConfigPreprocessors(sc);
+
+    /* Need to do this after dynamic detection stuff is initialized, too */
+    FlowBitsVerify();
+
+    if ((sc->file_mask != 0) && (sc->file_mask != snort_conf->file_mask))
+        umask(sc->file_mask);
+
+    /* Transfer any user defined rule type outputs to the new rule list */
+    {
+        RuleListNode *cur = snort_conf->rule_lists;
+
+        for (; cur != NULL; cur = cur->next)
+        {
+            RuleListNode *new = sc->rule_lists;
+
+            for (; new != NULL; new = new->next)
+            {
+                if (strcasecmp(cur->name, new->name) == 0)
+                {
+                    OutputFuncNode *alert_list = cur->RuleList->AlertList;
+                    OutputFuncNode *log_list = cur->RuleList->LogList;
+
+                    sc->head_tmp = new->RuleList;
+
+                    for (; alert_list != NULL; alert_list = alert_list->next)
+                    {
+                        AddFuncToOutputList(sc, alert_list->func,
+                                            OUTPUT_TYPE__ALERT, alert_list->arg);
+                    }
+
+                    for (; log_list != NULL; log_list = log_list->next)
+                    {
+                        AddFuncToOutputList(sc, log_list->func,
+                                            OUTPUT_TYPE__LOG, log_list->arg);
+                    }
+
+                    sc->head_tmp = NULL;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* XXX XXX Can't do any output plugins */
+    //PostConfigInitPlugins(sc->plugin_post_config_funcs);
+
+    fpCreateFastPacketDetection(sc);
+
+#ifdef PPM_MGR
+    PPM_PRINT_CFG(&sc->ppm_cfg);
+#endif
+
+    return sc;
+}
+
+static int VerifyReload(SnortConfig *sc)
+{
+    if (sc == NULL)
+        return -1;
+
+#ifdef TARGET_BASED
+    {
+        SnortPolicy *p1 = sc->targeted_policies[getDefaultPolicy()];
+        SnortPolicy *p2 = snort_conf->targeted_policies[getDefaultPolicy()];
+
+        if ((p1->target_based_config.args != NULL) &&
+            (p2->target_based_config.args != NULL))
+        {
+            if (strcasecmp(p1->target_based_config.args,
+                           p2->target_based_config.args) != 0)
+            {
+                ErrorMessage("Snort Reload: Changing the attribute table "
+                             "configuration requires a restart.\n");
+                return -1;
+            }
+        }
+        else if (p1->target_based_config.args !=
+                 p2->target_based_config.args)
+        {
+            /* Covers one being NULL and not the other */
+            ErrorMessage("Snort Reload: Changing the attribute table "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+#endif
+
+    if ((snort_conf->alert_file != NULL) && (sc->alert_file != NULL))
+    {
+        if (strcasecmp(snort_conf->alert_file, sc->alert_file) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the alert file "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->alert_file != sc->alert_file)
+    {
+        ErrorMessage("Snort Reload: Changing the alert file "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->asn1_mem != sc->asn1_mem)
+    {
+        ErrorMessage("Snort Reload: Changing the asn1 memory configuration "
+                     "requires a restart.\n");
+        return -1;
+    }
+
+    if ((sc->bpf_filter == NULL) && (sc->bpf_file != NULL))
+        sc->bpf_filter = read_infile(sc->bpf_file);
+
+    if ((sc->bpf_filter != NULL) && (snort_conf->bpf_filter != NULL))
+    {
+        if (strcasecmp(snort_conf->bpf_filter, sc->bpf_filter) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the bpf filter configuration "
+                         "requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (sc->bpf_filter != snort_conf->bpf_filter)
+    {
+        ErrorMessage("Snort Reload: Changing the bpf filter configuration "
+                     "requires a restart.\n");
+        return -1;
+    }
+
+#ifdef ACTIVE_RESPONSE
+    if ( sc->respond_attempts != snort_conf->respond_attempts ||
+         sc->respond_device != snort_conf->respond_device )
+    {
+        ErrorMessage("Snort Reload: Changing config response "
+                     "requires a restart.\n");
+        return -1;
+    }
+#endif
+
+    if ((snort_conf->chroot_dir != NULL) &&
+        (sc->chroot_dir != NULL))
+    {
+        if (strcasecmp(snort_conf->chroot_dir, sc->chroot_dir) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the chroot directory "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->chroot_dir != sc->chroot_dir)
+    {
+        ErrorMessage("Snort Reload: Changing the chroot directory "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->run_flags & RUN_FLAG__DAEMON) !=
+        (sc->run_flags & RUN_FLAG__DAEMON))
+    {
+        ErrorMessage("Snort Reload: Changing to or from daemon mode "
+                     "requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->interface != NULL) && (sc->interface != NULL))
+    {
+        if (strcasecmp(snort_conf->interface, sc->interface) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the interface "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->interface != sc->interface)
+    {
+        ErrorMessage("Snort Reload: Changing the interface "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    /* Orig log dir because a chroot might have changed it */
+    if ((snort_conf->orig_log_dir != NULL) &&
+        (sc->orig_log_dir != NULL))
+    {
+        if (strcasecmp(snort_conf->orig_log_dir, sc->orig_log_dir) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the log directory "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->orig_log_dir != sc->orig_log_dir)
+    {
+        ErrorMessage("Snort Reload: Changing the log directory "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+#ifdef TARGET_BASED
+    if (snort_conf->max_attribute_hosts != sc->max_attribute_hosts)
+    {
+        ErrorMessage("Snort Reload: Changing max_attribute_hosts "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+    if (snort_conf->max_attribute_services_per_host != sc->max_attribute_services_per_host)
+    {
+        ErrorMessage("Snort Reload: Changing max_attribute_services_per_host "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+#endif
+
+    if (snort_conf->no_log != sc->no_log)
+    {
+        ErrorMessage("Snort Reload: Changing from log to no log or vice "
+                     "versa requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->run_flags & RUN_FLAG__NO_PROMISCUOUS) !=
+        (sc->run_flags & RUN_FLAG__NO_PROMISCUOUS))
+    {
+        ErrorMessage("Snort Reload: Changing to or from promiscuous mode "
+                     "requires a restart.\n");
+        return -1;
+    }
+
+#ifdef PPM_MGR
+    /* XXX XXX Not really sure we need to disallow this */
+    if (snort_conf->ppm_cfg.rule_log != sc->ppm_cfg.rule_log)
+    {
+        ErrorMessage("Snort Reload: Changing the ppm rule_log "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+#endif
+
+#ifdef PERF_PROFILING
+    if ((snort_conf->profile_rules.num != sc->profile_rules.num) ||
+        (snort_conf->profile_rules.sort != sc->profile_rules.sort) ||
+        (snort_conf->profile_rules.append != sc->profile_rules.append))
+    {
+        ErrorMessage("Snort Reload: Changing rule profiling number, sort "
+                     "or append configuration requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->profile_rules.filename != NULL) &&
+        (sc->profile_rules.filename != NULL))
+    {
+        if (strcasecmp(snort_conf->profile_rules.filename,
+                       sc->profile_rules.filename) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the rule profiling filename "
+                         "configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->profile_rules.filename !=
+             sc->profile_rules.filename)
+    {
+        ErrorMessage("Snort Reload: Changing the rule profiling filename "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->profile_preprocs.num !=  sc->profile_preprocs.num) ||
+        (snort_conf->profile_preprocs.sort != sc->profile_preprocs.sort) ||
+        (snort_conf->profile_preprocs.append != sc->profile_preprocs.append))
+    {
+        ErrorMessage("Snort Reload: Changing preprocessor profiling number, "
+                     "sort or append configuration requires a restart.\n");
+        return -1;
+    }
+
+    if ((snort_conf->profile_preprocs.filename != NULL) &&
+        (sc->profile_preprocs.filename != NULL))
+    {
+        if (strcasecmp(snort_conf->profile_preprocs.filename,
+                       sc->profile_preprocs.filename) != 0)
+        {
+            ErrorMessage("Snort Reload: Changing the preprocessor profiling "
+                         "filename configuration requires a restart.\n");
+            return -1;
+        }
+    }
+    else if (snort_conf->profile_preprocs.filename !=
+             sc->profile_preprocs.filename)
+    {
+        ErrorMessage("Snort Reload: Changing the preprocessor profiling "
+                     "filename configuration requires a restart.\n");
+        return -1;
+    }
+#endif
+
+    if (snort_conf->group_id != sc->group_id)
+    {
+        ErrorMessage("Snort Reload: Changing the group id "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->user_id != sc->user_id)
+    {
+        ErrorMessage("Snort Reload: Changing the user id "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->pkt_snaplen != sc->pkt_snaplen)
+    {
+        ErrorMessage("Snort Reload: Changing the packet snaplen "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->threshold_config->memcap !=
+        sc->threshold_config->memcap)
+    {
+        ErrorMessage("Snort Reload: Changing the threshold memcap "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->rate_filter_config->memcap !=
+        sc->rate_filter_config->memcap)
+    {
+        ErrorMessage("Snort Reload: Changing the rate filter memcap "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->detection_filter_config->memcap !=
+        sc->detection_filter_config->memcap)
+    {
+        ErrorMessage("Snort Reload: Changing the detection filter memcap "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (VerifyLibInfos(snort_conf->dyn_engines, sc->dyn_engines) == -1)
+    {
+        ErrorMessage("Snort Reload: Any change to the dynamic engine "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (VerifyLibInfos(snort_conf->dyn_rules, sc->dyn_rules) == -1)
+    {
+        ErrorMessage("Snort Reload: Any change to the dynamic detection "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (VerifyLibInfos(snort_conf->dyn_preprocs, sc->dyn_preprocs) == -1)
+    {
+        ErrorMessage("Snort Reload: Any change to the dynamic preprocessor "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (snort_conf->so_rule_memcap != sc->so_rule_memcap)
+    {
+        ErrorMessage("Snort Reload: Changing the so rule memcap "
+                     "configuration requires a restart.\n");
+        return -1;
+    }
+
+    if (VerifyOutputs(snort_conf, sc) == -1)
+        return -1;
+
+#ifdef SIDE_CHANNEL
+    if (SideChannelVerifyConfig(sc) != 0)
+    {
+        ErrorMessage("Snort Reload: Changing the side channel configuration requires a restart.\n");
+        return -1;
+    }
+#endif
+
+    return 0;
+}
+
+static int VerifyOutputs(SnortConfig *old_config, SnortConfig *new_config)
+{
+    OutputConfig *old_output_config, *new_output_config;
+    int old_outputs = 0, new_outputs = 0;
+
+    /* Get from output_configs to see if output has changed */
+    for (old_output_config = old_config->output_configs;
+         old_output_config != NULL;
+         old_output_config = old_output_config->next)
+    {
+        old_outputs++;
+    }
+
+    for (new_output_config = new_config->output_configs;
+         new_output_config != NULL;
+         new_output_config = new_output_config->next)
+    {
+        new_outputs++;
+    }
+
+    if (new_outputs != old_outputs)
+    {
+        ErrorMessage("Snort Reload: Any change to any output "
+                     "configurations requires a restart.\n");
+        return -1;
+    }
+
+    for (old_output_config = old_config->output_configs;
+         old_output_config != NULL;
+         old_output_config = old_output_config->next)
+    {
+
+        for (new_output_config = new_config->output_configs;
+                new_output_config != NULL;
+                new_output_config = new_output_config->next)
+        {
+            if (strcasecmp(old_output_config->keyword, new_output_config->keyword) == 0)
+            {
+                if ((old_output_config->opts != NULL) &&
+                        (new_output_config->opts != NULL) &&
+                        (strcasecmp(old_output_config->opts, new_output_config->opts) == 0))
+                {
+                    new_outputs++;
+                    break;
+                }
+                else if (old_output_config->opts == NULL &&
+                        new_output_config->opts == NULL)
+                {
+                    new_outputs++;
+                    break;
+                }
+            }
+
+        }
+
+        old_outputs++;
+    }
+
+    if (new_outputs != old_outputs)
+    {
+        ErrorMessage("Snort Reload: Any change to any output "
+                     "configurations requires a restart.\n");
+        return -1;
+    }
+
+    /* Check user defined rule type outputs */
+    for (old_output_config = old_config->rule_type_output_configs;
+         old_output_config != NULL;
+         old_output_config = old_output_config->next)
+    {
+        old_outputs++;
+    }
+
+    for (new_output_config = new_config->rule_type_output_configs;
+         new_output_config != NULL;
+         new_output_config = new_output_config->next)
+    {
+        new_outputs++;
+    }
+
+    if (new_outputs != old_outputs)
+    {
+        ErrorMessage("Snort Reload: Any change to any output "
+                     "configurations requires a restart.\n");
+        return -1;
+    }
+
+    /* Do user defined rule type outputs as well */
+    for (old_output_config = old_config->rule_type_output_configs;
+         old_output_config != NULL;
+         old_output_config = old_output_config->next)
+    {
+        for (new_output_config = new_config->rule_type_output_configs;
+             new_output_config != NULL;
+             new_output_config = new_output_config->next)
+        {
+            if (strcasecmp(old_output_config->keyword,
+                           new_output_config->keyword) == 0)
+            {
+                if (strcasecmp(old_output_config->opts,
+                               new_output_config->opts) == 0)
+                {
+                    new_outputs++;
+                    break;
+                }
+            }
+        }
+
+        old_outputs++;
+    }
+
+    if (new_outputs != old_outputs)
+    {
+        ErrorMessage("Snort Reload: Any change to any output "
+                     "configurations requires a restart.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int VerifyLibInfos(DynamicLibInfo *old_info, DynamicLibInfo *new_info)
+{
+    if ((old_info != NULL) && (new_info != NULL))
+    {
+        unsigned i;
+
+        if (old_info->type != new_info->type)
+        {
+            FatalError("%s(%d) Incompatible library types.\n",
+                       __FILE__, __LINE__);
+        }
+
+        if (old_info->count != new_info->count)
+            return -1;
+
+        for (i = 0; i < old_info->count; i++)
+        {
+            unsigned j;
+            DynamicLibPath *old_path = old_info->lib_paths[i];
+
+            for (j = 0; j < new_info->count; j++)
+            {
+                DynamicLibPath *new_path = new_info->lib_paths[j];
+
+                if ((strcmp(old_path->path, new_path->path) == 0) &&
+                    (old_path->ptype == new_path->ptype))
+                {
+                    if (old_path->last_mod_time != new_path->last_mod_time)
+                        return -1;
+
+                    break;
+                }
+            }
+
+            if (j == new_info->count)
+                return -1;
+        }
+    }
+    else if (old_info != new_info)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+#endif  /* SNORT_RELOAD */
+
--- /dev/null
+++ b/snort/snort-patches/0001-add-dependancy-for-lrt.patch
@@ -0,0 +1,30 @@ 
+From 1cc044fb3b00c290afcacab3ca044d371bb039be Mon Sep 17 00:00:00 2001
+From: Maxim Uvarov <maxim.uvarov@linaro.org>
+Date: Wed, 9 Apr 2014 18:42:29 +0400
+Subject: [PATCH] add dependancy for -lrt
+
+Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
+---
+ snort-2.9.6.0/src/snort.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/snort-2.9.6.0/src/snort.c b/snort-2.9.6.0/src/snort.c
+index 1481d4f..0280107 100644
+--- a/snort-2.9.6.0/src/snort.c
++++ b/snort-2.9.6.0/src/snort.c
+@@ -777,6 +777,12 @@ static int InlineFailOpen (void)
+  */
+ int main(int argc, char *argv[])
+ {
++	/* hack to add deps to -lrt for timer_create() and friends from odp */
++	static volatile int link_rt = 0;
++	timer_t timerid = 0;
++	if (link_rt)
++		timer_settime(timerid, 0, NULL, NULL);
++
+ #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+     /* Do some sanity checking, because some people seem to forget to
+      * put spaces between their parameters
+-- 
+1.7.9.5
+