nova与neutron交互

Posted 赤焰军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nova与neutron交互相关的知识,希望对你有一定的参考价值。

1     nova命令

先介绍一下nova命令中与网络相关的一些参数。

 

1.1   指定网络启动虚机

usage: nova boot [--flavor <flavor>] [--image <image>]

                 [--image-with <key=value>] [--boot-volume <volume_id>]

                 [--snapshot <snapshot_id>] [--min-count <number>]

                 [--max-count <number>] [--meta <key=value>]

                 [--file <dst-path=src-path>] [--key-name <key-name>]

                 [--user-data <user-data>]

                 [--availability-zone <availability-zone>]

                 [--security-groups <security-groups>]

                 [--block-device-mapping <dev-name=mapping>]

                 [--block-device key1=value1[,key2=value2...]]

                 [--swap <swap_size>]

                 [--ephemeral size=<size>[,format=<format>]]

                 [--hint <key=value>]

                 [--nic <net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,port-id=port-uuid>]

                 [--config-drive <value>] [--poll]

                 <name>

 

其中,v4/6-fixed-ip不能单独配置,必须和net-id一起配置;在一个--nic中net-id与port-id只能选择一个。

 

命令示例:

根据Port-ID启动虚机:

# neutron port-create  accd72eb-2cd0-4961-ad67-d028c92e5254  --fixed-ip ip_address=1.2.3.20

# nova boot --flavor 100 --image 18f8b6e1-a957-4d94-a3dd-eca757afdeb9  \\

  --nic port-id=10e7e093-156e-402b-9a45-ff8ab13dfb03 test_vm_1

 

启动虚机时指定网络,指定IP:

# nova boot --flavor 100 --image 18f8b6e1-a957-4d94-a3dd-eca757afdeb9 \\

  --nic net-id=accd72eb-2cd0-4961-ad67-d028c92e5254,v4-fixed-ip=1.2.3.10 test_vm_2

 

创建多网络虚机:

# nova boot --flavor 100 --image 18f8b6e1-a957-4d94-a3dd-eca757afdeb9 \\

  --nic net-id=accd72eb-2cd0-4961-ad67-d028c92e5254 \\

  --nic net-id= 2125e96e-d2a3-42b3-931f-5a90149d0f90 test_vm_3

 

 

1.2   修改虚机网络

nova支持对于active的虚机添加或删除网卡,对应命令如下:

 

interface-attach            Attach a network interface to a server.

interface-detach            Detach a network interface from a server.

interface-list              List interfaces attached to a server.

 

用法:

nova interface-attach [--port-id <port_id>] [--net-id <net_id>]

                             [--fixed-ip <fixed_ip>]

                             <server>

nova interface-detach <server> <port_id>

 

命令示例:

 

绑定一个端口、网络或者IP地址到虚机:

nova interface-attach 06fd79d1-99a8-451d-955c-f466b8986f34 --port-id c310babc-c833-4b10-9d76-78d60a58af98

将port-id从虚机解绑:

nova interface-detach 8dd2fb5d-30a9-45c7-8931-ba039adcd20f  5138a9ce-7114-4126-82e8-8685a6aeccee

 

查看虚机对应的Port端口:

[root@node-82 ~]# nova interface-list   f09c0b84-8e5a-4a3d-8da9-7d57d105e0e3

+------------+--------------------------------------+--------------------------------------+--------------+-------------------+

| Port State | Port ID                              | Net ID                               | IP addresses | MAC Addr          |

+------------+--------------------------------------+--------------------------------------+--------------+-------------------+

| ACTIVE     | 182b1ed7-beab-46cd-84b1-1daf72f4e266 | accd72eb-2cd0-4961-ad67-d028c92e5254 | 1.2.3.12     | fa:16:3e:3f:3a:91 |

| ACTIVE     | 51b10239-005d-4d20-8d03-269bc85bacc6 | 2125e96e-d2a3-42b3-931f-5a90149d0f90 | 1.1.1.32     | fa:16:3e:d5:6c:5a |

+------------+--------------------------------------+--------------------------------------+--------------+-------------------+

2     nova介绍

2.1   Nova服务

nova主要服务包括:

