方便随时查看,对Linux内核来说

  • 栏目:软件 时间:2020-04-02 02:57
<返回列表

贾斯玻.布鲁勒在2015年澳大利亚Linux研讨会(LCA)的有关内核的小型研讨会上提到:100GB的网卡即将来临(见幻灯片,PDF格式的)。对Linux内核来说,要以最大的速度驱动这样的适配器将是巨大的挑战。应对这一挑战是目前和未来一段时间内工作的重心。好消息是Linux网络通信速度已经有了很大的提高-不过还有一些问题有待解决。

翻译来自这里

##使用过程中查了很多资料,特整理如下,方便随时查看##

挑战

由于网络适配器的速度越来越快,那么发送数据包的时间间隔(也就是内核处理一个包的时间)就会越来越短。就当前正在使用的10GB适配器而言,发送两个1538字节数据包的时间间隔是1230纳秒,40GB的网络通信会把这个时间间隔大幅缩减到307纳秒。很自然,100GB的网络适配器会急剧缩减这个时间间隔,即缩减一个包的处理时间大约为120纳秒。此时,网卡每秒就要处理八百一十五万个数据包。这样就不会有太多时间来进行数据包的处理了。

那么,如果像大多数人一样没有100GB的网络适配器把玩一下,你该怎么做呢? 你可以替代性地使用10GB的网络适配器发送很小的帧。以太网所能发送的最小帧长度是84字节;贾斯玻说使用10G网络适配器发送最小尺寸的以太网帧的时间间隔是67.2纳秒。能够处理最小尺寸以太网帧负载的系统就适宜于处理100GB的网络通信,不过目前还未实现。而且对这种负载的处理也非常困难:对一个3GHz的CPU来说,处理一个包只需要200个CPU周期。贾斯玻还提醒说:这点时间本身就不算多。

以往,内核就没有在处理密集型网络通信的工作负载方面做太多工作。这也使得大量次要的网络通信实现完全不包含在内核网络协议栈中。如此的系统需求就表明内核没有充分利用上硬件;由单个CPU执行的次要实现就可以以最大速度驱动适配器,这就是内核主线开发犯难的地方。

贾斯玻说现在的问题是:内核开发人员过去曾经集中力量添加多核支持。在此情形下,他们就不会关心单核运行效率的衰退情况。由此而产生的结果就是:现今的网络通信协议栈可以很好地处理许多种工作负载,然而对于哪些对时延特别敏感的工作负载则无能为力了。现今的内核每秒每核心只能处理一百万到两百万之间个数据包,而某些不使用内核的方法每秒每核心可处理的数据包数可达一千五百万个。

介绍

NFQUEUE是一个iptables和ip6tables目标,它将数据包的决定委托给用户空间软件。 例如,以下规则将要求所有去往包的数据包都要听取用户安全计划的决定:

iptables -A INPUT -j NFQUEUE --queue-num 0

在用户空间中,一个软件必须使用libnetfilter_queue连接到队列0(默认的)并从内核获取消息。 然后它必须对包进行判决。

##介绍##

报文分组从输入网卡(入口)接收进来,经过路由的查找,以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的,则会从输出网卡(出口)发出。网络流量的控制通常发生在输出网卡处,Linux内核中由TC(Traffic Control)实现。TC是利用队列规定建立处理数据包的队列,并定义队列中的数据包被发送的方式,从而实现流量控制。基本原理:

图片 1

接收包从输入接口(Input Interface)进来后,经过流量限制(Ingress Policing)丢弃不符合规定的数据包,由输入多路分配器(Input De-Multiplexing)进行判断选择。如果接收包的目的地是本主机,那么将该包送给上层处理,否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。转发块同时也接收本主机上层(TCP、UDP等)产生的包。转发块通过查看路由表,决定所处理包的下一跳。然后,对包进行排列以便将它们传送到输出接口(Output Interface)。一般我们只能限制网卡发送的数据包,不能限制网卡接收的数据包,所以我们可以通过改变发送次序来控制传输速率。

