linux中,管理网卡收发报文的结构是sk_buff,这个结构比freebsd中的m_buf复杂的多,这个也是为什么现在用户态协议栈大多采用bsd为基础来实现的一个原因。

struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;-------------有没有人想过为啥不用内核标准的list来,而是单独两个成员?如果你有好的想法,可以跟我讨论。
struct sk_buff *prev;
#ifdef __GENKSYMS__
ktime_t tstamp;
#else
union {
ktime_t tstamp;
struct skb_mstamp skb_mstamp;
};
#endif
struct sock *sk;
struct net_device *dev; /*
* This is the control buffer. It is free to use for every
* layer. Please put your private variables there. If you
* want to keep them across layers you have to do a skb_clone()
* first. This is owned by whoever has the skb queued ATM.
*/
char cb[] __aligned();------------------------------------这个可以看很多private的处理 unsigned long _skb_refdst;
#ifdef CONFIG_XFRM
struct sec_path *sp;
#endif
unsigned int len,
data_len;
__u16 mac_len,
hdr_len;
union {
__wsum csum;
struct {
__u16 csum_start;
__u16 csum_offset;
};
};
__u32 priority;
kmemcheck_bitfield_begin(flags1);
__u8 RH_KABI_RENAME(local_df, ignore_df):,
cloned:,
ip_summed:,
nohdr:,
nfctinfo:;
__u8 pkt_type:,
fclone:,
ipvs_property:,
peeked:,
nf_trace:;
kmemcheck_bitfield_end(flags1);
__be16 protocol; void (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct nf_conntrack *nfct;
#endif
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct nf_bridge_info *nf_bridge;
#endif /* fields enclosed in headers_start/headers_end are copied
* using a single memcpy() in __copy_skb_header()
*/
/* private: */
RH_KABI_EXTEND(__u32 headers_start[])
/* public: */ int skb_iif; RH_KABI_REPLACE(__u32 rxhash,
__u32 hash) __be16 vlan_proto;
__u16 vlan_tci; #ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
__u16 tc_verd; /* traffic control verdict */
#endif
#endif __u16 queue_mapping;
kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:;
#endif
__u8 pfmemalloc:;
__u8 ooo_okay:;
__u8 RH_KABI_RENAME(l4_rxhash, l4_hash):;
__u8 wifi_acked_valid:;
__u8 wifi_acked:;
__u8 no_fcs:;
__u8 head_frag:;
/* Indicates the inner headers are valid in the skbuff. */
__u8 encapsulation:;
RH_KABI_EXTEND(__u8 encap_hdr_csum:)-----------------------这个使用在我之前一篇博客中有描述。
RH_KABI_EXTEND(__u8 csum_valid:)
RH_KABI_EXTEND(__u8 csum_complete_sw:)
RH_KABI_EXTEND(__u8 xmit_more:)
RH_KABI_EXTEND(__u8 inner_protocol_type:)
RH_KABI_EXTEND(__u8 remcsum_offload:)
/* 0/2 bit hole (depending on ndisc_nodetype presence) */
kmemcheck_bitfield_end(flags2); #if defined CONFIG_NET_DMA_RH_KABI || defined CONFIG_NET_RX_BUSY_POLL || defined CONFIG_XPS
union {
unsigned int napi_id;
RH_KABI_EXTEND(unsigned int sender_cpu)
RH_KABI_DEPRECATE(dma_cookie_t, dma_cookie)
};
#endif
#ifdef CONFIG_NETWORK_SECMARK
__u32 secmark;
#endif
union {
__u32 mark;
__u32 dropcount;
__u32 reserved_tailroom;
}; #ifdef __GENKSYMS__
__be16 inner_protocol;
#else
union {
__be16 inner_protocol;
__u8 inner_ipproto;
};
#endif __u16 inner_transport_header;
__u16 inner_network_header;
__u16 inner_mac_header;
__u16 transport_header;
__u16 network_header;
__u16 mac_header; RH_KABI_EXTEND(kmemcheck_bitfield_begin(flags3))
RH_KABI_EXTEND(__u8 csum_level:)
RH_KABI_EXTEND(__u8 rh_csum_pad:)
RH_KABI_EXTEND(__u8 csum_bad:)
RH_KABI_EXTEND(__u8 offload_fwd_mark:)
RH_KABI_EXTEND(__u8 sw_hash:)
RH_KABI_EXTEND(__u8 csum_not_inet:)
RH_KABI_EXTEND(__u8 dst_pending_confirm:)
/* 8 bit hole */
RH_KABI_EXTEND(kmemcheck_bitfield_end(flags3)) /* private: */
RH_KABI_EXTEND(__u32 headers_end[])
/* public: */ /* RHEL SPECIFIC
*
* The following padding has been inserted before ABI freeze to
* allow extending the structure while preserve ABI. Feel free
* to replace reserved slots with required structure field
* additions of your backport, eventually moving the replaced slot
* before headers_end, if it need to be copied by __copy_skb_header()
*/
u32 rh_reserved1;
u32 rh_reserved2;
u32 rh_reserved3;
u32 rh_reserved4; /* These elements must be at the end, see alloc_skb() for details. */
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head,
*data;
unsigned int truesize;
atomic_t users;
};