nova-api:对外提供rest-api。

nova-conductor:用于分发消息。

nova-scheduler:在创建虚机时,选择计算节点。

nova-compute:在计算节点上运行,负责管理虚机的生命周期。

 

3     处理流程

3.1   创建虚机流程


用户创建虚机的命令到达nova-api后,通过rpc发给nova-conductor处理。conductor中,先通过nova-scheduler选择虚机调度到的主机,然后发送到对应主机的nova-compute上进行处理。

 

如下是nova-compute处理虚机创建的详细流程。

 

与网络相关的部分,简要地可以分为几部:

1)  创建网络资源,此时更新neutron port,或者创建neutron port,返回VIF列表

2)  libvirt spawn,根据VIF列表,配置虚机底层网络,然后起虚机进程,并等待虚机启动完成。

3)  ovs-agent捕获到虚机网卡添加到br-int中,发送rpc给plugin更新neutron db port状态为up。

4)  neutron db检测到端口up,发送network-vif-plug event通知nova端口。

 

l  日志分析

创建虚机,通过查看nova-computedebug日志,可以大致了解虚机启动过程。

allocate_for_instance /usr/lib/python2.7/site-packages/nova/network/neutronv2/api.py

GET http://controller:9696/v2.0/networks.json?id=2

GET http://controller:9696/v2.0/security-groups.json?tenant_id=

 POST http://controller:9696/v2.0/ports.json

'{"port": {"binding:host_id": "compute1", "admin_state_up": true, "network_id": "2337cce4-512c-4b36-a5a7-6af99bfe21d2", "tenant_id": "47227b9865f64869aee959af81caf8dd", "device_owner": "compute:nova", "security_groups": ["17be47bc-1629-4266-812f-a0750975f89f"], "device_id": "74f3bd67-4362-477d-b700-c10866dea8a6"}}'

 GET http://controller:9696/v2.0/ports.json?tenant_id=47227b9865f64869aee959af81caf8dd&device_id=74f3bd67-4362-477d-b700-c10866dea8a6

GET http://controller:9696/v2.0/floatingips.json?fixed_ip_address=1.1.1.4&port_id=2cbc7875-b460-4c59-b87f-078e1ff1d5b6

GET http://controller:9696/v2.0/subnets.json?id=dd0ea246-b2f8-498e-adce-c59eec7f8d91

GET http://controller:9696/v2.0/ports.json?network_id=2337cce4-512c-4b36-a5a7-6af99bfe21d2&device_owner=network%3Adhcp

sudo nova-rootwrap /etc/nova/rootwrap.conf brctl addbr qbr2cbc7875-b4

sudo nova-rootwrap /etc/nova/rootwrap.conf brctl setfd qbr2cbc7875-b4 0

sudo nova-rootwrap /etc/nova/rootwrap.conf brctl stp qbr2cbc7875-b4 off

sudo nova-rootwrap /etc/nova/rootwrap.conf tee /sys/class/net/qbr2cbc7875-b4/bridge/multicast_snooping

sudo nova-rootwrap /etc/nova/rootwrap.conf ip link add qvb2cbc7875-b4 type veth peer name qvo2cbc7875-b4

sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set qvb2cbc7875-b4 up

sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set qvb2cbc7875-b4 promisc on

sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set qvo2cbc7875-b4 up

sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set qvo2cbc7875-b4 promisc on

 sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set qbr2cbc7875-b4 up

 sudo nova-rootwrap /etc/nova/rootwrap.conf brctl addif qbr2cbc7875-b4 qvb2cbc7875-b4

sudo nova-rootwrap /etc/nova/rootwrap.conf ovs-vsctl --timeout=120 -- --if-exists del-port qvo2cbc7875-b4 -- add-port br-int qvo2cbc7875-b4 -- set Interface qvo2cbc7875-b4 external-ids:iface-id=2cbc7875-b460-4c59-b87f-078e1ff1d5b6 external-ids:iface-status=active external-ids:attached-mac=fa:16:3e:d9:e1:2f external-ids:vm-uuid=74f3bd67-4362-477d-b700-c10866dea8a6

 Received event network-vif-plugged-2cbc7875-b460-4c59-b87f-078e1ff1d5b6 external_instance_event

 

 

