博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ip_conntrack的extend机制以及扩展
阅读量:6785 次
发布时间:2019-06-26

本文共 2296 字,大约阅读时间需要 7 分钟。

ip_conntrack为无状态无连接的IP增加了一个流记录机制,你可以把任何和一个流相关的东西放进去,但是放在哪里呢?原则上ip_conntrack应该是一个可以无限扩展的东西,但事实上,内核的设计者或者说Netfilter的ip_conntrack设计者并没有给用户程序员留下任何可以扩展它的接口和机制,你只能用现有的连接跟踪机制,虽然可以通过nf_ct_extend_register接口注册一个nf_ct_ext_type,但是这个接口也只是内核源码树自己使用的,你无法从外部定义一个心的nf_ct_ext_type。

      既然有一个nf_ct_extend_register,为何不让从外部定一个nf_ct_ext_type,然后注册进去呢?除了C语言定义的数据结构不能自己解释自己实现反序列化之外,我觉得这是ip_conntrack代码树的一个缺陷,但是也许是内核开发模式和应用开发模式的不同导致的。一般的,内核API非常不稳定,对于应用来讲,内核的系统调用接口尽可能保持稳定就可以了,至于内部则完全是一个黑盒子。再者,内核开发需要一定的功底,不仅仅是你熟悉一些编程技巧和熟读API文档就能搞得定的。以上的原因,或者说是我的个人猜测,导致了不允许对ip_conntrack的结构体本身进行任何修改,你能改的仅仅是实现逻辑。Linux内核怎么做到这种限制的呢?很简单啊,把相关的头文件放到内核开发的头文件目录就可以了,事实上,只要是那个目录的头文件,你就别指望修改任何结构体和声明,因为那些是要参与符号CRC计算的。
      理解了ip_conntrack的extend实际上并不能扩展之后,下面就展示一下老湿是怎么扩展它的。首先看一下ip_conntrack的extend结构是怎么组织的。实际上,我觉得这种组织非常好,非常紧凑,不容易产生内存碎片,它之所以如此紧凑是因为所有的extend相关的内容在内存中全部都是连续的。连续的内存当然没有指针寻址不连续内存方便,但是使用偏移也是不错的,更大的优势是申请/拷贝/释放比较方面,不用考虑深拷贝浅拷贝的问题。类似的数据结构还有iptables的rule在内核中的表示。
      连续内存的表示法的最大好处就是可以任意扩展,因为它完全是靠偏移来定位位置的,如果你知道C++和JAVA这类OO语言,就会知道,一个普通类的内存布局中,处在开头的总是基类,所谓的扩展正是处在紧接着基类的内存位置,从而构成了一个子类,当然这只是从实现上来讲的,这里不谈思想!当然这也不是一种有性生殖行为,因为有性生殖从来都不是连续的,你不能说孩子是一个爸爸(是爸爸的一部分...),但是在内存连续的世界里,我们可以说:

struct B {       struct A a;       ....       char *privatedata};

是一个struct A,毕竟我可以把struct B从a字段往后的字段切掉。知道了这一切之后,我就可以对任意Linux预定义好的所有的nf_ct_ext_type进行任意的扩展了!事实上,我只需要扩展一个指针!虽然我很崇尚连续内存的布局,但是在我还是比较喜欢灵活,毕竟现在的内存价格已经不贵了,干嘛那么在乎内存啊。仅仅扩展一个指针,你想把它解释成一个什么机构都行!我们以一幅图来做解释:


理解了上面的那个图,就明白下面的定义了,不需要改变nf_conn_counter的结构体,只改变它的大小即可,即:

struct nf_conn_counter {    u_int64_t packets;    u_int64_t bytes;};
的大小不是sizeof(struct nf_conn_counter),而是sizeof(struct nf_conn_counter)+sizeof(char *),定义为:

struct nf_conn_counter {    u_int64_t packets;    u_int64_t bytes;    char *p;};
但是这样便改变了nf_conn_counter结构体的定义,但是考虑以上结构体, 在内存结构上,等价于:

struct my_st {    struct nf_conn_counter nfc;    char *p;};
这样没有改变结构体的定义,结构体my事实上真的就“是一个”结构体nf_conn_counter,在这之后,需要修改的地方真的就不多了,仅仅是一个nf_ct_ext_type的len字段的修改。剩下的工作就是,在需要设置或者取出自己自定义的结构体的时候,按照下面这样:

struct my_st *ms = (struct my_st *)a_instance_of_struct_of_nf_conn_counter;

取出my_st的指针即可。接下来就可以访问my_st里面的p了,至于p是什么,自有作者解释。为何我不提倡连续内存而是用一个指针,关键是我觉得并不是每个conntrack都需要这个字段,为了节省内存只为需要的结构体分配内存,只能用指针。

      这就是老湿的做法,JAVA编程思想,真的有思想。老湿很低级,不怎么懂编程,不符合编程高手的口味,但是老湿懂湿想,老湿知道这个机器奴役人的世界是多么的残酷,一个数字化的世界是多么的可悲,而是是编程的人特别是以编程为命的人所很难理解的...
 本文转自 dog250 51CTO博客,原文链接:
http://blog.51cto.com/dog250/1391308

转载地址:http://itdgo.baihongyu.com/

你可能感兴趣的文章
MemDc Test
查看>>
Codeforces Round #228 (Div. 1) 解题报告
查看>>
Red Hat 6.5 本地yum源的配置
查看>>
【杭电ACM】1.2.3 hide handkerchief
查看>>
linux kernel笔记
查看>>
Django配置、静态文件与路由
查看>>
Hello World
查看>>
将HG版本库推送到Git服务器
查看>>
Struts2中ValueStack结构和总结
查看>>
如何从一个传统开发团队转向敏捷开发团队
查看>>
基于Vue.js 2.0 + Vuex打造微信项目
查看>>
作业十三
查看>>
Unity3D 常用 英文单词
查看>>
Go语言标准库_输入/输出
查看>>
题目1489:计算两个矩阵的乘积
查看>>
GPU-BASED PROCEDURAL PLACEMENT IN HORIZON ZERO DAWN
查看>>
mysql中[Err] 1366 - Incorrect string value: '\xE5\x8D\x问题
查看>>
Hadoop生态上几个技术的关系与区别:hive、pig、hbase 关系与区别
查看>>
Mysql用户管理(远程连接、授权)
查看>>
Coursera机器学习编程作业Python实现(Andrew Ng)—— 2.1 Logistic Regression
查看>>