预算所需时间

如果你打算解决这个问题,那么你就需要仔细地看看处理一个包的每一个步骤所花费的时间。例如,贾斯玻提到的3GHz的处理器上出现一次高速缓冲未命中需要32纳秒才找到对应的数据。因此,只要有两次未命中就可以占完处理一个数据包所需要的时间。假如套接字缓冲(“SKB”)在64位系统上占有四个高速缓冲行,而且许多套接字缓冲(“SKB”)都是在包处理期间写入的,那么问题的第一部分就非常明显了-四次高速缓冲未命中需要的时间将会比可使用的时间更长。

除上述外,X86架构上的锁的原子级别的操作大概需要费时8.25ns. 也就是说,在实践中一次最短的自旋锁的上锁/解锁的过程就要耗时16ns还多一点。 所以尽管有大量的锁操作,但是在这方面却没有多少空间可以降低延时。

接下来是与系统进行一次通信的时间消耗。在安装有SELinux及审计功能(auditing enabled)的系统上,一次系统的调用就要耗时75ns — 超过了帧处理的整个时间。 禁用审计和SELinux可以减少时间,使系统通信降到42ns以下。这看上去好多了,但是还是很大的时间消耗。有许多方法可以在处理多个包的时候降低时间消耗,包括调用sendmmsg(),recvmmsg(),sendfile()和splice()这样的函数。但是在实际中,有开发者觉得这些函数的表现并不如预期的那么好,但是他们又找不出原因。Chirstoph Lameter站在旁观者的角度指出来说,那些对延时敏感的用户可以倾向于使用InfiniBand架构的“IB verbs”机制。

贾斯玻询问:如果上面所要花费的时间已经确定,那么不需要网络通信的方案是如何获得更高的性能呢?关键在于批量进行操作处理和资源的预分配和预获取。这样的操作始终在CPU范围内运行,而且不需要上锁。这些因素对于缩减包的元数据和减少系统调用的次数来说也非常重要。要想在速度上再提高一点,哪些可充分利用高速缓冲的数据结构可以帮一些忙。在上面所述的所有技术中,批量进行操作处理是最最重要的。一个包所需要的处理时间可能无法接受,但如果是一次性执行多个包的话,你就很容易接受了。一个包加锁需要16纳秒让人很受伤,如果一次性加锁16个包,那么每个包所需要的处理时间就缩减到1纳秒了。

内在工作

要理解NFQUEUE,最简单的方法就是了解Linux内核的架构。 当一个数据包到达一个NFQUEUE目标时,它就会进入与--queue-num选项给定的编号对应的队列。 数据包队列被实现为链接列表,元素是数据包和元数据(Linux内核skb):

这在用户空间方面有一些含义:

##流量控制对象:QDISC(排队规则)  CLASS(类别)  FILTER(过滤器)##

流量控制的一个基本概念是队列(Qdisc),每个网卡都与一个队列(Qdisc)相联系每当内核需要将报文分组从网卡发送出去,都会首先将该报文分组添加到该网卡所配置的队列中,由该队列决定报文分组的发送顺序。因此可以说,所有的流量控制都发生在队列中。有些队列的功能是非常简单的,它们对报文分组实行先来先走的策略。有些队列则功能复杂,会将不同的报文分组进行排队、分类,并根据不同的原则,以不同的顺序发送队列中的报文分组。为实现这样的功能,这些复杂的队列需要使用不同的过滤器(Filter)来把报文分组分成不同的类别(Class)。这里把这些复杂的队列称为可分类(Classiful)的队列。通常,要实现功能强大的流量控制,可分类的队列是必不可少的。因此,类别(Class)和过滤器(Filter)也是流量控制的另外两个重要的基本概念。类别(Class)和过滤器(Filter)是队列的内部结构,并且可分类的队列可以包含多个类别,同时,一个类别又可以进一步包含有子队列,或者子类别。所有进入该类别的报文分组可以依据不同的原则放入不同的子队列 或子类别中,以此类推。而过滤器(Filter)是队列用来对数据报文进行分类的工具,它决定一个数据报文将被分配到哪个类别中。

