编程语言
首页 > 编程语言> > Suricata6.0流管理源码注释一:流管理简介

Suricata6.0流管理源码注释一:流管理简介

作者:互联网

Suricata6.0流管理代码梳理

目录

1. 流管理内容简介... 1

2. 流管理基本思想... 1

3. 流建立入口函数... 1

4. 流结构体flow的分配... 1

5. 流存储关键数据结构... 2

6. 流管理主要函数... 2

  1. 流管理内容简介

包括新建流和老化流两大部分,一个流用一个flow结构体表示,具体工作又包括为packet获取一个flow,更新流的状态,流的老化回收,空闲flow个数维护即flow空闲数量少于预分配数量的90%时则进行补充,如果flow空闲数量多于预分配的flow数量的110%时则进行释放。

释放逻辑:多出来的flow数量x是flow队列(固定100个)数量的10倍及以上则释放x/10个flow,就是多出来的flow数量必须小于单个flow队列flow数量的10倍,比如单个flow队列固定flow数量为100,则由于从内存分配而多出来的flow数量必须小于1000(100*10),如果为1000则释放的数量为1000/10=100,如果为1100,则需要释放1100/10=110。

多出来的flow是因为预分配的flow使用完了,而且当前flow占用的总内存没有超过配置的内存字节数,于是flowalloc分配新flow,这样flow数量就会增多。

  1. 流管理基本思想

(1)根据流的状态设置流的超时时间,时间到了则老化之,回收flow到全局的flow_spare_pool中,哪个flow队列不够100,就放入哪个flow队列。

         (2)如果预先分配的flow结构体不够用了,配置的flow内存也用完了,则设置进入紧急模式状态,一个是把流的超时时间设置为紧急超时时间,这个时间远远短于正常老化时间,二是流老化处理线程轮询间隔时间也会缩短,轮询间隔时间正常时667毫秒检查一次老化,紧急模式为250毫秒检查一次;另外,每个线程只老化自己负责的flowbucket上的flow,这个flowbucket的范围在FlowInitConfig初始化时设置,就是按照flowbucket的数量平均分配给每个老化线程即运行FlowManager函数的线程。

(3)进入紧急模式后,会不断检查可用flow的数量,如果这个数量达到预分配flow数量的一定的百分比,则退出紧急模式。

  1. 流建立入口函数

当一个网络数据包到达时,经过收包,解码产生了packet结构体指针p,这时进入下一个模块第一个工作就是为这个p查找其所属流flow,这个工作从函数FlowHandlePacket开始,不同的suricata版本对这个函数的调用位置不一样,但都是在解码后进行调用,从4.0开始在FlowWorker函数中调用,3.0及以前的版本都在解码模块的解码函数中调用比如在DecodeUDP,DecodeTCP等函数中调用。

FlowHandlePacket函数做了大部分流查找分配及状态设置更新的工作,有一部分更新状态的工作放在另外一个函数FlowUpdate,在如果没有找到则分配一个flow,如果找到则更新流状态。

  1. 流结构体flow的分配

流的flow存放在全局flow哈希数组中:FlowBucket *flow_hash,所以操作bucket时需要对其上锁,每个bucket存放若干哈希值相同的flow结构体,哈希值就是五元组哈希后与数组大小的模,解码后为一个包获取flow时,先从全局变量flow_hash[hash%hash_size]数组里进行查找,存在则进行状态更新操作,不存在则需要从空闲的flow池子里分配一个flow结构体。

分配flow两个方式,一个是从预先分配的全局flow池子里获取,如果没有可用的flow,则在配置的内存空间范围内直接从内存上分配flow,这个池子就称为空闲flow池子,它是个根据配置文件预先分配一定数量flow的内存池,需要的时候从里边取,不需要了则归还进去,取到flow后,设置相关成员数据,然后放入全局变量flow_hash中,该flow后续的packet都可以匹配到该flow结构体。

不同版本的全局flow池子有所区别,比如4.0和之前的版本都是FlowQueue flow_spare_q(带锁的flow链表)这样的全局变量(5.0左右版本没看过),直接用锁子从这个全局变量获取可用的flow结构体。

