宿舍上网的原理
学校给每个宿舍的网口分配了一个 IP。这个 IP 是校园网的 IP,完全由网管部门控制。宿舍网的 IP 地址多为 192.168.1.x。校园网的 IP 地址,假设是 10.10.x.x。
有两个办法上网:
- 让舍长再买一个网卡。这个时候舍长的电脑里就有两张网卡。一张网卡的线插到宿舍的交换机上,另一张网卡的线插到校园网的网口。而且,这张新的网卡的 IP 地址要按照学校网管部门分配的配置,不然上不了网。这种情况下需要一直开着宿舍长的电脑。
- 共同出钱买个家庭路由器。家庭路由器会有内网网口和外网网口。把外网网口的线插到校园网的网口上,将这个外网网口配置成和网管部的一样。内网网口连上你们宿舍的所有的电脑。这种情况下需要一直开着路由器。
本质上第一种方式只是让舍长的电脑变成了一个有多个口的路由器,两种方法的本质是一样的。当舍长可以上网后,需要解决其他人电脑怎么上网的问题,就需要配置网卡,DHCP 进行网卡配置,除了 IP 地址,还需要配置Gateway ,也就是网关。
MAC 头和 IP 头的细节
在任何一台机器上,当要访问另一个 IP 地址的时候,都会先判断,这个目标 IP 地址,和当前机器的 IP 地址,是否在同一个网段。怎么判断同一个网段呢?需要 CIDR
和子网掩码
。
如果是同一个网段,例如,访问室友的电脑,就没网关什么事情,直接将源地址
和目标地址
放入IP 头
中,然后通过 ARP
获得 MAC
地址,将源 MAC
和目的 MAC
放入 MAC 头
中,发出去就可以了。
如果是不同网段,例如,访问你们校园网里面的 BBS。这就需要发往默认网关 Gateway
。Gateway 的地址一定是和源 IP 地址是一个网段的。往往不是第一个,就是第二个。例如 192.168.1.0/24 这个网段,Gateway 往往会是 192.168.1.1/24 或者 192.168.1.2/24。
发往默认网关
的过程就和发往同一个网段的其他机器是一样的:将源地址和目标 IP 地址放入 IP 头中,通过 ARP 获得网关的 MAC 地址,将源 MAC 和网关的 MAC 放入 MAC 头中,发送出去。
**网关往往是一个路由器,是一个三层转发的设备。**三层设备就是把 MAC 头和 IP 头都取下来,然后根据里面的内容,看看接下来把包往哪里转发的设备。宿舍里面,网关就是舍长的电脑。一个路由器往往有多个网口,如果是一台服务器做这个事情,则就有多个网卡,其中一个网卡是和源 IP 同网段的。
路由器是一台设备,它有五个网口或者网卡,相当于有五只手,分别连着五个局域网。每只手的 IP 地址都和局域网的 IP 地址相同的网段,每只手都是它握住的那个局域网的网关。
任何一个想发往其他局域网的包,都会到达其中一只手,被拿进来,拿下 MAC 头和 IP 头,看看,根据自己的路由算法,选择另一只手,加上 IP 头和 MAC 头,然后扔出去。
静态路由
IP 头和 MAC 头加什么内容,大致可以分为两类,一个是静态路由(不变),一个是动态路由(变)。
静态路由就是在路由器上,配置一条一条规则。这些规则包括:想访问 BBS 站(它肯定有个网段),从 2 号口出去,下一跳是 IP2;想访问教学视频站(它也有个自己的网段),从 3 号口出去,下一跳是 IP3,然后保存在路由器里。
MAC 地址是一个局域网内才有效的地址。因而,MAC 地址只要过网关,就必定会改变,因为已经换了局域网。两者主要的区别在于 IP 地址是否改变。不改变 IP 地址的网关,我们称为转发网关。改变IP 地址的网关,我们称为NAT 网关。
转发网关
服务器 A 要访问服务器 B。首先,服务器 A 会思考,192.168.4.101 和我不是一个网段的,因而需要先发给网关。网关是 192.168.1.1。发送 ARP 获取网关的 MAC 地址,然后发送包的内容是这样的:
- 源 MAC:服务器 A 的 MAC
- 目标 MAC:192.168.1.1 这个网口的 MAC
- 源 IP:192.168.1.101
- 目标 IP:192.168.4.101
包到达 192.168.1.1 这个网口,发现 MAC 一致,将包收进来。在路由器 A 中配置了静态路由之后,要想访问 192.168.4.0/24,要从 192.168.56.1 这个口出去,下一跳为 192.168.56.2。
从 192.168.56.1 这个口发出去,发给 192.168.56.2,路由器 A 发送 ARP 获取 192.168.56.2 的 MAC 地址,然后发送包:
- 源 MAC:192.168.56.1 的 MAC 地址
- 目标 MAC:192.168.56.2 的 MAC 地址
- 源 IP:192.168.1.101
- 目标 IP:192.168.4.101
到达 192.168.56.2 这个网口,发现 MAC 一致,将包收进来,在路由器 B 中配置了静态路由,要想访问 192.168.4.0/24,要从 192.168.4.1 这个口出去。
发给 192.168.4.101。路由器 B 发送 ARP 获取 192.168.4.101 的 MAC 地址,然后发送包。包的内容是这样的:
- 源 MAC:192.168.4.1 的 MAC 地址
- 目标 MAC:192.168.4.101 的 MAC 地址
- 源 IP:192.168.1.101
- 目标 IP:192.168.4.101
包到达服务器 B,MAC 地址匹配,将包收进来。
可以观察到所有的包都只是MAC地址在发生改变,IP地址不变。所谓的下一跳是,通过ARP
将某个 IP 要将这个 IP 地址转换为 MAC 放入 MAC 头。
IP 地址在三个局域网都可见,在三个局域网之间的网段都不会冲突。在三个网段之间传输包,IP 头不改变。也就是经过的是转发网关。
NAT网关
局域网之间没有商量过,各定各的网段,因而 IP 段冲突了。比如上图的服务器A和服务器B。
虽然在各自的局域网相同,但他们都需要在“大环境”下有对应的身份,假设服务器B为192.168.56.2。在网关 B 上,记下国际身份 192.168.56.2 对应国内身份 192.168.1.101。凡是要访问 192.168.56.2,都转成 192.168.1.101。
于是,源服务器 A 要访问目标服务器 B,要指定的目标地址为 192.168.56.2。于是原理同上,先发给网关A:
- 源 MAC:服务器 A 的 MAC
- 目标 MAC:192.168.1.1 这个网口的 MAC
- 源 IP:192.168.1.101
- 目标 IP:192.168.56.2
核对MAC后被路由器接收,在路由器A中,要从 192.168.56.1 这个口发出去,发给 192.168.56.2。当网络包发送到中间的局域网的时候,服务器 A 也需要有个国际身份,因而在国际上,源 IP 地址也不能用 192.168.1.101,需要改成 192.168.56.1:
- 源 MAC:192.168.56.1 的 MAC 地址
- 目标 MAC:192.168.56.2 的 MAC 地址
- 源 IP:192.168.56.1
- 目标 IP:192.168.56.2
到达192.168.56.2 这个网口,路由器 B 是一个 NAT 网关
,它上面配置了,要访问国际身份 192.168.56.2 对应国内身份 192.168.1.101,于是改为访问 192.168.1.101。
从 192.168.1.1 这个口出去,包内容是这样的:
- 源 MAC:192.168.1.1 的 MAC 地址
- 目标 MAC:192.168.1.101 的 MAC 地址
- 源 IP:192.168.56.1
- 目标 IP:192.168.1.101
包到达服务器 B,MAC 地址匹配,将包收进来。从服务器 B 接收的包可以看出,源 IP 为服务器 A 的国际身份,因而发送返回包的时候,也发给这个国际身份,由路由器 A 做 NAT,转换为国内身份。
观察以上所有包可以发现,IP地址在发生改变,也就是Network Address Translation,简称 NAT。而NAT
更常见,现在大家每家都有家用路由器,家里的网段都是 192.168.1.x,所以你肯定访问不了你邻居家的这个私网的 IP 地址的。
配置路由
出了网关后,会面临很多路由器,有很多道路可选,而如何选择一个更快速的道路,需要进行一些配置。
配置路由
路由器就是一台网络设备,它有多张网卡。当一个入口的网络包送到路由器时,它会根据一个本地的转发信息库,来决定如何正确地转发流量。这个转发信息库通常被称为路由表。
而每条规则包含三个信息:
目的网络
:这个包想去哪儿?出口设备
:将包从哪个口扔出去?下一跳网关
:下一个路由器的地址。
通过 route
命令和 ip route
命令都可以进行查询或者配置。
例如,设置
ip route add 10.176.48.0/20 via 10.173.32.1 dev eth0
就说明要去 10.176.48.0/20 这个目标网络,要从 eth0 端口出去,经过 10.173.32.1。这种配置方式的一个核心思想是:根据目的 IP 地址来配置路由。
配置策略路由
除了可以根据目的 ip 地址配置路由外,还可以根据多个参数来配置路由,这就称为策略路由。
设置
ip rule add from 192.168.1.0/24 table 10
ip rule add from 192.168.2.0/24 table 20
表示从 192.168.1.10/24 这个网段来的,使用 table 10 中的路由表,而从 192.168.2.0/24 网段来的,使用 table20 的路由表。
而在规则
ip route add default scope global nexthop via 100.100.100.1 weight 1 nexthop via 200.200.200.1 weight 2`
指下一跳有两个地方,分别是 100.100.100.1 和 200.200.200.1,权重分别为 1 比 2。
为上述复杂的配置举个例子:
房东运营商那里拉了两根网线。这两根网线分别属于两个运行商。一个带宽大一些,一个带宽小一些。这个时候需要可以接两个外网的路由器。
家里的网络就是普通的家用网段 192.168.1.x/24。家里有两个租户,分别把线连到路由器上。IP 地址为 192.168.1.101/24 和 192.168.1.102/24,网关是 192.168.1.1/24在路由器上。
家里的网段是私有网段,出去的包需要NAT
成公网的 IP 地址,因而路由器是一个 NAT 路由器
。
运行商里面也有一个 IP 地址,在运营商网络里面的网关。例如,运营商 1 给路由器分配的地址是 183.134.189.34/32,而运营商网络里面的网关是 183.134.188.1/32。/32 的即一个一对一连接。有的是 /30 的,也就是分了一个特别小的网段。运营商 2 给路由器分配的地址是 60.190.27.190/30,运营商网络里面的网关是 60.190.27.189/30。
于是根据该网络拓扑,可以配置为:
$ ip route list table main
60.190.27.189/30 dev eth3 proto kernel scope link src 60.190.27.190
183.134.188.1 dev eth2 proto kernel scope link src 183.134.189.34
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.1
127.0.0.0/8 dev lo scope link
default via 183.134.188.1 dev eth2
翻译过来就是:
- 如果去运营商二,就走 eth3;
- 如果去运营商一呢,就走 eth2;
- 如果访问内网,就走 eth1;
- 如果所有的规则都匹配不上,默认走运营商一,也即走快的网络。
租户 A 不想多付钱,他说我就上上网页,从不看电影,凭什么收我同样贵的网费啊?也可以针对解决。
添加一个 Table,名字叫 atab。
# echo 200 atab >> /etc/iproute2/rt_tables
添加一条规则:
# ip rule add from 192.168.1.101 table atab
# ip rule ls
0: from all lookup local
32765: from 10.0.0.10 lookup atab
32766: from all lookup main
32767: from all lookup default
设定规则为:从 192.168.1.101 来的包都查看个 atab 这个新的路由表。
在 atab 路由表中添加规则:
# ip route add default via 60.190.27.189 dev eth3 table atab
# ip route flush cache
默认的路由走慢的。
上面说的都是静态的路由,一般来说网络环境简单的时候,在自己的可控范围之内,自己捣鼓还是可以的。但是有时候网络环境复杂并且多变,如果总是用静态路由,一旦网络结构发生变化,让网络管理员手工修改路由太复杂了,因而需要动态路由算法。
动态路由
动态路由路由器,可以根据路由协议算法生成动态路由表,随网络运行状况的变化而变化。
将网络拓扑抽象为图,于是问题转化为如何在途中找到最短路径。
最短路径常用的有两种方法,一种是Bellman-Ford
算法,一种是Dijkstra
算法。
距离矢量路由算法
距离矢量路由(distance vector routing)是基于 Bellman-Ford
算法的。
基本思路是,每个路由器都保存一个路由表,包含多行,每行对应网络中的一个路由器,每一行包含两部分信息,一个是要到目标路由器,从那条线出去,另一个是到目标路由器的距离。
每个路由器都是知道全局信息的。每个路由器都知道自己和邻居之间的距离,每过几秒,每个路由器都将自己所知的到达所有的路由器的距离告知邻居,每个路由器也能从邻居那里得到相似的信息。每个路由器根据新收集的信息,计算和其他路由器的距离,比如自己的一个邻居距离目标路由器的距离是 M,而自己距离邻居是 x,则自己距离目标路由器是 x+M。
然而存在的第一个问题是好消息传得快,坏消息传得慢。 如果有个路由器加入了这个网络,它的邻居就能很快发现它,然后将消息广播出去。要不了多久,整个网络就都知道了。但是一旦一个路由器挂了,挂的消息是没有广播的。当每个路由器发现原来的道路到不了这个路由器的时候,感觉不到它已经挂了,而是试图通过其他的路径访问,直到试过了所有的路径,才发现这个路由器是真的挂了。
第二个问题是,每次发送的时候,要发送整个全局路由表。网络大了,谁也受不了,所以最早的路由协议 RIP
就是这个算法。它适用于小型网络(小于 15 跳)。当网络规模都小的时候,没有问题。现在一个数据中心内部路由器数目就很多,因而不适用了。
链路状态路由算法
链路状态路由(link state routing),基于Dijkstra
算法。
基本思路是:当一个路由器启动的时候,首先是发现邻居,向邻居 say hello,邻居都回复。然后计算和邻居的距离,发送一个 echo,要求马上返回,除以二就是距离。然后将自己和邻居之间的链路状态包广播出去,发送到整个网络的每个路由器。这样每个路由器都能够收到它和邻居之间的关系的信息。因而,每个路由器都能在自己本地构建一个完整的图,然后针对这个图使用 Dijkstra 算法,找到两点之间的最短路径。
不像距离距离矢量路由协议那样,更新时发送整个路由表。链路状态路由协议只广播更新的或改变的网络拓扑,这使得更新信息更小,节省了带宽和 CPU 利用率。而且一旦一个路由器挂了,它的邻居都会广播这个消息,可以使得坏消息迅速收敛。
动态路由协议
基于距离矢量路由算法的 BGP
由于每个数据中心都有自己的规则,所以不光要考虑距离,也要适应规则的方便。外网路由协议(Border Gateway Protocol,简称 BGP)就是这样一个综合考虑上述因素的协议。
自治系统 AS(Autonomous System),有以下几种类型:
Stub AS
:对外只有一个连接。这类 AS 不会传输其他 AS 的包。例如,个人或者小公司的网络。Multihomed AS
:可能有多个连接连到其他的 AS,但是大多拒绝帮其他的 AS 传输包。例如一些大公司的网络。Transit AS
:有多个连接连到其他的 AS,并且可以帮助其他的 AS 传输包。例如主干网。
每个自治系统都有边界路由器,通过它和外面的世界建立联系。
BGP 又分为两类,eBGP 和 iBGP。自治系统间,边界路由器之间使用 eBGP 广播路由。内部网络也需要访问其他的自治系统。边界路由器通过运行 iBGP将 BGP 学习到的路由导入到内部网络,使得内部的路由器能够找到到达外网目的地的最好的边界路由器。
BGP 协议使用的算法是路径矢量路由协议(path-vector protocol)。它是距离矢量路由协议
的升级版。
在 BGP 里面,除了下一跳 hop 之外,还包括了自治系统 AS 的路径,从而可以避免坏消息传得慢的问题,解决了距离矢量路由协议的缺点
基于链路状态路由算法的 OSPF
OSPF(Open Shortest Path First,开放式最短路径优先)主要用在数据中心内部,用于路由决策,因而称为内部网关协议(Interior Gateway Protocol,简称 IGP)。
内部网关协议的重点就是找到最短的路径。在一个组织内部,路径最短往往最优。当然有时候 OSPF 可以发现多个最短的路径,可以在这多个路径中进行负载均衡,这常常被称为等价路由。
有了等价路由,到一个地方去可以有相同的两个路线,可以分摊流量,还可以当一条路不通的时候,走另外一条路。
小结
- 离开本局域网,就需要经过网关,网关是路由器的一个网口
- 路由器是一个三层设备,里面有如何寻找下一跳的规则
- 经过路由器之后 MAC 头要变,如果 IP 不变,就是
转发网关
,如果 IP 变,就是NAT
- 路由分静态路由和动态路由,静态路由可以配置复杂的策略路由,控制转发策略;
- 动态路由主流算法有两种,距离矢量算法和链路状态算法。基于两种算法产生两种协议,BGP 协议和 OSPF 协议。