在Linux中,可以配置很多类型的队列,比如CBQ、HTB等,其中CBQ 比较复杂,不容易理解。HTB(Hierarchical Token Bucket)是一个可分类的队列, 与其他复杂的队列类型相比,HTB具有功能强大、配置简单及容易上手等优点。

在TC中,使用"major:minor"这样的句柄来标识队列和类别,其中major和minor都是数字。对于队列来说,minor总是为0,即"major:0"这样的形式,也可以简写为"major: "。比如,队列1:0可以简写为1:。需要注意的是,major在一个网卡的所有队列中必须是惟一的。对于类别来说,其major必须和它的父类别或父队列的major相同,而minor在一个队列内部则必须是惟一的(因为类别肯定是包含在某个队列中的)。举个例子,如果队列2:包含两个类别,则这两个类别的句柄必须是2:x这样的形式,并且它们的x不能相同,比如2:1和2:2

对批量操作的改进

因此,毫不奇怪,贾斯玻的工作过去曾经集中精力改进网络层的批量操作。其中包括 TCP 层的批量传输工作,这里十月份的文章中有所介绍;有关它是如何运行的详细情况请参阅上面链接的那篇文章。简要的来说,机制是这样的:通知网络驱动还有更多的数据包等着传输,让驱动延迟花费时间较多的操作,直到所有的包都填满队列。如果把这样的修改放在适当的地方,那么在同样小的数据包一个接着一个传输的情况下,他编写的系统每秒至少能传输一千四百八十万个数据包。

他说做到这些技巧在于给网络通信层添加了进行批量操作处理的应用程序接口(API),同时不会增加系统延迟时间。通常,延迟和吞吐量之间必须要进行某种权衡;然而,在这里,延迟和吞吐量都有所改进。特别难于处理的技巧是对传输延迟的推测-这就好比赌博后续的包马上就到来。这样的技巧常常用在改进基准测试的结果上,在现实世界中的工作负载上极少用到。

批量操作可以并且应当在通信协议栈的的多个层实现。例如,排队子系统(“qdisc”)就是非常适合进行批量操作;毕竟,排队就意味着延迟。目前,在最理想的情况下,排队子系统(“qdisc”) 编码部分处理一个包需要六个锁操作-仅锁操作就需要48纳秒。而对一个包进行排队处理的全部时间是58-68纳秒,可见大量的时间都用在锁操作上了。贾斯玻已经添加了批量操作,这样就可以把所消耗的时间分散在对多个包的处理上了,不过,这段代码实只在对包进行排队的情况下才运行。

排队子系统(“qdisc”)代码名义上的最快运行路径只有在不进行排队的情况下才运行;此时,这些包通常直接传送给网络接口,根本就不需要进行排队处理。不过目前,处理这些包依然需要完完整整地进行6次锁操作。他说,改进这样的处理过程是可能的。无锁的排队子系统几乎不需要花费时间对包进行排队处理,贾斯玻对现有的实现进行了测试,确定了哪些地方可以优化,他说,至少剔除48纳秒的锁操作就值得一试。

他说,传输的性能现在看起来已经够好了,不过接收的处理过程仍然可以进行改进。一个调整的非常好的接收系统每秒可接收的最大包数目大约是六百五十万个-不过这种情况只在接收到包后即刻就丢弃的情况下才发生。优化接收过程的一些工作一直在进行着,最大处理速度可提升到每秒处理九百多万个数据包。然而,对优化后的基准测试也暴露出了问题,它没有给出与内存管理子系统交互所花费的时间。

关于内核和用户空间之间的协议有几句话

内核和用户空间之间使用的协议是nfnetlink。 这是一个基于消息的协议,不涉及任何共享内存。 当一个数据包进入队列时,内核发送一个包含数据包数据和相关信息的nfnetlink格式的消息到一个套接字,用户空间读取这个消息。 为了做出判定,用户空间格式化一个包含索引号的nfnetlink消息并发送给通信套接字。

