纸上得来终觉浅,绝知此事要躬行
在我们的Infortaiment系统里面,大量的用到了DBus来进行模块之间的通信,但是在DBus高负载的情况下,性能不是很好。于是又这样的一个项目尝试对DBus进行优化,我对此也非常的感兴趣,希望能对其进一步的学习。该项目试图把DBus封装为一个Linux内核里面的协议,通过套接字接口来进行访问。由于我不熟悉怎么样在Linux的网络子系统通添加一个新的协议族,正好过google发现了这边博文,故学习并翻译记录之,希望对大家有用。
Linux内核网络子系统支持许多协议,它足够灵活使得我们可以增加一种新的协议。这些协议可以通过套接字接口的协议族(Protocol family)的方式来让用户应用程序使用。接下来的部分会介绍增加一个新的协议族的主要步骤(基于Linux内核2.6.24),然而本文不会覆盖新的协议的具体实现。
Linux 网络子系统的一个高层的视图:
如上图所示,对于本文所考虑的范围,我们可以认为Linux的网络子系统由如下三层组成:
在Linux内核网路子系统里面,数据结构"struct proto" (/include/net/sock.h)和"struct netprotofamily" (/include/linux/net.h)封装了网络协议族的实现。 下面的这些代码展示了一个简化的例子,一步一步的实现了注册一个类似于TCP/IP栈(基于IP作为网络层)的新的协议族。 所有的协议相关的新的待实现函数都以"my_"作为前缀。
proto"的一个实例并且注册通过调用"proto_register()"注册到Linux网络子系统。
/* Protocol specific socket structure */
struct my_sock {
struct inet_sock isk;
/* Add the Protocol implementation specific data members per socket here from here on */
};
struct proto my_proto = {
.close = my_close,
.connect = my_connect,
.disconnect = my_disconnect,
.accept = my_accept,
.ioctl = my_ioctl,
.init = my_init_sock,
.shutdown = my_shutdown,
.setsockopt = my_setsockopt,
.getsockopt = my_getsockopt,
.sendmsg = my_sendmsg,
.recvmsg = my_recvmsg,
.unhash = my_unhash,
.get_port = my_get_port,
.enter_memory_pressure = my_enter_memory_pressure,
.sockets_allocated = &sockets_allocated,
.memory_allocated = &memory_allocated,
.memory_pressure = &memory_pressure,
.orphan_count = &orphan_count,
.sysctl_mem = sysctl_tcp_mem,
.sysctl_wmem = sysctl_tcp_wmem,
.sysctl_rmem = sysctl_tcp_rmem,
.max_header = 0,
.obj_size = sizeof(struct my_sock),
.owner = THIS_MODULE,
.name = "NEW_TCP",
};
rc = proto_register(&my_proto, 1);
struct net_proto_family my_net_proto = {
.family = AF_INET_NEW_TCP,
.create = my_create_socket,
.owner = THIS_MODULE,
};
rc = sock_register(&my_net_proto, 1);
(/include/linux/net.h)的实例。如步骤1里面指定的,套接字层通过调用proto_ops实例的函数成员来调用协议相关的函数。创建一个面向连接的类TCP/IP协议的套接字例程的典型实现如下面的代码所示:
static struct proto_ops my_proto_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = inet_release,
.bind = my_bind,
.connect = inet_stream_connect,
.socketpair = sock_no_socketpair,
.accept = inet_accept,
.getname = inet_getname,
.poll = my_poll,
.ioctl = inet_ioctl,
.listen = my_inet_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
.sendmsg = inet_sendmsg,
.recvmsg = sock_common_recvmsg,
};
static int my_create_socket(struct socket *sock, int protocol)
{
struct sock *sk;
int rc;
sk = sk_alloc(PF_INET_NEW_TCP, GFP_KERNEL, &my_proto, 1);
if (!sk) {
printk("failed to allocate socket.\n");
return -ENOMEM;
}
sock_init_data(sock, sk);
sk->sk_protocol = 0x0;
sock->ops = &my_proto_ops;
sock->state = SS_UNCONNECTED;
/* Do the protocol specific socket object initialization */
return 0;
};
https://lwn.net/Articles/504722/ https://lwn.net/Articles/504970/