Neutron-server配置
[default]
service_plugins=$original_service_plugins,qos,group_policy
[group_policy]
extension_drivers = proxy_group
policy_drivers = implicit_policy,resource_mapping
ml2_conf.ini
[ml2]
extension_drivers = xxxx,qos
entry_points
gbpservice.neutron.group_policy.extension_drivers =
proxy_group = gbpservice.neutron.services.grouppolicy.drivers.extensions.proxy_group_driver:ProxyGroupDriver
gbpservice.neutron.group_policy.policy_drivers =
resource_mapping = gbpservice.neutron.services.grouppolicy.drivers.resource_mapping:ResourceMappingDriver
implicit_policy = gbpservice.neutron.services.grouppolicy.drivers.implicit_policy:ImplicitPolicyDriver
chain_mapping = gbpservice.neutron.services.grouppolicy.drivers.chain_mapping:ChainMappingDriver
neutron.service_plugins =
group_policy = gbpservice.neutron.services.grouppolicy.plugin:GroupPolicyPlugin
说明:
- 由于代码有很多重复,为控制篇幅,只针对一些关键流程作说明,不对所有的流程详细描述
- 当前只针对neutron资源的port、subnet、network、router、security group分析。
- Plugin资源处理函数结构:
def action_resource(self, context, rousource_info): session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).action_resource(context, resource_info) self.extension_manager.process_action_resource( session, resource_info, result) self._validate_shared_create(self, context, result, 'resource') resource_context = p_context.ResourceContext(self, context, result) // 在资源写入数据库前作检查,一般包括资源租户对应及资源参数的检验 self.policy_driver_manager.action_resource_precommit( policy_context) try: // 对象写入数据库后,policy driver来管理资源: // ImplicitPolicyDriver:创建隐示的资源,如l2 policy, l3 policy等 // ResourceMappingDriver:创建neutron侧对应的资源,如network, router等 self.policy_driver_manager.action_resource_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("action_resource_postcommit " "failed, deleting resource %s"), result['id']) self.delete_resource(context, result['id']) return self.get_resource(context, result['id'])
代码分析
create l2 policy
// GroupPolicyPlugin def create_l2_policy(self, context, l2_policy): self._ensure_tenant(context, l2_policy['l2_policy']) session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).create_l2_policy(context, l2_policy) self.extension_manager.process_create_l2_policy( session, l2_policy, result) self._validate_shared_create(self, context, result, 'l2_policy') policy_context = p_context.L2PolicyContext(self, context, result) // 对network、l3policy做租户校验 self.policy_driver_manager.create_l2_policy_precommit( policy_context) try: self.policy_driver_manager.create_l2_policy_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("create_l2_policy_postcommit " "failed, deleting l2_policy %s"), result['id']) self.delete_l2_policy(context, result['id']) return self.get_l2_policy(context, result['id']) // ImplicitPolicyDriver // 未指定创建l3-policy,创建l3 policy def create_l2_policy_postcommit(self, context): if not context.current['l3_policy_id']: // 创建隐示的l3 policy,并与l2 policy关联 self._use_implicit_l3_policy(context) def _create_implicit_l3_policy(self, context): tenant_id = context.current['tenant_id'] filter = {'tenant_id': [tenant_id], 'name': [self._default_l3p_name]} // 查询租户默认的l3 policy l3ps = self._get_l3_policies(context._plugin_context, filter) l3p = l3ps and l3ps[0] if not l3p: attrs = {'tenant_id': tenant_id, 'name': self._default_l3p_name, 'description': _("Implicitly created L3 policy"), 'ip_version': self._default_ip_version, 'ip_pool': self._default_ip_pool, 'shared': context.current.get('shared', False), 'subnet_prefix_length': self._default_subnet_prefix_length} if self._proxy_group_enabled: attrs['proxy_ip_pool'] = ( self._default_proxy_ip_pool) attrs['proxy_subnet_prefix_length'] = ( self._default_proxy_subnet_prefix_length) try: l3p = self._create_l3_policy(context._plugin_context, attrs) // 通过指定owned关系,与未使用隐示的l3 policy区分,以便删除l2 // policy时只删除隐示创建的l3 policy self._mark_l3_policy_owned(context._plugin_context.session, l3p['id']) except exc.DefaultL3PolicyAlreadyExists: with excutils.save_and_reraise_exception( reraise=False) as ctxt: LOG.debug("Possible concurrent creation of default L3 " "policy for tenant %s", tenant_id) l3ps = self._get_l3_policies(context._plugin_context, filter) l3p = l3ps and l3ps[0] if not l3p: LOG.warning(_LW( "Caught DefaultL3PolicyAlreadyExists, " "but default L3 policy not concurrently " "created for tenant %s"), tenant_id) ctxt.reraise = True except exc.OverlappingIPPoolsInSameTenantNotAllowed: with excutils.save_and_reraise_exception(): LOG.info(_LI("Caught " "OverlappingIPPoolsinSameTenantNotAllowed " "during creation of default L3 policy for " "tenant %s"), tenant_id) context.current['l3_policy_id'] = l3p['id'] // ResourceMappingDriver def create_l2_policy_postcommit(self, context): if not context.current['network_id']: // 创建l2 polic关联的network self._use_implicit_network(context)
create l3 policy
//GroupPolicyPlugin def create_l3_policy(self, context, l3_policy): self._ensure_tenant(context, l3_policy['l3_policy']) session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).create_l3_policy(context, l3_policy) self.extension_manager.process_create_l3_policy( session, l3_policy, result) self._validate_shared_create(self, context, result, 'l3_policy') self._validate_l3p_es(context, result) policy_context = p_context.L3PolicyContext(self, context, result) self.policy_driver_manager.create_l3_policy_precommit( policy_context) try: self.policy_driver_manager.create_l3_policy_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("create_l3_policy_postcommit " "failed, deleting l3_policy %s"), result['id']) self.delete_l3_policy(context, result['id']) return self.get_l3_policy(context, result['id']) // ResourceMappingDriver // 限制: // 1. l3 policy与router一一对应 // 2. 同租户下不同l3 policy的的ip pool 址址不能重叠 def create_l3_policy_precommit(self, context): curr = context.current if len(curr['routers']) > 1: raise exc.L3PolicyMultipleRoutersNotSupported() # Validate non overlapping IPs in the same tenant l3ps = context._plugin.get_l3_policies( context._plugin_context, {'tenant_id': [curr['tenant_id']]}) subnets = [] for l3p in l3ps: if l3p['id'] != curr['id']: for prefix in gbp_utils.convert_ip_pool_string_to_list( l3p['ip_pool']): if prefix: subnets.append(prefix) if 'proxy_ip_pool' in l3p: subnets.extend(gbp_utils.convert_ip_pool_string_to_list( l3p['proxy_ip_pool'])) l3p_subnets = gbp_utils.convert_ip_pool_string_to_list(curr['ip_pool']) if 'proxy_ip_pool' in curr: l3p_subnets.extend(gbp_utils.convert_ip_pool_string_to_list( curr['proxy_ip_pool'])) current_set = netaddr.IPSet(subnets) l3p_set = netaddr.IPSet(l3p_subnets) if l3p_set & current_set: raise exc.OverlappingIPPoolsInSameTenantNotAllowed( ip_pool=l3p_subnets, overlapping_pools=subnets) # In Neutron, one external gateway per router is allowed. Therefore # we have to limit the number of ES per L3P to 1 if len(context.current['external_segments']) > 1: raise exc.MultipleESPerL3PolicyNotSupported() self._reject_invalid_router_access(context) // ImplicitPolicyDriver // 使用隐示创建的external_segemts def create_l3_policy_postcommit(self, context): if not context.current['external_segments']: self._use_implicit_external_segment(context) // ResourceMappingDriver def create_l3_policy_postcommit(self, context): // 创建l3 policy对应的subnet pool if MAPPING_CFG.use_subnetpools: self._create_l3p_subnetpools(context) l3p = context.current // 创建隐示的router if not l3p['routers']: self._use_implicit_router(context) if l3p['external_segments']: self._plug_router_to_external_segment( context, l3p['external_segments']) self._set_l3p_external_routes(context) if not MAPPING_CFG.use_subnetpools: self._process_new_l3p_ip_pool(context, context.current['ip_pool'])
create policy target group
//GroupPolicyPlugin def create_policy_target_group(self, context, policy_target_group): self._ensure_tenant(context, policy_target_group['policy_target_group']) session = context.session with session.begin(subtransactions=True): // 数据库gp,关联子网,关联proivided or consumed policy rule sets result = super(GroupPolicyPlugin, self).create_policy_target_group( context, policy_target_group) // ProxyGroupDriver 暂时未用到 self.extension_manager.process_create_policy_target_group( session, policy_target_group, result) self._validate_shared_create(self, context, result, 'policy_target_group') policy_context = p_context.PolicyTargetGroupContext( self, context, result) self.policy_driver_manager.create_policy_target_group_precommit( policy_context) try: self.policy_driver_manager.create_policy_target_group_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("create_policy_target_group_postcommit " "failed, deleting policy_target_group %s"), result['id']) self.delete_policy_target_group(context, result['id']) return self.get_policy_target_group(context, result['id']) // ResourceMappingDriver // 校验: // 1. L2 policy与l2 policy同属一个租户 // 2. group若指定子网必须属于l2 policy的network, // note: 若开启了use_subnetpools,l2 policy 的network的subnet从l3 policy的 // ip pool对应的subnet_pool中分配,之后该network下所有subnet都需要从该 // subnet_pool中分配 def create_policy_target_group_precommit(self, context): self._reject_cross_tenant_ptg_l2p(context) self._validate_ptg_subnets(context) self._validate_nat_pool_for_nsp(context) self._validate_proxy_ptg(context) // ImplicitPolicyDriver // 若未指定l2 policy,会隐示创建一个 def create_policy_target_group_postcommit(self, context): if not context.current['l2_policy_id']: self._use_implicit_l2_policy(context) def _use_implicit_l2_policy(self, context): // 创建l2 policy,并关联(创建)l3 policy self._create_implicit_l2_policy(context) // 将l2 policy id 记录到 相应的target group db entry中 context.set_l2_policy_id(context.current['l2_policy_id']) def _create_implicit_l2_policy(self, context): attrs = {'tenant_id': context.current['tenant_id'], 'name': context.current['name'], 'description': _("Implicitly created L2 policy"), 'l3_policy_id': None, 'shared': context.current.get('shared', False), 'network_id': None} if context.current.get('proxied_group_id'): # The L3P has to be the same as the proxied group group = context._plugin.get_policy_target_group( context._plugin_context, context.current['proxied_group_id']) l2p = context._plugin.get_l2_policy( context._plugin_context, group['l2_policy_id']) attrs['l3_policy_id'] = l2p['l3_policy_id'] l2p = self._create_l2_policy(context._plugin_context, attrs) context.current['l2_policy_id'] = l2p['id'] self._mark_l2_policy_owned(context._plugin_context.session, l2p['id']) // 调用plugin创建l2 policy,具体调用流程参创建l2 policy // 若没有指定l3 policy且使用implicit driver,该租户下没有默认(名字配置)的l3 policy, // neutron-server会对该租户创建一个默认的l3 policy def _create_l2_policy(self, plugin_context, attrs): return self._create_resource(self._group_policy_plugin, plugin_context, 'l2_policy', attrs, False) // ResourceMappingDriver def create_policy_target_group_postcommit(self, context): # REVISIT(ivar) this validates the PTG L2P after the IPD creates it # (which happens in the postcommit phase) self._validate_proxy_ptg(context) # connect router to subnets of the PTG l2p_id = context.current['l2_policy_id'] l2p = context._plugin.get_l2_policy(context._plugin_context, l2p_id) l3p_id = l2p['l3_policy_id'] l3p = context._plugin.get_l3_policy(context._plugin_context, l3p_id) if not context.current['subnets']: is_proxy = bool(context.current.get('proxied_group_id')) // use_subnetpools 默认为True,会从subnetpool中自动分配置subnet // proxy是什么意思,需要确认? if (not MAPPING_CFG.use_subnetpools or (is_proxy and context.current.get('proxy_type') == proxy_ext.PROXY_TYPE_L2)): self._use_implicit_subnet(context, is_proxy=is_proxy) else: try: subnet_specifics = {} if context.current.get('proxied_group_id'): # Since this is proxy group, we need to allocate # subnet with proxy-specific prefix len subnet_specifics = { 'prefixlen': l3p['proxy_subnet_prefix_length']} // 从subnetpool中获取subnet并与target-group关联 subnets = self._use_implicit_subnet_from_subnetpool( context, subnet_specifics) context.add_subnets([sub['id'] for sub in subnets]) except neutron_exc.SubnetAllocationError: # Translate to GBP exception raise exc.NoSubnetAvailable() // 将target group下所有的subnets都挂到l3 policy对应的router下 self._stitch_ptg_to_l3p(context, context.current, l3p, context.current['subnets']) self._handle_network_service_policy(context) // 根据policy rule创建security-group-rule self._handle_policy_rule_sets(context) self._update_default_security_group(context._plugin_context, context.current['id'], context.current['tenant_id'], context.current['subnets']) def _stitch_ptg_to_l3p(self, context, ptg, l3p, subnet_ids): if l3p['routers']: router_id = l3p['routers'][0] if ptg.get('proxied_group_id'): self._stitch_proxy_ptg_to_l3p(context, ptg, l3p, subnet_ids) else: try: for subnet_id in subnet_ids: self._plug_router_to_subnet( context._plugin_context, subnet_id, router_id) except n_exc.InvalidInput: # This exception is not expected. LOG.exception(_LE("adding subnet to router failed")) for subnet_id in subnet_ids: self._delete_subnet(context._plugin_context, subnet_id) raise exc.GroupPolicyInternalError() def _handle_policy_rule_sets(self, context): # This method handles policy_rule_set => SG mapping # context is PTG context # for all consumed policy_rule_sets, simply associate # each EP's port from the PTG # rules are expected to be filled out already consumed_policy_rule_sets = context.current[ 'consumed_policy_rule_sets'] provided_policy_rule_sets = context.current[ 'provided_policy_rule_sets'] subnets = context.current['subnets'] ptg_id = context.current['id'] self._set_sg_rules_for_subnets(context, subnets, provided_policy_rule_sets, consumed_policy_rule_sets) self._update_sgs_on_ptg(context, ptg_id, provided_policy_rule_sets, consumed_policy_rule_sets, "ASSOCIATE") def _update_default_security_group(self, plugin_context, ptg_id, tenant_id, subnets=None): // 查找该租户下target group的默认安全组(sg_name = “gbp_%s” % ptg_id) sg_id = self._get_default_security_group(plugin_context, ptg_id, tenant_id) ip_v = {4: n_const.IPv4, 6: n_const.IPv6} if not sg_id: sg_name = DEFAULT_SG_PREFIX % ptg_id sg = self._create_gbp_sg(plugin_context, tenant_id, sg_name, description='default GBP security group') sg_id = sg['id'] // 初始化sg, 该target group下所有的子网都允许通过 for subnet in self._get_subnets( plugin_context, filters={'id': subnets or []}): self._sg_rule(plugin_context, tenant_id, sg_id, 'ingress', cidr=subnet['cidr'], ethertype=ip_v[subnet['ip_version']]) self._sg_rule(plugin_context, tenant_id, sg_id, 'egress', cidr=subnet['cidr'], ethertype=ip_v[subnet['ip_version']]) // 用于放行cloudint dhcp dns等功能 self._sg_rule(plugin_context, tenant_id, sg_id, 'egress', cidr='169.254.0.0/16', ethertype=ip_v[4]) // 放行dns 端口 for ether_type in ip_v: for proto in [n_const.PROTO_NAME_TCP, n_const.PROTO_NAME_UDP]: self._sg_rule(plugin_context, tenant_id, sg_id, 'egress', protocol=proto, port_range='53', ethertype=ip_v[ether_type]) return sg_id
create policy target
//GroupPolicyPlugin def create_policy_target(self, context, policy_target): self._ensure_tenant(context, policy_target['policy_target']) // 若创建target时指定fixed-ips(ip and subnet),保存fixed-ip信息保存,以便在创建port指定 self._add_fixed_ips_to_port_attributes(policy_target) session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).create_policy_target(context, policy_target) self.extension_manager.process_create_policy_target( session, policy_target, result) self._validate_shared_create( self, context, result, 'policy_target') policy_context = p_context.PolicyTargetContext(self, context, result) self.policy_driver_manager.create_policy_target_precommit( policy_context) try: self.policy_driver_manager.create_policy_target_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("create_policy_target_postcommit " "failed, deleting policy_target %s"), result['id']) self.delete_policy_target(context, result['id']) return self.get_policy_target(context, result['id']) // ResourceMappingDriver def create_policy_target_precommit(self, context): self._check_create_policy_target(context) def _check_create_policy_target(self, context, verify_port_subnet=True): self._validate_cluster_id(context) if not context.current['policy_target_group_id']: raise exc.PolicyTargetRequiresPolicyTargetGroup() // 检查port子网在target group的子网内 if context.current['port_id'] and verify_port_subnet: # Validate if explicit port's subnet # is same as the subnet of PTG. self._validate_pt_port_subnets(context) group_id = context.current['policy_target_group_id'] if context.current.get('proxy_gateway'): pts = context._plugin.get_policy_targets( context._plugin_context, {'policy_target_group_id': group_id, 'proxy_gateway': True}) pts = [x['id'] for x in pts if x['id'] != context.current['id']] if pts: exc.OnlyOneProxyGatewayAllowed(group_id=group_id) if context.current.get('group_default_gateway'): pts = context._plugin.get_policy_targets( context._plugin_context, {'policy_target_group_id': group_id, 'group_default_gateway': True}) pts = [x['id'] for x in pts if x['id'] != context.current['id']] if pts: exc.OnlyOneGroupDefaultGatewayAllowed(group_id=group_id) // ResourceMappingDriver def create_policy_target_postcommit(self, context): // 若没有指定port创建policy target,则创建一个 if not context.current['port_id']: self._use_implicit_port(context) self._update_cluster_membership( context, new_cluster_id=context.current['cluster_id']) // 将port与target group关联的sg绑定(通过consumed和provided的rule set) self._assoc_ptg_sg_to_pt(context, context.current['id'], context.current['policy_target_group_id']) // QOS和fip的功能也能做,有必要统一? // 没有,仅仅使用GBP来完成,高级功能不需要GBP来接管,但是要考虑他们之间的相互影响? self._associate_fip_to_pt(context) self._associate_qosp_to_pt(context) if context.current.get('proxy_gateway'): self._set_proxy_gateway_routes(context, context.current)
create Policy rule set
// 创建policy rule set时会创建security group // GroupPolicyPlugin def create_policy_rule_set(self, context, policy_rule_set): self._ensure_tenant(context, policy_rule_set['policy_rule_set']) session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).create_policy_rule_set( context, policy_rule_set) self.extension_manager.process_create_policy_rule_set( session, policy_rule_set, result) self._validate_shared_create( self, context, result, 'policy_rule_set') policy_context = p_context.PolicyRuleSetContext( self, context, result) self.policy_driver_manager.create_policy_rule_set_precommit( policy_context) try: self.policy_driver_manager.create_policy_rule_set_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE( "policy_driver_manager.create_policy_rule_set_postcommit " "failed, deleting policy_rule_set %s"), result['id']) self.delete_policy_rule_set(context, result['id']) return self.get_policy_rule_set(context, result['id']) // ResourceMappingDriver def create_policy_rule_set_postcommit(self, context): # creating SGs policy_rule_set_id = context.current['id'] // 以rule set为单位,consumed和provided分别创建一个安全组 consumed_sg = self._create_policy_rule_set_sg(context, 'consumed') provided_sg = self._create_policy_rule_set_sg(context, 'provided') consumed_sg_id = consumed_sg['id'] provided_sg_id = provided_sg['id'] // rule set 与consume和provided security对应关系存数据库 self._set_policy_rule_set_sg_mapping( context._plugin_context.session, policy_rule_set_id, consumed_sg_id, provided_sg_id) rules = context._plugin.get_policy_rules( context._plugin_context, {'id': context.current['policy_rules']}) self._apply_policy_rule_set_rules(context, context.current, rules) if context.current['child_policy_rule_sets']: self._recompute_policy_rule_sets( context, context.current['child_policy_rule_sets']) def _apply_policy_rule_set_rules(self, context, policy_rule_set, policy_rules): policy_rules = self._get_enforced_prs_rules( context, policy_rule_set, subset=[x['id'] for x in policy_rules]) # Don't add rules unallowed by the parent self._manage_policy_rule_set_rules( context, policy_rule_set, policy_rules) def _manage_policy_rule_set_rules(self, context, policy_rule_set, policy_rules, unset=False, unset_egress=False): policy_rule_set_sg_mappings = self._get_policy_rule_set_sg_mapping( context._plugin_context.session, policy_rule_set['id']) policy_rule_set = context._plugin.get_policy_rule_set( context._plugin_context, policy_rule_set['id']) // 获取与rule_set关联的consumed和provided的target_group对应子网的cidr cidr_mapping = self._get_cidrs_mapping(context, policy_rule_set) for policy_rule in policy_rules: self._add_or_remove_policy_rule_set_rule( context, policy_rule, policy_rule_set_sg_mappings, cidr_mapping, unset=unset, unset_egress=unset_egress)
// 创建安全组规则 def _add_or_remove_policy_rule_set_rule(self, context, policy_rule, policy_rule_set_sg_mappings, cidr_mapping, unset=False, unset_egress=False, classifier=None): in_out = [gconst.GP_DIRECTION_IN, gconst.GP_DIRECTION_OUT] prov_cons = [policy_rule_set_sg_mappings['provided_sg_id'], policy_rule_set_sg_mappings['consumed_sg_id']] cidr_prov_cons = [cidr_mapping['providing_cidrs'], cidr_mapping['consuming_cidrs']] if not classifier: classifier_id = policy_rule['policy_classifier_id'] classifier = context._plugin.get_policy_classifier( context._plugin_context, classifier_id) protocol = classifier['protocol'] port_range = classifier['port_range'] admin_context = n_context.get_admin_context() prs = context._plugin.get_policy_rule_set( admin_context, policy_rule_set_sg_mappings.policy_rule_set_id) tenant_id = prs['tenant_id']
// classifier方向只有一个 in/out/bi,所以classifier与security group有如下组合:
由于rule set作用在provided和consumed的两个组,所以sg rule里需要加上对端组所有的子网cidr以作限制
for pos, sg in enumerate(prov_cons): if classifier['direction'] in [gconst.GP_DIRECTION_BI, in_out[pos]]: for cidr in cidr_prov_cons[pos - 1]: self._sg_ingress_rule(context, sg, protocol, port_range, cidr, tenant_id, unset=unset) if classifier['direction'] in [gconst.GP_DIRECTION_BI, in_out[pos - 1]]: for cidr in cidr_prov_cons[pos - 1]: self._sg_egress_rule(context, sg, protocol, port_range, cidr, tenant_id, unset=unset or unset_egress)
// GroupPolicyPlugin def delete_l2_policy(self, context, l2_policy_id): session = context.session with session.begin(subtransactions=True): l2_policy = self.get_l2_policy(context, l2_policy_id) policy_context = p_context.L2PolicyContext(self, context, l2_policy) self.policy_driver_manager.delete_l2_policy_precommit( policy_context) super(GroupPolicyPlugin, self).delete_l2_policy(context, l2_policy_id) try: self.policy_driver_manager.delete_l2_policy_postcommit( policy_context) except Exception: LOG.exception(_LE("delete_l2_policy_postcommit failed " "for l2_policy %s"), l2_policy_id) // ImplicitPolicyDriver // 若l3 policy为隐示创建则删除 l3 policy def delete_l2_policy_postcommit(self, context): l3p_id = context.current['l3_policy_id'] self._cleanup_l3_policy(context, l3p_id) def _cleanup_l3_policy(self, context, l3p_id): if self._l3_policy_is_owned(context._plugin_context.session, l3p_id): // 调用plugin删除l3 policy context._plugin.delete_l3_policy(context._plugin_context, l3p_id, check_unused=True) // ResourceMappingDriver // 若network为隐示创建则删除 def delete_l2_policy_postcommit(self, context): network_id = context.current['network_id'] self._cleanup_network(context._plugin_context, network_id) def _cleanup_network(self, plugin_context, network_id): if self._network_is_owned(plugin_context.session, network_id): // 调用core_plugin 删除network self._delete_network(plugin_context, network_id)
create network service policy
def create_network_service_policy(self, context, network_service_policy): self._ensure_tenant( context, network_service_policy['network_service_policy']) session = context.session with session.begin(subtransactions=True): result = super(GroupPolicyPlugin, self).create_network_service_policy( context, network_service_policy) self.extension_manager.process_create_network_service_policy( session, network_service_policy, result) self._validate_shared_create(self, context, result, 'network_service_policy') policy_context = p_context.NetworkServicePolicyContext( self, context, result) pdm = self.policy_driver_manager pdm.create_network_service_policy_precommit( policy_context) try: pdm.create_network_service_policy_postcommit( policy_context) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE( "create_network_service_policy_postcommit " "failed, deleting network_service_policy %s"), result['id']) self.delete_network_service_policy(context, result['id']) return self.get_network_service_policy(context, result['id']) // ResourceMappingDriver def create_network_service_policy_precommit(self, context): // 对network service policy支持的型及格式做校验 self._validate_nsp_parameters(context) // 命令举例 // gbp network-service-policy-create --network-service-params // type=qos_maxrate,name=qos_maxrate,value=10 test // network service policy支持的类型及取值组合如下:
def _validate_nsp_parameters(self, context): nsp = context.current nsp_params = nsp.get("network_service_params") supported_static_nsp_pars = { gconst.GP_NETWORK_SVC_PARAM_TYPE_IP_SINGLE: [ gconst.GP_NETWORK_SVC_PARAM_VALUE_SELF_SUBNET, gconst.GP_NETWORK_SVC_PARAM_VALUE_NAT_POOL], gconst.GP_NETWORK_SVC_PARAM_TYPE_IP_POOL: [ gconst.GP_NETWORK_SVC_PARAM_VALUE_NAT_POOL]} # for params without a static value - later evaluation needed: supported_flexible_nsp_params = ( gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_BURST, gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_MAX) // service policy一种类型只能有一个值 # validate unique param types: types_inside = set((d['type'] for d in nsp_params)) if len(types_inside) != len(nsp_params): raise exc.InvalidNetworkServiceParameters() for params in nsp_params: type_ = params.get("type") value_ = params.get("value") if (type_ not in supported_flexible_nsp_params): if (type_ not in supported_static_nsp_pars or value_ not in supported_static_nsp_pars[type_]): raise exc.InvalidNetworkServiceParameters() else: try: if int(value_) < 0: raise exc.InvalidNetworkServiceParameters() except ValueError: raise exc.InvalidNetworkServiceParameters() def create_network_service_policy_postcommit(self, context): p = context.current['network_service_params'] max = burst = 0 setting_qos = False # assumes single value per parameter type, as the API currently states params = {p[n]['type']: p[n]['value'] for n in range(len(p))} # check for QoS param types.. if gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_MAX in params: max = params[gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_MAX] setting_qos = True if gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_BURST in params: burst = params[gconst.GP_NETWORK_SVC_PARAM_TYPE_QOS_BURST] setting_qos = True # ..and create needed Neutron resources if setting_qos: // 创建使用qos service_plugin创建qos policy // qos policy命名规则gbp_$(network_service_policy_name) qos_policy_id = self._create_implicit_qos_policy(context) nsp_id = context.current['id'] // 创建qos policy rule // qos policy rule命名规则gbp_$(network_service_policy_name) // attrs = {'max_kbps': max, 'max_burst_kbps': burst} self._create_implicit_qos_rule(context, qos_policy_id, max, burst) // 数据库记录network service policy与qos policy的关系 self._set_nsp_qos_mapping(context._plugin_context.session, nsp_id, qos_policy_id)
delete l3 policy
//GroupPolicyPlugin def delete_l3_policy(self, context, l3_policy_id, check_unused=False): session = context.session with session.begin(subtransactions=True): // 若有关联的l2 policy,删除失败 if (check_unused and (session.query(group_policy_mapping_db.L2PolicyMapping). filter_by(l3_policy_id=l3_policy_id).count())): return False l3_policy = self.get_l3_policy(context, l3_policy_id) policy_context = p_context.L3PolicyContext(self, context, l3_policy) self.policy_driver_manager.delete_l3_policy_precommit( policy_context) super(GroupPolicyPlugin, self).delete_l3_policy(context, l3_policy_id) try: self.policy_driver_manager.delete_l3_policy_postcommit( policy_context) except Exception: LOG.exception(_LE("delete_l3_policy_postcommit failed " "for l3_policy %s"), l3_policy_id) return True // ResourceMappingDriver def delete_l3_policy_postcommit(self, context): for router_id in context.current['routers']: // 若router为隐示创建,则删除router; router与l3 policy是一一对应关系 self._cleanup_router(context._plugin_context, router_id) // 删除 l3 poicy创建的subnet Pool if MAPPING_CFG.use_subnetpools: self._delete_l3p_subnetpools(context) else: self._process_remove_l3p_ip_pool(context, context.current['ip_pool'])
1. GBP作为应用层,架构在neutron之上,可以通过GBP的抽象资源来管理neutron的网络资源,所以用户可以将精力放在应用层资源的构建上
2. GBP实现了以下的资源映射关系(通过group policy driver-resource_mapping)
3. GBP可以建立policy rule并与policy group绑定来完成一组资源的网络白名单功能,底层使用neutron的安全组功能
4. 除了之前提到的四种基本的neutron资源以外,GBP还可以fip、fw、qos等neutron高级服务,这样可以使用户进一步脱离开直接操作neutron资源
不足:
1. GBP并未在neutron侧提供详细的api文档,不能给开发人员直接提供的充足参考
附classifier 与neutron security group的对应关系:
参考
overview of GroupBasedPolicy. http://gbp.readthedocs.io/en/latest/usage.html
IP protocol number. https://en.wikipedia.org/wiki/List_of_IP_protocol_number