workers模式流程

main:注册运行模式(添加到全局的运行模式数组runmodes中)
RunModeRegisterRunModes();
--------------------------
RunModeIdsPcapRegister();
{
    RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "workers",
                              "Workers pcap live mode, each thread does all"
                              " tasks from acquisition to logging",
                              RunModeIdsPcapWorkers);
}
--------------------------
void RunModeRegisterNewRunMode(int runmode, const char *name,
                               const char *description,
                               int (*RunModeFunc)(DetectEngineCtx *))
{
    // 添加到全局的runmodes中
    RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].no_of_runmodes];
    runmodes[runmode].no_of_runmodes++;
    mode->runmode = runmode;
    mode->name = SCStrdup(name);
    mode->description = SCStrdup(description);
    mode->RunModeFunc = RunModeFunc;  // 执行函数:RunModeIdsPcapWorkers
}
====================================
main:注册模块(添加到全局的模块数组tmm_modules中)
    TmModuleReceivePcapRegister();
    TmModuleDecodePcapRegister();
    TmModuleStreamTcpRegister();
   
    TmModuleDetectRegister();
   
    TmModuleRespondRejectRegister();
--------------------------------
// 添加到全局的模块数组中
void TmModuleReceivePcapRegister (void) 
{
  tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap";
  tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit;
  tmm_modules[TMM_RECEIVEPCAP].Func = NULL;
  tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop;
  tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats;
  tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL;
  tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL;
  tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW;
  tmm_modules[TMM_RECEIVEPCAP].flags = TM_FLAG_RECEIVE_TM;
}
======================================
main:运行模式调度
RunModeDispatch(run_mode, runmode_custom_mode, de_ctx);
{
   mode->RunModeFunc(de_ctx); // workers模式调度RunModeIdsPcapWorkers函数
}
----------------------------------------------------
int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx)
{
   int ret;
   char *live_dev = NULL;
   SCEnter();

   RunModeInitialize();
   TimeModeSetLive();

   (void) ConfGet("pcap.single-pcap-dev", &live_dev);

   ret = RunModeSetLiveCaptureWorkers(de_ctx,
                                    ParsePcapConfig,
                                    PcapConfigGeThreadsCount,
                                    "ReceivePcap",
                                    "DecodePcap", "RxPcap",
                                     live_dev);
--------------
typedef定义函数指针类型:
typedef void *(*ConfigIfaceParserFunc) (const char *);
typedef void *(*ConfigIPSParserFunc) (int);
typedef int (*ConfigIfaceThreadsCountFunc) (void *);
--------------
int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx,
       ConfigIfaceParserFunc ConfigParser,
       ConfigIfaceThreadsCountFunc ModThreadsCount,
       char *recv_mod_name,
       char *decode_mod_name, char *thread_name,
       const char *live_dev)
{
    live_dev_c = LiveGetDeviceName(ldev); // liev_dev_c = 'eth0'
    aconf = ConfigParser(live_dev_c);
 
    RunModeSetLiveCaptureWorkersForDevice( de_ctx,
                                           ModThreadsCount,
                                           recv_mod_name,
                                           decode_mod_name,
                                           thread_name,
                                           live_dev_c,
                                           aconf,
                                           0);
}
--------------
static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx,
                              ConfigIfaceThreadsCountFunc ModThreadsCount,
                              char *recv_mod_name,
                              char *decode_mod_name, char *thread_name,
                              const char *live_dev, void *aconf,
                              unsigned char single_mode)
{
    n_thread_name = 'RxPcapeth01'
    // 创建tv实例
    tv = TmThreadCreatePacketHandler(n_thread_name,
                                     "packetpool", "packetpool",
                                     "packetpool", "packetpool",
                                     "pktacqloop");
   回到这里继续:
   创建tv实例,设置出入队列,设置tv->tm_func函数
 
   // 收包模块插入槽
   tm_module = TmModuleGetByName(recv_mod_name);
   TmSlotSetFuncAppend(tv, tm_module, aconf);
   // 解码模块插入槽
   tm_module = TmModuleGetByName(decode_mod_name);
   TmSlotSetFuncAppend(tv, tm_module, NULL);
   // tcp流管理模块插入槽
   tm_module = TmModuleGetByName("StreamTcp");
   TmSlotSetFuncAppend(tv, tm_module, NULL);
   // 检测模块插入槽(延迟作用是什么?)
   tm_module = TmModuleGetByName("Detect");
   TmSlotSetFuncAppendDelayed(tv, tm_module,
   (void *)de_ctx, de_ctx->delayed_detect);
   // 回应拒绝模块插入槽(啥意思?)
   tm_module = TmModuleGetByName("RespondReject");
   TmSlotSetFuncAppend(tv, tm_module, NULL);
 
   // 真正创建线程
   TmThreadSpawn(tv);
}
--------------------
模块插入槽函数:
static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
{
   TmSlot *slot = SCMalloc(sizeof(TmSlot));
   SC_ATOMIC_INIT(slot->slot_data);
   slot->tv = tv;
   slot->SlotThreadInit = tm->ThreadInit;
   slot->slot_initdata = data;
   SC_ATOMIC_INIT(slot->SlotFunc);
   (void)SC_ATOMIC_SET(slot->SlotFunc, tm->Func);
   slot->PktAcqLoop = tm->PktAcqLoop;
   slot->SlotThreadExitPrintStats = tm->ThreadExitPrintStats;
   slot->SlotThreadDeinit = tm->ThreadDeinit;
   slot->tm_id = TmModuleGetIDForTM(tm);

   tv->cap_flags |= tm->cap_flags;

   if (tv->tm_slots == NULL) {
      tv->tm_slots = slot;
      slot->id = 0;
   } else {
      TmSlot *a = (TmSlot *)tv->tm_slots, *b = NULL;

   for ( ; a != NULL; a = a->slot_next) {
     b = a;
   }
   if (b != NULL) {
     b->slot_next = slot;
     slot->id = b->id + 1;
   }
  }

return slot;
}
---------------------
ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name,
                                        char *inqh_name, char *outq_name,
                                        char *outqh_name, char *slots)
{
   ThreadVars* tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name,
                                   slots, NULL, 0);
    returnt tv;
}
-------------
参数:name是tv实例的名称
 inq_name是入队列名称
 inqh_name是入队列处理名称(set by TmqhSetup())
 outq_name是出队列名称
 outqh_name是出队列处理名称(set by TmqhSetup())
 slots是描述槽的作用
 
ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name,
                         char *outq_name, char *outqh_name, char *slots,
                          void * (*fn_p)(void *), int mucond)
{
   ThreadVars *tv = NULL;
   tv = SCMalloc(sizeof(ThreadVars));
   tv->name = name;
   // 设置入队列
   Tmq *tmq = NULL;
   tmq = TmqGetQueueByName(inq_name);
   tv->inq = tmq;
   Tmqh *tmqh = NULL;
   tmqh = TmqhGetQueueHandlerByName(inqh_name);
   tv->tmqh_in = tmqh->InHandler;
   tv->InShutdownHandler = tmqh->InShutdownHandler;
   // 设置出队列
   tmqh = TmqhGetQueueHandlerByName(outqh_name);
   tv->tmqh_out = tmqh->OutHandler;
   tv->outqh_name = tmqh->name;
   // 设置槽函数
   TmThreadSetSlots(tv, slots, fn_p)
}
-------------
TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *))
{
   // 这几个槽的名称区别
   if (strcmp(name, "1slot") == 0) {
      tv->tm_func = TmThreadsSlot1;
   } else if (strcmp(name, "1slot_noout") == 0) {
      tv->tm_func = TmThreadsSlot1NoOut;
   } else if (strcmp(name, "1slot_noin") == 0) {
      tv->tm_func = TmThreadsSlot1NoIn;
   } else if (strcmp(name, "1slot_noinout") == 0) {
      tv->tm_func = TmThreadsSlot1NoInOut;
   } else if (strcmp(name, "varslot") == 0) {
      tv->tm_func = TmThreadsSlotVar;
   } else if (strcmp(name, "pktacqloop") == 0) {  // 走到这里
      tv->tm_func = TmThreadsSlotPktAcqLoop;
   } else if (strcmp(name, "custom") == 0) {
      if (fn_p == NULL)
      goto error;
      tv->tm_func = fn_p;
   } else {
      printf("Error: Slot "%s" not supported\n", name);
      goto error;
  }
}
------------
回到RunModeSetLiveCaptureWorkersForDevice函数
------------
真正创建线程:
TmEcode TmThreadSpawn(ThreadVars *tv)
{
   // 创建线程,调用tv->tm_func函数: TmThreadsSlotPktAcqLoop
   pthread_create(&tv->t, &attr, tv->tm_func, (void *)tv);
}
==================================================
void *TmThreadsSlotPktAcqLoop(void *td)
{
   ThreadVars *tv = (ThreadVars *)td;
   TmSlot *s = tv->tm_slots;    // slot链表头
   // 设置线程名称
   SCSetThreadName(tv->name);
   // 循环slot初始化
   for (slot = s; slot != NULL; slot = slot->slot_next)
   
      // slot中模块初始化Recive->Decode->StreamTcp->Detect->Alert ……
      r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot_data);
   }
   // 真正循环slot
   while(run) 
   {   
      // 收包,执行 ReceivePcapLoop 函数,在注册模块时设置的
      r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s);
   }
   // 销毁函数执行
   for (slot = s; slot != NULL; slot = slot->slot_next)
   {
      slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data));
      r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data));
   }
}
===============================
// data是初始化阶段生成的PcapThreadVars结构体
TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
{
   PcapThreadVars *ptv = (PcapThreadVars *)data;
   TmSlot *s = (TmSlot *)slot;
   ptv->slot = s->slot_next;// 第2个slot即Decode模块
 
   while (1) 
   {   // 收包,每次收取一个数据包
      r = pcap_dispatch(ptv->pcap_handle, (int)packet_q_len,
      (pcap_handler)PcapCallbackLoop, (u_char *)ptv);
   }
}

