概述
ML2Plugin的主要工作是管理虚拟网络资源,保证数据正确无误,具体物理设备的设置则由Agent完成。L2Agent通常运行在Hypervisor,与neutron-server通过RPC通信,监听并通知设备的变化,创建新的设备来确保网络segment的正确性,应用security groups规则等。例如,OVS Agent,使用Open vSwitch来实现VLAN, GRE,VxLAN来实现网络的隔离,还包括了网络流量的转发控制。
初始化
各个组件启动流程图
Agent初始化
Agent启动命令
/usr/bin/python /usr/local/bin/neutron-openvswitch-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini
脚本内容:
#!/usr/bin/python
# PBR Generated from u'console_scripts'
import sys
from neutron.cmd.eventlet.plugins.ovs_neutron_agent import main
if __name__ == "__main__":
sys.exit(main())
通过查看setup.cfg文件可知,ovs agent的入口位于:
# 根据setup.cfg文件可以看出neutron-openvswitch-agent的代码路径是
# neutron\cmd\eventlet\plugins.ovs_neutron_agent
neutron-openvswitch-agent = neutron.cmd.eventlet.plugins.ovs_neutron_agent:main
Ovs agent在初始化阶段根据ml2_conf.ini的配置文件建立基本完整的虚拟网络环境,建立vlan和tunnel转发所需要的主要流表和默认规则。参考配置信息如下:
[ml2]
tenant_network_types = vxlan
extension_drivers = port_security
mechanism_drivers = openvswitch,linuxbridge
[ml2_type_flat]
flat_networks = public,
[ml2_type_geneve]
vni_ranges = 1:1000
[ml2_type_gre]
tunnel_id_ranges = 1:1000
[ml2_type_vlan]
network_vlan_ranges = public
[ml2_type_vxlan]
vni_ranges = 1:1000
[securitygroup]
firewall_driver = iptables_hybrid
[agent]
tunnel_types = vxlan
root_helper_daemon = sudo /usr/local/bin/neutron-rootwrap-daemon /etc/neutron/rootwrap.conf
root_helper = sudo /usr/local/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
[ovs]
datapath_type = system
bridge_mappings = public:br-ex
tunnel_bridge = br-tun
local_ip = 192.168.209.134
启动过程代码分析
neutron.cmd.eventlet.plugins.ovs_neutron_agent:main cmd.ovs_neutron-agent.py
import neutron.plugins.ml2.drivers.openvswitch.agent.main as agent_main
# 虚拟交换机(vswitch)主要有两个作用:
# 1. 传递虚拟机VM之间的流量。
# 2. 实现VM和外界网络的通信
def main():
agent_main.main()
neutron/plugins/ml2/drivers/openvswitch/agent/main.py:main
LOG = logging.getLogger(__name__)
cfg.CONF.import_group('OVS', 'neutron.plugins.ml2.drivers.openvswitch.agent.'
'common.config')
_main_modules = {
'ovs-ofctl': 'neutron.plugins.ml2.drivers.openvswitch.agent.openflow.'
'ovs_ofctl.main',
'native': 'neutron.plugins.ml2.drivers.openvswitch.agent.openflow.'
'native.main',
}
# neutron/plugins/ml2/drivers/openvswitch/agent/main.py:main
def main():
common_config.init(sys.argv[1:])
# driver_name = ovs-ofctl
driver_name = cfg.CONF.OVS.of_interface
mod_name = _main_modules[driver_name]
mod = importutils.import_module(mod_name)
mod.init_config()
common_config.setup_logging()
n_utils.log_opt_values(LOG)
profiler.setup("neutron-ovs-agent", cfg.CONF.host)
# 调用ovs-ofctl对应的main方法
mod.main()
neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl.main
# neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl.main
def main():
bridge_classes = {
'br_int': br_int.OVSIntegrationBridge,
'br_phys': br_phys.OVSPhysicalBridge,
'br_tun': br_tun.OVSTunnelBridge,
}
# 启动解析过程
ovs_neutron_agent.main(bridge_classes)
neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py:main
# neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py:main
def main(bridge_classes):
# cfg.CONF中包含了agent的配置信息,主要是network-mappings,各个bridges的名称
prepare_xen_compute()
ovs_capabilities.register()
validate_tunnel_config(cfg.CONF.AGENT.tunnel_types, cfg.CONF.OVS.local_ip)
try:
# 创建agent实例,在实例初始化过程中完成以下操作
# 启动时做了以下工作:
# 1.设置br - int。
# 2.设置plugin_rpc,这是用来与neutron - server通信的。
# 3.设置state_rpc,用于agent状态信息上报。
# 4.设置connection,用于接收neutron - server的消息。
# 5.启动心跳周期上报。
# 6.设置bridge_mapping对应的网桥。br-eth
# 7.设置DVR agent
# 8.初始化sg_agent,用于处理security group。
# 9.run_daemon_loop=True 开始循环
# 周期检测br - int上的端口变化,调用process_network_ports处理添加 / 删除端口。
# 实例化一个OVSAgent,并完成OVS Agent的一系列初始化工作
agent = OVSNeutronAgent(bridge_classes, cfg.CONF)
capabilities.notify_init_event(n_const.AGENT_TYPE_OVS, agent)
except (RuntimeError, ValueError) as e:
LOG.error("%s Agent terminated!", e)
sys.exit(1)
# 循环检查一些状态,发现状态发生变化,执行相应的操作
agent.daemon_loop()
neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py:init
# 在OVSNeutronAgent的docstring中,概要说明了agent实现虚拟的方式,有以下几点:
# 1) 创建br-int, br-tun以及每个物理网络接口一个bridge。
# 2) 虚拟机的虚拟网卡都会接入到br-int。
# 使用同一个虚拟网络的虚拟网卡共享一个local的VLAN(与外部网络的VLAN无关,vlan id可以重叠)。
# 这个local的VLAN id会映射到外部网络的某个VLAN id。
# 3) 对于network_type是VLAN或者FLAT的网络,
# 在br-int和各个物理网络bridge之间创建一个虚拟网卡,
# 用于限定流规则、映射或者删除VLAN id等处理。
# 4) 对于network_type是GRE的,每个租户在不同hypervisor之间的
# 网络通信通过一个逻辑交换机标识符(Logical Switch identifier)进行区分,
# 并创建一个连通各个hypervisor的br-tun的通道(tunnel)网络。
# Port patching用于连通br-int和各个hypervisor的br-tun上的VLAN。
@profiler.trace_cls("rpc")
class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
dvr_rpc.DVRAgentRpcCallbackMixin):
'''Implements OVS-based tunneling, VLANs and flat networks.
Two local bridges are created: an integration bridge (defaults to
'br-int') and a tunneling bridge (defaults to 'br-tun'). An
additional bridge is created for each physical network interface
used for VLANs and/or flat networks.
All VM VIFs are plugged into the integration bridge. VM VIFs on a
given virtual network share a common "local" VLAN (i.e. not
propagated externally). The VLAN id of this local VLAN is mapped
to the physical networking details realizing that virtual network.
For virtual networks realized as GRE tunnels, a Logical Switch
(LS) identifier is used to differentiate tenant traffic on
inter-HV tunnels. A mesh of tunnels is created to other
Hypervisors in the cloud. These tunnels originate and terminate on
the tunneling bridge of each hypervisor. Port patching is done to
connect local VLANs on the integration bridge to inter-hypervisor
tunnels on the tunnel bridge.
For each virtual network realized as a VLAN or flat network, a
veth or a pair of patch ports is used to connect the local VLAN on
the integration bridge with the physical network bridge, with flow
rules adding, modifying, or stripping VLAN tags as necessary.
'''
# history
# 1.0 Initial version
# 1.1 Support Security Group RPC
# 1.2 Support DVR (Distributed Virtual Router) RPC
# 1.3 Added param devices_to_update to security_groups_provider_updated
# 1.4 Added support for network_update
target = oslo_messaging.Target(version='1.4')
def __init__(self, bridge_classes, conf=None):
'''Constructor.
:param bridge_classes: a dict for bridge classes.
:param conf: an instance of ConfigOpts
'''
super(OVSNeutronAgent, self).__init__()
self.conf = conf or cfg.CONF
self.ovs = ovs_lib.BaseOVS()
agent_conf = self.conf.AGENT
ovs_conf = self.conf.OVS
self.fullsync = False
# init bridge classes with configured datapath type.
self.br_int_cls, self.br_phys_cls, self.br_tun_cls = (
functools.partial(bridge_classes[b],