目录
一、概述
二、Linux网络子系统的分层
2.1 为何要分层
2.2 协议无关接口
2.3 网络协议层
2.4 设备无关接口
2.5 设备层
三、参考
开篇,总结一下对linux协议栈的理解,备忘。
关于符号约定,代码路径使用[]包含,结构体使用结构体定义名称+{}表示
linux网络子系统实现需要:
需要屏蔽协议、硬件、平台(API)的差异,因而采用分层结构:
协议无关接口对应socket layer,我的理解是按照如下图组织的:
上图左半部分的socket layer提供了两个接口
同时,网络协议层为socket层提供具体协议接口——proto{},以上三个接口功能即作用总结如下表:
接口名称 | 定义位置 | 注册接口 | 作用 |
net_proto_family{} | include/linux/net.h | sock_register | 为网络协议层提供address family的注册接口 |
proto{} | include/net/sock.h | proto_register/ inet_register_protosw |
为网络协议层提供protocol注册接口 |
proto_ops{} | include/linux/net.h | inet_register_protosw | 为VFS提供BSD socket注册接口 |
下面以具体的协议INET来分析,对于address family接口,可以看到family<->create的对应
struct net_proto_family {
int family;
int (*create)(struct net *net, struct socket *sock,
int protocol, int kern);
struct module *owner;
};
对于proto接口,情况稍有不同,proto基本上是方法的合集,需要建立和type的映射关系,另一方面作为对上层提供的proto_ops,也需要建立和type的对应,因此inet引入另一个结构,集中进行管理注册,该结构是inet_protosw
[include/net/protocol.h]
/* This is used to register socket interfaces for IP protocols. */
struct inet_protosw {
struct list_head list;
/* These two fields form the lookup key. */
unsigned short type; /* This is the 2nd argument to socket(2). */
unsigned short protocol; /* This is the L4 protocol number. */
struct proto *prot;
const struct proto_ops *ops;
unsigned char flags; /* See INET_PROTOSW_* below. */
};
看定义看到type<->proto<->proto_ops的对应关系
实际上实现也是如此,通过接口inet_register_protosw将proto和proto_ops加入到inetsw的type数组中便于检索。这里面还有一个永久协议的概念,参见其中的flag参数。
至此,socket层的抽象接口已经建立并管理起来了。
再来看图的右半部分,可以发现每一层都有一个抽象的实体与之对应:file,socket,sock,从图中可以看出socket的承上启下的作用:向上指向file,向下指向sock,所以上面描述的三个分层可以看作是以抽象数据结构作为对象,使用抽象出来的接口作为对象拥有的行为。
这里sock是一个基类,不同的address family有不同的sock,如对于INET来说,初始化为inet_sock。
以INET层为例,网络协议层分为transport layer和network layer,我的理解如下:
这里看到提供接口的方向是向下的,实际对应报文接收流程,报文由下到上需要解复用。
网络层和传输层之间使用net_protocol建立protocol<->handler的对应关系,即通过IP包头protocol分析出传输层handler(tcp/udp/icmp/igmp)在网络层和设备无关层使用packet_type建立type<->func的对应关系,即通过二层头type分析出网络层func(arp, ip)。
接口 | 定义位置 | 注册接口 | 作用 |
net_protocol{} | include/net/protocol.h | inet_add_protocol | 传输层和网络层收包解复用 |
packet_type{} | include/linux/netdevice.h | dev_add_pack | 网络层和设备无关层收报解复用 |
上图中只说明了发方向,对于发方向,由于在INET中,网络层只有IP,因此就无需提供注册了,网络层向传输层提供的接口有:
ip_append_data/ip_append_page ,ip_push_pending_frames
ip_append_data() and ip_append_page() can make one large IP datagram from many pieces of data. Each pieces will be holded on the socket until ip_push_pending_frames() is called
net_device是对网络设备的抽象,针对net_device有许多通用的接口,在发送侧,向网络层提供接口名称为dev_queue_xmit的接口,这里还有一个QOS层,如上图所示
接口名称 | 定义位置 | 注册接口 | 作用 |
net_device_ops{} | include/linux/netdevice.h | register_netdev | 提供操作具体物理设备的通用接口 |
具体的网络驱动实现,这里先不详细展开。
【1】Linux 网络栈剖析
【2】浅析Linux网络子系统(一)
【3】深入浅出Linux TCP/IP协议栈 罗钰 编著