OpenStack-Neutron-Fwaas-代码【一】
Kilo的代码中对Fwaas做了优化,可以将规则应用到单个路由上
但是juno里面还是应用到租户的所有路由上的,因此对juno的代码做了修改
1. 介绍
在FWaaS中,一个租户可以创建多个防火墙,而每一个防火墙和多个Policies关联,每个Policies由多个Rules按序组成。不能直接应用一个rule,它必须先加入到一个policy中,因为它需要先审计。如下图:
审计的功能目前是这样的:新建一个策略的时候默认审计是False,在新加或者修改一个规则时这个值都是False,需要手动去确认后设置为True
代码里暂时没有看到用这个字段作功能上的判断,fwaas的规则是写在qr-这个port上的
2. 创建一个防火墙
juno中创建墙是不指定路由id的,因为会应用到所有的路由上。kilo中优化了这里,让用户在创建防火墙的时候给定路由的id列表,如果不给定,默认是所有路由
文件路径:neutron\services\firewall\fwaas_plugin.py
line:230
方法:create_firewall
这个plugin是在配置文件中指定的setup.cfg中 [neutron.service_plugins] section下面
def create_firewall(self, context, firewall):
LOG.debug("create_firewall() called")
tenant_id = self._get_tenant_id_for_create(context,
firewall['firewall']) fw_new_rtrs = self._get_routers_for_create_firewall( #【1】获取用户参数中的router_ids,如果没有给定返回所有的路由ids。同时会校验给定的路由是否已经被使用
tenant_id, context, firewall) if not fw_new_rtrs: #当前租户没有创建路由
# no messaging to agent needed, and fw needs to go
# to INACTIVE(no associated rtrs) state.
status = const.INACTIVE
fw = super(FirewallPlugin, self).create_firewall(
context, firewall, status)
fw['router_ids'] = []
return fw
else:
fw = super(FirewallPlugin, self).create_firewall(
context, firewall) #【2】调用db中的create_firewall方法,创建防火墙数据库记录以及防火墙和路由的绑定记录
fw['router_ids'] = fw_new_rtrs fw_with_rules = (
self._make_firewall_dict_with_rules(context, fw['id'])) #【3】根据policy_id获取数据库对象,获取到策略中的防火墙规则列表 fw_with_rtrs = {'fw_id': fw['id'],
'router_ids': fw_new_rtrs}
self.set_routers_for_firewall(context, fw_with_rtrs) #【4】创建防火墙和路由的绑定记录
fw_with_rules['add-router-ids'] = fw_new_rtrs #【5】表示是添加的路由 和修改或者删除路由方法对应
fw_with_rules['del-router-ids'] = [] self.agent_rpc.create_firewall(context, fw_with_rules) #通知防火墙agent去创建防火墙 return fw
【1】获取路由id列表
def _get_routers_for_create_firewall(self, tenant_id, context, firewall):
# pop router_id as this goes in the router association db
# and not firewall db
router_ids = firewall['firewall'].pop('router_ids', None)
if router_ids == attr.ATTR_NOT_SPECIFIED: #object() 即用户没有给定路由id列表
# old semantics router-ids keyword not specified pick up
# all routers on tenant.
l3_plugin = manager.NeutronManager.get_service_plugins().get(
const.L3_ROUTER_NAT)
ctx = neutron_context.get_admin_context()
routers = l3_plugin.get_routers(ctx) #获取租户所有路由列表
router_ids = [
router['id']
for router in routers
if router['tenant_id'] == tenant_id]
# validation can still fail this if there is another fw
# which is associated with one of these routers.
self.validate_firewall_routers_not_in_use(context, router_ids) #验证路由是否被占用
return router_ids
else:
if not router_ids:
# This indicates that user specifies no routers.
return []
else:
# some router(s) provided.
self.validate_firewall_routers_not_in_use(context, router_ids) #验证路由是否被占用
return router_ids
【2】db中的create_firewall方法
def create_firewall(self, context, firewall, status=None):
LOG.debug("create_firewall() called")
fw = firewall['firewall']
tenant_id = self._get_tenant_id_for_create(context, fw)
# distributed routers may required a more complex state machine;
# the introduction of a new 'CREATED' state allows this, whilst
# keeping a backward compatible behavior of the logical resource.
if not status:
status = (p_const.CREATED if cfg.CONF.router_distributed
else p_const.PENDING_CREATE)
with context.session.begin(subtransactions=True):
if not fw.get('tenant_id'):
fw['tenant_id'] = self._get_tenant_id_for_create(context, fw) #_validata_fw_parameters方法会校验fw对象中的tenant_id
self._validate_fw_parameters(context, fw) #验证firewall对象的tenent_id和policy中的tenant_id是否一致,验证policy的shared字段是否为True
firewall_db = Firewall(
id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=fw['name'],
description=fw['description'],
firewall_policy_id=fw['firewall_policy_id'],
admin_state_up=fw['admin_state_up'],
status=status)
context.session.add(firewall_db) #添加数据库记录
return self._make_firewall_dict(firewall_db)
【3】获取防火墙规则
def _make_firewall_dict_with_rules(self, context, firewall_id):
firewall = self.get_firewall(context, firewall_id)
fw_policy_id = firewall['firewall_policy_id']
if fw_policy_id:
fw_policy = self.get_firewall_policy(context, fw_policy_id) #根据策略id获取数据库对象
fw_rules_list = [self.get_firewall_rule(
context, rule_id) for rule_id in fw_policy['firewall_rules']] #遍历出规则列表
firewall['firewall_rule_list'] = fw_rules_list
else:
firewall['firewall_rule_list'] = []
# FIXME(Sumit): If the size of the firewall object we are creating
# here exceeds the largest message size supported by rabbit/qpid
# then we will have a problem.
return firewall
【4】防火墙和路由绑定
def set_routers_for_firewall(self, context, fw):
"""Sets the routers associated with the fw."""
with context.session.begin(subtransactions=True):
for r_id in fw['router_ids']:
fw_rtr_db = FirewallRouterAssociation(fw_id=fw['fw_id'],
router_id=r_id)
context.session.add(fw_rtr_db)
neutron\services\firewall\agents\l3reference\firewall_l3_agent.py
【5】agent中创建防火墙
def create_firewall(self, context, firewall, host):
"""Handle Rpc from plugin to create a firewall.""" router_ids = self._get_router_ids_for_fw(context, firewall) #获取防火墙对象中的add-router-ids属性值
if not router_ids:
return
router_info_list = self._get_router_info_list_for_tenant(
router_ids,
firewall['tenant_id']) #根据路由id获取数据库对象列表
LOG.debug("Create: Add firewall on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
# call into the driver
try:
self.fwaas_driver.create_firewall( #【5.1】这里默认使用iptables driver
self.conf.agent_mode,
router_info_list,
firewall)
if firewall['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for create_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
status = constants.ERROR try:
# send status back to plugin
self.fwplugin_rpc.set_firewall_status(
context,
firewall['id'],
status) #【5.2】rpc调用plugin中的更新防火墙状态的方法
except Exception:
LOG.error(
_LE("FWaaS RPC failure in create_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
self.services_sync = True
neutron\services\firewall\drivers\linux\iptables_fwaas.py
【5.1】创建防火墙
def create_firewall(self, agent_mode, apply_list, firewall):
LOG.debug('Creating firewall %(fw_id)s for tenant %(tid)s)',
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
try:
if firewall['admin_state_up']:
self._setup_firewall(agent_mode, apply_list, firewall) #【5.1.1】设置防火墙规则
else:
self.apply_default_policy(agent_mode, apply_list, firewall) #这个方法自行查看,就是初始化了基本的规则
except (LookupError, RuntimeError):
# catch known library exceptions and raise Fwaas generic exception
LOG.error(_LE("Failed to create firewall: %s"), firewall['id'])
raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
【5.1.1】设置防火墙规则
这里我们重点看规则的添加顺序,规则的拼凑其实很简单
def _setup_firewall(self, agent_mode, apply_list, firewall):
fwid = firewall['id']
for router_info in apply_list: #apply_list就是路由对象列表
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info) #获取iptables_manager和网卡前缀列表
for ipt_if_prefix in ipt_if_prefix_list:
ipt_mgr = ipt_if_prefix['ipt']
# the following only updates local memory; no hole in FW
self._remove_chains(fwid, ipt_mgr) #删除v4 v6 上行和下行方向的链
self._remove_default_chains(ipt_mgr) #删除default链,default只有一条drop规则 # create default 'DROP ALL' policy chain
self._add_default_policy_chain_v4v6(ipt_mgr) #重新添加default链
#create chain based on configured policy
self._setup_chains(firewall, ipt_if_prefix) #重点,请看下面方法中的解释 # apply the changes immediately (no defer in firewall path)
ipt_mgr.defer_apply_off() #将规则应用到iptables中 def _get_chain_name(self, fwid, ver, direction):
return '%s%s%s' % (CHAIN_NAME_PREFIX[direction],
IP_VER_TAG[ver],
fwid) #命令规则 i/0+v4/v6+防火墙uuid,这里字符串的长度已经超过设置了,后面在iptables_mangager中会过滤 def _setup_chains(self, firewall, ipt_if_prefix):
"""Create Fwaas chain using the rules in the policy
"""
fw_rules_list = firewall['firewall_rule_list']
fwid = firewall['id']
ipt_mgr = ipt_if_prefix['ipt'] #default rules for invalid packets and established sessions
invalid_rule = self._drop_invalid_packets_rule() #drop invalid包
est_rule = self._allow_established_rule() #允许established包,这些都是默认规则,在初始化链规则的时候使用 for ver in [IPV4, IPV6]:
if ver == IPV4:
table = ipt_mgr.ipv4['filter']
else:
table = ipt_mgr.ipv6['filter']
ichain_name = self._get_chain_name(fwid, ver, INGRESS_DIRECTION)
ochain_name = self._get_chain_name(fwid, ver, EGRESS_DIRECTION)
for name in [ichain_name, ochain_name]:
table.add_chain(name) #add_chain方法会将链的长度裁剪,长度小于16
table.add_rule(name, invalid_rule) #添加默认规则
table.add_rule(name, est_rule) #添加默认规则 for rule in fw_rules_list:
if not rule['enabled']: #如果值为False,跳过
continue
iptbl_rule = self._convert_fwaas_to_iptables_rule(rule) #将界面给定的规则转换成iptables规则,就是拼凑
if rule['ip_version'] == 4:
ver = IPV4
table = ipt_mgr.ipv4['filter']
else:
ver = IPV6
table = ipt_mgr.ipv6['filter']
ichain_name = self._get_chain_name(fwid, ver, INGRESS_DIRECTION)
ochain_name = self._get_chain_name(fwid, ver, EGRESS_DIRECTION)
table.add_rule(ichain_name, iptbl_rule) #将界面规则添加到上行和下行链中,这里可以看到是同时添加到两个链中
table.add_rule(ochain_name, iptbl_rule)
self._enable_policy_chain(fwid, ipt_if_prefix) #【5.1.1.1】重点,看下面的解释 def _remove_default_chains(self, nsid):
"""Remove fwaas default policy chain."""
self._remove_chain_by_name(IPV4, FWAAS_DEFAULT_CHAIN, nsid)
self._remove_chain_by_name(IPV6, FWAAS_DEFAULT_CHAIN, nsid) def _remove_chains(self, fwid, ipt_mgr):
"""Remove fwaas policy chain."""
for ver in [IPV4, IPV6]:
for direction in [INGRESS_DIRECTION, EGRESS_DIRECTION]:
chain_name = self._get_chain_name(fwid, ver, direction)
self._remove_chain_by_name(ver, chain_name, ipt_mgr) def _add_default_policy_chain_v4v6(self, ipt_mgr):
ipt_mgr.ipv4['filter'].add_chain(FWAAS_DEFAULT_CHAIN)
ipt_mgr.ipv4['filter'].add_rule(FWAAS_DEFAULT_CHAIN, '-j DROP')
ipt_mgr.ipv6['filter'].add_chain(FWAAS_DEFAULT_CHAIN)
ipt_mgr.ipv6['filter'].add_rule(FWAAS_DEFAULT_CHAIN, '-j DROP')
【5.1.1.1】将规则添加到链中
def _enable_policy_chain(self, fwid, ipt_if_prefix):
bname = iptables_manager.binary_name #获取前缀字符串,这里获取到的是neutron-l3-agent
ipt_mgr = ipt_if_prefix['ipt']
if_prefix = ipt_if_prefix['if_prefix'] for (ver, tbl) in [(IPV4, ipt_mgr.ipv4['filter']),
(IPV6, ipt_mgr.ipv6['filter'])]:
for direction in [INGRESS_DIRECTION, EGRESS_DIRECTION]:
chain_name = self._get_chain_name(fwid, ver, direction)
chain_name = iptables_manager.get_chain_name(chain_name) #这里的chain_name已经是一个长度小于16的字符串了
if chain_name in tbl.chains:
jump_rule = ['%s %s+ -j %s-%s' % (IPTABLES_DIR[direction],
if_prefix, bname, chain_name)]
self._add_rules_to_chain(ipt_mgr, #在neutron-l3-agent-FORWARD链中添加跳跃规则,跳到neutron-l3-agent-iv4xxx链或者neutron-l3-agent-ov4xxx链
ver, 'FORWARD', jump_rule) #jump to DROP_ALL policy
chain_name = iptables_manager.get_chain_name(FWAAS_DEFAULT_CHAIN)
jump_rule = ['-o %s+ -j %s-%s' % (if_prefix, bname, chain_name)]
self._add_rules_to_chain(ipt_mgr, IPV4, 'FORWARD', jump_rule)
self._add_rules_to_chain(ipt_mgr, IPV6, 'FORWARD', jump_rule) #在neutron-l3-agent-FORWARD链中添加跳跃规则,跳到neutron-l3-agent-fwaas-defau链
#jump to DROP_ALL policy
chain_name = iptables_manager.get_chain_name(FWAAS_DEFAULT_CHAIN)
jump_rule = ['-i %s+ -j %s-%s' % (if_prefix, bname, chain_name)]
self._add_rules_to_chain(ipt_mgr, IPV4, 'FORWARD', jump_rule)
self._add_rules_to_chain(ipt_mgr, IPV6, 'FORWARD', jump_rule)#在neutron-l3-agent-FORWARD链中添加跳跃规则,跳到neutron-l3-agent-fwaas-defau链
总结一下链添加规则的流程
1. 初始化链(增加内置链的包装链,并将包装链作为规则添加到内置链中),这一步是在iptables_manager.py中初始化的
2. 创建并初始化iv4xxx/ov4xxx链
3. 将界面的规则添加到链中(同时添加到出和入链中)
4. 将iv4xxx/ov4xxx链放到neutron-l3-agent-FORWARD链中
5. 更新iptables规则
下一节通过查看iptables的具体规则来说明fwaas的流程
OpenStack-Neutron-Fwaas-代码【一】的更多相关文章
- [转] Neutron FWaaS
OpenStack Neutron FWaaS 学习 ( by quqi99 ) 作者:张华 发表于:2013-06-24 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息 ...
- openstack——neutron网络服务
一.neutron 介绍: Neutron 概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能需要 ...
- 深入浅出新一代云网络——VPC中的那些功能与基于OpenStack Neutron的实现(一)
VPC的概念与基于vxlan的overlay实现很早就有了,标题中的"新"只是一个和传统网络的相对概念.但从前年开始,不同于以往基础网络架构的新一代SDN网络才真正越来越多的走进国 ...
- openstack neutron L3 HA
作者:Liping Mao 发表于:2014-08-20 版权声明:能够随意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 近期Assaf Muller写了一篇关于Neutro ...
- openstack Neutron分析(3)—— neutron-dhcp-agent源码分析
1.neutron dhcp3个主要部件分别为什么?2.dhcp模块包含哪些内容?3.Dnsmasq配置文件是如何创建和更新的?4.DHCP agent的信息存放在neutron数据库的哪个表中? 扩 ...
- OpenStack Neutron 之 Load Balance
OpenStack Neutron 之 Load Balance 负载均衡(Load Balance)是 OpenStack Neutron 支持的功能之一.负载均衡能够将网络请求分发到多个实际处理请 ...
- Openstack Neutron OVS ARP Responder
ARP – Why do we need it? In any environment, be it the physical data-center, your home, or a virtual ...
- Openstack Neutron L2 Population
Why do we need it, whatever it is? VM unicast, multicast and broadcast traffic flow is detailed in m ...
- openstack neutron中涉及的网络设备
一.openstack neutron网络设备介绍 Bridge(网桥) 用于将两个LAN连接起来,主要靠的MAC地址学习机制.当网桥的Port收到包时会将包的源mac和port ID关联起来记入ma ...
- [转]OpenStack Neutron运行机制解析概要
转载自:http://panpei.net.cn/2013/12/04/openstack-neutron-mechanism-introduce/ 自从开学以来,玩OpenStack也已经3个月了, ...
随机推荐
- Kali Linux常用服务配置教程获取IP地址
Kali Linux常用服务配置教程获取IP地址 下面以Kali Linux为例,演示获取IP地址的方法 (1)设置网络接口为自动获取IP地址.在Kali Linux的收藏夹中单击图标,将显示所有的程 ...
- webpack打包后的文件
用了webpack打包工具,你是不是有时会疑惑,写了一个很简单的函数,结果生成那么多东西,而且还没有问题?下面,我从三种情况来分析打包后的入口文件,帮助自己理解webpack打包,也为平时定位产出目录 ...
- npm的一些常用命令(在国内,建议使用cnpm,在淘宝镜像里面下载就行)
npm的一些常用命令(在国内,npm操作可能会比较慢,建议使用cnpm,在淘宝镜像里面下载就行,用法和npm一样) cnpm安装地址,直接安装 npm install cnpm -g --regist ...
- Vs2017 typescript 开发小问题
最近想写点ts的东西,以前用vs2015很方便,直接创建一个ts app项目就折腾了. Vs2017打开,居然发现这个项目模板不见了. 于是研究了一下,由于原来的ts app项目就是一个asp.n ...
- django——web框架简介
1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式C/S.B/S.C/S是客户 ...
- React(六)Props属性
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变.这就是为什么有些容器组件需要定义 state 来更新和修改数据. 而子组件只能通过 pro ...
- 移动端web开发常见问题
1.移动端如何定义字体font-family 三大手机系统的字体: ios 系统 默认中文字体是Heiti SC 默认英文字体是Helvetica 默认数字字体是HelveticaNeue 无微软雅黑 ...
- iview select filterable属性使用下拉小bug
今天做项目时候在iview 原生自带的select中设置filterable,下拉时候可进行查询,但是发现选中载打开模态框每次都绑定上一次的值,解决方案就是在关闭弹框时候将this.$refs.sto ...
- centos出现could not resolve host:mirrorlist...错误
这意思是没联网. 看这篇:https://www.cnblogs.com/Sabre/p/10665173.html
- SVN 服务器端权限管理
创建用户 点击菜单上的Users可以在右侧窗口区域中看见已经创建的用户 创建组 同样也可以修改组: 分配权限 示例一:开发人员拥有读写权限(组权限) 进入权限分配界面: 添加组或用户: 在添加页面可 ...