本科加上研究生大概有七年时间,一直都是学的通信,不过覆盖面不是很全,一直对一些网络相关的概念和实现有些模糊。最近补了补通信网络中的一些基础知识和盲点,有目的地看了看《云计算网络珠玑》、《图解网络硬件》等和网络相关的书和一些文章,做一下记录总结。主要包括了二层交换、三层路由、Linux网络相关的内容。
1. 二层交换
二层交换指的是传统的二层交换机实现的功能,主要的功能就是将以太网帧从一个端口接收,并从合适的端口发送出去。
1.1 以太网帧

以太网帧如上图所示,如此构造主要是为了表达这个帧:到哪去(目的MAC,6字节)、从哪来(源MAC,6字节)、什么帧(长度/类型,2字节)、有什么(数据,40~1500字节)、错没错(FCS,CRC,4字节)。
用户数据的长度不同,以太网帧的长度也不同,范围为64-1518字节。
1.2 存储转发与地址学习

存储转发:转发时,常用的方式为存储转发方式(store forward),即数据帧先入存储队列再根据转发表进行转发。使用存储转发,一来可以为多种速率端口的数据进行缓冲,二来也可以将残损、CRC错误等异常帧进行丢弃。小科普:除了存储转发外,还有直通转发(cut through,只读到DA后就转发,无法处理冲突帧、CRC错帧)、碎片隔离(fragment free,读一个slot共64字节,无冲突再转发,无法处理CRC帧)。
地址学习:在完成存储转发时,需要查询转发表,从而得知数据帧应该从哪个端口发出,因此,转发表存的就是目的MAC地址与端口的映射,转发表生成的过程就是地址学习。大致过程就是,来一个帧,读他的源MAC,然后把源MAC和接收的端口号存下来。这样,交换机就知道了,从X端口来过MAC地址为Y的数据,当下次Y需要转发时,就可以把他转发到X端口了。从而,完成“从哪来去回哪去”的任务
1.3 广播风暴
在几个交换机构成环时,会产生广播风暴,造成广播风暴的根本原因是交换机之间不能感知到互相的存在,导致地址学习时,一个交换将某个MAC的转发端口学习成了另一个交换机的端口。可以通过STP协议进行抑制,从逻辑上“断开”环。
1.4 VLAN

VLAN可以将广播域分隔为多个逻辑网段。从帧格式上来看,增加了VLAN相关的域,VLAN相关域包括0x8100标志位,然后3bit的优先级,1bit的丢帧优先级,12bit的VLANID。在做转发学习时,通过SA+VLAN来学习转发端口。值得注意的是:当某个DA+VLAN查不到表时,仅在VLAN域广播。
换一种思想来看,可以认为VLAN是一种网络的虚拟化,将一个端口虚拟化成多个端口。
2. 三层路由
路由的主要功能是根据目的IP转发到相应的网络中。和二层中的转发表类似,三层路由也存在一个类似的表,叫做路由表。
也就是说如果一个LAN希望连接另一个LAN,那么需要借助路由完成。另外,在大型的LAN中,由于连接设备多,导致MAC多,导致广播负担大,因此切分子网来避免这一问题,而子网之间所属不同LAN所以也需要借助路由完成通信。

在进行路由的时候,路由首先根据最长匹配原则在路由表中查找下一跳IP地址,之后,根据ARP表,获取下一跳的MAC信息,便进入ARP流程,最后,根据下一跳MAC地址生成以太网数据帧,并将该数据帧从接口转发至网络。
路由与三层交换有类似的地方,L3交换虽具有路由功能,但其核心功能主要在于数据交换上,而路由仅具有路由转发功能。
2.1 NAT
Network Adress Translator,网络地址转换。
对于源地址NAT,主要用于内网访问外网,源地址进行转换;
对于目的地址NAT,一般用于外网访问内网,目的地址进行转换。
3. Linux网络
由于目前大部分云计算服务器、网络设备都是运行在Linux上的,因此,学习一些和Linux网络底层相关的实现,有助于我们理解。如Linux 上的基础网络设备详解一文中所述:
Linux 用户想要使用网络功能,不能通过直接操作硬件完成,而需要直接或间接的操作一个 Linux 为我们抽象出来的设备,既通用的 Linux 网络设备来完成。一个常见的情况是,系统里装有一个硬件网卡,Linux 会在系统里为其生成一个网络设备实例,如 eth0,用户需要对 eth0 发出命令以配置或使用它了。
另外,对于Linux网络中的数据流在kernel flow中有所描述,文中更有一张神图。
3.1 网络驱动