代码分析如下:

l  nova-compute

 

1. conductor创建虚机的消息通过到达计算节点的nova-compute。

2. nova-compute创建虚机过程:

    代码路径:ComputeManager.build_and_run_instance

    通过spawn_n异步执行 _do_build_and_run_instance,这样rpcworker可以立即返回接着处理后面的消息了

    _do_build_and_run_instance:

    1)记录虚机状态为BUILDING

    2)记录任务状态为SCHEDULING

    3)如果conductor没有传入主机名,已当前主机作为创建资源的node。

    4) _build_and_run_instance函数。见下面 _build_and_run_instance

    5)捕获异常RescheduledException,如果配置了不retry,_cleanup_allocated_networks,然后结束。

    6)捕获异常RescheduledException,如果配置了retry:

        执行cleanup_instance_network_on_host,但这里实际并不会删除neutron port。

         记录任务状态为SCHEDULING

         本地调用conductor api重新build_instances。

    7)捕获InstanceNotFound,UnexpectedDeletingTaskStateError,执行_cleanup_allocated_networks。

    8)捕获BuildAbortException,执行_cleanup_allocated_networks。

    9)其他异常,_cleanup_allocated_networks,_cleanup_volumes。

    结束。



    _build_and_run_instance 

    1)_build_resources()创建各种资源,包括网络相关资源。

        _build_networks_for_instance()配置网络,见_build_networks_for_instance

        如果失败,报error log,Failed to allocate network(s)。结束。

    2)调用driver.spawn创建实例。详见12 spawn.

    3)报日志:Took %0.2f seconds to spawn the instance on 'the hypervisor.

    4)捕获异常:InstanceNotFound,ComputeResourcesUnavailable,报异常BuildAbortException

         捕获异常:ComputeResourcesUnavailable,报异常:RescheduledException

         捕获异常:BuildAbortException,

         捕获异常FixedIpLimitExceeded,NoMoreNetworks,NoMoreFixedIps,报异常:BuildAbortException

         捕获异常VirtualInterfaceCreateException,VirtualInterfaceMacAddressException,报异常BuildAbortException

         捕获异常:FlavorDiskTooSmall,FlavorMemoryTooSmall,ImageNotActive,ImageUnacceptable,报异常:BuildAbortException

         捕获其他异常:报异常RescheduledException。

    5)删除实例的system_metadata, network_allocated

    6)根据network_info分配IP地址。

    7)_update_instance_after_spawn

         更新虚机的状态为ACTIVE

    8)_update_scheduler_instance_info

    结束。

 

 

    

3. nova-compute build网络过程:

    代码路径: ComputeManager._build_networks_for_instance

    1)从instance的system_metadata中查看network_allocated属性,如果已经创建,说明虚机之前调度过,执行如下过程,然后结束。

        · 在host上重新setup网络,setup_instance_network_on_host,参数:instance, host。见4 setup_instance_network_on_host

        · 获取并返回网络信息。

    2)调用driver.macs_for_instance,生成mac地址。

        libvirt driver不需要指定mac,ironic driver需要指定mac。

    3)调用driver.dhcp_options_for_instance,生成dhcp_options。

        libvirt driver不需要指定dhcp options。

    4)更新实例的staus为NETWORKING,调用self._allocate_network分配网络资源。参考6 nova-compute 异步分配网络。

    5)结束。

 

4. nova-compute setup_instance_network_on_host

    代码路径: network.neutronv2.api.API._update_port_binding_for_instance()

    1)通过neutronclient遍历Port,根据instance上的device_id和tenant_id过滤Port。

    2)如果port的binding:host_id属性不是要配置的host,通过neutronclient的update_port方法更新端口信息。参考5. neutron update_port:

    3)结束。

 

    6. nova-compute异步分配网络:

        代码路径:nova/compute/manager.ComputeManager._allocate_network_async

    1)调用driver.network_binding_host_id取得虚机所在的host信息。

    2)调用network_api.allocate_for_instance,参照7。如果失败,进行重试。

    关于重试:

        a)配置文件中network_allocate_retries,指定了重试次数,默认为0,表示只创建1次,不重试。

        b)重试间隔,1s,2s,4s,8,16,30,30...。

        c)重试超过数目后,报异常,Instance failed network setup after %(attempts)d attempt(s)'。

        d)结束。

