conntrack删除链表

在删除conntrack时,首先设置IPS_DYING_BIT标志位,如果此位已经设置,表明conntrack正在被删除。

bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
{
    struct nf_conn_tstamp *tstamp;

    if (test_and_set_bit(IPS_DYING_BIT, &ct->status))
        return false;


    nf_conntrack_ecache_work(nf_ct_net(ct));
    nf_ct_delete_from_lists(ct);
    nf_ct_put(ct);

将conntrack由全局的nf_conntrack_hash链表中删除,之后,添加到dying链表中。

static void nf_ct_delete_from_lists(struct nf_conn *ct)
{
    struct net *net = nf_ct_net(ct);
    unsigned int hash, reply_hash;
    unsigned int sequence;

    nf_ct_helper_destroy(ct);

    local_bh_disable();
    do {
        sequence = read_seqcount_begin(&nf_conntrack_generation);
        hash = hash_conntrack(net,
                      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
        reply_hash = hash_conntrack(net,
                       &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
    } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));

    clean_from_lists(ct);
    nf_conntrack_double_unlock(hash, reply_hash);

    nf_ct_add_to_dying_list(ct);

要删除的conntrack的原始方向的tuple添加到当前处理器对应的dying链表上。

static void nf_ct_add_to_dying_list(struct nf_conn *ct)
{
    struct ct_pcpu *pcpu;

    /* add this conntrack to the (per cpu) dying list */
    ct->cpu = smp_processor_id();
    pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);

    spin_lock(&pcpu->lock);
    hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
                 &pcpu->dying);
    spin_unlock(&pcpu->lock);

在conntrack引用计数减小到零时,由函数nf_conntrack_destroy进行销毁。

static inline void nf_conntrack_put(struct nf_conntrack *nfct)
{
    if (nfct && atomic_dec_and_test(&nfct->use))
        nf_conntrack_destroy(nfct);
}

最终,在函数destroy_conntrack中,将conntrack由dying链表中删除。

static void
destroy_conntrack(struct nf_conntrack *nfct)
{   
    struct nf_conn *ct = (struct nf_conn *)nfct;
    
    pr_debug("destroy_conntrack(%p)\n", ct);
    WARN_ON(atomic_read(&nfct->use) != 0);
    
    /* Expectations will have been removed in clean_from_lists,
     * except TFTP can create an expectation on the first packet,
     * before connection is in the list, so we need to clean here,
     * too.
     */
    nf_ct_remove_expectations(ct);
    
    nf_ct_del_from_dying_or_unconfirmed_list(ct);

将会话的原始方向的tuple结构由每处理器结构的dying链表中删除。这里的BUG_ON判断确保tuple处于某个链表上。

/* must be called with local_bh_disable */
static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct)
{
    struct ct_pcpu *pcpu;

    /* We overload first tuple to link into unconfirmed or dying list.*/
    pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);

    spin_lock(&pcpu->lock);
    BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
    hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
    spin_unlock(&pcpu->lock);

内核版本 5.10

### 关于 `nf_ct_delete_from_list` 函数详解 #### 函数定义与作用 `nf_ct_delete_from_list` 是 Linux 内核中的一个重要函数,用于从连接跟踪表中删除指定的连接条目。该操作通常发生在连接超时、主动关闭或其他异常情况触发时[^1]。 #### 参数说明 此函数主要接受一个参数——指向要被移除的连接对象 (`struct nf_conn`) 的指针。通过这个指针可以访问到特定连接的相关信息并执行相应的清理工作。 #### 实现细节 当调用 `nf_ct_delete_from_list` 时,会先检查传入的对象是否有效以及其状态是否允许被删除。如果一切正常,则将其从未完成队列或已建立列表中摘下,并更新内部计数器以反映当前活动连接数量的变化。此外,在某些情况下还会释放与此连接关联的资源,比如内存空间等。 ```c void nf_ct_delete_from_list(struct nf_conn *ct) { spin_lock_bh(&nf_conntrack_lock); hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); if (NFCT_DIRECTION(ct)) hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); __nf_conntrack_free(ct); spin_unlock_bh(&nf_conntrack_lock); } ``` 上述代码片段展示了如何安全地锁定全局互斥锁来保护并发环境下的数据一致性;接着分别处理双向链表节点的卸载动作;最后调用了私有的析构方法来进行最终处置。 #### 使用场景 - 当某个 TCP 连接进入 TIME_WAIT 或 FIN_WAIT 状态超过设定时限; - 用户态应用程序显式请求终止某项服务对应的网络对话; - 内存压力过大导致系统自动削减不活跃记录的数量以防止单元溢出等问题发生[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值