##使用基本步骤##

Linux流量控制主要分为建立队列、建立分类和建立过滤器三个方面。

1) 针对网络物理设备(如以太网卡eth0)绑定一个队列qdisc;

2) 在该队列上建立分类class;

3) 为每一分类建立一个基于路由的过滤器filter;

4) 最后与过滤器相配合,建立特定的路由表。

内存管理

有证据表明与内存管理系统的交互很花时间。网络通信栈的接收过程似乎采用了这样的行为:使用slab分配器时其性能不是最佳。接收代码每次可给高达64个包进行内存空间分配,而传输过程的批处理操作中可释放内存的包数目达256个。这样的模式似乎特意把SLUB分配器用到了相对处理较慢的代码段上了。贾斯玻对其进行了一些小型基准测试,他发现在kmam_cache_free()后只有调用kemem_cache_alloc()一次需要大约19纳秒。然而,当完成256次分配和释放时,所需要的时间就会增加到40纳秒。实际的网络通信中,内存分配和释放是与其他操作同时进行的,这样内存分配和释放所花费的时间就会更多,高达77纳秒-超过预计分配给它的时间。

因此,贾斯玻得出这样的结论:要么必须对内存管理代码部分进行改进,要么必须通过某钟方式完全绕过这段代码。为了看看后一种方法是否可行,他实现了qmempool子系统;这个子系统可以以无锁的方式批量进行内存分配和释放。通过使用qmempool,他在简单测试中节省了12纳秒,而在包转发测试中则节省高达40纳秒。qmempool为了使自身运行更快采用了许多技术,然而杀手级技术是批量处理操作。

贾斯玻平静地说:qmempool的实现是一种激励。他想去表明哪些地方可以进行修改,同时鼓励内存管理系统的开发人员在这方面做些工作。内存管理团队的回应将在下一次谈话中介绍,我们将单独对其进行报导。

在C中使用libnetfilter_queue

libnetfiler_queue的主要信息来源是Doxygen生成的文档。

库的使用有三个步骤:

##相关单位##

tc命令所有的参数都可以使用浮点数,可能会涉及到以下计数单位。

带宽或流速单位:

kbps  千字节/s               mbps 兆字节/s     (bps或者一个无单位数字,表示字节数/s)

kbit  KBits/s                   mbit  MBits/s

数据的数量单位

kb或k  千字节                 mb或m 兆字节  (b或者一个无单位数字,字节)

kbit     千bit                    mbit 兆bit   

时间的计量单位

s, sec或secs   秒            ms, msec或mescs  毫秒

us, use, usecs或一个无单位数字  微s

示例软件架构

最简单的架构是由一个线程读取数据包并发布判决。 下面的代码不完整,但显示了实现的逻辑。

/* Definition of callback function */
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
              struct nfq_data *nfa, void *data)
{
    int verdict;
    u_int32_t id = treat_pkt(nfa, &verdict); /* Treat packet */
    return nfq_set_verdict(qh, id, verdict, 0, NULL); /* Verdict packet */
}

/* Set callback function */
qh = nfq_create_queue(h,  0, &cb, NULL);
for (;;) {
    if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
        nfq_handle_packet(h, buf, rv); /* send packet to callback */
        continue;
    }
}

读线程和判决线程也是可能的:

PacketPool *ppool;

/* Definition of callback function */
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
              struct nfq_data *nfa, void *data)
{
    /* Simply copy packet date and send them to a packet pool */
    return push_packet_to_pool(ppool, nfa);
}

int main() {
    /* Set callback function */
    qh = nfq_create_queue(h,  0, &cb, NULL);
    /* create reading thread */
    pthread_create(read_thread_id, NULL, read_thread, qh);
    /* create verdict thread */
    pthread_create(write_thread_id, NULL, verdict_thread, qh);
    /* ... */
}

