标签:
内核与用户态通信的接口简直太多了,有时候如果非要将它们分个三六九等也是不合适的,比如臭名昭著的ioctl,一旦臭起来就抽到底了,没人说它得好。有时候它并非想象中的那么坏,绝大多数是因为人们误用了它们,然后哪位大师说了一句它不好,从此以后人们就随大师而去了...对于ioctl,对应到socket类型文件描述符上,就是get/setsockopt两个接口函数,其实我不明白从函数名称上区分操作类型和从命令类型上区分有什么不同,一个对于UNIX文件描述符统一的ioctl为何会在socket上衍生出两个函数,这实在是不应该,比如我在一个setsockopt上面调用一个GETxxx命令,会怎样?当然会出错,但我不认为这样回答就等于理解了全部,这个API根本就不应该这么设计。当然我不是什么大师,也没人会跟随我的思想。/* Fast function for those who don‘t want to parse /proc (and I don‘t blame them). */事实上,作者是有所不知,他应该自己去parse /proc/net/ip_conntrack试试。如果调用conntrack-tools然后截取输出更麻烦,因此你真的就需要一个C API级别的接口,那么set/getsockopt就再好不过了。这两个sockopt系统调用接口和ioctl系统调用接口几乎是一样的,也是职责不明确的链式尝试执行,也就是说,只要你在某个地方定义了实现,并且挂入执行路径,那么它就一定可以被找到并执行。
static int getXXXYYYZZZ(struct sock *sk, int optval, void __user *user, int *len) { const struct inet_sock *inet = inet_sk(sk); const struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; memset(&tuple, 0, sizeof(tuple)); tuple.src.u3.ip = inet->rcv_saddr; tuple.src.u.tcp.port = inet->sport; tuple.dst.u3.ip = inet->daddr; tuple.dst.u.tcp.port = inet->dport; tuple.src.l3num = PF_INET; tuple.dst.protonum = sk->sk_protocol; ...//如何想象 h = nf_conntrack_find_get(sock_net(sk), &tuple); ...//天高任飞翔 }下面我来告诉你使用set/getsockopt或者ioctl的好处吧,我说这话说明我承认了“虽然它在API方面设计得确实不怎么样,但是好处在别处”。和procfs的文件IO相比,ioctl可以实现直接的内存copy,使用procfs的代价是数据必须先转成字符串,然后写入内核,在内核中再根据“相关的规则”将数据转回裸格式,这意味着需要进行“一次数据交换”,而交换的编解码规则必须让数据交换双方(即procfs的操作者以及内核)都知道才行,对于二进制数据而言,这意味着必须起码进行一次BASE64编码,然后在内核中再BASE64解码,这个事实必须让内核和用户态的Reader,Writer同时知晓。所有这一切只是因为在命令行上,你很难“定义结构体并将其进行传输”,而在系统的底层,本质上就是使用指针在各个结构体之间或者内部进行数据直接寻址的。因此要想使得数据和编码无关,就必须支持直接的内存copy操作。
/* * Convert an ASCII string to binary IP. * This is outside of net/ipv4/ because various code that uses IP addresses * is otherwise not dependent on the TCP/IP stack. */对于经常折腾Linux内核网络协议栈的家伙来讲,经常需要如此做。
可任意操作nf_conntrack的nf_sockopt_ops
标签:
原文地址:http://blog.csdn.net/dog250/article/details/42046515