IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Neutron DVR —Dive into Human Defined DVR

    hu, xueqing发表于 2016-04-20 09:38:27
    love 0

    本文旨在通过全部手动的方式,来完成DVR的手动部署。大体思路是,在一个DVR的环境里,手动创建虚拟机,手动创建各种Linux网络设备,手动添加各种流表,完成新建虚拟机和在DVR模式下的虚拟机的DHCP,二层,三层通信。

    拓扑结构和机器角色信息

    拓扑结构

    1111

    机器角色信息

    Server-233:Allinone节点,上面运行着Neutron Server,DHCP agent,L3 agent,OVS agent等
    Server-64:Compute节点,上面运行着L3 agent,OVS agent等
    Server-68:Compute节点,上面运行着L3 agent,OVS agent等
    这三台机器之间通过p3p1.1124进行VXLAN隧道的通信。

    Human Defined DVR之DHCP

    手动创建虚拟机

    下载镜像

    wget http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img

    镜像格式转化(img->qcow2)

    qemu-img convert -O qcow2 cirros-0.3.4-x86_64-disk.img cirros-0.3.4-x86_64-disk.qcow2

    创建XML模板

    Expand source

    通过Libvirt启动虚拟机
    在通过Libvirt启动虚拟机之前,由于我们在XML文件中定义了虚拟机的TAP设备会挂载到Linux Bridge qbr-cirros下,因此我们手动创建这个桥

    brctl addbr qbr-cirros

    ok,启动虚拟机

    virsh define cirros.xml
    virsh start cirros

    验证虚拟机是否正常发包

    在虚拟机里DHCP,并在tap设备上抓包
    虚拟机里发包:

    sudo ifdown eth0; sudo ifup eth0

    宿主机上抓包:

    [root@server-233 ~]# tcpdump -nei tap-cirros
    tcpdump: WARNING: tap-cirros: no IPv4 address assigned
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on tap-cirros, link-type EN10MB (Ethernet), capture size 65535 bytes

    15:57:59.003843 fa:16:3e:ff:aa:66 > Broadcast, ethertype IPv4 (0x0800), length 332: 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from fa:16:3e:ff:aa:66, length 290

    ok,一切正常。
    配置虚拟机用到的网络设备
    设置网桥转发延迟为0s:

    brctl setfd qbr-cirros 0

    关闭生成树:

    brctl stp qbr-cirros off

    关闭网桥的multicat_snoop

    echo 0 |tee /sys/class/net/qbr7eb6afbb-69/bridge/multicast_snooping

    创建Linux Veth设备

    ip link add qvb-cirros type veth peer name qvo-cirros

    UP网络设备

    ip link set qvo-cirros up

    设置qvb设备为混杂模式

    ip link set qvb-cirros promisc on

    UP网络设备

    ip link set qvb-cirros up

    桥接网络设备

    brctl addif qbr-cirros qvb-cirros

    把qvo设备桥接到br-int上

    ovs-vsctl add-port br-int qvo-cirros

    ok,现在的拓扑是这样的:

    2222

    我们想让虚拟机获取IP为192.168.10.168/24的地址,如何才能让虚拟机获取呢?
    下面介绍两种方式:

    一. DHCP Server在本节点上
    DHCP Server里的TAP设备对应的VLAN tag是1,那么也把qvo设备的tag设置成1:

    ovs-vsctl set Port qvo-cirros tag=1

    接下来,手动修改DHCP配置文件
    host文件:

    3333

    addn_hosts文件:

    4444

    修改后,给Dnsmasq服务发送reload信号:

    kill -HUP [pid]

    虚拟机DHCP即可获取IP地址

    5555

    二. DHCP Server不在本节点上

    方式一比较简单,下面介绍当DHCP Server不在本节点上时的虚拟机DHCP过程。
    首先,由于qvo设备直接桥接在了br-int上,我们将qvo的流量直接导到br-tun上,添加如下流表:

    ovs-ofctl add-flow br-int priority=1,actions=NORMAL

    然后,由于br-int和br-tun有patch口相连接,那么,虚拟机的DHCP请求包就会到达br-tun的table0上,我们让从patch口来的数据包,resubmit table1,
    table1上默认的规则是resubmit table2:

    ovs-ofctl add-flow br-tun table=0,priority=1,in_port=1,actions=resubmit(,1)
    ovs-ofctl add-flow br-tun table1,priority=0,actions=resubmit(,2)

    在table2上,对于请求的单播地址,resubmit table 20

    ovs-ofctl add-flow br-tun table=2,priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00,actions=resubmit(,20)

    对于请求目的地址是广播地址的,resubmit table 22

    ovs-ofctl add-flow br-tun table=2,priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00,actions=resubmit(,22)

    对于DHCP请求,是广播地址,会resubmit到table 22
    在table22上做VLAN和VXLAN的转化,发到其他两个计算节点:

    ovs-ofctl add-flow br-tun table=22,dl_vlan=1,actions=strip_vlan,set_tunnel:0x813,output:2,output:3

    注,0x813的来历:

    6666
    我们可以在对端的计算节点上抓到DHCP的请求包:

    7777

    ok,我们抓到了DHCP请求,我们在br-tun上添加流表,让从233(in_port是3,可以通过ovs-ofctl dump-ports-desc br-tun看到port)上发来的数据包resubmit table4:

    ovs-ofctl add-flow br-tun table=0,priority=1,in_port=3,actions=resubmit(,4)

    我们在table4上完成VXLAN和本地VLAN的转换,然后resubmit table 9:

    ovs-ofctl add-flow br-tun table=4,priority=1,tun_id=0x813 actions=mod_vlan_vid:1,resubmit(,9)

    table9默认resubmit table 10

    ovs-ofctl add-flow br-tun table=9,priority=0,actions=resubmit(,10)

    table10上写MAC学习的流表,然后output到br-int的patch口

    ovs-ofctl add-flow br-tun table=10,priority=1,actions=learn(table=20,hard_timeout=300,priority=1,cookie=0xb8a7772eecbcd5b8,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1

    这样br-int上就会收到这个带有本地VLAN1的DHCP请求了,这是仍然不能获取IP,因为DHCP Server里没有写租约信息,在本节点上进行和233上一样的动作
    图略
    此时在虚拟机里DHCP一把:

    8888

    搞定。
    Human Defined DVR之虚拟机二层通信

    下面介绍如何手动实现DVR场景下的虚拟机二层通信。首先看一张拓扑图:

    11111

    我们要实现cirros虚拟机和VM-1、VM-2的通信。

    Cirros和本地虚拟机的二层通信

    因为本地的虚拟机VM-1在br-int上的Tag是1,那么我们首先在qvo-cirros上打上Tag为1

    ovs-vsctl set Port qvo-cirros tag=1
    虚拟机里开ping,咦,怎么不通?
    抓下VM-1的qvo设备上的包和tap设备上的包看下

    [root@server-233 ~(keystone_admin)]# tcpdump -nei tapd65c7b33-e0 arp or icmp
    tcpdump: WARNING: tapd65c7b33-e0: no IPv4 address assigned
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on tapd65c7b33-e0, link-type EN10MB (Ethernet), capture size 65535 bytes
    ^C
    0 packets captured
    0 packets received by filter
    0 packets dropped by kernel
    [root@server-233 ~(keystone_admin)]# tcpdump -nei qvod65c7b33-e0 arp or icmp
    tcpdump: WARNING: qvod65c7b33-e0: no IPv4 address assigned
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on qvod65c7b33-e0, link-type EN10MB (Ethernet), capture size 65535 bytes
    09:48:35.290981 fa:16:3e:ff:aa:66 > fa:16:3e:ff:3a:67, ethertype IPv4 (0x0800), length 98: 192.168.10.222 > 192.168.10.10: ICMP echo request, id 27649, seq 95, length 64
    09:48:36.291047 fa:16:3e:ff:aa:66 > fa:16:3e:ff:3a:67, ethertype IPv4 (0x0800), length 98: 192.168.10.222 > 192.168.10.10: ICMP echo request, id 27649, seq 96, length 64
    09:48:37.291100 fa:16:3e:ff:aa:66 > fa:16:3e:ff:3a:67, ethertype IPv4 (0x0800), length 98: 192.168.10.222 > 192.168.10.10: ICMP echo request, id 27649, seq 97, length 64
    ^C
    3 packets captured
    3 packets received by filter
    0 packets dropped by kernel

    天呐!典型的安全组没有允许ICMP的原因呀!因为qvo设备上有包,tap设备上没包。
    果断找到对端虚拟机的Port对应的安全组,并添加相应的ICMP规则:

    [root@server-233 ~(keystone_admin)]# neutron port-list –device-id 764bacc1-dc11-42ea-bc12-54334c31efb2
    +————————————–+——+——————-+————————————————————————————–+
    | id | name | mac_address | fixed_ips |
    +————————————–+——+——————-+————————————————————————————–+
    | d65c7b33-e05b-4a3e-aaa5-ba9ec3b8dd1b | | fa:16:3e:ff:3a:67 | {“subnet_id”: “bb6d2cda-c31d-40f5-9d00-50f9b6540753″, “ip_address”: “192.168.10.10”} |
    +————————————–+——+——————-+————————————————————————————–+
    [root@server-233 ~(keystone_admin)]# neutron port-show d65c7b33-e05b-4a3e-aaa5-ba9ec3b8dd1b|grep security
    | security_groups | 4616d6e2-3491-43cc-9411-9463b20d1a11 |
    [root@server-233 ~(keystone_admin)]# neutron security-group-rule-create –protocol=icmp 4616d6e2-3491-43cc-9411-9463b20d1a11
    Created a new security_group_rule:
    +——————-+————————————–+
    | Field | Value |
    +——————-+————————————–+
    | direction | ingress |
    | ethertype | IPv4 |
    | id | 44a52ecc-83ca-4c19-a84d-506ab3753d26 |
    | port_range_max | |
    | port_range_min | |
    | protocol | icmp |
    | remote_group_id | |
    | remote_ip_prefix | |
    | security_group_id | 4616d6e2-3491-43cc-9411-9463b20d1a11 |
    | tenant_id | ef979882f1954a0fa4ce7daf244aa557 |
    +——————-+————————————–+

    加完后,搞定!ping通了

    2222

    Cirros和其他计算节点上虚拟机的二层通信

    依然给qvo-cirros上打上Tag为1

    ovs-vsctl set Port qvo-cirros tag=1

    这里需要说明一点,为了防止虚拟机进行中间人攻击,即:虚拟机对目的IP不是自己的请求进行回复,我们通过流表的形式进行防止,规则如下:

    ovs-ofctl add-flow br-int “priority=10,arp,in_port=43,actions=resubmit(,24)”
    ovs-ofctl add-flow br-int “table=24,priority=2,arp,in_port=43,arp_spa=192.168.10.222,actions=NORMAL”

    其中,43是Cirros虚拟机的ofport,这样获得:

    [root@server-233 ~(keystone_admin)]# ovs-vsctl get Interface qvo-cirros ofport
    43

    arp_spa的含义是:进行ARP回复的原地址是192.168.10.222
    OK,开ping!通了!

    33333



沪ICP备19023445号-2号
友情链接