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

目录

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

2. 流的新建... 1

3. 流的老化... 2

4. 流空闲数量的动态维护... 2

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

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

  1. 流管理内容简介

流管理包括流表的初始化,流的新建、查找、更新、检查老化、流的回收、空闲流数量的动态维护等。

  1. 流的新建

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

FlowHandlePacket函数做了大部分流查找分配及状态设置更新的工作,有一部分更新状态的工作放在另外一个函数FlowUpdate,在如果没有找到则分配一个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后,设置相关成员数据,然后放入全局变量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. 流的老化

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

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

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

  1. 流空闲数量的动态维护

空闲flow个数动态维护是在流老化线程的第1个线程中,就是在老化线程函数会检查自己是否第一个老化线程,是的话则做这项工作,检查空闲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. 流存储关键数据结构

全局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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>