skb是管理结构,目前linux 3.10是使用slub的方式来管理skb的缓存,但这个管理有没有什么问题?

据说曾经有人测试过,在2G主频上的cpu从slab中分配一个skb需要耗时4us,这个我自己没有测试过,我想如果是获取的slab位于percpu上,应该不需要这么长时间。但是只要看过slab的管理的话,应该也明白这个消耗虽然比从buddly中分配要小很多,但是从绝对值来说也不会太少。对于大量需要消耗skb的网络服务器来说,申请skb和释放skb的消耗就显得比较重了。

解决方法:

1.做一个自己的skb的缓存池,这样申请的时候,不走slab,释放的时候,也只是减少引用计数,不需要还给slab。

2.显然应该实现为percpu的模式,避免查找skb的时候,锁的消耗。

3.percpu的缓存池消耗不一,所以要有一个cpu的node级别的二级缓存池,保证各个核在的增长和消耗达到阈值之后有一个平衡,如果没绑定的话,比如对于某个流来说,完全可能在Acpu上申请,在Bcpu上释放,不要问我为什么不绑定,因为假设你用docker的话,不太适合绑定,因为虚拟网卡一般配置单队列,而且开启xps的话,是根据当前cpuid而不是根据四元组来选择tx,可能选择到不同的tx来发送报文,而各个tx明显会有忙闲的区别,docker中程序的发包很可能导致tcp乱序严重。

4.在物理机上,有条件的话尽量做flow的绑定,也就是说,某个flow只在某个cpu上运行,保证局部性,这样的话,因为flow可以和一部分skb关联,这样填充二层和三层头的动作都可以节省了,如果你觉得节省这一点无所谓的话,大可以测试一下节省掉这些memcpy的消耗,从我们的测试效果看,很好。如果把skb看做一辆货车的话,对应的二层和三层的头就可以看做司机了,你说

我们运点货,犯得着老换货车,老换司机么?肯定有人会说,我每次发送的位置又不一样,所以得拷贝二层和三层的头,那假设你大多数发包的时候长度一样呢?

5.因为是自己管理skb的缓存,所以cb 成员就可以随便怎么处理了,很多控制信息都可以放在这里,方便。

6.对于单个流需要的流量比较多的情况,比如流媒体服务器,高清发送,预占的skb可以保证时延可控。

缺点:

1.预占部分内存,通过drop_cache也放不掉,如果是缓存自增长和收缩模式,也会有一些消耗。

