nf_conntrack: falling back to vmalloc.

本文深入探讨了Linux系统中内存管理的问题,特别是当系统logmessagefile报告kernel:nf_conntrack:fallingbacktovmalloc时,如何检查内存页面可用性及解决内存碎片化问题。文章解释了Linux使用kmalloc和vmalloc两种方法分配内存,以及当kmalloc无法找到连续物理页时如何回退到vmalloc。并提供了解决内存碎片化的命令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

System log message file is reporting "kernel: nf_conntrack: falling back to vmalloc".

Memory page availability can be further checked from /proc/buddyinfo as below.

#  cat /proc/buddyinfo
Node 0, zone      DMA      1      0      1      0      1      1      1      0      1      1      3
Node 0, zone    DMA32   3342   2441   2138   5025   1871    236      3      0      0      0      0
Node 0, zone   Normal 143135   6057 150803   4005    330     62      1      0      0      0      0

Linux uses two methods to allocate memory

kmalloc
vmalloc

kmalloc allocates contiguous physical memory pages and it will fail if contiguous physical pages are not available.Then kernel falls back to vmalloc.

vmalloc is usually slower than kmalloc. It has to remap virtual memory range to physical space.

Once above message is reported from system log message. It highly indicates the memory is being fragmented.

Following command can be used to compact fragmented memory pages.

echo 1 > /proc/sys/vm/compact_memory

这个报错不能算一个错误,只是说没有足够的连续内存可以分配kmalloc,因此启用vmalloc来分配内存。

内存碎片化。

转载于:https://blog.51cto.com/ipcpu/2406782