7. nova-compute 分配网络:

    代码路径:nova/network/neutronv2/api.API.allocate_for_instance

    1)如果neutronclient有port_binding_extension,使用neutronclient,否则使用admin的neutronclient。

    2)检查实例是否有project_id,如果没有,报异常,empty project id for instance %s。结束。

    3)根据传入的requested_networks、hypervisor_macs属性,调用_process_requested_networks函数

         取得ports, net_ids, ordered_networks, available_macs。详见8.

    4)调用_get_available_networks,通过neutronclient取得net_ids对应的network详情。

    5)如果配置了requested_networks,但没有查询到networks,报NetworkNotFound异常。结束。

    6)如果没有requested_networks,并且没有查询到networks,返回空的network。

    7)检测虚机所附属的网络,如果是外部网络,必须是shared网络,否则报ExternalNetworkAttachForbidden异常,然后结束。

    8)处理安全组,传入的安全组是安全组名称或者uuid列表。

         通过neutronclient查询租户内的安全组。

         如果有多个安全组有相同的名称,报NoUniqueMatch异常,Multiple security groups found matching  '%s'. Use an ID to be more specific.

         如果查询不到安全组,报SecurityGroupNotFound异常。

         查询得到安全组ID列表。

    9)遍历所有虚机附属的网络,

          如果配置了安全组,并且网络没有配置子网,报SecurityGroupCannotBeApplied异常。

          如果配置了安全组,并且port_security_enabled配置为False,报SecurityGroupCannotBeApplied异常。

    10)port的device_id配置为instance.uuid,port的device_owner配置为compute:+instance.availability_zone,

           port的binding:host_id配置为bind_host_id。

            如果网络指定了port-id,通过neutronclient update_port

            如果网络没指定port-id,调用self._create_port创建port,详见9

    11)通过get_instance_nw_info获取网络信息,详见11。

    12)返回网络列表。

    13)结束。



8. nova-compute 处理已存在port-id:

    代码路径:nova/network/neutronv2/api.API._process_requested_networks

    1)遍历request 列表。request包含net-id, port-id

    2)如果request中包含port-id:

          通过neutronclient取得port详情。如果失败报异常,然后结束。

          如果tenant_id不是实例的project_id,报PortNotUsable异常,然后结束。

          如果port中包含device_id属性,报PortInUse异常,然后结束。

          如果port的binding:vif_type属性为VIF_TYPE_BINDING_FAILED,报PortBindingFailed异常,然后结束。

         如果指定了available_macs,port的mac_address值必须在available_macs中,否则报PortNotUsable异常,然后结束。

    3)结束。



9. nova-compute创建port:

    代码路径:nova/network/neutronv2/api.API._create_port

    1)如果指定了fixed_ip,填上port['fixed_ips']属性。

    2)填上network_id,admin_state_up,tenant_id属性。

    3)如果指定了security_group_ids,填上security_groups属性。

    4)如果指定了available_macs,如果available_macs为空,报PortNotFree异常。然后结束创建port。

         否则弹出一个mac,填到port mac_address属性里。

    5)如果指定了dhcp_opts,填上extra_dhcp_opts属性。

    6)通过neutronclient调用create_port。详见10.

         如果port的binding:vif_type属性为VIF_TYPE_BINDING_FAILED,调neutronclient删除端口,然后报PortBindingFailed异常。

         如果neutron client报InvalidIpForNetworkClient异常,报InvalidInput异常,并且报error log,Neutron error: %(ip)s is not a valid IP address '

                            'for network %(network_id)s.

         如果neutron client报文IpAddressInUseClient异常,报FixedIpAlreadyInUse异常,并报error log,Neutron error: Fixed IP %s is '

                            'already in use.

        如果neutron client报OverQuotaClient异常,报PortLimitExceeded异常,并报error log,Neutron error: Port quota exceeded in tenant: %s

        如果neutron client报IpAddressGenerationFailureClient异常,报NoMoreFixedIps异常,并报error log,Neutron error: No more fixed IPs in network: %s

        如果neutron client报MacAddressInUseClient异常,报PortInUse异常,并报error log,Neutron error: MAC address %(mac)s is already '

                            'in use on network %(network)s.

        其他异常,保存并直接报一次,并且log,Neutron error creating port on network %s

    7)结束。

 