static void *read_thread(void *fd)
{
    for (;;) {
        if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
            nfq_handle_packet(h, buf, rv); /* send packet to callback */
            continue;
        }
    }
}

static void *verdict_thread(void *fd)
{
    for (;;) {
        Packet p = fetch_packet_from_pool(ppool);
        u_int32_t id = treat_pkt(nfa, &verdict); /* Treat packet */
        nfq_set_verdict(qh, id, verdict, 0, NULL); /* Verdict packet */
    }
}

##举例##

『创建根队列--》创建类别class--》为类别创建对应过滤器,对应网卡接收的数据包会一层一层下发到过滤器进行过滤或相关处理』

1)为网卡创建根队列或htb队列或cbq队列

有关队列的TC命令的一般形式为:

# tc qdisc [add | change | replace | link] dev DEV [parent qdisk-id |root] [handle qdisc-id] qdisc [qdisc specific parameters]

==》sar -n DEV 1 2 命令查看当前机器所使用的以太网卡是哪个

==》tc qdisc add dev eth1 root handle 1: prio

       为网卡eth1建议一个队列,名字为root,句柄为1

 ==》tc qdisc add dev eth1 root handle 1:htb default 11

        为网卡eth1添加root根队列,"handle 1:"表示队列的句柄为1: ,"htb"表示要添加的队列为HTB队列,命令最后的"default 11"是htb特有的队列参数,意思是所有未分类的流量都将分配给类别1:11。

==》tc qdisc add dev xgbe0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8;为网卡xbge0创建一个cbq队列,限制网卡总带宽为100Mbit/s,avpkt表示平均包大小,单位字节,avpkt 1000表示平均包大小为1000B,cell表示一个数据包被发送出去的平均时间,通常设置为8,必须是2的整数次幂

2)为根队列创建相应的类别,对于句柄编号一般根队列为一位数,子类别为两位数

有关类别的TC 命令的一般形式为:

# tc class [add | change | replace] dev DEV parent qdisc-id [classid class-id] qdisc [qdisc specific parameters]

可以利用下面这三个命令为根队列1创建三个类别,分别是1:11、1:12和1:13,它们分别占用40、40和20mbit的带宽。

  tc class add dev eth1 parent 1: classid 1:11 htb rate 40mbit ceil 40mbit

  tc class add dev eth1 parent 1: classid 1:12 htb rate 40mbit ceil 40mbit

  tc class add dev eth1 parent 1: cllassid 1:13 htb rate 20mbit ceil 20mbit

命令中,"parent 1:"表示类别的父亲为根队列1: 。"classid1:11"表示创建一个标识为1:11的类别,"rate 40mbit"表示系统将为该类别确保带宽40mbit,"ceil 40mbit",表示该类别的最高可占用带宽为40mbit。

3)为各个类别设置过滤器

有关过滤器的TC 命令的一般形式为:

# tc filter [add | change | replace] dev DEV [parent qdisc-id | root] protocol protocol prio priority filtertype [filtertype specific parameters] flowid flow-id

比如,需要将WWW、E-mail、Telnet三种流量分配到三个类别,即上述1:11、1:12和1:13,因此,需要创建三个过滤器,如下面的三个命令:

# tc filter add dev eth0  parent 1:0 protocol ip prio 1 u32 match ip dport 80 0xffff flowid 1:11 

# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 25 0xffff flowid 1:12 

# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 23 oxffff flowid 1:13

这里,"protocol ip"表示该过滤器应该检查报文分组的协议字段。"prio 1"表示它们对报文处理的优先级是相同的。对于不同优先级的过滤器,系统将按照从小到大的优先级顺序来执行过滤器,对于相同的优先级,系统将按照命令的先后顺序执行。这几个过滤器还用到了u32选择器(命令中u32后面的部分)来匹配不同的数据流。以第一个命令为例,判断的是dport字段,如果该字段与0xffff进行与操作的结果是80,则"flowid 1:11"表示将把该数据流分配给类别1:11。更加详细的有关TC的用法可以参考TC的手册页。

