suricata 3.1 源码分析14 (流查找分配)

    xiaoxiao2022-06-23  31

    流查找/分配

    通过FlowWorker线程函数中调用FlowHandlePacket来找到流。 下面将按照FlowHandlePacket的流程,分析flow engine对于新送入的解码后的数据包是如何处理的。 对于一个Packet,首先在流表中查找其所属的流是否已经存在,若存在,则直接返回该流的引用即可,否则就需要分配一个新流。 该过程的实现由FlowGetFlowFromHash完成,函数会返回一个Flow指针,表示找到的或新分配的流。

    /** \brief Get Flow for packet * * Hash retrieval function for flows. Looks up the hash bucket containing the * flow pointer. Then compares the packet with the found flow to see if it is * the flow we need. If it isn't, walk the list until the right flow is found. * * If the flow is not found or the bucket was emtpy, a new flow is taken from * the queue. FlowDequeue() will alloc new flows as long as we stay within our * memcap limit. * * The p->flow pointer is updated to point to the flow. * * \param tv thread vars * \param dtv decode thread vars (for flow log api thread data) * * \retval f *LOCKED* flow or NULL */ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p, Flow **dest) { Flow *f = NULL; /* get our hash bucket and lock it */ const uint32_t hash = p->flow_hash; //获取包的hash,这里的hash是由p带来的。p的flow_hash是通过在FlowSetupPacket函数调用FlowGetHash,又通过FlowGetHash中的hashword生成的,对于 hash_key的获取方法以后另行分析。 FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; //以获取到的key为索引,在流表flow_hash中获取到一个FlowBucket的指针 FBLOCK_LOCK(fb); //使用FBLOCK_LOCK对该bucket上锁。实际使用的锁可能为spin lock或mutext,取决于FBLOCK_SPIN是否定义。 SCLogDebug("fb %p fb->head %p", fb, fb->head); /* see if the bucket already has a flow */ if (fb->head == NULL) { //说明这个bucket中还没有流 f = FlowGetNew(tv, dtv, p); //调用FlowGetNew新分配一个流 if (f == NULL) { FBLOCK_UNLOCK(fb); return NULL; } /* flow is locked */ fb->head = f; fb->tail = f; /* got one, now lock, initialize and return */ FlowInit(f, p); //使用Packet的信息初始化这个新流 f->flow_hash = hash; f->fb = fb; //设置流的flow_hash和fb /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); //记录最后一次更新流的时间 FlowReference(dest, f); //使用FlowReference将p->flow指向刚获取流,该函数内部会使用FlowIncrUsecnt增加该流的使用计数。注意,该机制的目的与通常的引用计数不同,不是为了在没有引用时回收资源,而是为了避免出现误删除等问题 FBLOCK_UNLOCK(fb); //FBLOCK_UNLOCK解锁并返回这个流。由于FlowGetNew中会调用FLOWLOCK_WRLOCK对flow进行上锁(因为后面需要使用),因此这里就不需要再锁了。 return f; } //以下代码为fb->head不为NULL,即bucket中有流时,尝试从其中的Flow链表中查找该packet所属的Flow /* ok, we have a flow in the bucket. Let's find out if it is our flow */ f = fb->head; /* see if this is the flow we are looking for */ if (FlowCompare(f, p) == 0) { //代表f和p不匹配,为1匹配,为0不匹配 Flow *pf = NULL; /* previous flow */ while (f) { pf = f; f = f->hnext; if (f == NULL) { f = pf->hnext = FlowGetNew(tv, dtv, p); if (f == NULL) { FBLOCK_UNLOCK(fb); return NULL; } fb->tail = f; /* flow is locked */ f->hprev = pf; /* initialize and return */ FlowInit(f, p); f->flow_hash = hash; f->fb = fb; /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; } //若未找到,则与4类似,获取一个新流并初始化,然后挂到链表尾部再返回。注意,这里并没有移到头部,因为新流不代表就是活跃流。 if (FlowCompare(f, p) != 0) { /* we found our flow, lets put it on top of the * hash list -- this rewards active flows */ if (f->hnext) { f->hnext->hprev = f->hprev; } if (f->hprev) { f->hprev->hnext = f->hnext; } if (f == fb->tail) { fb->tail = f->hprev; } f->hnext = fb->head; f->hprev = NULL; fb->head->hprev = f; fb->head = f; /* found our flow, lock & return */ FLOWLOCK_WRLOCK(f); if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { f = TcpReuseReplace(tv, dtv, fb, f, hash, p); if (f == NULL) { FBLOCK_UNLOCK(fb); return NULL; } } /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; } //使用FlowCompare比较head flow与packet,若相匹配,则说明已经找到了,且这个流已经在头部不需要再调整,则先锁上该flow再解锁bucket,然后返回。 } } /* lock & return */ FLOWLOCK_WRLOCK(f); if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { f = TcpReuseReplace(tv, dtv, fb, f, hash, p); if (f == NULL) { FBLOCK_UNLOCK(fb); return NULL; } } /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); //记录最后一次更新流的时间 FlowReference(dest, f); //将dest指向f,此处dest为p->flow,由函数传入。 FBLOCK_UNLOCK(fb); return f; }
    转载请注明原文地址: https://ju.6miu.com/read-1123443.html

    最新回复(0)