linux 自定义模块来缓存skb的意义的更多相关文章

  1. Android开发笔记——ListView模块、缓存及性能

    ListView是Android开发中最常用的组件之一.本文将重点说明如何正确使用ListView,以及使用过程中可能遇到的问题. ListView开发模块 图片缓存 可能遇到的问题 一.ListVi ...

  2. python开发学习-day05(正则深入、冒泡排序算法、自定义模块、常用标准模块)

    s12-20160130-day05 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  3. python基础知识8——模块1——自定义模块和第三方开源模块

    模块的认识 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需 ...

  4. Python开发【第一篇】Python基础之自定义模块和内置模块

    为什么要有模块,将代码归类.模块,用一砣代码实现了某个功能的代码集合. Python中叫模块,其他语言叫类库. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代 ...

  5. nginx自定义模块编写-实时统计模块--转载

    原文:http://www.vimer.cn/2012/05/nginx%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A8%A1%E5%9D%97%E7%BC%96%E5%86%99- ...

  6. python-Day5-深入正则表达式--冒泡排序-时间复杂度 --常用模块学习:自定义模块--random模块:随机验证码--time & datetime模块

    正则表达式   语法:             mport re #导入模块名 p = re.compile("^[0-9]") #生成要匹配的正则对象 , ^代表从开头匹配,[0 ...

  7. Python爬虫与数据分析之模块:内置模块、开源模块、自定义模块

    专栏目录: Python爬虫与数据分析之python教学视频.python源码分享,python Python爬虫与数据分析之基础教程:Python的语法.字典.元组.列表 Python爬虫与数据分析 ...

  8. Linux 释放cache化缓存

    Linux 释放cache化缓存 free -g查看空余内存以及已使用内存 原文  https://blog.csdn.net/tomspcc/article/details/78131468 机械硬 ...

  9. 万恶之源 - Python 自定义模块

    自定义模块 我们今天来学习一下自定义模块(也就是私人订制),我们要自定义模块,首先就要知道什么是模块啊 一个函数封装一个功能,比如现在有一个软件,不可能将所有程序都写入一个文件,所以咱们应该分文件,组 ...

随机推荐

  1. npm 淘宝镜像

    npm config set registry https://registry.npm.taobao.org

  2. ORA-22922: 不存在的 LOB 值 可以使用外层嵌套wm_concat()解决

    select kw0408id, sjbh, ksrs, kch, to_char(wm_concat(kcmc)) as kcmc, ksxs, kssc, ksfs, kcxz, xsyx, nj ...

  3. 查看计算机CPU、内存使用情况

    Shift + Ctrl + Esc,打开Windows任务管理器,点击性能,如图: 可以清楚的看到整台机子的CPU.内存使用情况,其中CPU使用记录下有8个小窗口,因为博主的CPU是8核的,讲讲CP ...

  4. git解决冲突插件之Beyond Compare

    Beyond Compare主要作用: 1. 可以比较文件.文件夹的差异: 2. 将一个文件或文件夹的两个不同版本进行变更合并,生成一个输出. 基于以上两个特性,可以将beyond compare集成 ...

  5. linux下mysql-5.6忘记root密码,重置root密码详细过程

      在linux平台下使用mysql过程中忘记了root密码,对于运维和DBA来讲都是一件头疼的事情,下面来讲解下怎么进行重置mysql数据库root 密码: 1.首先停止mysql服务进程: 1 s ...

  6. jsfiddle将demo设置为public公开的

    jsfiddle的demo虽然可以通过链接分享给所有人,但是进入个人主页是没有的,需要将项目设置为公开public的 根据提示,打开demo项目页==>左侧菜单==>填写标题和描述==&g ...

  7. python-类里面各种方法的学习补充

    #-*- coding:utf-8 -*- #本次学习:类里面各种方法的学习 class SeniorTestingEngineer: work_year=3 salary=15000 def cod ...

  8. Linux系统及常用软件的安装

    注释:看了很多人说在Windows下面跑机器学习就和大人一直用勺子吃饭一样,应该用更...刚写到这里Linux又奔溃了-- 以后就在Linux上跑程序了,告别Windows的时代... 别看下面的安装 ...

  9. embsysregview 0.26 无法安装的解决方法。

    最近看到一个比较好的 eclipse 插件:embsysregview,于是想装起来用用看.结果安装过程出错,4个 jar 的包下载不下来,并且通过本地安装的方法也不行. 后来终于找到作者的回复,作者 ...

  10. REST api文档管理工具

    问题: 不同软件/程序在网络中互相传递信息不统一. 交互不便. REST API 作用: RESTful API就是一套协议,用来规范多种形式的前端和同一个后台的交互方式. 原理: 组成/流程/规范: ...