Linux内核协议栈的socket查找缓存路由机制

是查路由表快呢?还是查socket哈希表快?这不是问题的根本。问题的根本是怎么有效利用这两者,让两者成为合作者而不是竞争者。这是怎么回事?
       我们知道,如果一个数据包要到达本地,那么它要经过两次查找过程(暂时不考虑conntrack):IP层查找路由和传输层查找socket。怎么合并这两者。
       Linux内核协议栈采用了一种办法:在socket中增加一个dst字段作为缓存路由的手段,skb在查找路由之前首先查找socket,找到的话,就将缓存的dst设置到skb,接下来在查找路由的时候,发现已经有了dst,就省去了路由查找的过程。

问题是,socket的dst字段什么时候设置的呢?当然是“和该socket相关的第一个skb”到来的时候设置上的,无疑即便这第一个skb找到了
socket,此时的socket上的dst也是NULL,那么它会去老老实实查找路由表,如果找到,则将找到的路由项设置到socket的dst字段。
       这个特性在Linux的实现中叫做ip_early_demux,在内核文档中,描述如下:
ip_early_demux - BOOLEAN Optimize input packet processing down to one demux for
    certain kinds of local sockets.  Currently we only do this
    for established TCP sockets.
    It may add an additional cost for pure routing workloads that
    reduces overall throughput, in such case you should disable it.
    Default: 1
对于forward转发,这个特性必然要降低性能,但是我并不是想说这个显而易见的问题,我想说的有两点:
1.层次cache逻辑

们知道,路由查找是一个“尽力而为”的多对一匹配过程,skb和路由entry并不是精确的一一对应关系,因此不能在路由entry中缓存socket,
但是却可以在socket中缓存路由entry,因为socket和skb是一个一一对应的关系(我说的不是TCP listen
socket..),同样,我也能在路由cache中缓存socket,因为路由cache和skb也是一一对应的关系。
      
然而linux内核还是去掉了路由cache的支持,不过这没关系,只要知道一点就够了:一一对应的精确匹配项可以缓存更加松散的非一一对应的匹配项。如
果将目光移到conntrack,就知道该怎么做了,我曾经将路由entry缓存到了conntrack里面,按照这个逻辑,是合理的,同样
的,socket也可以被缓存到conntrack里面,这一点已经有了iptables相关的match和target。
2.自动还是手动

然Linux有了ip_early_demux配置参数,问题就是什么时候开启它而什么时候关闭它。特别是,在你事先不知道有多少包是到达本地,有多少包
是forward的情况下,这个问题显得更加不易回答。此时,是相信管理员的非0即1的配置呢,还是让系统去动态自适应?
      
如何统计包显得尤为重要,典型情况下,如果有超过60%的包是到达本地的,那么就开启它,反之则关闭它。ip_early_demux配置参数作为一个全
局的参数并没有什么不好,因为如果不是这样,那么就会出现另一个问题,即如何判断一个包是否要进行early_demux...对于边界非七层设备,一般
而言,流量是分类的,分为管理面流量和数据面流量,对于前者而言,流量的终点就是本地,而对于后者,本机仅仅做forward,如果能事先高效地将包进行
平面分类,那么两个ip_early_demux配置会显得更好,对于带外管理而言,Linux的nsnamespace可以很好地完成这个任务。

时间: 2024-10-04 12:49:44

Linux内核协议栈的socket查找缓存路由机制的相关文章

模仿Linux内核kfifo实现的循环缓存

http://www.cnblogs.com/wangguchangqing/p/6070286.html 想实现个循环缓冲区(Circular Buffer),搜了些资料多数是基于循环队列的实现方式.使用一个变量存放缓冲区中的数据长度或者空出来一个空间来判断缓冲区是否满了.偶然间看到分析Linux内核的循环缓冲队列kfifo的实现,确实极其巧妙.kfifo主要有以下特点: 保证缓冲空间的大小为2的次幂,不是的向上取整为2的次幂. 使用无符号整数保存输入(in)和输出(out)的位置,在输入输出

