Linux中的网络虚拟化
网络虚拟化的类型:
桥接:创建一个虚拟桥设备,将虚拟机连接至桥设备上,再给桥设备配置一个IP地址,作为宿主机与外部通信的地址,即可完成与外网的通信(一起使用物理网卡的硬件功能),不过此时虚拟机使用的公网地址;
隔离:仅将需要互相通信的虚拟机的后半段网卡添加到同一个虚拟的桥设备上,即可完成虚拟机之间的通信,且与外网乃至是物理机隔离;
路由:将虚拟机关联至虚拟桥设备上,再给桥设备配置一个与虚拟机同段的ip地址(内网地址)作为虚拟机的网关(物理网卡是连接外网的,所以应该与内网IP地址不是一个段),最后再打开物理主机的核心转达功能,即可让虚拟机可以ping外部主机,但是外部主机无法发送相应包,因为外部主机没有到达虚拟机的路由;
NAT:在路由模型的基础上,为其配置SNAT规则,即可完成真正的虚拟机与外网通信,且自己使用的是内网地址;但是这样还有一个问题,就是外网不能主动访问内网的虚拟机,除非再为其配置DNAT规则;
Linux内核支持的隔离功能:
namespace(名称空间):netns是在内核中实现的,使用iproute所提供的netsn这个OBJECT来对其进行管理;且Centos6所提供的iproute工具不具有此OBJECT,需要依赖于OpenStack Icehouse源(https://repos.fedorapeople.org/openstack/EOL/openstack-icehouse/epel-6/)来提供;
文件系统隔离:让分离的多个空间都认为仅有自己在使用文件系统;
网络隔离:主要用于实现网络资源的隔离,包括隔离网络设备、IPV4及IPV6地址、IP路由表、防火墙、/proc/net、/sys/class/net以及套接字等;
IPC隔离:各个被分离的空间中的进程互不影响,不可通信;
用户和用户组隔离
PID隔离:对各名称空间中的PID进行重新标号,两个不懂的名称空间可以使用相同的PID号;
UTS隔离:提供主机名和域名的隔离;
NETNS:
ip netns list:显示名称空间列表;
ip netns add NAME:添加一个名称空间;
ip [-all] netns delete [NAME]:删除名称空间;
ip [-all] netns exec [NAME] cmd ...:在指定名称空间中运行命令;
例子:~]# ip netns exec r1 ifconfig -a
ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ netns { PID | NAME } ]:将某个网卡设备分配个某个名称空间;
ip link add DEVICE1 type TYPE(此处为veth) peer name DEVICE2:创建一对虚拟网卡;
TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
bridge | bond | ipoib | ipip | sit | vxlan |gre | gretap |vti | nlmon |bond_slave | geneve | bridge_slave | macsec }
cgroups:
用于完成资源配置,限制被各namespace隔离起来的资源;还可以为资源设置权重(比如某个名称空间占用总资源的百分之80,另一个名称空间仅占用总资源的百分之10,因为前者更重要或者他花的钱更多)、计算资源使用量、完成各种所需的管理任务等;
通过虚拟设备(OpenVSwitch)解决跨越物理主机的虚拟机通信问题:
在linux中我们可以通过创建成对的虚拟机网卡接口,然后将这些虚拟网卡接口与隔离出来的namespace相连接,从而在linux内部创建复杂的虚拟网络;比如创建一对虚拟网卡(~]# ip link add veth1.1 type veth peer name veth1.2),再创建出一块名称空间(~]# ip netns add r1),将成对儿的虚拟机网卡的一端分配给名称空间(~]# ip link set vetn1.2 netns r2),将另一端分配给宿主机上为虚拟机创建的虚拟桥设备,就可以实现类似将虚拟机连接至路由器(隔离出来的namespace就可以看成是一个路由器)的功能;
示例:
创建两个KVM虚拟机,使其连接到一个名为br-in的虚拟桥设备(s)上,创建一个名称为r1的namespace作为路由器,通过一对虚拟网卡(rinr,rins)将br-in与r1相连,使虚拟机可以通过r1与外网通信,再创建一对虚拟网卡(rexr,rexs),用于连接r1与同外网交互的虚拟网桥,从而实现与外网通信;
配置过程:
1.创建虚拟机并将虚拟机连接至桥br-in:
~]# brctl addbr br-in
~]# ip link set br-in up
~]# brctl addbr br-ex
~]# ip link set br-ex up
~]# ip addr del 192.168.0.8/24 dev ens34; ip addr add 192.168.0.8/24 dev br-ex; brctl addif br-ex ens34 将IP地址配置到桥设备上,使物理网卡作为硬件设备发送数据包;
~]# mkdir -pv /images/kvm/
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm1.qcow2
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm2.qcow2
~]# cat /etc/qemu-ifup
#!/bin/bash
BRIDGE=br-in
if [ -n "$1" ] ; then
ip link set $1 up
brctl addif $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No Interface specified."
exit 1
fi
~]# chmod +x /etc/qemu-ifup
~]# qemu-kvm -m 128 -smp 2 -name kvm1 -drive file=/images/kvm/kvm1.qcow2,if=virtio,media=disk -net nic,macaddr=52:54:00:12:34:55 -net tap,ifname=vif1.0,script=/etc/qemu-ifup -nographic
登录虚拟机,为KVM1配置ip地址:ifconfig eth1 10.0.1.1/24 up
~]# qemu-kvm -m 128 -smp 2 -name kvm2 -drive file=/images/kvm/kvm2.qcow2,if=virtio,media=disk -net nic,macaddr=52:54:00:12:34:66 -net tap,ifname=vif2.0,script=/etc/qemu-ifup -nographic
登录虚拟机,为KVM2配置ip地址:ifconfig eth1 10.0.1.2/24 up
2.创建作为路由器的namespace(创建namespace之前要打开物理机的核心转发功能:~]# echo 1 > /proc/sys/net/ipv4/ip_forward):
~]# ip netns add r1 创建一个namespace
~]# ip link add rinr type veth peer name rins 添加一个对儿用于连接内网的网卡
~]# ip link show
~]# ip link set rinr up
~]# ip link set rins up
~]# brctl addif br-in rins 将路由器与内网交换机相连
~]# ip link set rinr netns r1 将内网成对儿网卡的一端添加至路由器(r1)
~]# ip netns exec r1 ip link set rinr name eth0
~]# ip netns exec r1 ip link set eth0 up
~]# ip netns exec r1 ip addr add 10.0.1.254/24 dev eth0 设置路由器对内网的接口的IP地址,且作为虚拟机的网关(回到虚拟机里面设置网关:~]# route add default gw 10.0.1.25)
~]# ip link add rexr type veth peer name rexs 添加一对儿用于连接外网的网卡
~]# brctl addif br-ex rexs 将路由器与同外网交互的虚拟网桥相连
~]# ip link set rexr netns r1 将外网成对儿网卡的一端添加至路由器(r1)
~]# ip netns exec r1 ip link set rexr name eth1
~]# ip netns exec r1 ip link set eth1 up
~]# ip netns exec r1 ip addr add 192.168.0.100/24 dev eth1 设置路由器对外网的接口的IP地址
Note:此时可以做一些ping测试,并且使用tcpdump抓包查看过程;此时虚拟机与外网是无法通信的,数据包只能出去,但是回不来;
~]# ip netns exec r1 iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! -d 10.0.1.0/24 -j SNAT --to-source 192.168.0.8 添加一条SNAT规则,此时虚拟机才可与外网互相通信;
~]# ip netns exec r1 dnsmasq --dhcp-range=10.0.1.100,10.0.1.120 为虚拟机配置DHCP,使其动态获得地址
# udhcpc -R 虚拟机重新获得IP地址
Note:上面的内容与OpenVswitch没有直接关系,仅仅是展示linux本身也可以实现路由交换功能;
OpenVswitch:软件模拟的交换机;
支持802.1q
支持NIC bonding
支持NetFlow,sFlow
支持Qos
支持GRE,Vxlan
……
OVS的组成部分:
ovs-vswitchd:OVS的守护进程,实现数据报文的交换功能,其与linux内核兼容模块一起实现了基于流的交换技术;
ovsdb-server:轻量级的OVS数据库服务,用于存储OVS的配置信息;
ovs-dpctl:用于配置转发规则;
ovs-vsctl:用于获取或者更改ovs-vswitchd的配置信息,将修改信息保存至ovsdb-server中;
常用选项:
show:查看已配置的信息;
add-br BRIDGE:添加桥设备;
del-br BRIDGE:删除桥设备;
add-port BRIDGE PORT:往桥设备上添加端口;
del-port [BRIDGE] PORT:从桥设备上删除端口;
list-ports BRIDGE:显示指定桥设备上的端口;
list-br:显示当前主机上的所有已添加的桥设备;
list TBL [REC]:显示指定表中的数据;
TBL可以为interface、port、br等
set TBL REC COL[:KEY]=VALUE:设置某个表中的某条数据的值;
例子:ovs-vsctl set port vif0.0(name字段) tag=10(欲修改字段)
remove TBL REC COL [KEY=]VALUE:将某个表中的某条数据的值移除;
例子:ovs-vsctl set port vif0.0 tag 10
示例1:
在Vmware中开启一个虚拟机作为物理机,并且为其添加两块网卡;一块作为管理接口(VMnat8),一块作为物理机互相通信的接口(VMnat2自定义);接着在物理机中创建多个虚拟机,通过OpenVswitch的vlan功能使同一物理主机的相同vlan中的虚拟机通信;
配置过程:
~]# yum install openvswitch
~]# systemctl restart network.service
~]# ovs-vsctl add-br br-in 创建一个桥设备
~]# ovs-vsctl show
Bridge br-in:桥设备
Port br-in:端口,可以看作交换机上的物理端口
Interface br-in:接口,可以看作交换机上的端口号
type: internal:接口类型
~]# cat /etc/qemu-ifup
#!/bin/bash
BRIDGE=br-in
if [ -n "$1" ]; then
ip link set $1 up
sleep 1
ovs-vsctl add-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# cat /etc/qemu-ifdown
#!/bin/bash
BRIDGE=br-in
if [ -n "$1" ]; then
ip link set $1 down
sleep 1
ovs-vsctl del-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# chmod +x /etc/qemu-ifdown /etc/qemu-ifup
~]# mkdir -pv /images/kvm/
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm1.qcow2
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm2.qcow2
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm3.qcow2
~]# qemu-kvm -m 128 -smp 2 -name vm1 -drive file=/images/kvm/kvm1.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:33 -net tap,ifname=vif0.0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -nographic
~]# qemu-kvm -m 128 -smp 2 -name vm2 -drive file=/images/kvm/kvm2.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:55 -net tap,ifname=vif1.0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -nographic
vm1:# ifconfig eth0 10.0.10.1/24 up 为vm1配置IP地址
vm2:# ifconfig eth0 10.0.10.2/24 up 为vm2配置IP地址
Note:可以互ping一下,看网络是否畅通;
~]# ovs-vsctl list port 查看接口的vlan tag值;
~]# ovs-vsctl set port vif0.0 tag=10 设置vif0.0接口的tag值为10,即将其添加至vlan10中;
~]# ovs-vsctl list port 再查看一下接口的vlan tag值,发现已经更改;
Note:在让vm1与vm2互ping一下,发现已经ping不通了;
~]# ovs-vsctl add-br br-test 再添加一个桥设备
~]# cat /etc/qemu-ifup2
#!/bin/bash
BRIDGE="br-test"
if [ -n "$1" ]; then
ip link set $1 up
sleep 1
ovs-vsctl add-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# cat /etc/qemu-ifdown2
#!/bin/bash
BRIDGE="br-test"
if [ -n "$1" ]; then
ip link set $1 down
sleep 1
ovs-vsctl del-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# qemu-kvm -m 128 -smp 2 -name vm3 -drive file=/images/kvm/kvm3.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:55 -net tap,ifname=vif2.0,script=/etc/qemu-ifup2,downscript=/etc/qemu-ifdown2 -nographic
# ifconfig eth0 10.0.10.3/24 up
~]# ip link add s0 type veth peer name s1 添加一对儿连接br-in与br-test的网卡
~]# ip link set s0 up
~]# ip link set s1 up
~]# ovs-vsctl add-port br-in s0
~]# ovs-vsctl add-port br-test s1
将br-in与br-test连接起来,且接口默认就为trunk类型;但是两个虚拟交换机上的虚拟机在都没有添加vlan tag时是无法通信的,只有配置其为某一vlan才可以通信;
~]# ovs-vsctl set port vif2.0 tag=10 将vm3的vlan tag改为10
Note:用vm1 ping vm3发现可以通信,用vm2 ping vm3无法通信,至此目的完成;
示例2:
通过GRE技术连接使不在同一网段中的物理机中的虚拟机通信;
在Vmware中开启两个虚拟机作为物理机,并且为其添加两块网卡;一块作为管理接口(VMnat8),一块作为物理机互相通信的接口(VMnat2自定义);接着在物理机中创建多个虚拟机,通过OpenVswitch的vlan与GRE功能使不同物理主机的相同vlan中的虚拟机通信;
配置过程:
Host1:
~]# ip netns add r0 创建一个namespace名为r0
~]# ip link add sif0 type veth peer name rif0 添加一对儿网卡用于连接r0与br-in;
~]# ip link set sif0 up
~]# ip link set rif0 up
~]# ip link set rif0 netns r0 将其一端的网卡分配给r0
~]# ovs-vsctl add-port br-in sif0 将另一端连接至br-in
~]# ip netns exec r0 ip link set rif0 up
~]# ip netns exec r0 ip addr add 10.0.20.254/24 dev rif0
~]# ip netns exec r0 dnsmasq --dhcp-range=10.0.20.200,10.0.20.250,86400 --dhcp-option=option:router,10.0.20.154 在r0中配置dhcp服务,用于给Host1中的vm1与mv2以及Host2中的vm1分配IP地址;
~]# qemu-kvm -m 128 -smp 2 -name vm1 -drive file=/images/kvm/kvm1.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:33 -net tap,ifname=vif0.0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -nographic
~]# qemu-kvm -m 128 -smp 2 -name vm2 -drive file=/images/kvm/kvm2.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:55 -net tap,ifname=vif1.0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -nographic
vm1:# udhcpc -R 使虚拟机自动获取IP地址;
vm2:# udhcpc -R
~]# ifconfig ens34 192.168.20.1/24 up 为VMnet2中的物理网卡配置IP地址;
~]# ovs-vsctl add-port br-in gre0 在br-in桥上添加一个名为gre0的端口;
~]# ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.20.2 将gre0端口的类型改为gre,并且指定远端IP地址;
~]# ovs-vsctl list interface gre0
Host2:
~]# ovs-vsctl add-br br-in
~]# mkdir -pv /images/kvm/
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm1.qcow2
~]# cp cirros-no_cloud-0.3.0-x86_64-disk.img /images/kvm/kvm2.qcow2
~]# cat /etc/qemu-ifup
#!/bin/bash
BRIDGE=br-in
if [ -n "$1" ]; then
ip link set $1 up
sleep 1
ovs-vsctl add-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# cat /etc/qemu-ifdown
#!/bin/bash
BRIDGE=br-in
if [ -n "$1" ]; then
ip link set $1 down
sleep 1
ovs-vsctl del-port $BRIDGE $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error:No port specified."
exit 2
fi
~]# chmod +x /etc/qemu-ifdown /etc/qemu-ifup
~]# qemu-kvm -m 128 -smp 2 -name vm1 -drive file=/images/kvm/kvm1.qcow2,media=disk,if=virtio -net nic,model=virtio,macaddr=52:54:00:11:22:66 -net tap,ifname=vif0.0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -nographic
~]# ifconfig ens34 192.168.20.2/24 up
~]# ovs-vsctl add-port br-in gre0 在br-in桥上添加一个名为gre0的端口;
~]# ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.20.1 将gre0端口的类型改为gre,并且指定远端IP地址;
Note:现在Host2中的vm1虚拟机也可以通过Host1中的r0中的dnsmasq获取IP地址了(别忘记关闭防火墙);且Host1与Host2中的虚拟机都是互通的;
在Host1的ens34上的抓包结果:
现在我们已经启动了三个虚拟机,其中Host1中有vm1和vm2,Host2中有vm1,且三者可以互通;我们可以通过vlan功能,让Host1的vm2与Host2中的vm1通信,但是Host1的vm1却不能与自己的 vm2通信;但是因为示例1已经演示过了,这里就不赘述了!!!
示例3:
通过VxLAN技术实现不同物理主机上的虚拟机互通;
相比于VLAN,VxLAN可以支持更多的vlan;且VxLAN可以完成类似GRE(隧道)的功能;
拓扑同示例2
配置过程:
在示例2的基础上继续配置(没有添加vlan控制);
Host1:
~]# ovs-vsctl del-port gre0
~]# ovs-vsctl add-port br-in vx0 -- set interface vx0 type=vxlan options:remote_ip=192.168.20.2
Host2:
~]# ovs-vsctl del-port gre0
~]# ovs-vsctl add-port br-in vx0 -- set interface vx0 type=vxlan options:remote_ip=192.168.20.1
此时Host1与Host2中的虚拟机通过VxLAN互通;
根据马哥视频做的学习笔记,如有错误欢迎指正;侵删