4)查看当前网卡上配过的流量控制规则

    # tc[-s | -d ] qdisc show [ dev DEV ]               tc -s qdisc show dev eth1

    # tc[-s | -d ] class show dev DEV  

    # tc filter show dev DEV

    # tc -s -d qdisc ls

5)删除已配置的规则

    # tc qdisc del dev eth1 root

其他语言

Pierre Chifflier(又名pollux)开发了libnetfilter_queue的绑定,可以用于大多数高级语言(python,perl,ruby,...):nfqueue-bindings。

##实际项目使用场景篇##

1)配合netem模块对特定ip或port模拟超时(netem 是 Linux2.6 及以上内核版本提供的一个网络模拟功能模块。该功能模块可以用来在性能良好的局域网中,模拟出复杂的互联网传输性能,诸如低带宽、传输延迟、丢包等等情况。tc 可以用来控制 netem 的工作模式,也就是说,如果想使用 netem ,需要至少两个条件,一个是内核中的 netem 功能被包含,另一个是要有 tc 。)##亲测有效##

# tc qdisc add dev xgbe0 root netem delay 100ms  ##这个是对整个网卡xgbe0的数据包延迟100ms发送。如果要对发送到特定ip或从特定端口发送的数据包延迟100ms,再加下面的命令设置class和filter。

# tc class add dev xgbe0 parent 1: classid 1:11

# tc filter add dev xgbe0 parent 1:0 protocol ip  prio 1 u32 match ip dst 10.10.10.91 flowid 1:1 ##到特定ip

# tc filter add dev xgbe0 parent 1:0 protocol ip  prio 1 u32 match ip dport 9988 flowid 1:1 ##从特定port发出的

2)模拟丢包

# tc  qdisc  add  dev  eth0  root  netem  loss  1% 

该命令将eth0网卡的传输设置为随机丢掉1%的数据包,也是对整个网卡有效,如果也是要特定ip或port试着按上述进行配置class和filter

也可以设置丢包的成功率:

# tc  qdisc  add  dev  eth0  root  netem  loss  1%  30%

该命令将eth0网卡的传输设置为随机丢掉1%的数据包,成功率为30%。

3)模拟包损坏 ##没试过##

# tc  qdisc  add  dev  eth0  root  netem  corrupt  0.2%

该命令将eth0网卡的传输设置为随机产生0.2%的损坏的数据包 。 (内核版本需在2.6.16以上)

4)模拟包乱序

# tc  qdisc  change  dev  eth0  root  netem  delay  10ms   reorder  25%  50%

该命令将eth0网卡的传输设置为:有25%的数据包(50%相关)会被立即发送,其他的延迟10ms。

新版本中,如下命令也会在一定程度上打乱发包的次序:

# tc  qdisc  add  dev  eth0  root  netem  delay  100ms  10ms

5)模拟包重复

# tc  qdisc  add  dev  eth0  root  netem  duplicate 1%

该命令将eth0网卡的传输设置为随机产生1%的重复数据包 。

6)模拟网络抖动

可以写个脚本进行loop:先tc命令设置好延时——》隔随机时间后,将tc规则删除-->再隔随机时间后,tc命令加入延时如此往复

脚本运行期间就可以看服务在网络抖动时整体时延或资源消耗是否符合预期或是否出现服务异常warning日志等。

高级功能

##使用之中遇到的几个问题##

1)tc执行必须root账号;只针对出口流量有效

2)如果机器是64位,执行tc之前先创建一个软链,不然在用netem库时会出现错误『[Netem] Unknown qdisc "netem"』:ln -s /usr/lib64/tc/ /usr/lib/tc

参考:

1. linux下流量控制工具TC详细说明及应用实例   写得很赞的一篇博文

  1. Linux TC 带宽管理队列规则   

  2. Linux TC(Traffic Control) 简介(一)

  3. Linux 流量控制工具 TC 详解

5. Linux网络流量控制工具—Netem