<think>我们正在处理一个内核编译错误,错误信息指出在结构体`struct netns_ct`中缺少成员`nf_conntrack_event_cb`。这个错误发生在文件`nf_conntrack_ecache.c`中。 首先,我们需要理解这个错误的原因。在内核开发中,不同版本的内核可能会修改结构体的定义,删除或重命名某些成员。因此,当使用一个为旧版本内核编写的代码或配置在新版本内核上编译时,可能会出现此类问题。 根据错误信息,我们尝试在`struct netns_ct`中访问一个名为`nf_conntrack_event_cb`的成员,但该成员在当前内核版本的结构体定义中不存在。 为了验证这一点,我们需要检查当前内核版本中`struct netns_ct`的定义。我们可以通过查找内核头文件(通常是`include/net/netns/conntrack.h`)来确认。 然而,由于用户没有提供具体的内核版本,我们需要考虑两种可能性: 1. 在较新的内核版本中,该成员被重命名或移除了。 2. 用户的内核配置可能没有启用某些选项,导致该成员没有被定义。 根据引用[4]中提到的连接跟踪机制,我们知道`nf_conntrack`是Linux内核中用于连接跟踪的模块。而`nf_conntrack_ecache`(事件缓存)是连接跟踪的一个扩展,用于向用户空间报告连接跟踪事件。 在历史版本中,`struct netns_ct`可能包含一个名为`nf_conntrack_event_cb`的成员,用于事件回调。但在新版本中,这个成员可能已经被改变。 我们可以通过搜索内核源代码的历史变更来了解这个成员的变化情况。但这里我们假设用户遇到了一个由于内核升级导致的问题。 **解决方案思路:** 1. **确认当前内核中`struct netns_ct`的定义**:查看`include/net/netns/conntrack.h`文件,检查`struct netns_ct`有哪些成员。 2. **查找替代成员**:如果`nf_conntrack_event_cb`被移除,那么可能事件回调机制已经被改变,我们需要找到新的方式来处理事件回调。 3. **检查内核版本和补丁**:查看当前内核版本中关于`nf_conntrack_ecache`的改动,特别是与事件回调相关的部分。 根据经验,在较新的内核版本(例如4.0以后)中,事件回调机制可能已经被重构。在旧版本中,`nf_conntrack_event_cb`可能是一个指向回调函数的指针,但在新版本中,事件通知可能通过其他方式实现,比如使用RCU回调或者新的通知链。 **具体步骤:** 1. 首先,确定当前内核版本。可以通过`uname -r`命令查看。 2. 在`include/net/netns/conntrack.h`中查找`struct netns_ct`的定义。例如,在较新的内核版本(如5.10)中,该结构体可能如下所示: ```c struct netns_ct { #ifdef CONFIG_NF_CONNTRACK_EVENTS struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; #endif // ... 其他成员 }; ``` 注意,这里我们看到了一个成员`nf_conntrack_event_cb`,但它被包装在`#ifdef CONFIG_NF_CONNTRACK_EVENTS`中。因此,如果内核配置没有启用`CONFIG_NF_CONNTRACK_EVENTS`,那么这个成员就不会被定义。 3. 检查内核配置中是否启用了`CONFIG_NF_CONNTRACK_EVENTS`。可以通过查看`.config`文件或使用`zcat /proc/config.gz`(如果支持)来检查。 4. 如果启用了该配置选项,那么可能是成员名字发生了变化。可以尝试在头文件中搜索类似的名字,比如`event_cb`、`ecache_cb`等。 5. 如果发现成员名字确实已经改变,那么需要修改代码,使用新的成员名。 6. 如果在新版本中该成员被完全移除,那么我们需要了解事件回调机制是如何工作的。可能事件回调不再通过这个结构体成员,而是通过全局通知链或其他机制。此时,需要参考新版本内核中`nf_conntrack_ecache.c`的实现,看它是如何设置事件回调的。 **实际例子:** 在旧版本内核(如3.10)中,`struct netns_ct`可能包含: ```c struct netns_ct { // ... struct nf_ct_event_notifier *nf_conntrack_event_cb; // ... }; ``` 而在新版本(如5.10)中,它变成了: ```c struct netns_ct { #ifdef CONFIG_NF_CONNTRACK_EVENTS struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; #endif // ... }; ``` 这里,除了条件编译外,还增加了`__rcu`修饰符,表示该指针受RCU保护。因此,在访问时需要使用RCU相关函数。 另外,在更晚的版本中,这个成员可能被完全移除,取而代之的是一个新的机制。例如,在5.12以后的内核中,事件通知可能被重构,使用一个全局的事件通知结构体,而不是每个网络命名空间一个。 **如何修改代码?** 假设在用户的内核版本中,该成员被条件编译所包围,那么需要确保在代码中访问该成员时,也使用相同的条件编译。例如,在`nf_conntrack_ecache.c`中,原来的代码可能是: ```c struct netns_ct *ct_net = &net->ct; if (ct_net->nf_conntrack_event_cb) { // 调用回调 } ``` 应该改为: ```c #ifdef CONFIG_NF_CONNTRACK_EVENTS struct netns_ct *ct_net = &net->ct; struct nf_ct_event_notifier *notify; rcu_read_lock(); notify = rcu_dereference(ct_net->nf_conntrack_event_cb); if (notify) { // 调用回调 } rcu_read_unlock(); #endif ``` 注意,在新版本中,由于使用了RCU,我们需要通过`rcu_dereference`来安全地获取指针。 如果用户的内核版本中已经完全移除了这个成员,那么就需要寻找新的方法。例如,事件通知可能通过一个全局的链表来实现。此时,我们需要参考新内核中事件通知的注册和触发机制。 **总结步骤:** 1. 确认内核版本和配置。 2. 检查头文件`include/net/netns/conntrack.h`中`struct netns_ct`的定义。 3. 如果成员存在但被条件编译包围,确保在代码中正确使用条件编译和RCU保护。 4. 如果成员不存在,查找内核源码中类似功能的实现(例如搜索`nf_conntrack_event_cb`的引用,看它被哪些函数使用,然后这些函数在新内核中是如何实现的)。 5. 根据新内核的机制修改代码。 由于用户没有提供具体的内核版本,我们只能给出一般性建议。如果用户能提供更多信息(如内核版本),我们可以给出更具体的解决方案。 最后,注意在修改内核代码时,要遵循内核的编码规范和同步机制(如RCU),以避免并发问题。</think>在编译 Linux 内核模块时遇到错误 `error: 'struct netns_ct' has no member named 'nf_conntrack_event_cb'`,这通常是由内核版本升级导致的 API 变更引起的。以下是解决方案和详细分析: ### 问题原因 1. **内核 API 变更**: - `nf_conntrack_event_cb` 成员在较新内核版本(5.10+)中已被移除或重构 - 连接跟踪事件机制被简化为直接使用 `nf_conntrack_ecache_work()` 处理[^3][^4] 2. **条件编译依赖**: - 该成员受 `CONFIG_NF_CONNTRACK_EVENTS` 配置控制 - 若未启用事件支持,结构体中将不存在此成员[^4] ### 解决方案 #### 方法 1:更新代码适配新内核 ```c // 修改前(旧内核) struct nf_ct_event_notifier *notify; notify = rcu_dereference(net->ct.nf_conntrack_event_cb); // 修改后(新内核) #if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) struct nf_ct_event_notifier *notify = rcu_dereference(net->ct.nf_conntrack_event_cb); #else // 新内核使用直接事件处理 nf_conntrack_ecache_work(net, NETEVENT_DESTROY, ct); #endif ``` #### 方法 2:检查内核配置 确保启用必要配置选项: ```bash # 检查内核配置 grep CONFIG_NF_CONNTRACK_EVENTS /boot/config-$(uname -r) # 若未启用,重新编译内核时开启 CONFIG_NF_CONNTRACK_EVENTS=y ``` #### 方法 3:版本适配补丁 ```diff --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -180,8 +180,12 @@ static void __nf_conntrack_event_cached(struct nf_conn *ct, void nf_conntrack_event_cached(struct nf_conn *ct, enum ip_conntrack_events event) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + nf_conntrack_ecache_work(dev_net(ct->dev), event, ct); +#else struct net *net = dev_net(ct->dev); __nf_conntrack_event_cached(ct, event, net->ct.nf_conntrack_event_cb); +#endif } ``` ### 根本原因分析 1. **连接跟踪优先级变更**: - 新内核中 `NF_IP_PRI_CONNTRACK_CONFIRM` 优先级调整为 `INT_MAX`[^4] - 事件回调机制被简化为直接工作队列处理 2. **结构体精简**: ```c // 新内核 struct netns_ct (include/net/netns/conntrack.h) struct netns_ct { // 移除了 nf_conntrack_event_cb struct nf_conntrack_ecache ecache; // 直接使用ecache结构 }; ``` 3. **事件处理路径变化**: ```mermaid graph TD A[ipv4_conntrack_in] --> B[nf_conntrack_in] B --> C[resolve_normal_ct] C --> D[__nf_conntrack_confirm] // 引用[2] D --> E[nf_ct_deliver_cached_events] // 直接触发事件 ``` 建议优先使用方法1进行版本适配,并参考内核文档 `Documentation/networking/nf_conntrack.rst` 获取最新实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值