免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5938 | 回复: 27

内核netfilter处理问题(暨packet接受与NAPI介绍) [复制链接]

论坛徽章:
0
发表于 2006-01-08 18:41 |显示全部楼层
我认为,一个数据报在netfilter处理的过程中,一直是在softirq中进行的,因此,不可能被其他softirq打断,

如果在一个netfilter的动作,也即target中,直接调用dev_queue_xmit()来发送自己构造的数据报,会出现内存泄漏吗?

内核中,一个最为接近的类似的处理是ipt_REJECT,单它使用NF的钩子来发送自己的数据,而不是直接调用dev_queue_xmit()。

[ 本帖最后由 albcamus 于 2006-1-11 16:17 编辑 ]

论坛徽章:
0
发表于 2006-01-08 20:29 |显示全部楼层
原帖由 guotie 于 2006-1-8 18:41 发表
我认为,一个数据报在netfilter处理的过程中,一直是在softirq中进行的,因此,不可能被其他softirq打断,

如果在一个netfilter的动作,也即target中,直接调用dev_queue_xmit()来发送自己构造的数据报,会出现内存泄漏吗?


1)报文在netfilter处理的过程中,不一定是在softirq中。比如本机发出的报文,可能在进程上下文中。

2)不会内存泄露。倒不是说不可以用dev_queue_xmit(),但这样就bypass了ARP协议等的处理,你必须自己构造链路层桢头。

论坛徽章:
0
发表于 2006-01-09 09:53 |显示全部楼层
楼主的前提是错误的,报文的处理过程不一定在软中断中进行,即使是接收和ip层处理,请参考NAPI和softirqd代码。当接收报文长时间占用软中断后,会启动softirqd内核线程执行报文处理。 内核2.6.15-rt2

感觉楼主想要实现的东西和我以前做过的一个项目很类似,把报文送到用户空间处理,用PF_packet也可以。

用netfilter,使用正确的接口,也不会出现内存泄露。

论坛徽章:
0
发表于 2006-01-09 09:57 |显示全部楼层
原帖由 xiaozhaoz 于 2006-1-9 09:53 发表
楼主的前提是错误的,报文的处理过程不一定在软中断中进行,即使是接收和ip层处理,请参考NAPI和softirqd代码。当接收报文长时间占用软中断后,会启动softirqd内核线程执行报文处理。 内核2.6.15-rt2

感觉楼主 ...


能仔细讲讲NAPI,softirq和接受报文的关系吗?

论坛徽章:
0
发表于 2006-01-09 10:15 |显示全部楼层
hehe,我对数据报直接在内核处理,并不把它转移到用户空间。

所以,不用PF_packet

论坛徽章:
0
发表于 2006-01-09 10:27 |显示全部楼层
NAPI的由来:

NAPI是2.4.20后的内核版本在网卡驱动做的一项优化措施,当年某个商业测试2.2的Linux和Winnt的网络效率,Linux在小包处理吞吐量输了,这个报告引起了很大的争议,后来Linux在驱动采取了一系列的优化措施,NAPI是很重要的一个。

NAPI的原理: 一般情况下,每接收到一个帧,都会出发一次网络中断,然后软中断处理这个报文,直到报文到目的地(转发或用户socket buffer).
现在的做法,大流量情况下,收中断是不启用的。这样收帧不会频繁触发网络中断,而是报文到了一定数量后触发一次中断,如8139网卡。在cp_interrupt()中,会调用NAPI的接口,将网卡加入到softirq任务链表中,然后唤醒softirq, 在softirq中,回调dev中的接口批量处理报文。

        if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
                if (netif_rx_schedule_prep(dev)) {
                        cpw16_f(IntrMask, cp_norx_intr_mask);
                        __netif_rx_schedule(dev);
                }

__netif_rx_schedule() -->
{
        unsigned long flags;

        raw_local_irq_save(flags);
        dev_hold(dev);
/* 将dev加入到软中断处理链表中 */
        list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
        if (dev->quota < 0)
                dev->quota += dev->weight;
        else
                dev->quota = dev->weight;
/* 唤醒软中断 */
        raise_softirq_irqoff(NET_RX_SOFTIRQ);
        raw_local_irq_restore(flags);
}

软中断处理中,会利用dev->poll() 函数,实现一次软中断,处理大量报文,如8139
cp_rx_poll() -->
批量处理网卡buffer中的报文。

softirq处理过程也有同样的优化,正常情况下,所有的报文都是在软中断中完成,但是当软中断一直有处理不完的报文,为了提高系统实时行,软中断处理完一定数量的报文后,必须退出,剩余的报文通过唤醒softirqd 内核线程来完成。
void ___do_softirq(void) -->
/* 如果处理一轮后,仍然后报文要处理,唤醒softirqd任务代为处理 */
        if (pending)
                trigger_softirqs();

trigger_softirqs()-->
static void trigger_softirqs(void)
{
        u32 pending = local_softirq_pending();
        int curr = 0;

        while (pending) {
                if (pending & 1)
                                             /* 唤醒softirqd */
                        wakeup_softirqd(curr);
                pending >>= 1;
                curr++;
        }
}

内核: 2.6.15-rt2

论坛徽章:
0
发表于 2006-01-09 10:55 |显示全部楼层
非常感谢。

ip_rcv,netfilter的处理链都是在softirq中进行的,对吗?

论坛徽章:
0
发表于 2006-01-09 11:04 |显示全部楼层

回复 6楼 xiaozhaoz 的帖子

> 现在的做法,大流量情况下,收中断是不启用的。
> 这样收帧不会频繁触发网络中断,而是报文到了一定数量后触发一次中断

这个说法欠妥,并不是“报文到了一定数量后触发一次中断”,
而是,只有第一个中断会触发,然后NAPI会关中断,进入poll(),持续收包。

论坛徽章:
0
发表于 2006-01-09 12:13 |显示全部楼层

回复 8楼 wheelz 的帖子

同意你的说法。

to guotie:
ip_rcv,netfilter 不一定都是在软中断中进行:
我上面的描述中已经说了:
当软中断持续被触发时,为了保持系统实时行,会将后续的报文处理放到softirqd任务中进行,这时一个内核任务,默认情况下,每个CPU启一个。

所以ip_rcv可能运行在两种上下文中:
1. 软中断 (软中断有自己的栈,但是上下文是在被中断的任务中)
2. softirqd 内核线程

用户程序报文的发送是在自己的上下文中完成。

论坛徽章:
0
发表于 2006-01-09 13:14 |显示全部楼层
非常感谢!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP