Ubuntu软路由使用 netplan 创建虚拟网桥实现多网卡一拖N上网

  |   2 评论   |   1,164 浏览

这篇文章实际与软路由实际并没有太大关系. 只是我在一个软路由机器上最终实现了下而已.

背景

我的网络拓扑如下, 一个路由器只有三个LAN口. 但是实际小主机比较多.无法全部直接与路由器实现物理连接. 因此需要如下的网络结构. 把软路由上多余的网口利用起来给我那台老破的HomeNas提供互联网访问. 具体的软硬件环境说明如下:

  • 光猫是联通光猫.已经通桥接方式. 把拨号权限下放给到了路由器.
  • 路由: AX3600 , 1个WAN口, 3个 LAN口.
  • HPE G10V2 ,就是那个HP的小服务器. 虽然不怎么用.但是还是得要给它网. 万一要用呢,是不.
  • 软路由: 之前提到过的N6000那台. 这个破机器问题很多. 以后有机会再展开说. 它是一个有4网口的千兆(不确认,好像是2.5G,但是AX3600只支持千兆)的软路由. 但是我并没有拿它来作软路由,并且也没有安装EXSI这些虚拟化平台. 就装了一个普通的Ubuntu
  • HomeNas: 最早的工控机, 最稳定的就是它. 单网口(千兆)

image.png

目标

实现上网的方案与目标:

  • HomeNas 连接软路由小主机就像连接在AX3600路由器上一样. 不要有新的IP和新的子网. 要在连软路由和连AX3600时得到的IP都是一样的. 这样在任何时候都可以把这个工控机直接插到AX3600路由器上后的所有配置不变
  • 软路由小主机 当一台Server使用. 因此它本身当一个Ubuntu服务器使用. 同时把多余的网口提供给HomeNas小主机上网.
  • 留最小需要的2个LAN口给 GP10V2 , 一个用于iLO一个用于LAN , 这个iLO 真感觉有点鸡肋.

关键技术:

这里实际要用到的是网卡桥接(windows系统上大家常见的概念). 但是这个桥接理解上可能会有偏差. 比如大家想象的桥接可能是这样的,不管你理解是否是这样的,我第一印象确实如此.
image.png

同时在查询相关的资料时, 桥接相关的文章基本也是这样写的. 需要桥接哪张网卡,就把哪张网卡放到网桥中. 比如这个: 在 Ubuntu 上使用 Netplan 配置 Linux 桥接/VLAN 接口. 乍一看好像似乎并没有什么不妥.但是就是怎么配置都不对.

实际的网桥是这样的. 参考: 集线器、网桥、交换机的区别(详解干货!!!), 可以更详细的了解网桥的细节.
image.png

在最开始的时候,网络是计算机直连的. 因为大家的pc进行数据交换的时候,只需要把两台PC直连起来即可. 这样就像我们平时用双绞线直接把两个计算机的网口连接在一起.就可以通信了. 就像这样:
image.png

后来计算机多了后. 如果要多个计算机通信. 而同一个计算机只有一个网口. 那总不能a和b通信完后,再重新把a插到c上面吧. 于是就有了集线器(HUB) .

集线器(HUB)

集线器类似于一个总线. 把所有的计算机都挂上去, 然后通过总线的仲裁算法进行通信. 呃,这是我胡诌的, 实际hub的工作原理不是这样的. 其工作在物理层. 它就是简单的把数据从发出端口全部转发到其它所有端口.然后其它端口上的所有电脑根据是否是自己的mac地址的数据包.如果不是就是理睬. 这是一个半双工的通信. 同时只有一个在发. 其它的都处于收的状态.

集线器(HUB),它是工作在物理层的设备, 由于它只是工作在物理层的设备,所以它并不关心也不可能关心OSI上面几层所涉及的,它的工作机制流程是:从一个端口接收到数据包时,会在其他端口把这个包转发一次,因为它不知道也不可能知道这个包是发给谁的(物理层设备只关心电压这些物理概念),它也只能对所有人广播.

image.png

由于上面的网络是中心化的,同时所有的计算机都连接到了一个hub上. 那一个是计算机多了后.一个hub没有那么多的网口.一般是4-8个. 此时有人会说把多个hub集到一起不就可以了. 这样就可以多个hub串多个局域网.
image.png

但是这有一个问题,那就是如果hub多了以后. 串在一起的电脑会更多. 而所有的hub是一起共享带宽的. 比如PC1在发数据的时候,两个hub上的其它所有电脑都得接收. 换言之,其它电脑不能发数据. 当电脑过多以后, 那每个电脑分到的带宽就会非常少. 假设带宽为10M. 现在有100台电脑. 第个电脑只能分到100KBps. 但是如果更多呢. 那就会更慢. 一个电脑连接的网线上可能一直有数据在传输.但是都不是自己的数据. 直到多到所有的电脑都无法通信. 因此有了网桥.