11. nova-compute get_instance_nw_info:

    代码路径:nova/network/api.API.get_instance_nw_info

    1)调用_get_instance_nw_info,将nw_info写入db cache。

    2)_build_network_info_model。

 

    _build_network_info_model:

    1)通过admin权限的neutron client,获取port列表,通过tenant_id和device_id过滤port。

    2)返回的结果数据结构是network_model.NetworkInfo,是个list,成员是network_model.VIF.

    3)network_model.VIF是个dict,对应虚机虚拟网卡的信息,

        包括属性:id, address, type,details, devname, ovs_interfaceid, qbh_params, qbg_params,

                     active, vnic_type, profile, preserve_on_delete,meta, 

        这个VIF用于driver plug_vif。



12. driver.spawn:

    代码路径:nova/virt/libvirt/driver.LibvirtDriver.spawn

    1)查询disk_info信息。

    2)_create_image。

    3)查询xml _get_guest_xml

    4)创建_create_domain_and_network。详见13.

    5)等待instance的state为RUNNING

    6)结束。



13. _create_domain_and_network

    代码路径:nova/virt/libvirt/driver.LibvertDriver._create_domain_and_network

    1) 配置项:vif_plugging_timeout表示读取neutron发来的port_plugin_event消息的超时时间,默认300秒。

    2)执行下面的操作,等待neutron发来的event消息。
    3)plug_vifs,创建qvo/qbr/qvb,将qvo加入br-int。详见14。
    4)setup_basic_filtering
    5)prepare_instance_filter
    6)apply_instance_filter

    7)如果上面执行的动作超时,如果vif_plugging_is_fatal配置为True(默认为True,北基中配置为False),虚机创建失败,否则虚机可以创建成功。

 

14. plug_vifs

    代码路径:nova/virt/libvirt/driver.LibvertDriver.plug_vifs

    1) 遍历虚机网络的vif(即neutron port),执行libvirt_vif_driver的plug动作。

    2)libvirt_vif_driver为:LibvirtGenericVIFDriver

    3)根据vif_type选择不同的plug函数。对于ovs类型的vif_type:

    4)如果端口binding:vif_details上配置了port_filter,并且使能了安全组,或者binding:vif_details中配置了ovs_hybrid_plug。调用plug_ovs_hybrid。

        其他情况调用:plug_ovs_bridge,不做任何处理。



    plug_ovs_hybrid:

    1)如果qbr网桥不存在,

           utils.execute('brctl', 'addbr', br_name, run_as_root=True)

            utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True)

            utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True)

            utils.execute('tee',

                          ('/sys/class/net/%s/bridge/multicast_snooping' %

                           br_name),

                          process_input='0',

                          run_as_root=True,

                          check_exit_code=[0, 1])

 

    2)如果qvo不存在,

           linux_net._create_veth_pair(v1_name, v2_name)

            utils.execute('ip', 'link', 'set', br_name, 'up', run_as_root=True)

            utils.execute('brctl', 'addif', br_name, v1_name, run_as_root=True)

           _ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--',

                'add-port', bridge, dev,

                '--', 'set', 'Interface', dev,

                'external-ids:iface-id=%s' % iface_id,

                'external-ids:iface-status=active',

                'external-ids:attached-mac=%s' % mac,

                'external-ids:vm-uuid=%s' % instance_id])

           如果使能了MTU配置,

           utils.execute('ip', 'link', 'set', dev, 'mtu',

                      mtu, run_as_root=True,

                      check_exit_code=[0, 2, 254])

 

l  neutron plugin