之前,有做过网络驱动,其实回想起来,核心的实现就2个:发送函数和接收函数。
1. 发送函数(回调)
核心功能是将上层网络传来的帧,写入到网卡中;
在网络驱动初始化时,会通过注册的方式对网络驱动进行初始化,
1 | static const struct net_device_ops netdev_ops = { |
当上层有帧传来时,就会回调driver_xmit函数,因此,在driver_xmit函数中,就应当实现将帧写入到硬件,一般硬件会提供插入帧的接口,完成插入时帧会进入网卡硬件的插入队列中。
2. 接收函数(中断)
核心功能是将网卡中的帧,传送到上层协议栈中。
对于接收函数,则需要依靠硬件的中断,数据帧到达网卡,硬件以中断的方式告知系统,然后,接收函数回调,回调时,需通过硬件的接口读取数据帧,然后将其上传值上层接口。一般调用netif_rx()进行传输。
3.2 Linux Bridge
Linux Bridge名释其意,像一个桥梁一样把网络设备桥接起来。Linux bridge是802.1D的实现,可以参考链接。

如上图所示是eth0和eth1加入到br0后的实现,可以看出,网桥向上屏蔽了桥下的网卡设备,从上层协议上来看,仅能看到网桥设备br0。
在《Understanding Linux Network Internals》一书中,分析了Linux Bridge的实现:
在br中有个链表来链net_device,每个net_device也反向链着br。在br中有个hash结构叫做fdb_entry,存储着转发表(forward databse),若某个MAC地址在fdb中,那么就直接发到某个net_device,如果没在的话,就广播给链接到该br的所有设备。
3.3 Linux VLAN
交换与隔离是VLAN的两大功能,现实世界中的802.1q交换机存在多个VLAN,每个VLAN拥有多个端口,同一VLAN的端口可数据交换,不同VLAN的端口之间隔离。而Linux VLAN实现的是隔离,需要交换的话,需要在Linux Bridge上attach一个VLAN。即Linux Bridge加VLAN device能在功能层面完整模拟现实世界里的802.1.q交换机。
在关于linux 802.1d (bridge) 和 802.1q(vlan) 实现的再思考一文中,举了个例子,觉得很不错,画了个图加深理解:
一个盒子有6个物理interface, eth0,eth1,eth2,eth3,eth4,eth5,eth6.
bridge0 { eth0, eth1, eth2 }, vlan id 是2
bridge1 { eth3, eth4, eth5 }, vlan id 是3
eth0,eth1,eth2,eth3,eth4,eth5都在混杂模式,并且没有ip地址,它们是bridge的port.
创建vlan interface, bridge0.2, bridge1.3。在bridge0.2和bridge1.3上配置ip地址。vlan 2的机器,把bridge0.2的地址设置为缺省网关;vlan 3的机器,把bridge1.3设置为缺省网关。当有包要从vlan 2发往vlan 3是,它将送到bridge0.2,然后,通过路由,找到bridge1.3,然后由bridge1.3发出去。这个过程中,packet里面的vlan id会发生改变。这个例子里面,要求从bridge port上收到的包都必须是打tag的,在bridge里面,并不能识别和处理tag,只有到三层的vlan interface才能识别并处理这些tag.
另外,Linux VLAN则是802.1Q的实现,可以参考链接
参考链接
《云计算网络珠玑》
《 图解网络硬件》
kernel flow
linux bridge
《Understanding Linux Network Internals》
关于linux 802.1d (bridge) 和 802.1q(vlan) 实现的再思考
802.1Q VLAN implementation for Linux