解析 Linux 内核可装载模块的版本检查机制

转自:http://www.ibm.com/developerworks/cn/linux/l-cn-kernelmodules/ 为保持 Linux 内核的稳定与可持续发展,内核在发展过程中引进了可装载模块这一特性.内核可装载模块就是可在内核运行时加载到内核的一组代码.通常 , 我们会在两个版本不同的内核上装载同一模块失败,即使是在两个相邻的补丁级(Patch Level)版本上.这是因为内核在引入可装载模块的同时,对模块采取了版本信息校验.这是一个与模块代码无关,却与内核相连的机制.该校验机

把握linux内核设计(三):下半部机制之软中断

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 中断处理程序以异步方式执行,其会打断其他重要代码,其运行时该中断同级的其他中断会被屏蔽,并且当前处理器上所有其他中断都有可能会被屏蔽掉,还有中断处理程序不能阻塞,所以中断处理需要尽快结束.由于中断处理程序的这些缺陷,导致了中断处理程序只是整个硬件中断处理流程的一部分,对于那些对时间要求不高的任务,留给中断处理流程的另外一部分,也就是本节要讲的中断处理流程的下半部. 那哪些工作

Linux内核协议栈 NAT性能优化之FAST NAT

各位看官非常对不起,本文是用因为写的,如果多有不便敬请见谅 代码是在商业公司编写的,在商业产品中也不能开源,再次抱歉 This presentation will highlight our efforts on optimizing the Linux TCP/IP stack for providing networking in an OpenStack environment, as deployed at our industrial customers. Our primary go

把握linux内核设计(四):下半部机制之tasklet

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] tasklet是利用软中断实现的一种下半部机制.tasklet相比于软中断,其接口更加简单方便,锁保护要求较低. tasklet由tasklet_struct结构体表示: struct tasklet_struct { struct tasklet_struct *next; //链表中下一个tasklet unsigned long state; //tasklet状态 a

把握linux内核设计(五):下半部机制之工作队列及几种机制的选择

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 工作队列是下半部的另外一种将工作推后执行形式.和软中断.tasklet不同,工作队列将工作推后交由一个内核线程去执行,并且该下半部总会在进程上下文中执行.这样,工作队列允许重新调度甚至是睡眠. 所以,如果推后执行的任务需要睡眠,就选择工作队列.如果不需要睡眠,那就选择软中断或tasklet.工作队列是唯一能在进程上下文中运行的下半部实现机制,也只有它才可以睡眠. 工作队列子系

linux内核网络协议栈架构分析,全流程分析-干货

https://download.csdn.net/download/wuhuacai/10157233 https://blog.csdn.net/zxorange321/article/details/75676063 LINUX内核协议栈分析 目  录 1      说明...4 2      TCP协议...4 2.1       分层...4 2.2       TCP/IP的分层...5 2.3       互联网的地址...6 2.4       封装...7 2.5       

理解 Linux 网络栈 (Linux networking stack)(1):Linux 网络协议栈简单总结

本系列文章总结 Linux 网络栈,包括: (1)Linux 网络协议栈总结 (2)非虚拟化Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO (3)QEMU/KVM虚拟化 Linux 环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO 1. Linux 网络路径 1.1 发送端 1.1.1 应用层 (1) Socket 应用层的各种网络应用程序基本上都是通过 Linux Socket 编程接口来和内核空间的网络协议栈通信的.Linux Socket 是从

linux 内核与用户空间通信之netlink使用方法

linux 内核与用户空间通信之netlink使用方法 1 引言 Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&T Unix和BSD Unix在进程通信实现机制上的各有所不同,前者形成了运行在单个计算机上的System V IPC,后者则实现了基于socket的进程间通信机制.同时Linux也遵循IEEE制定的Posix IPC标准,在三者的基础之上实现了以下几种主要的IPC机制:管道(Pipe)及命名管道(Named Pipe),信号(Signal),