5. neutron update_port

    Ml2Plugin继承db_base_plugin_v2.NeutronDbPluginV2,

    NeutronDbPluginV2实现了update_port方法。

    代码路径:

    1)检查device_owner和device_id。

        代码:_enforce_device_owner_not_router_intf_or_device_id

        如果普通租户要修改owner或者device_id,如果owner修改为network:router_interface或者network:router_interface_distributed,

         查询l3plugin中是否存在此router-id,如果存在,报异常,DeviceIDNotOwnedByTenant。

         如果l3plugin不存在,也报异常,DeviceIDNotOwnedByTenant

    2)检查mac地址:

        代码:_check_mac_addr_update

        如果修改mac字段,检测device_owner,如果以network:打头,不允许修改,报异常,UnsupportedPortDeviceOwner。

    3)如果修改fixed_ip字段:

         代码:_update_ips_for_port

         检测是否超过max_fixed_ips_per_port,默认5个。如果超过,报异常,Exceeded maximim amount of fixed ips per port。

         这里还有其他一些检查,报各种异常,不展开了。

         存储已分配的IP:_store_ip_allocation

    4)更新port,写入db:

         port.update(xxx)

         session.flush()

    5) 结束。

        

10. neutron 创建port:

    代码路径:neutron/plugins/ml2/plugin.ML2Plugin.create_port   

    1) _create_port_db 见下面

    2) 发送events.AFTER_CREATE

    3)调用mech_driver的create_port_postcommit

    4)_set_default_qos,配置端口默认qos

    5)如果port是dhcp或router,调security_groups_provider_updated

         否则触发security_groups_member_updated,更新安全组成员。

    6)_bind_port_if_needed,如果前面没有bind_port,这里会进行bind。



    _create_port_db:

    代码路径:neutron/plugins/ml2/plugin.ML2Plugin._create_port_db

    1)db.create_port,见下面。

    2)调extension.create_port

    3) 如果配置了port-security,处理port-security。

    4)调db.add_port_binding

    5)_process_port_binding

    6)处理allowed_address_pairs

    7)处理extra_dhcp_opts

    8)mech)driver.create_port_precommit



    db.create_port:

    代码路径:neutron/db/db_base_plugin_v2.NeutronDbPluginV2.create_port

    1)如果port中没有id属性,通过uuidutils.generate_uuid生成一个uuid。

    2)从port里,或者context里取tenant_id属性。如果两者不一致,报AdminRequired异常,Cannot create resource for another tenant。

    3)如果配置了device_owner,检查device_owner和device_id。

        代码:_enforce_device_owner_not_router_intf_or_device_id

        如果普通租户要修改owner或者device_id,如果owner修改为network:router_interface或者network:router_interface_distributed,

        查询l3plugin中是否存在此router-id,如果存在,报异常,DeviceIDNotOwnedByTenant。

        如果l3plugin不存在,也报异常,DeviceIDNotOwnedByTenant

   4)调用get_network,确保网络存在。

   5)如果mac不存在,调用_generate_mac生成mac。如果出错,按照配置文件中mac_generation_retries可以多试几次。

        如果mac生成失败,报MacAddressGenerationFailure异常,并且报error 日志,Unable to generate mac address after %s attempts。

   6)通过mac往neutron db中写port,如果db报DBDuplicateEntry异常,报MacAddressInUse异常。

    7)结束。

 

 

3.2   删除虚机流程

 

删除虚机相对于创建虚机比较简单,不重点分析了。

 

1. nova/compute/manager.py ComputeManager

terminate_instance, 

    _delete_instance

   1) clear_events_for_instance

    2) 置虚机状态delete.start

    3) _shutdown_instance

    4) instance.info_cache.delete()

    5) _cleanup_volumes

    6) 置虚机状态vm_states.DELETED

    7) instance.destroy() 删除db

    8) _complete_deletion,

        恢复quota, 删除block device mappings

        如果使能了vnc,清楚vnc授权key

        通知scheduler删除虚机调度信息



2 _shutdown_instance

    1) 从cache中取得network_info,如果没有cache,空的network_info

    2) 读取block_device_info,

    3) 调libvirt driver.destroy.

   4) _try_deallocate_network,删除在neutron中创建的nova port。

    5)删除volume。



