这篇文章接着上篇继续解释流的建立,其中最重要的一个函数FlowGetNew,主要目的是获取一个flow,获取过程中也是非常曲折的,求爷爷告奶奶才能求来一个flow。
1. FlowGetNew 这个函数也分几个方面理解:
FlowHandlePacket-》FlowGetFlowFromHash-》FlowGetNew
a。从线程自己的flow队列里获取flow,如果获取成功则返回flow,如果没有就从全局flow内存池获取一个flow队列,再从flow队列里获取flow。
b。如果线程自己的flow队列和全局flow内存池也没有可用的flow队列,且flow内存超过配置上限,则设置进入紧急模式。
c。接b,设置紧急模式之后,调用函数FlowGetUsedFlow获取flow,这个函数是从正在使用的全局flow_hash的bucket链表里获取一个,后续会注释这个函数。
d。如果线程自己的flow队列和全局flow内存池也没有可用的flow队列,且flow内存没有超过配置上限,则直接在内存上分配flow即调用函数FlowAlloc。
static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, const Packet *p)
{
//获取紧急模式标志
const bool emerg = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0);
//检查是否可以生成flow,icmp错误包不生成flow
//如果是紧急模式,tcp非sync的包不生成flow,可以看出sync包优先生成flow
if (FlowCreateCheck(p, emerg) == 0) {
return NULL;
}
//从线程自己的flow队列里获取flow,如果获取成功则返回flow
/* get a flow from the spare queue */
Flow *f = FlowQueuePrivateGetFromTop(&fls->spare_queue);
if (f == NULL) {
//如果获取flow失败,就从全局flow内存池获取一个flow队列,再从flow队列里获取flow。
//FlowSpareSync这个函数主要是从空闲的全局flow内存池获取一个flow队列,给自己用
f = FlowSpareSync(tv, fls, p, emerg);
}
//全局flow内存池也没有可用的flow队列
if (f == NULL) {
/* If we reached the max memcap, we get a used flow */
//判断如果flow内存超过配置上限,则进入紧急模式。
if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) {
/* declare state of emergency */
if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) {
//没有设置紧急模式标志才会设置,设置过