openvswitch
Open vSwitch即开放虚拟交换标准。是一款虚拟交换的软件。虚拟交换就是利用虚拟平台,通过软件的方式形成
交换机部件。跟传统的物理交换机相比,虚拟交换机同样具备众多优点,一是配置更加灵活。一台普通的服务器可以
配置出数十台甚至上百台虚拟交换机,且端口数目可以灵活选择。
实验环境:
centos7.3 3台。
node1 eth0 192.168.10.128/24 (仅主机 VMnet1)
eth1 (VMnet2)
网关 192.168.10.130
node2 eth0 192.168.10.129/24 (仅主机 VMnet1 ) (实现GRE 路由转发时用到,跨主机实现VLAN)
eth1 (VMnet2)
网关 192.168.10.130
node3 eth0 192.168.10.129/24 (仅主机 VMnet1 )
eth1 192.168.1.100 ( VMnet0 )
网关 192.168.1.1
安装openvswitch
他的安装包是在openstack的yum源里。所以配置openstack的yum源。
在CentOS中, ``extras``仓库提供用于启用 OpenStack 仓库的RPM包。 CentOS 默认启用``extras``仓库,
因此你可以直接安装用于启用OpenStack仓库的包。
# yum install centos-release-openstack-mitaka在主机上升级包
# yum upgrade安装openvswitch
# yum -y install openvswitch
启动openvswitch
# systemctl start openvswitch
创建一个桥设备
# ovs-vsctl add-br br-in
# ovs-vsctl show
1bfc1186-1781-4e91-96e9-5db9c334503e
Bridge br-in
Port br-in
Interface br-in
type: internal
ovs_version: "2.5.0"
此时一个软交换机已经诞生。他比brctl强大,多了一个VLan的功能。
ovs-vsctl 命令的使用:
show:ovsdb配置内容的查看
add-br:添加桥设备
del-br:删除桥
list-br:显示所有已定义的桥
add-port:为桥添加一个端口
del-port:移除一个端口 例:del-port br-in vif0.0
find port name=eth1:查找端口eth1的详细信息
现在激活那个eth1.然后将eth1添加至桥上
[root@localhost ~]# ip link set eth1 up
[root@localhost ~]# ovs-vsctl add-port br-in eth1
[root@localhost ~]# ovs-vsctl list-ports br-in
eth1
查看br-in的状态
[root@localhost ~]# ovs-vsctl show
1bfc1186-1781-4e91-96e9-5db9c334503e
Bridge br-in
Port br-in
Interface br-in
type: internal
Port "eth1"
Interface "eth1"
ovs_version: "2.5.0"
好了,现在启动虚拟机实例。(需要装qemu-kvm)
先创建桥接配置脚本。/etc/if-up
#!/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
启动虚拟机。
# qemu-kvm -name "test1" -m 256 -smp 1 \
> -drive file=/images/cirros/cirros-0.3.5-x86_64-disk.img,media=disk,if=virtio \
> -net nic,model=virtio,macaddr=52:54:00:00:00:01 \
> -net tap,ifname=vif0.0,script=/etc/if-up,downscript=no \
> --nographic
照此方法启动连个虚拟机。
配置两个虚拟机的IP地址。
test1 虚拟机
# ifconfig eth0 10.0.3.1 netmask 255.255.255.0 up
# ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:00:00:00:01
inet addr:10.0.3.1 Bcast:10.0.3.255 Mask:255.255.255.0
。。。
test2 虚拟机
# ifconfig eth0 10.0.3.2 netmask 255.255.255.0 up
# ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:00:00:00:02
inet addr:10.0.3.2 Bcast:10.0.3.255 Mask:255.255.255.0
。。。
两个虚拟机是可以互相ping通的。
# ping 10.0.3.2
PING 10.0.3.2 (10.0.3.2): 56 data bytes
64 bytes from 10.0.3.2: seq=0 ttl=64 time=5.327 ms
64 bytes from 10.0.3.2: seq=1 ttl=64 time=0.037 ms
。。。
接下来就可以开始试验了,将两个虚拟机放到不同的VLAN里面。
[root@localhost ~]# ovs-vsctl set port vif0.0 tag=10
[root@localhost ~]# ovs-vsctl set port vif1.0 tag=11
上面的命令将vif0.0设置为10号VLan,vif1.0设置为11号VLan。
十分简单吧。
现在再来实现一个场景,就是test1和test2虚拟机在一个交换机上,并且属于不同的VLan。而test3虚拟在另
一个交换机上,并且,同在10号VLan中。如下图所示
先添加一个交换机。
# ovs-vsctl add-br br-test
修改/etc/if-up和if-down,将里面的桥由br-in改成br-test。
启动一个虚拟机test3,接在这个br-test这个交换机上。
# qemu-kvm -name "test3" -m 256 -smp 1 \
-drive file=/images/cirros/test2.qcow2,media=disk,if=virtio \
-net nic,model=virtio,macaddr=52:54:00:00:00:03 \
-net tap,ifname=vif2.0,script=/etc/if-up2,downscript=/etc/if-down2 \
--nographic \
配置网卡信息。
# ifconfig eth0 10.0.3.3 netmask 255.255.255.0 up
# ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:00:00:00:03
inet addr:10.0.3.3 Bcast:10.0.3.255 Mask:255.255.255.0
接着创建一对网卡,将两个交换机连在一起。
# ip link add switch0 type veth peer name switch1
# ip link set switch0 up
# ip link set switch1 up
# ovs-vsctl add-port br-in switch0
# ovs-vsctl add-port br-test switch1
将test3设置为10号VLan
# ovs-vsctl set port vif2.0 tag=10
测试一下看看。在test1上来看看。
# ping 10.0.3.3
PING 10.0.3.3 (10.0.3.3): 56 data bytes
64 bytes from 10.0.3.3: seq=0 ttl=64 time=1.734 ms
## test1在 10 号VLAN,可以ping通test3
# ping 10.0.3.2
PING 10.0.3.2 (10.0.3.2): 56 data bytes
--- 10.0.3.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
# 虽然test1和test2在同一台交换机上,但是没有在相同的VLan中。所以不能ping通、
添加网关,使得真机与虚拟机可以通信,或者说可以虚拟机上外网。
# ip netns add r0 #添加namespace
# ip link add sif0 type veth peer name rif0 #添加一对网卡
# ip link set sif0 up
# ip link set rif0 up
# ip link set rif0 netns r0 #把网卡rif0给r0
# ovs-vsctl add-port br-in sif0 #把网卡sif0给br-in
激活添加在r0上的rif0网卡
# ip netns exec r0 ip link set rif0 up
并且给r0上网关添加一个IP地址。
# ip netns exec r0 ip addr add 10.0.3.254/24 dev rif0
配置dnsmasq
# yum -y install dnsmasq
# ip netns exec r0 dnsmasq -F 10.0.3.200,10.0.3.230,86400 -i rif0 #配置dns服务器
# ip netns exec r0 ss -unl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 *:53 *:*
UNCONN 0 0 *:67 *:*
UNCONN 0 0 :::53 :::*
启动一个虚拟机实例。
# qemu-kvm -name "test6" -m 256 -smp 1 \
-drive file=/images/cirros/test1.qcow2,media=disk,if=virtio \
-net nic,model=virtio,macaddr=52:54:00:00:00:11 \
-net tap,ifname=vif0.0,script=/etc/if-up,downscript=/etc/if-down \
--nographic
查看虚拟机的配置。
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 52:54:00:00:00:11 brd ff:ff:ff:ff:ff:ff
inet 10.0.3.230/24 brd 10.0.3.255 scope global eth0
inet6 fe80::5054:ff:fe00:11/64 scope link
valid_lft forever preferred_lft forever
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.3.254 0.0.0.0 UG 0 0 0 eth0
10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
上述只是想让虚拟机和真机通信
最后来实现一下,如果第四台主机不仅不再一个交换机上,而且还不在一台真机上。这就有点复杂了,怎么实现呢?
可能我的描述还是有些不准确,请看看下面这张图。
test1 如何和test6去通信。(假设test1和test6处在同一个Vlan中),而不让test2和test6去通信。
这就需要GRE技术了。Generic Routing Encapsulation:通用路由封装。是一种隧道技术。
类似LVS的隧道技术,ip内有ip。
给两边的eth1网卡都加上IP,因为两台主机的eth1需要通信。
主机一:
# ip addr add 192.168.20.1/24 dev eth1
主机二:
# ip addr add 192.168.20.2/24 dev eth1
要确保。两台主机可以ping通。
在第一个主机上的br-in交换机上添加一个接口(gre0不存在没关系)
# ovs-vsctl add-port br-in gre0
将eth1配置为隧道。
# ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.20.2
# ovs-vsctl list interface gre0
_uuid : ef8244cd-7d0e-4273-ade8-32ba231c6f4e
admin_state : up
bfd : {}
bfd_status : {}
cfm_fault : []
cfm_fault_status : []
cfm_flap_count : []
cfm_health : []
cfm_mpid : []
cfm_remote_mpids : []
cfm_remote_opstate : []
duplex : []
error : []
external_ids : {}
ifindex : 0
ingress_policing_burst: 0
ingress_policing_rate: 0
lacp_current : []
link_resets : 0
link_speed : []
link_state : up
lldp : {}
mac : []
mac_in_use : "8a:74:71:11:1b:64"
mtu : []
name : "gre0"
ofport : 13
ofport_request : []
options : {remote_ip="192.168.20.2"}
other_config : {}
statistics : {collisions=0, rx_bytes=0, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=0, tx_bytes=338, tx_dropped=0, tx_errors=0, tx_packets=1}
status : {tunnel_egress_iface="eth1", tunnel_egress_iface_carrier=up}
type : gre
同样,在二号主机的eth1上通杨进行相同的配置,IP指向对方。
# ovs-vsctl add-port br-in gre0
# ovs-vsctl set interface gre0 type=gre option:remote_ip=192.168.20.1
观察一下两个主机的设置的交换机。
主机一:
[root@localhost ~]# ovs-vsctl show
1bfc1186-1781-4e91-96e9-5db9c334503e
Bridge br-in
Port "vif2.0"
Interface "vif2.0"
Port "vif1.0"
Interface "vif1.0"
Port "gre0"
Interface "gre0"
type: gre
options: {remote_ip="192.168.20.2"}
Port br-in
Interface br-in
type: internal
ovs_version: "2.5.0"
主机二:
[root@localhost ~]# ovs-vsctl show
88260195-15df-41d5-ab55-2401905c4c38
Bridge br-in
Port br-in
Interface br-in
type: internal
Port "vif2.0"
Interface "vif2.0"
Port "vif1.0"
Interface "vif1.0"
Port "gre0"
Interface "gre0"
type: gre
options: {remote_ip="192.168.20.1"}
ovs_version: "2.5.0"
OK,现在在主机一上启动一个虚拟机,发现,在主机二上的DHCP服务器也可以给主机一上的服务器提供IP了。
# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 52:54:00:00:00:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.3.215/24 brd 10.0.3.255 scope global eth0
inet6 fe80::5054:ff:fe00:2/64 scope link
valid_lft forever preferred_lft forever
下来观察一下gre的基于隧道的通信技术。
# tcpdump -i eth1 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
22:23:04.841452 IP 192.168.20.1 > 192.168.20.2: GREv0, length 102: IP 10.0.3.215 > 10.0.3.230: ICMP echo request, id 26625, seq 40, length 64
22:23:04.842654 IP 192.168.20.2 > 192.168.20.1: GREv0, length 102: IP 10.0.3.230 > 10.0.3.215: ICMP echo reply, id 26625, seq 40, length 64
22:23:05.844358 IP 192.168.20.1 > 192.168.20.2: GREv0, length 102: IP 10.0.3.215 > 10.0.3.230: ICMP echo request, id 26625, seq 41, length 64
22:23:05.846782 IP 192.168.20.2 > 192.168.20.1: GREv0, length 102: IP 10.0.3.230 > 10.0.3.215: ICMP echo reply, id 26625, seq 41, length 64
22:23:06.248433 IP 192.168.20.1 > 192.168.20.2: GREv0, length 346: IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 52:54:00:00:00:01, length 296
22:23:06.846852 IP 192.168.20.1 > 192.168.20.2: GREv0, length 102: IP 10.0.3.215 > 10.0.3.230: ICMP echo request, id 26625, seq 42, length 64
22:23:06.848156 IP 192.168.20.2 > 192.168.20.1: GREv0, length 102: IP 10.0.3.230 > 10.0.3.215: ICMP echo reply, id 26625, seq 42, length 64
表面是192.168.20.1 在ping192.168.20.2,但是实质上有在里面封装了一个10.0.3.215 对10.0.3.230 的通信
还可以做个实验。一号主机的两台虚拟机一个在10号VLAN中,一个在11号VLAN中
二号主机的两台虚拟机一个在10号VLAN中,一个在11号VLAN中。
那么这下一号主机的两台主机是不能互相通信的。
最后再演示一下VXLAN的技术。
现在不要gre功能了,VXLAN本身支持VLAN的功能,有极大的提升了数量,还有基于隧道的技术。
所以要先取消gre。
# ovs-vsctl del-port br-in gre0
两个节点都需要去执行。
添加VXLAN
主机一:
# ovs-vsctl add-port br-in vx0
ovs-vsctl: Error detected while setting up 'vx0'. See ovs-vswitchd log for details.
# ovs-vsctl set interface vx0 type=vxlan options:remote_ip=192.168.20.2
主机二:
# ovs-vsctl add-port br-in vx0
ovs-vsctl: Error detected while setting up 'vx0'. See ovs-vswitchd log for details.
# ovs-vsctl set interface vx0 type=vxlan options:remote_ip=192.168.20.1
OK了,看,是不是和gre很像很像。
最后配置整个openstack 的网络模型。整个网络模型是这样的。再由一个节点让,所有的内部虚拟机可以去访问
外部网络,同时呢,又可以让外部网络可以访问内部虚拟机网络。
这下就需要第三台主机了,这台主机专门去做网络节点,负责网络数据的转发(内网与外网之间)
这台主机的模型是这样的。3块网卡,一个桥接(用来与外部网络去通信)
一个仅主机(所有的内部网络使用的线路,有可能包括openstack的主控制节点)
一个仅主机(所有虚拟机计算几点,加上网络节点)
好了。这个节点需要2个虚拟交换机,一个使用openvswitch去做,因为需要VXLan创建的Vlan技术。
第一个交换机与外部网络相接,可以直接使用brctl命令去创造。
我这里直接用配置文件了,eth1网卡是桥接网卡。
ifcfg-eth1
DEVICE="eth1"
BOOTPROTO="static"
ONBOOT="yes"
NM_CONTOLLED="no"
BRIDGE="br-ex"
ifcfg-br-ex
DEVICE="br-ex"
BOOTPROTO="static"
ONBOOT="yes"
IPADDR="192.168.1.30"
NETMASK="255.255.255.0"
GATEWAY="192.168.1.1"
NM_CONTOLLED="no"
TYPE="Bridge"
好了创建netns。
# ip netns add r0
# ip link add sin0 type veth peer name rin0
# ip link add sex0 type veth peer name rex0
# ip link set sin0 up
# ip link set sex0 up
# ip link set rin0 netns r0
# ip link set rex0 netns r0
创建新的内部桥
(在新主机上(网络控制节点))
# ovs-vsctl add-br br-in
# ovs-vsctl add-port br-in gre0
# ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.20.2
(在虚拟机主机上(192.168.20.2)再创建一个gre隧道,与之通信)
添加一对网卡。一个在r0上,一个在br-in上
# ip netns exec r0 ifconfig rin0 10.0.1.254/24 up
# ovs-vsctl add-port br-in sin0
OK,现在内部的虚拟机就可以去和10.0.1.254这个网关去联系了。
# ping 10.0.1.254(这里是10.0.1.1主机)
PING 10.0.1.254 (10.0.1.254): 56 data bytes
64 bytes from 10.0.1.254: seq=0 ttl=64 time=12.323 ms
64 bytes from 10.0.1.254: seq=1 ttl=64 time=2.020 ms
看看抓包结果。
01:27:12.187837 IP 192.168.20.3 > 192.168.20.2: GREv0, length 102: IP 10.0.1.254 > 10.0.1.1: ICMP echo reply, id 29953, seq 19, length 64
现在配置br-ex(注意:一对网卡,在r0上的需要配置Ip,在交换机上的不需要配置IP)
# brctl addif br-ex sex0
# ip netns exec r0 ifconfig rex0 192.168.1.30/24 up
# ip netns exec r0 sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
此时。内部网络的虚拟机已经可以去PING通网络调度节点上的外部地址了。
# ping 192.168.1.30
PING 192.168.1.30 (192.168.1.30): 56 data bytes
64 bytes from 192.168.1.30: seq=0 ttl=64 time=2.452 ms
64 bytes from 192.168.1.30: seq=1 ttl=64 time=2.754 ms
64 bytes from 192.168.1.30: seq=2 ttl=64 time=1.045 ms
64 bytes from 192.168.1.30: seq=3 ttl=64 time=5.689 ms
配置网络IP地址转换。
# ip netns exec r0 iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 192.168.1.30
此时,内部虚拟机已经可以去ping通网络调度主机的局域网内的主机了。
现在开始内外映射去做。内网对外网的IP访问。
所以先删掉上面配置的ip。
# ip netns exec r0 iptables -t nat -F
配置地址映射。(这个192.168.1.31是专门映射给内部虚拟机使用的)
# ip netns exec r0 ifconfig rex0:0 192.168.1.31/24 up
添加两条规则
# ip netns exec r0 iptables -t nat -A POSTROUTING -s 10.0.1.1/24 -j SNAT --to-source 192.168.1.31
# ip netns exec r0 iptables -t nat -A PREROUTING -d 192.168.1.31 -j DNAT --to-destination 10.0.1.1
好了。此时,连我的windows都可以ping通虚拟机了。
抓包得到:(192.168.1.103是windows的IP)
01:53:25.266024 IP 192.168.20.2.41374 > 192.168.20.1.4789: VXLAN, flags [I] (0x08), vni 0
IP 192.168.1.103 > 10.0.1.1: ICMP echo request, id 1, seq 10264, length 40
01:53:25.266459 IP 192.168.20.1.34056 > 192.168.20.2.4789: VXLAN, flags [I] (0x08), vni 0
IP 10.0.1.1 > 192.168.1.103: ICMP echo reply, id 1, seq 10264, length 40
01:53:25.270680 IP 192.168.20.2 > 192.168.20.3: GREv0, key=0x0, length 82: IP 10.0.1.1 > 192.168.1.103: ICMP echo reply, id 1, seq 10264, length 40