3 driver.destroy.

    _destroy

    1) virt_dom.destroy()删除虚机qemu进程

    cleanup

    1) _unplug_vifs

    2) unfilter_instance删除安全组规则

    3) 删除磁盘文件。



4. unplug_vifs

    1)只有binding:vif_details   | {"port_filter": true, "ovs_hybrid_plug": true}才会删除port。

    2)执行命令:'brctl', 'delif', br_name, v1_name, 将qvb从qbr中删除

    3) 执行命令'ip', 'link', 'set', br_name, 'down',将qbr down掉

    4)执行命令:'brctl', 'delbr', br_name,   删除qbr

    5)执行命令:_ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev]),从br-int中删除qvo

    6)执行命令:'ip', 'link', 'delete', dev,删除qbo

 

3.3    port-binding

nova-compute创建虚机时通过update-port,更新了device_id和device_owner和binding:host_id属性。

ml2plugin在收到update_port或者create_port时,会进行port-binding,填写port的binding:profile,binding:vif_details,binding:vif_type,和binding:vnic_type属性。

 

比如

 

+-----------------------+---------------------------------------------------------------------------------+

| Field                 | Value                                                                           |

+-----------------------+---------------------------------------------------------------------------------+

| admin_state_up        | True                                                                            |

| allowed_address_pairs |                                                                                 |

| binding:host_id       | node-84                                                                         |

| binding:profile       | {}                                                                              |

| binding:vif_details   | {"port_filter": true, "ovs_hybrid_plug": true}                                  |

| binding:vif_type      | ovs                                                                             |

| binding:vnic_type     | normal                                                                          |

| device_id             | 5aa2ccff-2a91-4256-afb6-d8cd0505a106                                            |

| device_owner          | compute:nova                                                                    |

| extra_dhcp_opts       |                                                                                 |

| fixed_ips             | {"subnet_id": "e4ec7c6b-117f-467f-adb3-33c280e4ccb3", "ip_address": "1.1.1.13"} |

| id                    | 43d61251-d85f-4358-a1cf-fbba6484c011                                            |

| mac_address           | fa:16:3e:06:9e:62                                                               |

| name                  |                                                                                 |

| network_id            | 2125e96e-d2a3-42b3-931f-5a90149d0f90                                            |

| security_groups       | e2325d15-6e49-4720-9496-3c73d362293b                                            |

| status                | ACTIVE                                                                          |

| tenant_id             | 0baf9c928cdc4192babdf869e0cee498                                                |

 

我们可能会遇到binding:vif_type为binding_failed的现象,一般这种情况出现在部署阶段,原因是配置错误

 

这里列举几个常见binding_failed的原因:

1. agent配置中没有配置tenant_type。

2. 创建vlan/flat网络时指定physical_network,但是配置文件中没有。

3. 创建的网络类型在所有的ovs-agent配置文件中都没有定义。

 

3.4   nova-compute中的数据结构

在查看代码时,经常可以看到网络相关变量,如果不知道数据结构代码比较难理解。

nova中网络相关的数据结构定义在:nova/network/model.py中。

主要的model:networkInfo,VIF, Network

 

 

networkInfo是基于list派生出的类,其成员是VIF。

 

 

VIF是基于dict派生出的类,描述的是虚机的一个虚拟网卡的信息。

VIF属性主要包括:id,address,network,type,details,devname,ovs_interfaceid,active,                     vnic_type,profile。

其中:

network是Network model。

ovs_interfaceid,在vif_type是ovs时,为port-uuid,vif_type是其他时,为空。

devname为tap+port uuid,截取14字符。

 

Network model描述了虚机网卡对应的网络信息。

主要属性包括:id,bridge,label,tenant_id ,subnets。

其中id是网络id,bridge是绑定的网桥,比如br-int,label是网络名称,

 

4     附录

4.1   虚机端口恢复脚本

我们可能会遇到虚机是存在的,但底层qvb/qvo/qbr配置不正确的现象,这有可能是虚机创建或迁移过程中出现的,在k版代码中,重启nova-compute可会恢复qvb/qbr/qvo的配置。

但在I版中,或者在上线业务中,不能随意重启nova-compute,此时我们需要手动恢复端口。

 

脚本内容如下:

