def _pgs_from_log_obj(self, context, log_obj): """Map Neutron log_obj into affected port groups in OVN. :param context: current running context information :param log_obj: a log_object to be analyzed. """ if not log_obj.resource_id and not log_obj.target_id: # No sg, no port: return all pgs return self._pgs_all() pgs = [] # include special pg_drop to log DROP and ALL actions if not log_obj.event or log_obj.event in (log_const.DROP_EVENT, log_const.ALL_EVENT): try: pg = self.ovn_nb.lookup("Port_Group", ovn_const.OVN_DROP_PORT_GROUP_NAME) pgs.append({ "name": pg.name, "acls": [r.uuid for r in pg.acls] }) except idlutils.RowNotFound: pass if log_obj.resource_id: try: pg = self.ovn_nb.lookup( "Port_Group", utils.ovn_port_group_name(log_obj.resource_id)) pgs.append({ "name": pg.name, "acls": [r.uuid for r in pg.acls] }) except idlutils.RowNotFound: pass # Note: when sg is provided, it is redundant to get sgs from port, # because model will ensure that sg is associated with neutron port elif log_obj.target_id: sg_ids = db_api._get_sgs_attached_to_port(context, log_obj.target_id) for sg_id in sg_ids: try: pg = self.ovn_nb.lookup("Port_Group", utils.ovn_port_group_name(sg_id)) pgs.append({ "name": pg.name, "acls": [r.uuid for r in pg.acls] }) except idlutils.RowNotFound: pass return pgs
def update_acls_for_security_group(plugin, admin_context, ovn, security_group_id, security_group_rule, is_add_acl=True): # Skip ACLs if security groups aren't enabled if not is_sg_enabled(): return # Check if ACL log name and severity supported or not keep_name_severity = _acl_columns_name_severity_supported(ovn) acl = _add_sg_rule_acl_for_port_group( utils.ovn_port_group_name(security_group_id), security_group_rule) # Remove ACL log name and severity if not supported if is_add_acl: if not keep_name_severity: acl.pop('name') acl.pop('severity') ovn.pg_acl_add(**acl, may_exist=True).execute(check_error=True) else: ovn.pg_acl_del(acl['port_group'], acl['direction'], acl['priority'], acl['match']).execute(check_error=True)
def _fake_pg(self, **kwargs): pg_defaults_dict = { "name": ovn_utils.ovn_port_group_name(uuidutils.generate_uuid()), "acls": [] } pg_dict = {**pg_defaults_dict, **kwargs} return mock.Mock(**pg_dict)
def add_acls_for_sg_port_group(ovn, security_group, txn, stateless_supported=True): stateful = is_sg_stateful(security_group, stateless_supported) for r in security_group['security_group_rules']: acl = _add_sg_rule_acl_for_port_group( utils.ovn_port_group_name(security_group['id']), stateful, r) txn.add(ovn.pg_acl_add(**acl, may_exist=True))
def _find_security_group_row_by_id(self, sg_id): if self.nb_api.is_port_groups_supported(): for row in self.nb_api._tables['Port_Group'].rows.values(): if row.name == utils.ovn_port_group_name(sg_id): return row else: for row in self.nb_api._tables['Address_Set'].rows.values(): if (row.external_ids.get( ovn_const.OVN_SG_EXT_ID_KEY) == sg_id): return row
def get_port_group(self, pg_name): if uuidutils.is_uuid_like(pg_name): pg_name = utils.ovn_port_group_name(pg_name) try: return self.lookup('Port_Group', pg_name, default=None) except KeyError: # TODO(dalvarez): This except block is added for backwards compat # with old OVN schemas (<=2.9) where Port Groups are not present. # This (and other conditional code around this feature) shall be # removed at some point. return
def add_acls_for_sg_port_group(ovn, security_group, txn, stateless_supported=True): if stateless_supported: stateful = security_group.get("stateful", True) else: stateful = True for r in security_group['security_group_rules']: acl = _add_sg_rule_acl_for_port_group( utils.ovn_port_group_name(security_group['id']), stateful, r) txn.add(ovn.pg_acl_add(**acl, may_exist=True))
def get_port_group(self, pg_name): if uuidutils.is_uuid_like(pg_name): pg_name = utils.ovn_port_group_name(pg_name) try: for pg in self._tables['Port_Group'].rows.values(): if pg.name == pg_name: return pg except KeyError: # TODO(dalvarez): This except block is added for backwards compat # with old OVN schemas (<=2.9) where Port Groups are not present. # This (and other conditional code around this feature) shall be # removed at some point. return
def test__pgs_from_log_obj_pg(self): with mock.patch.object(self._log_driver, '_pgs_all', return_value=[]) as mock_pgs_all: pg = self._fake_pg() self._nb_ovn.lookup.return_value = pg log_obj = self._fake_log_obj(resource_id='resource_id', target_id='target_id', event=log_const.ACCEPT_EVENT) pgs = self._log_driver._pgs_from_log_obj(self.context, log_obj) mock_pgs_all.assert_not_called() self._nb_ovn.lookup.assert_called_once_with( "Port_Group", ovn_utils.ovn_port_group_name('resource_id')) self.assertEqual([{'acls': [], 'name': pg.name}], pgs)
def test__pgs_from_log_obj_port(self): with mock.patch.object(self._log_driver, '_pgs_all', return_value=[]) as mock_pgs_all: sg_id = uuidutils.generate_uuid() pg_name = ovn_utils.ovn_port_group_name(sg_id) pg = self._fake_pg(name=pg_name) self._nb_ovn.lookup.return_value = pg log_obj = self._fake_log_obj(target_id='target_id', event=log_const.ACCEPT_EVENT) self.fake_get_sgs_attached_to_port.return_value = [sg_id] pgs = self._log_driver._pgs_from_log_obj(self.context, log_obj) mock_pgs_all.assert_not_called() self._nb_ovn.lookup.assert_called_once_with("Port_Group", pg_name) self.fake_get_sgs_attached_to_port.assert_called_once_with( self.context, 'target_id') self.assertEqual([{'acls': [], 'name': pg.name}], pgs)
def add_acls_for_sg_port_group(ovn, security_group, txn): for r in security_group['security_group_rules']: acl = _add_sg_rule_acl_for_port_group( utils.ovn_port_group_name(security_group['id']), r) txn.add(ovn.pg_acl_add(**acl, may_exist=True))
def _find_security_group_row_by_id(self, sg_id): for row in self.nb_api._tables['Port_Group'].rows.values(): if row.name == utils.ovn_port_group_name(sg_id): return row
def update_acls_for_security_group(plugin, admin_context, ovn, security_group_id, security_group_rule, sg_ports_cache=None, is_add_acl=True): # Skip ACLs if security groups aren't enabled if not is_sg_enabled(): return # Check if ACL log name and severity supported or not keep_name_severity = _acl_columns_name_severity_supported(ovn) # If we're using a Port Group for this SG, just update it. # Otherwise, keep the old behavior. if (ovn.is_port_groups_supported() and not ovn.get_address_set(security_group_id)): acl = _add_sg_rule_acl_for_port_group( utils.ovn_port_group_name(security_group_id), security_group_rule, ovn) # Remove ACL log name and severity if not supported if is_add_acl: if not keep_name_severity: acl.pop('name') acl.pop('severity') ovn.pg_acl_add(**acl).execute(check_error=True) else: ovn.pg_acl_del(acl['port_group'], acl['direction'], acl['priority'], acl['match']).execute( check_error=True) return # Get the security group ports. sg_ports_cache = sg_ports_cache or {} sg_ports = _get_sg_ports_from_cache(plugin, admin_context, sg_ports_cache, security_group_id) # ACLs associated with a security group may span logical switches sg_port_ids = [binding['port_id'] for binding in sg_ports] sg_port_ids = list(set(sg_port_ids)) port_list = plugin.get_ports(admin_context, filters={'id': sg_port_ids}) if not port_list: return acl_new_values_dict = {} update_port_list = [] # NOTE(lizk): We can directly locate the affected acl records, # so no need to compare new acl values with existing acl objects. for port in port_list: # Skip trusted port if utils.is_lsp_trusted(port): continue update_port_list.append(port) acl = _add_sg_rule_acl_for_port(port, security_group_rule) # Remove lport and lswitch since we don't need them acl.pop('lport') acl.pop('lswitch') # Remove ACL log name and severity if not supported, if not keep_name_severity: acl.pop('name') acl.pop('severity') acl_new_values_dict[port['id']] = acl if not update_port_list: return lswitch_names = {p['network_id'] for p in update_port_list} ovn.update_acls(list(lswitch_names), iter(update_port_list), acl_new_values_dict, need_compare=False, is_add_acl=is_add_acl).execute(check_error=True)
def get_port_group(self, pg_name): if uuidutils.is_uuid_like(pg_name): pg_name = utils.ovn_port_group_name(pg_name) return self.lookup('Port_Group', pg_name, default=None)
def _find_security_group_row_by_id(self, sg_id): return self.nb_api.lookup('Port_Group', utils.ovn_port_group_name(sg_id), default=None)