多队列

--queue-balance是Florian Westphal添加的NFQUEUE选项,可以将通过相同iptables规则排队的平衡分组加载到多个队列中。 用法相当简单。 例如,要将INPUT流量负载平衡到队列0到3,可以使用以下规则。

iptables -A INPUT -j NFQUEUE --queue-balance 0:3

有一点需要提及的是,负载平衡是针对流而言的,并且流的所有分组都被发送到相同的队列。
这个扩展是从Linux内核2.6.31和iptables v1.4.5开始的。

queue-bypass

--queue-bypass在其他NFQUEUE选项上设置了排队旁路。 当没有用户空间软件连接到队列时,它改变了iptables规则的行为。 如果没有软件正在监听队列,则数据包将被授权,而不是丢弃数据包。

从Linux内核2.6.39和iptables v1.4.11开始扩展。

这个特性从内核3.10到3.12被破坏:当使用最近的iptables时,传递选项--queue-bypass对这些内核没有影响。

fail-open

这个选项在Linux 3.6以后是可用的,并且允许接受数据包,而不是在队列满时丢弃数据包。 一个示例用法可以在suricata中找到。

批量判决

从Linux 3.1开始,可以使用批量判定。 不要为一个数据包发送一个判决,而是可以向一个id低于给定id的数据包发送判决。 为此,必须使用nfq_set_verdict_batch或nfq_set_verdict_batch2函数。

该系统具有性能优势,因为消息的限制增加了分组速率。 但是它可以引起延迟,因为数据包一次被判决。 因此,用户空间软件有责任找到自适应技术,通过更快地发布判决来限制延迟,特别是在数据包较少的情况下。

杂项

/proc中的nfnetlink_queue条目
nfnetlink_queue在/ proc:/proc/net/netfilter/ nfnetlink_queue中有一个专用的入口

cat /proc/net/netfilter/nfnetlink_queue 
   40  23948     0 2 65531     0     0      106  1

695/5000
内容如下:

经常问的问题

libnetfilter_queue和多线程
libnetfilter_queue取决于发送到套接字的消息。 send / recv操作需要通过锁保护,以避免并发写入。 这意味着nfq_set_verdict2和nfq_handle_packet函数需要通过锁定机制来保护。

接收消息和发送消息是完全独立的操作,不共享任何内存。 特别是判决只使用包索引作为信息。 因此,只要锁定不同,线程就可以为队列中的任何数据包进行判定。

数据包重新排序

使用NFQUEUE可以轻松地进行数据包重新排序,因为可以对任何已排队的数据包进行判定操作。 尽管有一点需要考虑的是排队数据包的内核实现是通过链表来实现的。 所以判断不在列表开头的数据包是昂贵的(最老的数据包是第一个)。

libnetfilter_queue和零拷贝

由于内核和用户空间之间的通信基于发送到netlink套接字的消息,因此不存在零拷贝等问题。 Patrick McHardy已经启动了netlink的内存映射实现,因此将来可能会有零拷贝。

上一篇:3.Linux使用 Shell检测进程内存使用量,2.Linux使用 Shell检测进程 CPU 利用率 下一篇:我们可以查看默认网关

更多阅读

方便随时查看,对Linux内核来说

软件 2020-04-02
贾斯玻.布鲁勒在2015年澳大利亚Linux研讨会(LCA)的有关内核的小型研讨会上提到:100GB的网卡...
查看全文

韦德体育工具不是目的,到底要不要桌面

软件 2020-04-02
建议读者范围 有开发经验者。 科研人员(由其Numrical)。 动手能力强的。 只是好奇,对于L...
查看全文

我们可以查看默认网关

软件 2020-04-02
问:1 如何查看当前的Linux服务器的运行级别? 答: ‘who -r’ 和 ‘runlevel’ 命令可以用来查看当...
查看全文

友情链接: 网站地图

Copyright © 2015-2019 http://www.koi-bumi.com. 韦德体育有限公司 版权所有