#cat yanxingan/gen_nova_cfg_by_ip.sh 

 

#!/bin/bash

 

if [ $# == 0 ]; then

 echo "usage: gen_nova_cfg_by_ip <VM-IP>";

 exit;

fi

 

echo VM-IP is: $1

 

source /root/openrc

 

echo

echo Retrieve port-id from neutron db. Please wait...

portid=`neutron port-list |grep $1 | awk -F '|' '{print $2}' |sed 's/^[ \\t]*//g' | sed 's/[ \\t]*$//g'  `

echo port-id is: ${portid}

if [ -z $portid ]; then

 echo "Fail to ecec neutron port-list. Please retry.";

 exit;

fi

 

echo

echo Retrieve port info by id from neutron db. Please wait...

portinfo=`neutron port-show $portid |grep -E '(binding:host_id|mac_address|device_id)' |sed 's/^[ \\t]*//g' | sed 's/[ \\t]*$//g' `

 

host=`echo -e $portinfo |awk -F '|' '{print $3}' |sed 's/^[ \\t]*//g' | sed 's/[ \\t]*$//g'`

device=`echo -e $portinfo |awk -F '|' '{print $6}' |sed 's/^[ \\t]*//g' | sed 's/[ \\t]*$//g' `

mac=`echo -e $portinfo |awk -F '|' '{print $9}' |sed 's/^[ \\t]*//g' | sed 's/[ \\t]*$//g'`

echo host is: $host

echo vm-id is: $device

echo mac is: $mac

echo

 

sleep 1s

echo Nova-compute commands: \\(Please exec these commands on HOST $host\\)

echo

 

tap=tap${portid:0:11}

qbr=qbr${portid:0:11}

qvo=qvo${portid:0:11}

qvb=qvb${portid:0:11}

 

echo sudo nova-rootwrap /etc/nova/rootwrap.conf brctl addbr ${qbr}

echo sudo nova-rootwrap /etc/nova/rootwrap.conf brctl setfd ${qbr} 0

echo sudo nova-rootwrap /etc/nova/rootwrap.conf brctl stp ${qbr} off

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link add ${qvb} type veth peer name ${qvo}

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set ${qvb} up

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set ${qvb} promisc on

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set ${qvo} up

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set ${qvo} promisc on

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ip link set ${qbr} up

echo sudo nova-rootwrap /etc/nova/rootwrap.conf brctl addif ${qbr} ${qvb} 

echo sudo nova-rootwrap /etc/nova/rootwrap.conf brctl addif ${qbr} ${tap} 

 

echo sudo nova-rootwrap /etc/nova/rootwrap.conf ovs-vsctl --timeout=120 -- --if-exists del-port ${qvo} -- add-port br-int ${qvo} -- set Interface ${qvo} external-ids:iface-id=${portid} external-ids:iface-status=active external-ids:attached-mac=${mac} external-ids:vm-uuid=${device}

echo

echo

 

 

 

5     FAQ

 

1. qbo口是哪个服务进程在何时加入br-int的?

nova-compute在spawn时,通过libvirtdriver plug方法加入的。

 

2. neutron db中的nova port是那哪个服务进程在何时创建的?

nova-compute在创建虚机创建网络资源时通过neutron client create-port创建的。

 

3.创建虚机时出现no valid host可能有哪些原因?

 

4. ovs-agent如何知道虚机创建了,如何指定qvo与虚机的对应关系?

nova-compute将qvo加入br-int时,会配置port-uuid信息,通过ovsdb-monitor监控db变化,

通过uuid找到对应的neutron port。

 

5.如果nova-compute始终收不到network-vif-plug的event,虚机行为是怎样?

根据vif_plugging_is_fatal配置项决定创建虚机是否失败。

以上是关于nova与neutron交互的主要内容,如果未能解决你的问题,请参考以下文章

nova boot代码流程分析:nova与neutron的l2 agent(neutron-linuxbridge-agent)交互

nova与neutron交互

nova boot代码流程分析:VM启动从neutron-dhcp-agent获取IP与MAC

nova boot代码流程分析:VM启动从neutron-dhcp-agent获取IP与MAC

openstack nova neutron cinder节点安装

opentack