网桥

网桥就是能够把子局域网(注意这里没有说子网. 子网是IP层的概念,网桥工作在L2. 因此没有子网的概念. 网桥与集线器不同的是:集线器工作在L1,即物理层. 因此它无法识别链路层的mac地址. 也因此它无法在发送数据报文的时候进行有目的的发送,只能把一个端口发送的数据转发到其它所有端口.
网桥工作在L2,这样网桥就可以识别数据包的目标MAC地址和源mac地址. 进行学习处理. 比如PC1发送的数据包要发送给PC2那在第一次bridge并不知道PC2mac地址,因此会尝试发给HUB2,然后hub2在物理层进行广播给pc4pc5,但是它们都不是目标机器,因此它们都不会进行响应. 此时bridge就学习到了pc2mac不在其它端口上. 因此以后就不会进行转发了.

image.png

同样,如果pc1发送包给pc4,则brigde在第一次进行尝试广播(注: 这里举例的网桥只有两个端口,实际可能有多个.这个更接近于Linux上的虚拟网桥) , 当接收到了PC4response包(注: 这里没有描述为ack实际上在链路层并没有这个概念)后bridge学习到了pc4位于右边的端口. 这样就慢慢知道了所有的端口上存在的mac地址列表有哪些.

注意: mac 地址学习应该只是通过源发送方与端口的对应关系. 而不是学习一个包是否被发送成功而得知目标mac地址的.

通过上面的网桥. 其在一定的学习时间后, 网桥知道左边的端口连接的是:pc1``pc2``pc3,而右边连接的是pc4pc5. 在进行数据包转发的时候,就可以通过目标mac地址与记录的端口与mac地址的对应关系. 决定是否把包发到另外一个端口. 这样就起到了左边网络与右边网络进行隔离的目的.
实际网桥与交换机的特征已经非常像了,只是上面的举例只有两个端口. 如果把它的端口扩展为N个. (N>=2) 那就是一个标准的交换机模式.

交换机

交换机与网桥工作原理非常类似. 同样工作在L2层. 只是它有更多的端口. 在进行数据转发的时候,如果已知mac地址与端口的对应关系后, 其发送的数据是端到端的了.我们画一个演变图进行说明. 由于交换机的口一般比较多.可以直接每个口连接一台电脑(当然也可以串接其它的交换机) 这样把hub与bridge全部放到里面.(实际应该把switch想象为更多端口的bridge更合理.直接把绿框中的hub去除. 更直观).

image.png

这样所有的计算机直接连接到了交换机上, 从物理结构上看似乎与用一个hub好像一模一样. 但是不同的是, switch是工作于L2层,同时发送数据的时候是端到端的. 不会出现广播风暴的问题.

Linux虚拟网桥

上面我们有提到网桥实际与交换机没有太大的差异. 工作原理与使用方式都基本一致. 以下是一些基本的总结:

网桥和交换机都是网络设备,负责在各个网络设备之间转发数据生。它们的主要区别如下:

  1. 工作层次:网桥和交换机都在OSI模型的第二层数据链路层工作。但在实际应用中,现代交换机通常比网桥更智能,有些交换机甚至可以在OSI模型的第三层 — 网络层工作,即所谓的三层交换机。
  2. 端口数量:网桥通常只有两个四个端口,用于连接两个或几个网络段;而交换机一般具有更多的端口,可以连接大量的网络设备
  3. 性能:由于交换机具有更高的带宽和更多的端口,因此在处理大量流量方面一般比网桥更好。
  4. 功能:现代交换机一般比网桥具有更多的高级功能,例如VLAN(虚拟局域网)支持、QoS(服务质量)支持等。
  5. 价格:由于交换机拥有更多的功能和更高的性能,所以交换机的价格通常也会比网桥更高。

简言之,交换机是网桥的升级版,具有更多的端口和更高的性能,同时也支持更多的高级网络功能。

因此,从上面的描述可以得知. 网桥与交换机的原理与特性都基本一致. 因此我们也可以把它理解为一个交换机,这校门可能更好的理解其工作原理.
而对于Linux的虚拟网桥.这个从原理上说,其是一个纯软件实现. 同时可以把它想象成一个物理设备. 同时它上面应该有一些端口可以连接设备或者其它网络. 因此它看起来应该是这样:
image.png

在真实的网桥中,网桥本身是没有IP的. 但是在Linux中的虚拟网桥是有一个IP.这个IP就是某一个网卡的IP本身.但是在逻辑上,这个IP是属于网桥而不是属性网卡的.
我们看一下以下的ifconfig的输出, 在这里我的网卡enp3enp4是放到了网桥br0下面. 这个命令输出时.这两个网卡都没有ip. 但是网桥br0有一个IP: 192.168.31.105
image.png

以下是通过命令: brctl show输出的内容: 可以看到这里有两个网桥. 一个是docker的,一个是br0.同时br0网桥attath了两个真实的物理接口.
image.png

从原理上看. 实际就把Linux内部的软件部分可以想象为一个网桥. 然后加入到网桥的所有网口都退化为端口. 也就是普通网卡时, 其作为一个终端网络接入口. 而当接入到虚拟网桥后,其本身退化为一个普通的网桥端口. 也就是我们常说的attached网卡. 同时在物理网桥上. 网桥本身是没有IP的.而在Linux的虚拟网桥中,网桥本身是有IP的. 也就是接入外部网络的端口.或者说从某个端口可以通过DHCP服务器获取到IP.那这个端口分配到的IP变记为了网桥的IP.

注: 可以实验把多个网桥中的网卡都接入到路由器上. 最后实际只有一个端口上分分配到IP.

实现

Ubuntn中在18.04以后, 特别是桌面版本使用NetPlan来进行网络配置与管理. 在默认的系统安装目录.下有一个文件,位于目录: /etc/netplan/...; 而在我的系统下有一个文件:
image.png

默认文件内容如下:

# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: NetworkManager

这个redender是前端渲染器. 对于桌面版本一般是: NetworkManager ,而对于服务器版本,一般是:networkd; 我用的是桌面版本,因此使用的是NetworkManager,这里我不做任何变更.

注: NetworkManagernetworkd 区别:

在Netplan中,renderer用于指定用于处理并应用配置的后端系统。Netplan设计为对几个不同的网络配置后端进行抽象。目前,它可以生成网络管理(NetworkManager)或systemd-networkd的配置。

networkd(Systemd-networkd)是一个系统守护进程,可以用于配置网络连接。它是systemd的一部分,适用于最小化设备、容器、服务器等环境,因为它轻便且低内存使用。
NetworkManager 则是一个更全面、基于GUI的工具,适用于桌面环境,特别是对于那些需要经常更改网络设置(例如Wi-Fi、VPN、移动网络等)的情况它更方便使用。NetworkManager 具有与许多不同的网络服务进行集成的能力,并易于与诸如 applet 或 NetworkManager 的命令行工具 nmcli 之类的用户级工具一起使用。
不过,一般推荐在服务器环境使用networkd,而在桌面环境使用NetworkManager。

添加网桥

要添加网桥就需要修改此文件,添加网桥相关的配置. 我的软路由上有4个网口. 分别是:

  • enps20 网卡0 直接连到路由器(测试用)
  • enps30 网卡1 连接到路由器
  • enps40 网卡2 连接到第二台电脑:HomeNAS
  • enps50 网卡3 暂空闲

我的修改后的netplan配置如下:

修改以后可以使用命令: sudo netplan apply使新的配置生效 .
如果要看一些调试信息可以使用: sudo netplan --debug apply

# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: NetworkManager
  ethernets:
          enp3s0: # 连接到互联网的网口 ( 连接AX3600 )
                  dhcp4: false
                  dhcp6: false
          enp4s0: # 连接到下游设备网口 ( HomeNAS )
                  dhcp4: false
                  dhcp6: false
          enp5s0:
                  dhcp4: false
                  dhcp6: false
  bridges:
          br0:
                  interfaces: [enp3s0,enp4s0,enp5s0]
                  dhcp4: true

可以用命令:ip a查看.
image.png

这里我的是enp2s0是单独接入到了路由器上. 可以忽略. 其它三张网卡加入到了网桥中.

  • 其中一个接入到路由器: 网卡2 - enp3s0
  • 第二个接到第二台电脑: 网卡2 - enp4s0
  • 第三个网卡空闲: 网卡3 - enp5s0

检查其它配置

在以上的配置后,你八成是可能下游电脑是联不上网的. 因为网桥部分的电脑还有一些配置工作需要做.

  • 首先要看是否开启了数据转发
  • 另外要看网络防火墙对于DHCP包的转发是否会被拦截.

首先通过命令:sysctl net.ipv4.ip_forward查看是否是1.如果是1表明电脑开启了ipv4数据转发.
image.png

如果没有开启,可以命令命令:

sudo sysctl -w net.ipv4.ip_forward=1

当然这个命令不是永久的,重启就会失效.如果你需要永久修改这个参数,你可以编辑 /etc/sysctl.conf 文件,在其中添加一行 net.ipv4.ip_forward = 1,然后保存文件并退出。这样,这个设置将在系统启动时自动生效。
添加完这行之后,您可以运行 sudo sysctl -p 使修改立刻生效,无需重启系统。

在确保数据转发已经开启的情况下, 有可能你的下游电脑仍然获取不到路由器分配的IP. 这个时候可以在第一台电脑上运行命令:sudo tcpdump -i br0 port 67 or port 68 -e -n dump网桥上的67和68端口.这个可以查看dhcp相关的数据包.image.png

这个表明下游的电脑一直在发送dhcp请求,但是并没有收到路由器的回复.因此下游电脑一直分配不到IP.
此时可以通过查看查看iptable相关的具体的转发策略:

命令: sudo iptables -L -n -v

image.png

可以发现这里的默认策略是DROP ; FORWARD链的默认策略是DROP,这意味着除非明确允许,否则所有转发的数据包都会被丢弃。如果DHCP请求需要通过这台电脑转发,那么可能就会在这里被阻止。
解决这个问题的一种方法是将FORWARD链的默认策略改为ACCEPT。这样,除非明确禁止,否则所有需要被转发的数据包都会被允许。要更改此策略,请运行以下命令:

# 默认没有阻止的数据包转发都接受
sudo iptables -P FORWARD ACCEPT

请注意,这将允许所有转发的数据包,可能会带来安全隐患。因此你需要根据自己的网络环境,实际情况和安全需求做适当的选择和调整。另外,这个命令只会影响当前的iptables策略,如果你重启机器,这个策略会恢复原状。如果你想要永久更改这个设置,你需要用iptables-save和iptables-restore命令,或者使用操作系统提供的防火墙管理工具来保存和恢复iptables规则。
由于我的电脑是在路由器内部的内网中.并没有直接曝露在外网上.同时这个电脑本身要承担一些路由的功能,因此我就直接修改为允许了. 修改以后,下游电脑就可以拿到正确的IP了.

转发策略持久化

上面的命令: sudo iptables -P FORWARD ACCEPT在电脑重启后,就会失效.这样下游的电脑就没法获取到IP地址了. 又需要登陆服务器上去手工操作后,才能恢复. 所以会比较麻烦.
简单的做法就是做一个开机自启服务. 且只运行一次. 在开机后自动执行上面的命令. 这样就达到了开机自动配置转发策略的目的. 具体创建一个systemd服务方法如下:

  1. 创建一个新的 Systemd 服务单元文件:
sudo vim /etc/systemd/system/iptables-forward-accept.service
  1. 在文件里面输入如下内容:
[Unit]
Description=Set iptables FORWARD chain default policy to ACCEPT
# 注意: 需要在 docker.service 服务后启动
After=docker.service

[Service]
Type=oneshot
# ExecStartPre=/bin/sleep 30
ExecStart=/sbin/iptables -P FORWARD ACCEPT

[Install]
WantedBy=multi-user.target
  1. 保存并关闭文件。然后启用并启动服务:
sudo systemctl enable iptables-forward-accept
sudo systemctl start iptables-forward-accept

通过以上的配置. 我们就得到了一个可用的网桥. 使软路由可以自己上网的同时, 让下游的电脑也可以用来上网. 这样就不用再单独购买一个交换机.或者换有更多网口的路由器. 值得说明的是,上面的service配置里面有一个非常特殊的就是其运行需要在docker.service服务之后. 原因是docker服务也会配置网桥,而它的配置可能会把我们的这里的相关的转发规则的配置给覆盖掉,导致配置仍然不生效的问题.

参考与总结

这个需求其实比较简单,但是在具体的环境下,可能会有很多细节.比如用什么配置.怎么配置. 等, 最后还要对Linux的网桥相关的知识有基本的理解. 最后还要结合历史中的网桥的概念加深对网桥的理解. 在排查问题时会更游刃有余些. 关于相关的基础知识和相关的知识点可以参考:

  1. https://zhuanlan.zhihu.com/p/421276975
  2. https://zhuanlan.zhihu.com/p/293667316
  3. https://zhuanlan.zhihu.com/p/440970417

评论

  • firfor @亲亲 回复»

    很好的建议,有需要的同学可以试试,我的网ipv4够用了也就没再深入折腾。

  • 亲亲 回复»

    谢谢分享!

    文章写得很棒,把原理和操作步骤都说得明明白白!

    提个建议,启动脚本加上ipv6支持。ip6tables -P FORWARD ACCEPT

发表评论


取消