RHEL 7 网络初探
Redhat Linux 7已经出来好久了,但是我一直没有仔细研究。
现在因为项目需要,我需要弄明白Oracle Linux 7上面的网络配置。
Oracle Linux其实和Redhat Linux 7是几乎完全一样的。
所以我下面要写的东西对于两者应该是通用的。CentOS 7应该也可以。
NetworkManager vs network
在RHEL 6里面,其实已经有NetworkManager这个东西了。
但是我们platform team总是给我们在ifcfg-*里面加上了NM_CONTROLLED=no
,
所以很长时间以来我们用的都是古老的network scripts。
为了方便地做各种实验,我用vagrant创建一台两个网口的虚拟机:
Vagrant.configure(2) do |config|
config.vm.box = "OL7DockerBtrfs"
config.vm.box_check_update = false
config.vm.network "private_network", ip: "192.168.56.101"
config.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
这个Vagrantfile里面的box OL7DockerBtrfs
是我自己用packer做出来的。
换用标准的rhel 7或者centos 7应该行为没有差别。
在我刚刚启动起来的OL7 vagrant虚拟机里面:
[root@BasicOL7-Docker ~]# systemctl status network
● network.service - LSB: Bring up/down networking
Loaded: loaded (/etc/rc.d/init.d/network)
Active: active (exited) since Tue 2016-06-14 07:18:52 EDT; 1min 25s ago
Docs: man:systemd-sysv-generator(8)
Process: 652 ExecStart=/etc/rc.d/init.d/network start (code=exited, status=0/SUCCESS)
Jun 14 07:18:52 BasicOL7-Docker systemd[1]: Starting LSB: Bring up/down network....
Jun 14 07:18:52 BasicOL7-Docker network[652]: Bringing up loopback interface: ...'
Jun 14 07:18:52 BasicOL7-Docker network[652]: Could not load file '/etc/sysconf...'
Jun 14 07:18:52 BasicOL7-Docker network[652]: Could not load file '/etc/sysconf...'
Jun 14 07:18:52 BasicOL7-Docker network[652]: Could not load file '/etc/sysconf...'
Jun 14 07:18:52 BasicOL7-Docker network[652]: [ OK ]
Jun 14 07:18:52 BasicOL7-Docker network[652]: Bringing up interface enp0s3: [ ...]
Jun 14 07:18:52 BasicOL7-Docker systemd[1]: Started LSB: Bring up/down networking.
Hint: Some lines were ellipsized, use -l to show in full.
[root@BasicOL7-Docker ~]# systemctl status NetworkManager
● NetworkManager.service - Network Manager
Loaded: loaded (/usr/lib/systemd/system/NetworkManager.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2016-06-14 11:18:46 EDT; 3h 58min left
Main PID: 530 (NetworkManager)
CGroup: /system.slice/NetworkManager.service
├─530 /usr/sbin/NetworkManager --no-daemon
└─590 /sbin/dhclient -d -q -sf /usr/libexec/nm-dhcp-helper -pf /var/r...
Jun 14 11:18:46 BasicOL7-Docker NetworkManager[530]: NetworkManager stat...
Jun 14 11:18:46 BasicOL7-Docker NetworkManager[530]: Policy set 'enp0s3'...
Jun 14 11:18:46 BasicOL7-Docker NetworkManager[530]: (enp0s3): Activatio...
Jun 14 11:18:46 BasicOL7-Docker dhclient[590]: bound to 10.0.2.15 -- renewal in....
Jun 14 07:18:52 BasicOL7-Docker NetworkManager[530]: startup complete
Jun 14 07:18:58 BasicOL7-Docker NetworkManager[530]: ifcfg-rh: new conne...
Jun 14 07:18:58 BasicOL7-Docker NetworkManager[530]: ifcfg-rh: Ignoring ...
Jun 14 07:18:58 BasicOL7-Docker NetworkManager[530]: (enp0s8): device st...
Jun 14 07:18:58 BasicOL7-Docker NetworkManager[530]: (enp0s8): link disc...
Jun 14 07:18:58 BasicOL7-Docker NetworkManager[530]: (enp0s8): link conn...
Hint: Some lines were ellipsized, use -l to show in full.
这里可以看到network和NetworkManager都起来了。
这里的network.service是由systemd-sysv-generator
在启动时创建的,为了兼容
古老的网络启动脚本。
启动网口
Vagrant虚拟机运行起来之后,我可以用ip -4 addr
看到,我要的两个网口都顺利
拿到了IP地址:
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: enp0s3: mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
valid_lft 86111sec preferred_lft 86111sec
3: enp0s8: mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 192.168.56.101/24 brd 192.168.56.255 scope global enp0s8
valid_lft forever preferred_lft forever
然后去看看这两个网卡的ifcfg文件:
[root@BasicOL7-Docker ~]# cd /etc/sysconfig/network-scripts/
[root@BasicOL7-Docker network-scripts]# ls ifcfg-*
ifcfg-enp0s3 ifcfg-enp0s8 ifcfg-lo
[root@BasicOL7-Docker network-scripts]# cat ifcfg-enp0s3
# Generated by dracut initrd
NAME="enp0s3"
DEVICE="enp0s3"
ONBOOT=yes
NETBOOT=yes
UUID="909dae31-7e36-4c00-a74f-d33399600fe0"
IPV6INIT=yes
BOOTPROTO=dhcp
TYPE=Ethernet
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
[root@BasicOL7-Docker network-scripts]# cat ifcfg-enp0s8
#VAGRANT-BEGIN
# The contents below are automatically generated by Vagrant. Do not modify.
NM_CONTROLLED=no
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.56.101
NETMASK=255.255.255.0
DEVICE=enp0s8
PEERDNS=no
#VAGRANT-END
看上去不错哦,一个网卡enp0s3
是用network manager管理的,另一个enp0s8
则是
用传统方法管理的。
这一点也可以在nmcli device
的输出里面看出来:
[root@BasicOL7-Docker network-scripts]# nmcli device
DEVICE TYPE STATE CONNECTION
enp0s3 ethernet connected enp0s3
enp0s8 ethernet unmanaged --
lo loopback unmanaged --
现在问题来了,如果我想让enp0s8也给network manager管理,怎么办?
我试试看去掉NM_CONTROLLED=NO
这一行,然后再次运行nmcli device
,发现
它依然是unmanaged。直到我运行过systemctl restart NetworkManager
之后,
设备enp0s8
现在才是connected状态:
[root@BasicOL7-Docker network-scripts]# nmcli device
DEVICE TYPE STATE CONNECTION
enp0s3 ethernet connected enp0s3
enp0s8 ethernet unmanaged --
lo loopback unmanaged --
[root@BasicOL7-Docker network-scripts]# systemctl restart NetworkManager
[root@BasicOL7-Docker network-scripts]# nmcli device
DEVICE TYPE STATE CONNECTION
enp0s3 ethernet connected enp0s3
enp0s8 ethernet connected enp0s8
lo loopback unmanaged --
不重启NetworkManager可以吗?
是可以的。
只需要nmcli connection load /etc/sysconfig/network-scripts/ifcfg-enp0s8
。
或者nmcli connection reload
。
检查网口状态
传统的命令当然还是能继续用的,比如说:
- ip link show
- ip -4 addr
- ifconfig enp0s8
现在,用nmcli,可以:
- nmcli device show enp0s8
- nmcli device status
要改变网口状态,比方说要把一个网口断线,以前我们有这些命令:
- ip link set enp0s8 down
- ifconfig enp0s8 down
- ifdown enp0s8
现在,用nmcli,可以:
- nmcli device disconnect enp0s8
我测试里面发现,ifup enp0s8
的效果和nmcli device connect enp0s8
相同。
应该ifup
就是简单封装了一下nmcli device connect
。
同样地,ifdown
和nmcli device disconnect
效果相同。
这两组命令执行完了之后,状态都可以通过nmcli device status
看出来。
但是,要小心了,底层的ip link
命令和ifconfig
就不一样了。仔细看下面的例子:
[root@BasicOL7-Docker ~]# nmcli device show enp0s8
GENERAL.DEVICE: enp0s8
GENERAL.TYPE: ethernet
GENERAL.HWADDR: 08:00:27:D1:3F:20
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION: System enp0s8
GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/3
WIRED-PROPERTIES.CARRIER: on
IP4.ADDRESS[1]: 192.168.56.101/24
IP4.GATEWAY:
IP6.GATEWAY:
[root@BasicOL7-Docker ~]# ip link set enp0s8 down
[root@BasicOL7-Docker ~]# nmcli device show enp0s8
GENERAL.DEVICE: enp0s8
GENERAL.TYPE: ethernet
GENERAL.HWADDR: 08:00:27:D1:3F:20
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION: System enp0s8
GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/3
WIRED-PROPERTIES.CARRIER: off
IP4.ADDRESS[1]: 192.168.56.101/24
IP4.GATEWAY:
IP6.GATEWAY:
这里我做过了ip link set enp0s8 down
之后,nmcli device show enp0s8
看到的
状态依旧是connected。不过有一个property发生了变化:WIRED-PROPERTIES.CARRIER变成了off。
__ 也就是说,我们要看一个网卡是不是能收发数据,除了看state,还需要看carrier属性。 __
监控网卡状态事件
用传统办法监控网卡状态,我们可以用netlink socket,可是那需要编程啊,
还挺费事的。
NetworkManager有一个好处,它是挂到dbus上面的一个服务。借助于dbus,
我们可以方便地查询状态、监控事件变化,还可以修改配置。
比方说,我们用gdbus命令监视NetworkManager上面的事件:
# gdbus monitor --system --dest org.freedesktop.NetworkManager
当我在另一个窗口做ip link set enp0s8 up
的时候,这个gdbus就会瞬间输出:
/org/freedesktop/NetworkManager/Devices/1: org.freedesktop.NetworkManager.Device.Wired.PropertiesChanged ({'Carrier': , 'AvailableConnections': <[objectpath '/org/freedesktop/NetworkManager/Settings/1']>},)
这里看到Carrier属性变成了true。org.freedesktop.NetworkManager.Device.Wired.PropertiesChanged
是一个signal,所以我们很容易写程序向dbus注册一个listener。
__ TODO: 写一个python程序监控网口状态 __
创建bond口
现在我想把enp0s8变成bond0。这个bond口里面只有这一个slave。
使用nmcli,这事情不难。
# nmcli connection add con-name bond0 ifname bond0 type bond
# nmcli connection modify bond0 bond.options "mode=active-backup,primary_reselect=failure"
# nmcli connection modify enp0s8 connection.master bond0 connection.slave-type bond
这就好了吗?
做完了这些之后,我去看ifcfg-bond0,没问题。看ifcfg-enp0s8,也没问题。
可是,下面的输出就奇怪了:
[root@BasicOL7-Docker network-scripts]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
什么鬼?我不是已经把mode改成active-backup了吗?另外,为什么enp0s8还没有到slave里面?
做一次nmcli connection reload
试试看,不起作用。
那么做一次nmcli connection down bond0
和nmcli connection up bond0
,
效果怎样?
Bonding Mode: fault-tolerance (active-backup)
Primary Slave: None
Currently Active Slave: None
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
好了,mode变了,可喜可贺。可是为什么slave还不出来?
再来做一次nmcli connection down enp0s8
和nmcli connection up enp0s8
。
这一次终于生效了。
__ 注意,这里发现了一个坑。修改bond options之后,必须connection down/up。 __
__ 注意,修改了eth口的master之后,必须connection down/up。 __
删除bond0口
这个操作和上面的操作刚好相反。我已经有bond口了,怎么把它删掉呢?
乍一看,简单嘛:nmcli connection connection delete bond0
。
这一步做完了之后,的确ifcfg-bond0消失了。
可是别忘了把slave网卡上面的master和slave属性去掉:
# nmcli connection modify enp0s8 connection.master "" connection.slave-type ""
这个命令执行完了之后,nmcli connection show enp0s8
显示的确master属性没了。
可是,可是……为什么检查ifcfg-enp0s8,这可恶的MASTER和SLAVE还在?
而且我做一次nmcli connection reload
之后,master和slave又回来了。
__ 这肯定是一个bug。明天上班之后向Oracle Linux team报bug去。__
今天就玩这么多,洗洗睡了。