1、基本概念
路由子系统工作在三层,用来转发入口流量。主要涉及 路由器、路由、路由表等概念。
路由器: 配备多个网络接口卡(NIC),并且能利用自身网络信息进行入口流量转发的设备。
路由:流量转发,决定目的地的过程
路由表:转发信息库,该库中储存路由需要本地接收还是转发的信息, 以及转发流量时所需要的信息。(即,信息库用来判断,要不要转发,如果要转发,向哪里转发)
不可路由地址,私有地址和本地环回地址不可路由。 当局域网(私有地址)的主机要与非该局域网的主机通信时,需要通过NAT来隐藏不可路由的子网。
定向广播:
子网广播:目的地址为本地子网的广播包。
定向广播:目的地址为远端子网的广播包。
定向子网广播针对ICMP ECHO REQUEST做特殊处理,以避免恶意攻击。
主地址、辅助地址、设备别名
地址属于主机而非接口,一个接口可以配置多个别名。(ip address add)。
一个NIC可配置多个朱地址和辅助地址,一个子网掩码只能有一个特定的主地址。
还有一个很重要的模块就是内核路由子系统,它应该是工作在L3层。发送报文时会在L3层打好IP头前,路由到具体的网络设备,然后才进入L2填充以太网头。路由的工作是通过函数ip_route_input()(/net/ipv4/route.c)实现的,对于进来的包可能的路由有这些:属于本地的数据(即是需要传递给TCP,UDP,IGMP这些上层协议的) ;需要要转发的数据包(网关或者NAT服务器之类的);不可能路由的数据包(地址信息有误);当路由发现是本地数据时,rth->u.dst.input = ip_local_deliver,返回后就可以在skb->dst->input(skb)中进入ip_local_deliver,找到对应的interface设备。如我们的eht0.y vlan虚拟设备,进入vlan处理流程。
2、Linux 作为一个路由器
Linux 作为一个路由器只需要打开 ipv4.forward 特性即可。
... net.ipv4.ip_forward=1 $ sysctl -p # 开启 NAT $ iptables -t nat -A POSTROUTING -j MASQUERADE
开启了路由功能之后的 Linux 服务器就相当于一个 Router,Linux 服务器的路由表就相当于 Router 的路由表,Linux 服务器上的网卡就相当于 Router Interface。数据包会根据路由表规则在这些 “网卡” 中选择下一跳。
同时要注意 iptables 规则是否可能会造成混乱,对于 Router 所有数据包都是 SNAT,所以不需要配置 DNAT 规则,建议清理干净
3、route 指令
命令行下输入 route -n 或 netstat -rn,就可以打印本机的 main 路由表:
route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.18.22.1 0.0.0.0 UG 0 0 0 br-ex 172.18.22.0 0.0.0.0 255.255.255.0 U 0 0 0 br-ex 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 o-hm0 192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
4、操作实例
-
1、要实现全网通信,也就是网络中任意两个节点都可以通信,就要求每个路由器的路由表中必须有到所有网段的路由。
-
2、对于路由器来说,它只知道与自己直接相连的网段,对于没有直连的网络,则需要人工添加到这些网段的路由。如 R1 路由器直接与 A、B 两个网段相连,R1 会自动生成 A、B 网段的路由表,所以 R1 天然就知道数据包如何在在 A、B 网段之间进行转发。但 R1 没有与直接 C、D 网段相连,A、B 网段发出的数据包无法被 R1 转发至 C、D 网段,此时就需要手动添加 C、D 网段的路由到 R1(如上图所示)。此时 A 网段(192.168.0.2/24)访问 C 网段(172.16.1.2/24),R1 就知道该数据包应该被转发至 R2 的网关 172.16.0.2/24,R2 在根据目标地址(172.16.1.2/24)转发至 R3。
-
3、“下一跳” 指的是数据包下一步转发给哪个路由器,应该为目标路由器的入口地址。对于点到点链路而言,“下一跳” 地址可以被写成目标网络的出口(如 serial 2/0),因为 PPP 协议,数据帧从一端发出,接收端只有一个;但对于路由器而言,因为路由器之间是一个以太网连接,这种情况下添加路由器,只能写下一跳地址,而不能写路由器的出口,因为路由器的出口连的是以太网,它无法知道该将数据包发给该以太网中的哪个路由器。
-
4、路由器只关心到某个 网段 如何转发数据包,所以添加路由时一定要是某个网段的地址,而不能是某个特定地址的路由,即一定要确保 IP 地址的主机位全是 0。如果要让路由器转发到一个 IP 地址的路由,子网掩码要写成 4 个 255。如:R1(config)#ip route 192.168.1.3 255.255.255.255 172.16.0.2。
简单来说,每个 Router 都会连接多个 LAN,如果当前 Router 没有这个 LAN,那么 Router 就应该将数据包 下一跳 到连接这个 LAN 的 Router 上,之间可能隔着多个 Routers。
NOTE:需要注意的是,路由器功能生效的前提是连接一个 LAN 的路由网关接口必须配置了同一网段的网关 IP 地址。笔者经历过使用 DPDK 用户态数据面转发软件的场景,就是因为没有配置网管 IP 所以没有触发数据包的转发动作。无论是传统的路由交换组网场景,还是基于用户态内核旁路技术的自定义网络的组网场景,路由网关都是必要需要存在的。
5、Linux Kernel 路由子系统
Linux 在发送数据时和接收数据时都会涉及到路由子系统的工作。
Routing Table(路由表)在 Kernel 中的另外一个别名是 FIB(Forwarding Information Base,转发信息库)。所以,在 Kernel 中看到的 fib 开头的定义基本上就是和路由表相关的功能。
在默认情况下,Linux 只有 local 和 main 两个路由表,如果内核编译时支持策略路由,那么最多可以配置 255 个独立的路由表。查看是否开启了 CONFIG_IP_MULTIPLE_TABLES 多路由表支持。
若开启了,此时 Linux 自身会维护 4 个路由表:
$ cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep
- 0 unspec table: 系统保留表。
- 253 defulte table:没特别指定的默认路由都放在该表。
- 254 main table:没指明路由表的所有路由都放在该表。
- 255 locale table:保存本地接口地址,广播地址、NAT 地址。该由系统维护,用户不得更改。
查看指定的路由表项目:
ip route list table {table_number}
# e.g.
$ ip route list table local
同时,Linux 支持 Network namespace,如果存在多个 Network namespace 的话,就会存在多套路由表。路由表在整个内核数据结构中的关联关系如下图所示。
6、发送数据时进行路由选择(选路)
Linux 在发送数据包的时候需要进行路由选路,因为服务器上可能会存在多张网卡设备。当待发送的数据包进入 IP 层的路由子系统时,就要进行路由选择(选路),以决定使用哪张网卡设备把数据包送出去。
IP 网络层数据包发送的入口函数是 ip_queue_xmit(),其中调用的 ip_route_output_ports() 函数实现了路由项的查找,继而完成路由选择,在路由表中进行匹配,然后决定使用哪个网卡发送出去。
7、接收数据时进行路由选择(选路)
因为 Linux 提供了路由器的功能,可以像路由器一样工作,将接收到的数据包通过合适的网卡将其转发出去。
IP 网络层数据包接收的入口函数是 ip_rcv(),执行后调用到 ip_rcv_finish(),在这里展开路由选择。
- 如果匹配确实就是本设备的网络包,那么就通过 ip_local_deliver() 送到更上层的 TCP 层进行处理。
- 如果匹配发现是非本设备的网络包,那就进入到 ip_forward() 进行转发,最后通过 ip_output() 发送出去。
8、路由查找
上述内容提到,数据包发送过程中调用了 ip_route_output_ports() 来查找路由,数据包接收过程中调用了 ip_route_input_slow() 来查找。其实这两个函数最终都会调用到 fib_lookup() 这个核心函数。
fib_lookup() 函数依次到 local 和 main 表中进行匹配,匹配到后就返回。并且 local 表的优先级要高于 main 表,如果 local 表中找到了规则,则路由过程就结束了。
根据这个实现,当我们 ping 本地 IP 地址的时,eth0 上是抓不到包的。因为所有命中 local 表的包,都会被送往 loopback 设备,而不是 eth0。
©著作权归作者所有:来自51CTO博客作者云物互联的原创作品,请联系作者获取转载授权,否则将追究法律责任
Linux Kernel TCP/IP Stack — L3 Layer — 路由器子系统
https://blog.51cto.com/u_15301988/5180942
本节详细内容请参考:https://blog.51cto.com/u_15301988/5180942



