概述
基于yoga版本学习neutron,通过源码、官方文档、部署环境进行学习
官方文档学习
概念
NAT network address transition
NTP network time protocol
DNS domain name system
NIC Network Interface Card
MAC Media Access Control
TCP Transmit Control Protocol
UDP User Datagram Protocol
ICMP Internet Control Messag Protocol
FQDN Fully qualified domain name 完全限定域名
安装
创db、导环境变量、创建neutron user、给neutron user添加admin role、创建neutron服务、创建neutron admin public internal endpoint
控制节点配置
有两种配置方案,provider network和self-service,前者直接用机器的网络和网卡,不需要创建什么东西,后者(self-network)扩展了provider network功能,使用了三层网络服务,虚机可挂在self-network上(仍然也可挂在provider network上),还提供了浮动ip。self-service network一般使用overlay 网络
overlay 网络一般使用vxlan,会在原有ip报文头部加一个overlay头部,在overlay转发包时就用这个overlay头进行转发
provider network
安装neutron linux模块neutron-server, neutron-plugin-ml2, neutron-openvswitch-agent, neutron-dhcp-agent, neutron-metadata-agent
basic server配置
[database]下connection,
Default.core_plugin = ml2(modular layer 2)
Default.transport_url = rabbit://xxx mq地址
Default.auth_strategy = keystone
keystone_authtoken
Default可以配置网络一些信息变更时是否通知nova,通知的话,还要配nova
core_plugin配置
[ml2] type_drivers=flat,vlan 使vlan和flat生效
[ml2] tenant_network_types = 配置空白可disable self-network
[ml2] mechanism_drivers = openvswitch 使用linux bridge
[ml2] extension_drivers = port_security
[ml2_type_flat] flat_networks = provider 配置provider虚拟网络作为一个flat network
openvswitch agent配置
openvswitch可以为虚机创建二层虚拟网络并操作安全组,配置文件在/etc/neutron/plugins/ml2/openvswitch_agent.ini
[ovs] bridge_mappings = provider:PROVIDER_BRIDGE_NAME map provider虚拟网络到provider物理网络
确保物理bridge已创建且已创了个port连到物理bridge
ovs-vsctl add-br PROVIDER_BRIDGE_NAME
ovs-vsctl add-port PROVIDER_BEIDGE_NAME PROVIDER_INTERFACE_NAME
配置安全组和firewall driver [securitygruop] enable_security_group = true; firewall_driver = openvswitch/iptables/hybrid
dhcp配置
配置linuxbridgedriver
[DEFAULT]
interface_driver = openvswitch
dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
enable_isolated_metadata = true
创建provider network
在provider network中,创虚机时必须使用一个网络,网络包含dhcp server来为虚机提供ip地址
创建network,创建子网
self-network
安装neutron模块,neutron-server、neutron-plugin-ml2、neutron-openvswitch-agent、neutron-l3-agent、neutron-dhcp-agent、neutron-metadata-agent
neutron server配置
和provider network类似,self-network需要配置service-plugins为router
core_plugin配置
[ml2] type_drivers=flat, vlan, vxlan
[ml2] tenant_network_types = vxlan
[ml2] mechanism_drivers = openvswitch, l2population
[ml2_type_vxlan] vni_ranges = 1:1000
openvswitch agent配置
需配物理网络interface的local_ip来处理overlay网络
其他
和provider netwokr差不多,还要配置l3 agent的interface_driver为openvswitch
计算节点配置
networking guide
introduction
网络基础
以太网
mac地址是主机的独立标识,是被生产商硬编码在网卡里的。可以通过ip link show eth0查看网卡mac地址
以太网是二层的概念
ff:ff:ff:ff:ff:ff是二层广播地址
默认情况,网卡收到帧后会检查帧是否为网卡的mac地址,如果不是则丢弃帧,实际我们不期望这样,此时可以配置开启网卡的混杂模式,该模式可以让网卡收到的帧即使帧目标mac与网卡mac不一样也可以将帧转发给os,可以为混杂模式配置适当的网卡
交换机内部会有一个mac地址和交换机端口的mapping表,收到未知mac时,交换机会广播帧然后监控流量学习mac对应哪个port,学会了以后就不需要广播了,直接转发到对应port,学会的映射表会放到交换机一个叫FIB的表
vlan
vlan技术可以让一个交换机变得像多个独立工作的交换机一样,不同vlan看不到彼此的流量
vlan工作原理 将交换机各端口赋予对应的vlanid,当交换机转发帧到其他交换机时,只能转发到支持vlanid的端口,不会到其他端口
发送帧的交换机会给帧打上vlanid
可以转发所有vlanid的交换机口叫trunk口(中继端口),trunk口是连接其他交换机的口
如果要在物理交换机使用vlan实现openstack网络隔离,需要将交换机所有端口都设置为trunk口
子网和ARP
arping可以用来获取目标ip对应的mac,映射关系保存在arp缓存
dhcp
主机连到dhcp协议的网络可以自动获取分配的ip地址,获取到ip地址的主机叫dhcp client
dhcp client需要发现dhcp server,client通过对local network广播来发现server,所有client都可以看到广播发送的消息。由于local network广播仅限于local network无法broadcast到其他网络,所以DHCP server需要在local network范围内
openstack使用dnsmasq实现dhcp,dhcp过程会写道syslog,可以在syslog查看到形如上述地址分配的记录
dhcp server用67端口,dhcp client用68端口
ip协议
ip协议决定了数据报怎么在主机间转发,ip协议依赖于路由器和网关。
路由器是连接至少两个网络的机器并且可以i将一个网络的数据报路由到另一个网络,路由器可以有多个ip地址,每个ip地址是路由器连接到的那个网络的接口地址
ip route show/ route -n/ netstat -rn三个命令都可查看本机路由表
路由表由子网和子网对应的网络地址构成的条目组成
dhcp server给client分配地址时一般会把网关地址带着分配的ip地址一起发给client
ip route get ip地址可看到某个ip地址会被路由到哪个设备
tcp/udp/icmp
tcp在client会由os随机分配一个端口,tcp连接终止后os收回端口,是可靠连接,会丢包重传,包检测等,但udp没有。udp和tcp可同时用一个端口
网络组件
switch(交换机):连接在同一个局域网的不同主机
router(路由器):可以沟通在不同网络中的主机
firewalls、load balancer
overlay(tunnel) protocol
隧道技术可用来在不兼容的网络之间传输数据报
Generic Routing Encapsulate(GRE)
VXLAN虚拟扩展局域网:是三层上实现了二层vlan原理的vxlan
NAT
一般nat由路由器实现,在openstack一般由服务器实现而不是路由器
SNAT,Source Network Address Transmission,常用来改变发送的ip数据报头的源ip地址,在私有和共有地址之间转换。SNAT在openstack中由路由器(常由server提供路由功能)实现,路由器会保存原有的私有ip地址。SNAT不光会改ip地址,也会改tcp和udp端口号
DNAT,Destination NAT,同SNAT
configuration
address scope
地址作用域用来避免子网中地址分配重叠,在地址作用域中分配的地址不会重叠
访问地址作用域
可以创建自己的地址作用域,管理员可以创建共享地址作用域,共享作用域可创建不同project的地址
对地址作用域的访问通过子网池实现,子网池可以在一个作用域内创建,或者修改归属到另一个作用域
多个子网池对owner来说地址范围相同,如果各子网池的owner在子网池创网络,可能会产生地址重叠,此时可将子网池放到地质作用域,作用域会对地址分配进行委派,防止地址重叠
路由器连到具有地址作用域和外网之间时,不需进行NAT,因为地址不重叠
创建地址作用域
创建ipv4或ipv6地址作用域 neutron address-scope-create --share tjh4 4
创建子网池时可选择对应的地址作用域,已有的子网池可以修改子网使其属于某个地质作用域
neutron subnetpool-create --address-scope tjh4 --share --pool-prefix [IP_ADDRESS/MASKNUM] --default-prefixlen 28 tjhpool4
可用域(availability zones)
主要用于高可用,通过az可以实现资源集中,避免了远程资源通信的消耗,也就高可用了
需要的extension
可用域需要核心plugin支持availability_zone和network_availavility_zone扩展,而ML2Plugin支持
路由服务需要支持router_availability_zone,而L3RouterPlugin支持
agent的可用域
availability_zone可在dhcp或l3 agent定义,具体可以在/etc/neutron对应的配置文件中的AGENT下定义,没配的话默认可用域是nova
可用域的属性
availability_zone和availability_zone_hints两个属性会被添加到网络和路由器中
x_hints表示当前resource所在可用域
x表示当创资源没指定az时,默认使用的az。配置文件和代码里默认配置为空
查看resource的az可查看resource目前实际托管在哪个az
网络拓扑自动分配
这简化了将创建的external network与终端用户连接的过程,也被称为Get Me A Network
没有自动分配时是这样:1创网络 2创子网 3创路由 4将路由连到external网络 5将路由连到创建的子网
局限性:这些步骤很多而且需要一定的知识储备才能正确执行
怎么做:先准备好external network和子网池,然后创虚机时,计算服务会自动应用这个特性最后将网络连到虚机,我们不用做其他事
打开auto-allocation
需要的extension:如果需要此特性,neutron需要这些extension:router,external-net,subnet_allocation,auto-allocated-topology
准备资源:先准备external network和子网池,并均设为default,然后就可以创建topology。创建的topology实际也是网络,创完回显有id,可以在创虚机时传参这个id,网络相关直接自动弄好
BGP dynamic routing
agents and service
一般安装网络服务有几个经常安装的agent和service:
1 neutron-server:提供api并可访问db,常在控制节点
2 l2 agent:可利用vlan、linux bridge和其他技术对project network实施网络隔离,常在计算节点和网络节点部署
3 l3 agent:常部署在网络节点
配置
service和agent的配置分布在/etc/neutron下自己对应的配置文件,主配置文件是neutron.conf,service和agent都会加载这个主配置
service和agent也有自己的配置,一般会先加载主配置(neutron.conf),再加载自己的配置
dhcp高可用
dhcp高可用需要extension agent和agent_scheduler
场景:如上图,部署三个节点,一控二计算,部署的服务也如图
控制节点配置如下
这个配置dhcp_agents_per_network可大于1,实际可与部署DHCP agent的节点数匹配实现dhcp 高可用
更新控制节点linux bridge配置如下
两个计算节点配置如下
用dhcp agent管理网络
一个网络可以归属多个dhcp agent,一个dhcp agent也可以管理多个网络
dhcp agent HA
创虚机时,用分配多个dhcp agent的网络即可。
测试:依次停止网络所在的dhcp agent,
停止并移除agent
系统升级时可能需要停掉agent
移除agent前需确认agent上的资源是否需要保留
删除agent需要先disable再remove/delete
dns integration
dns integration是dns_domain extension的一个子集,dns_domain用于port配置,如果dns_domain配置了,也连带dns integration配置了
neutron内部dns解决方案
1 修改neutron.conf的dns_domain配置使内部dns生效
2 neutron.conf的section ml2下的extension_drivers option添加dns(dns integration)或dns_domain_ports(dns_domain)
3 改完配置重启neutron-server生效,然后创port时,可指定选项--dns-name
注意:使以上dns生效有一个前提,是主机需要有外部dns服务
创建的port可多传入一个属性dns_name,internal dns配置好后,创虚机时给虚机自动分配的端口的dns_name会变成虚机的虚机名。此时再查看端口信息,端口的fqdn也会被刷成主机名+dns配置的后缀
dns integration与外部服务
前置条件:需要设置dns internal integration
配置:在neutron.conf定义external_dns_driver为希望的driver名。如果openstack的dns服务即为目标的dns服务,则需要在neutron.conf的designate section下定义很多必选项(如图)
应用:当做完如上配置并重启neutron-server后,用户就可以实现如下例子的情形
例子1 :创虚机后,用给虚机分配的端口,创floatingip,如果floating ip想用port的dns,可在创的时候和port关联
例子2:当想让创的虚机直接对接外部dns时,internal dns integration会给端口赋值fqdn,如果创floating ip时又给floating ip赋值了dns-name和dns-domain,则floating ip的会覆盖port的这两个属性
例子3:
neutron-dhcp-agent
neutron.agent.dhcp_agent.main
创建server,调oslo_service launch server,最后实际调了server的start方法
neutron.service.Service.start
Service创建时会传入一个manager路径,Service.start实际会调manager的一些方法启动业务,主要调了manager的init_host和after_start方法,after_start方法默认为空,主要是init_host
neutron没有prepare_service,而是把配置项注册汇聚到一个函数,可手动尝试
start方法周期运行service的report_state方法,这个方法默认为空,应该没啥用
neutron.agent.dhcp.agent.DhcpAgentWithStateReport.__init__
neutron.agent.dhcp.agent.DhcpAgent._populate_networks_cache
DhcpAgent初始化时从neutron 拿数据放入cache
然后调Dnsmasq的existing_dhcp_networks,实际获取/var/lib/neutron/dhcp底下的形如uuid的文件名作为已存在网络id,然后用id创dhcp对象,塞到cache
neutron.agent.dhcp.agent.DhcpAgentWithStateReport.init_host
实际调用了sync_state方法
neutron.agent.dhcp.agent.DhcpAgentWithStateReport.sync_state
从cache获取已存在的网络id,cache的东西初始从/var/lib/neutron/dhcp读取目录下所有形如uuid的文件名
DhcpAgent.plugin_rpc.get_active_networks_info
plugin_rpc传入target和transport,封装了一个oslo_messaging的RPCClient,topic从neutron_lib的topics常量文件读取,是q-plugin,transport用默认的rabbit,最后通过transport发消息到target
看了下rpc可能是core_plugins启的,不知道谁调core_plugins,后面再看
neutron-l3-agent
概述
主要在after_start,init_host没啥东西
流程
neutron.cmd.eventlet.agents.l3:main ->
neutron.agent.l3_agent.main ->
neutron.agent.l3.agent.L3NATAgentWithStateReport.after_start
neutron.agent.l3.agent.L3NATAgentWithStateReport._process_routers_loop
neutron.agent.l3.agent.L3NATAgentWithStateReport._report_state
neutron.agent.l3.agent.L3NATAgentWithStateReport.pd.after_start
neutron-linuxbridge-agent
流程
neutron.cmd.eventlet.plugins.linuxbridge_neutron_agent:main ->
neutron.plugins.ml2.drivers.linuxbridge.agent.linuxbridge_neutron_agent.main ->
neutron.plugins.ml2.drivers.agent._common_agent.CommonAgentLoop.start ->
neutron.plugins.ml2.drivers.linuxbridge.agent.linuxbridge_neutron_agent.main
physical_interface_mappings和bridge_mappings从配置文件读取,冒号分隔,可能是配的,返回一个mapping
neutron.plugins.ml2.drivers.agent._common_agent.CommonAgentLoop.start
report_interval默认是30
self.setup_rpc
创建队列监听,约10来个队列,均是q-plugin-agent开头的一些队列
self.daemon_loop
周期扫描主机所有tap口,默认周期30秒,提前扫完了则sleep
self.scan_devices
self.process_network_devices
扫描完新设备后,和上一周期设备信息对比,如果设备信息无变更或不需要刷新防火墙,则不处理等待下一周期,否则则集中处理:刷防火墙、处理安全组、更新网络信息,处理端口、清理arp,调用rpc接口处理设备等操作
self.ext_manager.names
names应该是配置文件对应的extensions的名称,可以是qos,local_ip,qos_linux等
太难了
self.mgr.get_agent_configurations
两个mapping从配置读取
vxlan_mode可以是none,ucast或mcast
self.mgr.__init__
enable_vxlan默认为True
self.mgr.check_vxlan_support
self.vxlan_ucast_supported
l2_population默认False,实际可为true或false。如果false则不支持,如果true则找一个空闲vxlan号,创vxlan,然后将创的vxlan加到fdb表,然后删vxlan
neutron.agent.linux.ip_lib.device_exists
调接口查interface是否存在,最后好像socket通信,调用栈太深不看了,外面给device_exists传各种vxlan-xx,检查interface是否存在,返回True或False
neutron.privileged.agent.linux.interface_exists ->
neutron.privileged.agent.linux.get_link_id
namespace默认None,返回pyroute2.IPRoute()
最后是socket通信,不看了
self.ensure_vxlan
确认vxlan不存在,不存在则创建,创完了disable这个vxlan的ipv6,通过sysctl修改变量来disable,然后up此vxlan
cfg.CONF.VXLAN.tos deprecated,默认应该是None
dscp_inherit默认False
1 ip.add_vxlan
self.ip是:
self.local_int:
最后返回第一个device的网卡名赋值给self.local_int
self.local_ip配的是overlay network endpoint
arp_responder默认false
更新fdb表
支持ucast的话,把创的vxlan加到fdb表,然后删除vxlan
neutron-linuxbridge-cleanup
不以服务形式工作 ,运行命令会清理无用bridge和bridge相关的vxlan,会便利bridge下的tap口,清理无tap口的bridge,tap口在bridge/brif目录下,遍历即可
neutron-metadata-agent
agent worker数期望是cpu数的一半,从配置读取,没有默认配置,读取不到则调neutron_lib获取,调multiprocessing.cpu_count()获取
socket mode默认deduce,可选项,deduce、user、group、all
metadata_proxy_socket默认是/var/lib/neutron/metadata_proxy
最后调用eventlet.wsgi.server启动服务,服务封装在MetadataProxyHandler,handerl作用类似一个转发器,自己做些操作,然后转发出去,代码好像没有存储改动等操作,感觉只是加header,cert,发给nova,需要确认监听哪个端口,是否从socket对象获取端口
neutron-server
加载配置文件,默认是neutron.conf, plugins/ml2/ml2_conf.ini
最后加载完配置文件,没有太多操作,调用oslo_service,加载api_paste.ini加载server
服务拉起
从setup.cfg出发
neutron.cmd.eventlet.server:main
neutron.server.boot_server函数先初始化配置,再调用neutron.server.wsgi_eventlet.eventlet_wsgi_server函数
neutron.server._init_configuration
从环境变量寻找配置文件名,环境变量不存在则使用默认配置文件名,默认有两个文件,参考上图
调用neutron.common.config.init函数,该函数初始化neutron三个rpc相关全局变量,然后校验CONF.base_mac是否为合法mac格式,使用re.match,ptn是'^[0-9A-Fa-f][aceACE02468](:[0-9A-Fa-f]{2}){5}$'
neutron.common.config.setup_logging安装log
neutron.common.config.set_config_defaults()设置api相关默认配置,如允许的请求头,允许的请求方法等
neutron.server.wsgi_eventlet.eventlet_wsgi_server
CONF.profiler.enabled默认在os.profiler.opts中,默认配置为False
neutron.service.serve_wsgi然后调用neutron.service.NeutronApiService的start方法,最后会调neutron.service._run_wsgi('neutron')方法
api逻辑封装
initialize_all注册接口对应的controller
route时,controller会找在initialize_all中注册的controller
startup.initialize_all(路由规则加载)
1 manager.init创建一个neutron.manager.NeutronManager实例,如果是首次运行,再创建_PluginDirectory实例。neutronmanager实例和_PluginDirectory实例应该都是单例模式,首次运行会加载,加载NeutronManager时会加载_PluginDirectory。主要功能:1 初始化core_plugins(可配ml2),在neutron_lib的directory中添加core plugin;2 从ml2对应的类加载所有extension alias,然后将与service匹配的alias加载到directory;3 加载配置文件配置的service plugin,判断配置是否本地存储,如果是,再新加载默认服务plugins
2 extensions.PluginAwareExtensionManager.get_instance是静态方法,创建一个自身实例并返回
创建实例时,创建一个全局的_PluginDirectory,其plugins属性包含extensions,默认为空
获取_PluginDirectory的plugins的路径,plugin空时路径只有一个目录的path
创PluginAwareExtensionManager实例时,将_PluginDirectory的plugins的路径和plugins作为初始化参数传入,初始化会加载plugin路径(extension目录,无子文件,因为是初始)下所有extension,每个extension是neutron/extensions下一个脚本,alias是neutron_lib仓库里同名脚本里对应的alias字段,加载脚本里对应的类,然后PluginAwareExtensionManager实例以map[alias] = extensions的形式保存extensions
3 NeutronManager.__init__
判断配置的core_plugin是否为空,如果空则异常,默认是ml2
加载core_plugin,将plugin加载到_PluginDirectory的plugin和NeutronManager的_loaded_plugin
判断core_plugin是否有支持的service类型,如果有则将支持的service对应的plugin也设为core_plugin,加到directory和neturonmanager的plugin
从配置获取服务plugin名称,如果neutron支持local存储则再获取默认service plugin名称,再看这些默认service plugin是否有必须plugin,如果有则将这些service plugin的必须plugin也加载
创建PluginAwareExtensionManager,将neutron.extensions下的plugin都加到PluginAwareExtensionManager的extensions字典中,键是extension的alias
neutron-api(接口)
net-create
走到neutron.pecan_wsgi.controllers.resource.CollectionsController处理:根据initialize_all加载的plugin,从plugin获取对应的方法,创network会调用ml2的create_network方法
request.context['resources']的生成
ML2Plugin.create_networks
_before_create_network
创建安全组
_create_network_db
在db依次创建:网络,rbac,segment,networksecuritybinding等db项
_after_create_network
只有这一步里才创底层的网络相关,看到这里看不下去了,麻了
neutron hooks
pecan
有很多hook,request里一些参数会在各hook里赋值
body_validation
python库网络操作
ip link
ip相关命令用pyroute2.IPRoute().link等实现
添加vxlan:ip link add vxlan-xxx type vxlan id xxx dstport 5678
bridge
bridge show
bridge fdb show dev vxlan-666 #查看某个vxlan fdb转发表
brctl
Linux下的虚拟Bridge实现 - zmkeil - 博客园 (cnblogs.com)
linux网桥bridge详解_linux网桥、-CSDN博客
Linux 虚拟网络设备详解之 Bridge 网桥 - bakari - 博客园 (cnblogs.com)
ip -> arp(ip地址和mac地址) -> fdb(物理地址和端口) -> bridge ?
brctl show
brctl addbr testbr0
brctl addif testbr0 eth0
brctl addif testbr0 eth1
ifconfig testbr0 up
ifconfig testbr0 ip_addr netmask mask_addr/ ip addr add ip_addr/mask_addr dev testbr0
vlan和vxlan
VLAN与VXLAN网络原理与实践 - 知乎 (zhihu.com)、
其他操作
/sys/class/et存放网络网卡和接口相关消息
好用的方法
socket.gethostname
multiprocessing.cpu_count()