// 收包后回调函数
// 参数: user是ptv结构指针,h是pcap文件头,pkt是真正数据
void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
{
    // 首先从packet pool中获取,如果失败。调用PacketGetFromAlloc新分配一个
    // 注:与pool中取出的数据包最终可以回收不同,这种使用malloc动态分配的数据包最后需要free.
    // 因此为了区分会在其flags中打上标记PKT_ALLOC。
    Packet *p = PacketGetFromQueueOrAlloc();
  
    // 数据包在callback中会送入outq中等待后续线程继续处理
    // 调用TmThreadsSlotProcessPkt让本线程中包含的其他slot中的模块对数据包进行后续处理
     TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p);
}
 
// 真正循环slot中模块执行函数
 static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet *p)
 {
      TmThreadsSlotVarRun(tv, p, s);
  
      // 线程创建时设置为与该线程绑定的outqh的处理函数OutHandler,
      // 在这里默认为TmqhOutputFlowActivePackets,将数据包送到后续队列中去
      tv->tmqh_out(tv, p);
  
      // 注: slot_pre_pq vs. slot_post_pq:
      // 某个slot在处理某个母数据包时新产生的子数据包,
      // 若放入slot_pre_pq中,则这个数据包将在本个slot处理完母数据包后,
      // 在后续slot处理母数据包之前,先将这些子数据包放到后续的slot去处理;
      // 而如果是放如slot_post_pq,则需要等到母数据包被所有slot都处理完后,
      // 在下一个数据包处理之前,再去集中处理,如上面所述。
 
      处理slot->slot_post_pq队列
}
 
TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, TmSlot *slot)
{
    循环调用Slot->SlotFun函数。
    Decode->StreamTcp->Detect->RespondRejectFunc->AlertFastLog-> ……
 
    处理 slot_pre_pq队列数据。
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值