6.0版本也是用的全局变量,只不过flow不是组织成一个链表,而是先根据配置文件配置的flow个数进行预分配,把这些flow每100个flow组织成一个空闲的flow队列,再把每个包含100个flow的队列组成pool,就是通过static FlowSparePool *flow_spare_pool链接起来形成pool,它是个全局变量,由static SCMutex flow_spare_pool_m保护。

处理包的每个线程都有自己的空闲flow队列,分配flow时,从线程自己的flow队列(变量名字:spare_queue)里获取,如果没有可用flow,则从上边说的全局pool里取一个flow队列赋值给spare_queue,后续有包到来就从spare_queue里取flow使用,所以从全局pool获取的flow是一个flow队列(100个),一次获取一个队列的flow,只有100个flow用完了才需要锁一次全局pool获取一个flow队列,而不像4.0及之前版本一次获取一个flow每次都要锁,从这点看,减小了锁的粒度,如果流的数量比较多的话,在获取flow时可以提高不少性能。

  1. 流存储关键数据结构

全局flow哈希数组中:FlowBucket *flow_hash,正则使用的流的结构体flow存放到这里

存放空闲Flow队列的pool定义:

typedef struct FlowSparePool {

FlowQueuePrivate queue;        //flow队列,就是个链表,由100个flow组成

     struct FlowSparePool *next; //池子链表,把多个flow队列组织成链表,线程自己的flow队列用完时,从这个pool里获取一个flow队列

 } FlowSparePool;

 static uint32_t flow_spare_pool_flow_cnt = 0;    //空闲flow总个数,包括所有flow队列的flow

 static uint32_t flow_spare_pool_block_size = 100;//每个flow队列里空闲flow的个数

 static FlowSparePool *flow_spare_pool = NULL;  //全局链表头指针,存储可用的flow

 static SCMutex flow_spare_pool_m = SCMUTEX_INITIALIZER;//保护上边那位爷

  1. 流管理主要函数

流初始化函数:

入口函数

被直接调用函数

FlowInitConfig

(flow.c)

FlowQueueInit

FlowSparePoolInit

FlowInitFlowProto

FlowSparePoolInit

(flow-spare-pool.c)

FlowSpareGetPool

FlowSparePoolUpdateBlock

流查询建立主要函数:

入口函数

被直接调用函数

FlowWorker (flow-worker.c)

FlowHandlePacket

FlowHandlePacket (flow.c)

FlowGetFlowFromHash

FlowGetFlowFromHash

(flow-hash.c)

FlowGetNew

MoveToWorkQueue

FlowInit

FlowUpdateState

FlowGetNew

(flow-hash.c)

FlowQueuePrivateGetFromTop

FlowSpareSync

FlowTimeoutsEmergency

FlowGetUsedFlow

FlowAlloc

流老化检查主要函数:

入口函数

被直接调用函数

FlowManage

(flow-manager.c)

FlowSpareGetPoolSize

FlowSparePoolUpdate

FlowTimeoutHash

FlowTimeoutHash

(flow-manager.c)

FlowManagerHashRowTimeout

FlowManagerHashRowClearEvictedList

ProcessAsideQueue

FlowManagerHashRowClearEvictedList

(flow-manager.c)

FlowQueuePrivateAppendFlow

FlowManagerFlowTimeout

(flow-manager.c)

FlowGetFlowTimeoutDirect

ProcessAsideQueue

(flow-manager.c)

FlowForceReassemblyForFlow

FlowQueuePrivateAppendFlow

FlowForceReassemblyForFlow

(flow-timeout.c)

TmThreadsInjectFlowById

TmThreadsInjectFlowById

(tm-threads.c)

FlowEnqueue

SCCondSignal

流回收主要函数:

入口函数

被直接调用函数

FlowRecycler

(flow-manager.c)

FlowQueueExtractPrivate

FlowQueuePrivateGetFromTop

Recycler

Recycler

(flow-manager.c)

OutputFlowLog

FlowClearMemory

FlowSparePoolReturnFlow

标签:Suricata6.0,函数,管理,队列,flow,源码,spare,100,pool
来源: https://blog.csdn.net/ljq32/article/details/122367100