def test_acl_port_ips(self): port4 = fakes.FakePort.create_one_port({ 'fixed_ips': [{'subnet_id': 'subnet-ipv4', 'ip_address': '10.0.0.1'}], }).info() port46 = fakes.FakePort.create_one_port({ 'fixed_ips': [{'subnet_id': 'subnet-ipv4', 'ip_address': '10.0.0.2'}, {'subnet_id': 'subnet-ipv6', 'ip_address': 'fde3:d45:df72::1'}], }).info() port6 = fakes.FakePort.create_one_port({ 'fixed_ips': [{'subnet_id': 'subnet-ipv6', 'ip_address': '2001:db8::8'}], }).info() addresses = ovn_acl.acl_port_ips(port4) self.assertEqual({'ip4': [port4['fixed_ips'][0]['ip_address']], 'ip6': []}, addresses) addresses = ovn_acl.acl_port_ips(port46) self.assertEqual({'ip4': [port46['fixed_ips'][0]['ip_address']], 'ip6': [port46['fixed_ips'][1]['ip_address']]}, addresses) addresses = ovn_acl.acl_port_ips(port6) self.assertEqual({'ip4': [], 'ip6': [port6['fixed_ips'][0]['ip_address']]}, addresses)
def _validate_address_sets(self, should_match=True): db_ports = self._list('ports')['ports'] db_sgs = {} for port in db_ports: sg_ids = port.get('security_groups', []) addresses = acl_utils.acl_port_ips(port) for sg_id in sg_ids: for ip_version in addresses: name = utils.ovn_addrset_name(sg_id, ip_version) addr_list = db_sgs.setdefault(name, []) addr_list.extend(addresses[ip_version]) _plugin_nb_ovn = self.mech_driver._nb_ovn nb_address_sets = _plugin_nb_ovn.get_address_sets() nb_sgs = {} for nb_sgid, nb_values in six.iteritems(nb_address_sets): nb_sgs[nb_sgid] = nb_values['addresses'] mn_sgs = {} for row in self.monitor_nb_db_idl.tables['Address_Set'].rows.values(): mn_sgs[getattr(row, 'name')] = getattr(row, 'addresses') if should_match: self.assertItemsEqual(nb_sgs, db_sgs) self.assertItemsEqual(mn_sgs, db_sgs) else: self.assertRaises(AssertionError, self.assertItemsEqual, nb_sgs, db_sgs) self.assertRaises(AssertionError, self.assertItemsEqual, mn_sgs, db_sgs)
def delete_port_postcommit(self, context): """Delete a port. :param context: PortContext instance describing the current state of the port, prior to the call to delete it. Called after the transaction completes. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ port = context.current with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.delete_lswitch_port(port['id'], utils.ovn_name(port['network_id']))) txn.add(self._nb_ovn.delete_acl( utils.ovn_name(port['network_id']), port['id'])) if port.get('fixed_ips'): addresses = ovn_acl.acl_port_ips(port) for sg_id in port.get('security_groups', []): for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses[ip_version])) # NOTE(lizk): Always try to clean port dhcp options, to make sure # no orphaned DHCP_Options row related to port left behind, which # may be created in get_port_dhcpv4_options. cmd = self._get_delete_lsp_dhcpv4_options_cmd(port) if cmd: txn.add(cmd)
def delete_port_postcommit(self, context): """Delete a port. :param context: PortContext instance describing the current state of the port, prior to the call to delete it. Called after the transaction completes. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ port = context.current with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.delete_lswitch_port(port['id'], utils.ovn_name(port['network_id']))) txn.add(self._nb_ovn.delete_acl( utils.ovn_name(port['network_id']), port['id'])) if port.get('fixed_ips'): addresses = ovn_acl.acl_port_ips(port) for sg_id in port.get('security_groups', []): for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses[ip_version]))
def delete_port_postcommit(self, context): """Delete a port. :param context: PortContext instance describing the current state of the port, prior to the call to delete it. Called after the transaction completes. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ port = context.current self._delete_lsp_dhcpv4_options(port) with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.delete_lswitch_port(port['id'], utils.ovn_name(port['network_id']))) txn.add(self._nb_ovn.delete_acl( utils.ovn_name(port['network_id']), port['id'])) if port.get('fixed_ips'): addresses = ovn_acl.acl_port_ips(port) for sg_id in port.get('security_groups', []): for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses[ip_version]))
def sync_address_sets(self, ctx): """Sync Address Sets between neutron and NB. @param ctx: neutron context @type ctx: object of type neutron.context.Context @var db_ports: List of ports from neutron DB """ LOG.debug('Address-Set-SYNC: started @ %s' % str(datetime.now())) neutron_sgs = {} with ctx.session.begin(subtransactions=True): db_sgs = self.core_plugin.get_security_groups(ctx) db_ports = self.core_plugin.get_ports(ctx) for sg in db_sgs: for ip_version in ['ip4', 'ip6']: name = utils.ovn_addrset_name(sg['id'], ip_version) neutron_sgs[name] = { 'name': name, 'addresses': [], 'external_ids': { const.OVN_SG_NAME_EXT_ID_KEY: sg['name'] } } for port in db_ports: sg_ids = port.get('security_groups', []) if port.get('fixed_ips') and sg_ids: addresses = acl_utils.acl_port_ips(port) for sg_id in sg_ids: for ip_version in addresses: name = utils.ovn_addrset_name(sg_id, ip_version) neutron_sgs[name]['addresses'].extend( addresses[ip_version]) nb_sgs = self.get_address_sets() sgnames_to_add, sgnames_to_delete, sgs_to_update =\ self.compute_address_set_difference(neutron_sgs, nb_sgs) LOG.debug('Address_Sets added %d, removed %d, updated %d', len(sgnames_to_add), len(sgnames_to_delete), len(sgs_to_update)) if self.mode == SYNC_MODE_REPAIR: LOG.debug('Address-Set-SYNC: transaction started @ %s' % str(datetime.now())) with self.ovn_api.transaction(check_error=True) as txn: for sgname in sgnames_to_add: sg = neutron_sgs[sgname] txn.add(self.ovn_api.create_address_set(**sg)) for sgname, sg in six.iteritems(sgs_to_update): txn.add(self.ovn_api.update_address_set(**sg)) for sgname in sgnames_to_delete: txn.add(self.ovn_api.delete_address_set(name=sgname)) LOG.debug('Address-Set-SYNC: transaction finished @ %s' % str(datetime.now()))
def sync_address_sets(self, ctx): """Sync Address Sets between neutron and NB. @param ctx: neutron context @type ctx: object of type neutron.context.Context @var db_ports: List of ports from neutron DB """ LOG.debug('Address-Set-SYNC: started @ %s' % str(datetime.now())) neutron_sgs = {} with ctx.session.begin(subtransactions=True): db_sgs = self.core_plugin.get_security_groups(ctx) db_ports = self.core_plugin.get_ports(ctx) for sg in db_sgs: for ip_version in ['ip4', 'ip6']: name = utils.ovn_addrset_name(sg['id'], ip_version) neutron_sgs[name] = { 'name': name, 'addresses': [], 'external_ids': {const.OVN_SG_NAME_EXT_ID_KEY: sg['name']}} for port in db_ports: sg_ids = port.get('security_groups', []) if port.get('fixed_ips') and sg_ids: addresses = acl_utils.acl_port_ips(port) for sg_id in sg_ids: for ip_version in addresses: name = utils.ovn_addrset_name(sg_id, ip_version) neutron_sgs[name]['addresses'].extend( addresses[ip_version]) nb_sgs = self.get_address_sets() sgnames_to_add, sgnames_to_delete, sgs_to_update =\ self.compute_address_set_difference(neutron_sgs, nb_sgs) LOG.debug('Address_Sets added %d, removed %d, updated %d', len(sgnames_to_add), len(sgnames_to_delete), len(sgs_to_update)) if self.mode == SYNC_MODE_REPAIR: LOG.debug('Address-Set-SYNC: transaction started @ %s' % str(datetime.now())) with self.ovn_api.transaction(check_error=True) as txn: for sgname in sgnames_to_add: sg = neutron_sgs[sgname] txn.add(self.ovn_api.create_address_set(**sg)) for sgname, sg in six.iteritems(sgs_to_update): txn.add(self.ovn_api.update_address_set(**sg)) for sgname in sgnames_to_delete: txn.add(self.ovn_api.delete_address_set(name=sgname)) LOG.debug('Address-Set-SYNC: transaction finished @ %s' % str(datetime.now()))
def create_port_in_ovn(self, port, ovn_port_info): external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port["name"]} lswitch_name = utils.ovn_name(port["network_id"]) admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: # The lport_name *must* be neutron port['id']. It must match the # iface-id set in the Interfaces table of the Open_vSwitch # database which nova sets to be the port ID. txn.add( self._nb_ovn.create_lswitch_port( lport_name=port["id"], lswitch_name=lswitch_name, addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, enabled=port.get("admin_state_up"), options=ovn_port_info.options, type=ovn_port_info.type, port_security=ovn_port_info.port_security, dhcpv4_options=ovn_port_info.dhcpv4_options, ) ) acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) for acl in acls_new: txn.add(self._nb_ovn.add_acl(**acl)) sg_ids = port.get("security_groups", []) if port.get("fixed_ips") and sg_ids: addresses = ovn_acl.acl_port_ips(port) # NOTE(rtheis): Fail port creation if the address set doesn't # exist. This prevents ports from being created on any security # groups out-of-sync between neutron and OVN. for sg_id in sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None, if_exists=False, ) )
def create_port_in_ovn(self, port, ovn_port_info): external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name']} lswitch_name = utils.ovn_name(port['network_id']) admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: # The lport_name *must* be neutron port['id']. It must match the # iface-id set in the Interfaces table of the Open_vSwitch # database which nova sets to be the port ID. txn.add( self._nb_ovn.create_lswitch_port( lport_name=port['id'], lswitch_name=lswitch_name, addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, enabled=port.get('admin_state_up'), options=ovn_port_info.options, type=ovn_port_info.type, port_security=ovn_port_info.port_security, dhcpv4_options=ovn_port_info.dhcpv4_options)) acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) for acl in acls_new: txn.add(self._nb_ovn.add_acl(**acl)) sg_ids = port.get('security_groups', []) if port.get('fixed_ips') and sg_ids: addresses = ovn_acl.acl_port_ips(port) # NOTE(rtheis): Fail port creation if the address set doesn't # exist. This prevents ports from being created on any security # groups out-of-sync between neutron and OVN. for sg_id in sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None, if_exists=False))
def delete_port_postcommit(self, context): """Delete a port. :param context: PortContext instance describing the current state of the port, prior to the call to delete it. Called after the transaction completes. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ port = context.current with self._nb_ovn.transaction(check_error=True) as txn: txn.add( self._nb_ovn.delete_lswitch_port( port['id'], utils.ovn_name(port['network_id']))) txn.add( self._nb_ovn.delete_acl(utils.ovn_name(port['network_id']), port['id'])) if port.get('fixed_ips'): addresses = ovn_acl.acl_port_ips(port) for sg_id in port.get('security_groups', []): for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=None, addrs_remove=addresses[ip_version])) # Delete the DHCP_Options row if created for this port. # A separate DHCP_Options row would have be created if the port # has extra DHCP options defined. for fixed_ip in port['fixed_ips']: if netaddr.IPAddress(fixed_ip['ip_address']).version == 4: lsp_dhcp_options = self._nb_ovn.get_port_dhcp_options( fixed_ip['subnet_id'], port['id']) if lsp_dhcp_options: txn.add( self._nb_ovn.delete_dhcp_options( lsp_dhcp_options['uuid'])) break
def test_sg_disabled(self): sg = fakes.FakeSecurityGroup.create_one_security_group().info() port = fakes.FakePort.create_one_port({ 'security_groups': [sg['id']] }).info() with mock.patch('networking_ovn.common.acl.is_sg_enabled', return_value=False): acl_list = ovn_acl.add_acls(self.plugin, self.admin_context, port, {}, {}, self.driver._ovn) self.assertEqual([], acl_list) ovn_acl.update_acls_for_security_group(self.plugin, self.admin_context, self.driver._ovn, sg['id'], None) self.driver._ovn.update_acls.assert_not_called() addresses = ovn_acl.acl_port_ips(port) self.assertEqual({'ip4': [], 'ip6': []}, addresses)
def test_sg_disabled(self): sg = fakes.FakeSecurityGroup.create_one_security_group().info() port = fakes.FakePort.create_one_port({ 'security_groups': [sg['id']] }).info() with mock.patch('networking_ovn.common.acl.is_sg_enabled', return_value=False): acl_list = ovn_acl.add_acls(self.plugin, self.admin_context, port, {}, {}) self.assertEqual([], acl_list) ovn_acl.update_acls_for_security_group(self.plugin, self.admin_context, self.driver._ovn, sg['id']) self.driver._ovn.update_acls.assert_not_called() addresses = ovn_acl.acl_port_ips(port) self.assertEqual({'ip4': [], 'ip6': []}, addresses)
def delete_port_postcommit(self, context): """Delete a port. :param context: PortContext instance describing the current state of the port, prior to the call to delete it. Called after the transaction completes. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ port = context.current with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.delete_lswitch_port(port["id"], utils.ovn_name(port["network_id"]))) txn.add(self._nb_ovn.delete_acl(utils.ovn_name(port["network_id"]), port["id"])) if port.get("fixed_ips"): addresses = ovn_acl.acl_port_ips(port) for sg_id in port.get("security_groups", []): for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses[ip_version], ) ) # Delete the DHCP_Options row if created for this port. # A separate DHCP_Options row would have be created if the port # has extra DHCP options defined. for fixed_ip in port["fixed_ips"]: if netaddr.IPAddress(fixed_ip["ip_address"]).version == 4: lsp_dhcp_options = self._nb_ovn.get_port_dhcp_options(fixed_ip["subnet_id"], port["id"]) if lsp_dhcp_options: txn.add(self._nb_ovn.delete_dhcp_options(lsp_dhcp_options["uuid"])) break
def create_port_in_ovn(self, port, ovn_port_info): external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name']} lswitch_name = utils.ovn_name(port['network_id']) admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: # The lport_name *must* be neutron port['id']. It must match the # iface-id set in the Interfaces table of the Open_vSwitch # database which nova sets to be the port ID. txn.add(self._nb_ovn.create_lswitch_port( lport_name=port['id'], lswitch_name=lswitch_name, addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, enabled=port.get('admin_state_up'), options=ovn_port_info.options, type=ovn_port_info.type, port_security=ovn_port_info.port_security)) acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) for acl in acls_new: txn.add(self._nb_ovn.add_acl(**acl)) sg_ids = port.get('security_groups', []) if port.get('fixed_ips') and sg_ids: addresses = ovn_acl.acl_port_ips(port) for sg_id in sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None))
def _update_port_in_ovn(self, original_port, port, ovn_port_info): external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port["name"]} admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: txn.add( self._nb_ovn.set_lswitch_port( lport_name=port["id"], addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, type=ovn_port_info.type, options=ovn_port_info.options, enabled=port["admin_state_up"], port_security=ovn_port_info.port_security, dhcpv4_options=ovn_port_info.dhcpv4_options, ) ) # Determine if security groups or fixed IPs are updated. old_sg_ids = set(original_port.get("security_groups", [])) new_sg_ids = set(port.get("security_groups", [])) detached_sg_ids = old_sg_ids - new_sg_ids attached_sg_ids = new_sg_ids - old_sg_ids is_fixed_ips_updated = original_port.get("fixed_ips") != port.get("fixed_ips") # Refresh ACLs for changed security groups or fixed IPs. if detached_sg_ids or attached_sg_ids or is_fixed_ips_updated: # Note that update_acls will compare the port's ACLs to # ensure only the necessary ACLs are added and deleted # on the transaction. acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) txn.add( self._nb_ovn.update_acls([port["network_id"]], [port], {port["id"]: acls_new}, need_compare=True) ) # Refresh address sets for changed security groups or fixed IPs. if len(port.get("fixed_ips")) != 0 or len(original_port.get("fixed_ips")) != 0: addresses = ovn_acl.acl_port_ips(port) addresses_old = ovn_acl.acl_port_ips(original_port) # Add current addresses to attached security groups. for sg_id in attached_sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None, ) ) # Remove old addresses from detached security groups. for sg_id in detached_sg_ids: for ip_version in addresses_old: if addresses_old[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses_old[ip_version], ) ) if is_fixed_ips_updated: # We have refreshed address sets for attached and detached # security groups, so now we only need to take care of # unchanged security groups. unchanged_sg_ids = new_sg_ids & old_sg_ids for sg_id in unchanged_sg_ids: for ip_version in addresses: addr_add = (set(addresses[ip_version]) - set(addresses_old[ip_version])) or None addr_remove = (set(addresses_old[ip_version]) - set(addresses[ip_version])) or None if addr_add or addr_remove: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addr_add, addrs_remove=addr_remove, ) ) if not ovn_port_info.dhcpv4_options: # Check if the DHCP_Options row exist for this port. # We need to delete it as it is no longer referenced by this # port. cmd = self._get_delete_lsp_dhcpv4_options_cmd(port) if cmd: txn.add(cmd)
def _update_port_in_ovn(self, original_port, port, ovn_port_info): external_ids = { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name']} admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.set_lswitch_port( lport_name=port['id'], addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, type=ovn_port_info.type, options=ovn_port_info.options, enabled=port['admin_state_up'], port_security=ovn_port_info.port_security)) # Determine if security groups or fixed IPs are updated. old_sg_ids = set(original_port.get('security_groups', [])) new_sg_ids = set(port.get('security_groups', [])) detached_sg_ids = old_sg_ids - new_sg_ids attached_sg_ids = new_sg_ids - old_sg_ids is_fixed_ips_updated = \ original_port.get('fixed_ips') != port.get('fixed_ips') # Refresh ACLs for changed security groups or fixed IPs. if detached_sg_ids or attached_sg_ids or is_fixed_ips_updated: # Note that update_acls will compare the port's ACLs to # ensure only the necessary ACLs are added and deleted # on the transaction. acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) txn.add(self._nb_ovn.update_acls([port['network_id']], [port], {port['id']: acls_new}, need_compare=True)) # Refresh address sets for changed security groups or fixed IPs. if (len(port.get('fixed_ips')) != 0 or len(original_port.get('fixed_ips')) != 0): addresses = ovn_acl.acl_port_ips(port) addresses_old = ovn_acl.acl_port_ips(original_port) # Add current addresses to attached security groups. for sg_id in attached_sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None)) # Remove old addresses from detached security groups. for sg_id in detached_sg_ids: for ip_version in addresses_old: if addresses_old[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses_old[ip_version])) if is_fixed_ips_updated: # We have refreshed address sets for attached and detached # security groups, so now we only need to take care of # unchanged security groups. unchanged_sg_ids = new_sg_ids & old_sg_ids for sg_id in unchanged_sg_ids: for ip_version in addresses: addr_add = (set(addresses[ip_version]) - set(addresses_old[ip_version])) or None addr_remove = (set(addresses_old[ip_version]) - set(addresses[ip_version])) or None if addr_add or addr_remove: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=addr_add, addrs_remove=addr_remove))
def _update_port_in_ovn(self, original_port, port, ovn_port_info): external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name']} admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: txn.add( self._nb_ovn.set_lswitch_port( lport_name=port['id'], addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, type=ovn_port_info.type, options=ovn_port_info.options, enabled=port['admin_state_up'], port_security=ovn_port_info.port_security, dhcpv4_options=ovn_port_info.dhcpv4_options)) # Determine if security groups or fixed IPs are updated. old_sg_ids = set(original_port.get('security_groups', [])) new_sg_ids = set(port.get('security_groups', [])) detached_sg_ids = old_sg_ids - new_sg_ids attached_sg_ids = new_sg_ids - old_sg_ids is_fixed_ips_updated = \ original_port.get('fixed_ips') != port.get('fixed_ips') # Refresh ACLs for changed security groups or fixed IPs. if detached_sg_ids or attached_sg_ids or is_fixed_ips_updated: # Note that update_acls will compare the port's ACLs to # ensure only the necessary ACLs are added and deleted # on the transaction. acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) txn.add( self._nb_ovn.update_acls([port['network_id']], [port], {port['id']: acls_new}, need_compare=True)) # Refresh address sets for changed security groups or fixed IPs. if (len(port.get('fixed_ips')) != 0 or len(original_port.get('fixed_ips')) != 0): addresses = ovn_acl.acl_port_ips(port) addresses_old = ovn_acl.acl_port_ips(original_port) # Add current addresses to attached security groups. for sg_id in attached_sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None)) # Remove old addresses from detached security groups. for sg_id in detached_sg_ids: for ip_version in addresses_old: if addresses_old[ip_version]: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=None, addrs_remove=addresses_old[ip_version])) if is_fixed_ips_updated: # We have refreshed address sets for attached and detached # security groups, so now we only need to take care of # unchanged security groups. unchanged_sg_ids = new_sg_ids & old_sg_ids for sg_id in unchanged_sg_ids: for ip_version in addresses: addr_add = (set(addresses[ip_version]) - set(addresses_old[ip_version])) or None addr_remove = (set(addresses_old[ip_version]) - set(addresses[ip_version])) or None if addr_add or addr_remove: txn.add( self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=addr_add, addrs_remove=addr_remove)) if not ovn_port_info.dhcpv4_options: # Check if the DHCP_Options row exist for this port. # We need to delete it as it is no longer referenced by this # port. cmd = self._get_delete_lsp_dhcpv4_options_cmd(port) if cmd: txn.add(cmd)
def _update_port_in_ovn(self, original_port, port, ovn_port_info): external_ids = { ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name']} admin_context = n_context.get_admin_context() sg_cache = {} subnet_cache = {} with self._nb_ovn.transaction(check_error=True) as txn: txn.add(self._nb_ovn.set_lswitch_port( lport_name=port['id'], addresses=ovn_port_info.addresses, external_ids=external_ids, parent_name=ovn_port_info.parent_name, tag=ovn_port_info.tag, type=ovn_port_info.type, options=ovn_port_info.options, enabled=port['admin_state_up'], port_security=ovn_port_info.port_security)) # Note that the ovsdb IDL suppresses the transaction down to what # has actually changed. txn.add(self._nb_ovn.delete_acl( utils.ovn_name(port['network_id']), port['id'])) acls_new = ovn_acl.add_acls(self._plugin, admin_context, port, sg_cache, subnet_cache) for acl in acls_new: txn.add(self._nb_ovn.add_acl(**acl)) # Refresh remote security groups for changed security groups old_sg_ids = set(original_port.get('security_groups', [])) new_sg_ids = set(port.get('security_groups', [])) detached_sg_ids = old_sg_ids - new_sg_ids attached_sg_ids = new_sg_ids - old_sg_ids if (len(port.get('fixed_ips')) != 0 or len(original_port.get('fixed_ips')) != 0): addresses = ovn_acl.acl_port_ips(port) addresses_old = ovn_acl.acl_port_ips(original_port) # Add current addresses to attached security groups. for sg_id in attached_sg_ids: for ip_version in addresses: if addresses[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=addresses[ip_version], addrs_remove=None)) # Remove old addresses from detached security groups. for sg_id in detached_sg_ids: for ip_version in addresses_old: if addresses_old[ip_version]: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name(sg_id, ip_version), addrs_add=None, addrs_remove=addresses_old[ip_version])) if original_port.get('fixed_ips') != port.get('fixed_ips'): # We have refreshed address sets for attached and detached # security groups, so now we only need to take care of # unchanged security groups. unchanged_sg_ids = new_sg_ids & old_sg_ids for sg_id in unchanged_sg_ids: for ip_version in addresses: addr_add = (set(addresses[ip_version]) - set(addresses_old[ip_version])) or None addr_remove = (set(addresses_old[ip_version]) - set(addresses[ip_version])) or None if addr_add or addr_remove: txn.add(self._nb_ovn.update_address_set( name=utils.ovn_addrset_name( sg_id, ip_version), addrs_add=addr_add, addrs_remove=addr_remove))