def test_add_acls_with_sec_group(self):
        expected_acls = []
        expected_acls += ovn_acl.drop_all_ip_traffic_for_port(
            self.fake_port_sg)
        expected_acls += ovn_acl.add_acl_dhcp(
            self.fake_port_sg, self.fake_subnet)
        sg_rule_acl = ovn_acl.add_sg_rule_acl_for_port(
            self.fake_port_sg, self.fake_sg_rule,
            'outport == "' + self.fake_port_sg['id'] + '" ' +
            '&& ip4 && ip4.src == 0.0.0.0/0 ' +
            '&& tcp && tcp.dst == 22')
        expected_acls.append(sg_rule_acl)

        # Test with caches
        acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                mock.Mock(),
                                self.fake_port_sg,
                                self.sg_cache,
                                self.sg_ports_cache,
                                self.subnet_cache)
        self.assertEqual(expected_acls, acls)

        # Test without caches
        with mock.patch('neutron.db.db_base_plugin_v2.'
                        'NeutronDbPluginV2.get_subnet',
                        return_value=self.fake_subnet), \
            mock.patch('neutron.db.securitygroups_db.'
                       'SecurityGroupDbMixin.get_security_group',
                       return_value=self.fake_sg):

            acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                    mock.Mock(),
                                    self.fake_port_sg,
                                    {}, {}, {})
            self.assertEqual(expected_acls, acls)
Exemple #2
0
    def _test_add_acls_with_sec_group_helper(self, native_dhcp=True):
        fake_port_sg = fakes.FakePort.create_one_port(
            attrs={
                'security_groups': [self.fake_sg['id']],
                'fixed_ips': [{
                    'subnet_id': self.fake_subnet['id'],
                    'ip_address': '10.10.10.20'
                }]
            }).info()

        expected_acls = []
        expected_acls += ovn_acl.drop_all_ip_traffic_for_port(fake_port_sg)
        if not native_dhcp:
            expected_acls += ovn_acl.add_acl_dhcp(fake_port_sg,
                                                  self.fake_subnet)
        sg_rule_acl = ovn_acl.add_sg_rule_acl_for_port(
            fake_port_sg, self.fake_sg_rule,
            'outport == "' + fake_port_sg['id'] + '" ' +
            '&& ip4 && ip4.src == 0.0.0.0/0 ' + '&& tcp && tcp.dst == 22')
        expected_acls.append(sg_rule_acl)

        # Test with caches
        acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(),
                                fake_port_sg, self.sg_cache, self.subnet_cache)
        self.assertEqual(expected_acls, acls)

        # Test without caches
        with mock.patch('neutron.db.db_base_plugin_v2.'
                        'NeutronDbPluginV2.get_subnet',
                        return_value=self.fake_subnet), \
            mock.patch('neutron.db.securitygroups_db.'
                       'SecurityGroupDbMixin.get_security_group',
                       return_value=self.fake_sg):

            acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(),
                                    fake_port_sg, {}, {})
            self.assertEqual(expected_acls, acls)

        # Test with security groups disabled
        with mock.patch('networking_ovn.common.acl.is_sg_enabled',
                        return_value=False):
            acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(),
                                    fake_port_sg, self.sg_cache,
                                    self.subnet_cache)
            self.assertEqual([], acls)

        # Test with multiple fixed IPs on the same subnet.
        fake_port_sg['fixed_ips'].append({
            'subnet_id': self.fake_subnet['id'],
            'ip_address': '10.10.10.21'
        })
        acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(),
                                fake_port_sg, self.sg_cache, self.subnet_cache)
        self.assertEqual(expected_acls, acls)
    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 = {}
        sg_ports_cache = {}
        subnet_cache = {}

        with self._ovn.transaction(check_error=True) as txn:
            txn.add(self._ovn.set_lport(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._ovn.delete_acl(
                    utils.ovn_name(port['network_id']),
                    port['id']))
            acls_new = ovn_acl.add_acls(self._plugin,
                                        admin_context,
                                        port,
                                        sg_cache,
                                        sg_ports_cache,
                                        subnet_cache)
            for acl in acls_new:
                txn.add(self._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 and
                len(original_port.get('fixed_ips')) == 0):
            # No need to process remote security group if the port
            # didn't have any IP Addresses.
            return port

        for sg_id in (attached_sg_ids | detached_sg_ids):
            ovn_acl.refresh_remote_security_group(
                self._plugin, admin_context, self._ovn, sg_id,
                sg_cache, sg_ports_cache,
                subnet_cache, [port['id']])

        # Refresh remote security groups if remote_group_match_ip is set
        if original_port.get('fixed_ips') != port.get('fixed_ips'):
            # We have refreshed 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:
                ovn_acl.refresh_remote_security_group(
                    self._plugin, admin_context, self._ovn, sg_id,
                    sg_cache, sg_ports_cache,
                    subnet_cache, [port['id']])
Exemple #4
0
    def _validate_acls(self, should_match=True):
        # Get the neutron DB ACLs.
        db_acls = []
        sg_cache = {}
        subnet_cache = {}
        for db_port in self._list('ports')['ports']:
            acls = acl_utils.add_acls(self.plugin, context.get_admin_context(),
                                      db_port, sg_cache, subnet_cache)
            for acl in acls:
                acl.pop('lport')
                acl.pop('lswitch')
                db_acls.append(acl)

        # Get the list of ACLs stored in the OVN plugin IDL.
        _plugin_nb_ovn = self.mech_driver._nb_ovn
        plugin_acls = []
        for row in _plugin_nb_ovn._tables['Logical_Switch'].rows.values():
            for acl in getattr(row, 'acls', []):
                plugin_acls.append(self._build_acl_to_compare(acl))

        # Get the list of ACLs stored in the OVN monitor IDL.
        monitor_nb_ovn = self.monitor_nb_db_idl
        monitor_acls = []
        for row in monitor_nb_ovn.tables['Logical_Switch'].rows.values():
            for acl in getattr(row, 'acls', []):
                monitor_acls.append(self._build_acl_to_compare(acl))

        if should_match:
            self.assertItemsEqual(db_acls, plugin_acls)
            self.assertItemsEqual(db_acls, monitor_acls)
        else:
            self.assertRaises(AssertionError, self.assertItemsEqual, db_acls,
                              plugin_acls)
            self.assertRaises(AssertionError, self.assertItemsEqual, db_acls,
                              monitor_acls)
    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 = {}
        sg_ports_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, sg_ports_cache, subnet_cache)
            for acl in acls_new:
                txn.add(self._nb_ovn.add_acl(**acl))

        if len(port.get('fixed_ips')):
            for sg_id in port.get('security_groups', []):
                ovn_acl.refresh_remote_security_group(
                    self._plugin, admin_context, self._nb_ovn, sg_id, sg_cache,
                    sg_ports_cache, subnet_cache, [port['id']])
    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 = {}
        sg_ports_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, sg_ports_cache,
                                        subnet_cache)
            for acl in acls_new:
                txn.add(self._nb_ovn.add_acl(**acl))

        if len(port.get('fixed_ips')):
            for sg_id in port.get('security_groups', []):
                ovn_acl.refresh_remote_security_group(
                    self._plugin, admin_context, self._nb_ovn,
                    sg_id, sg_cache, sg_ports_cache,
                    subnet_cache, [port['id']])
Exemple #7
0
    def sync_acls(self, ctx):
        """Sync ACLs 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
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' % str(datetime.now()))

        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in six.iteritems(db_ports):
            if port['security_groups']:
                acl_list = acl_utils.add_acls(self.core_plugin, ctx, port,
                                              sg_cache, subnet_cache)
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(acl_list)
                else:
                    neutron_acls[port_id] = acl_list

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        LOG.debug('ACLs-to-be-added %d ACLs-to-be-removed %d' %
                  (len(list(itertools.chain(*six.itervalues(neutron_acls)))),
                   len(list(itertools.chain(*six.itervalues(nb_acls))))))

        if self.mode == SYNC_MODE_REPAIR:
            LOG.debug('ACL-SYNC: transaction started @ %s' %
                      str(datetime.now()))
            with self.ovn_api.transaction(check_error=True) as txn:
                for acla in list(
                        itertools.chain(*six.itervalues(neutron_acls))):
                    txn.add(self.ovn_api.add_acl(**acla))
                for aclr in list(itertools.chain(*six.itervalues(nb_acls))):
                    # Both lswitch and lport aren't needed within the ACL.
                    lswitchr = aclr.pop('lswitch').replace('neutron-', '')
                    lportr = aclr.pop('lport')
                    aclr_dict = {lportr: aclr}
                    txn.add(
                        self.ovn_api.update_acls([lswitchr], [lportr],
                                                 aclr_dict,
                                                 need_compare=False,
                                                 is_add_acl=False))
            LOG.debug('ACL-SYNC: transaction finished @ %s' %
                      str(datetime.now()))
    def _test_add_acls_with_sec_group_helper(self, native_dhcp=True):
        fake_port_sg = fakes.FakePort.create_one_port(
            attrs={
                "security_groups": [self.fake_sg["id"]],
                "fixed_ips": [{"subnet_id": self.fake_subnet["id"], "ip_address": "10.10.10.20"}],
            }
        ).info()

        expected_acls = []
        expected_acls += ovn_acl.drop_all_ip_traffic_for_port(fake_port_sg)
        if not native_dhcp:
            expected_acls += ovn_acl.add_acl_dhcp(fake_port_sg, self.fake_subnet)
        sg_rule_acl = ovn_acl.add_sg_rule_acl_for_port(
            fake_port_sg,
            self.fake_sg_rule,
            'outport == "' + fake_port_sg["id"] + '" ' + "&& ip4 && ip4.src == 0.0.0.0/0 " + "&& tcp && tcp.dst == 22",
        )
        expected_acls.append(sg_rule_acl)

        # Test with caches
        acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(), fake_port_sg, self.sg_cache, self.subnet_cache)
        self.assertEqual(expected_acls, acls)

        # Test without caches
        with mock.patch(
            "neutron.db.db_base_plugin_v2." "NeutronDbPluginV2.get_subnet", return_value=self.fake_subnet
        ), mock.patch(
            "neutron.db.securitygroups_db." "SecurityGroupDbMixin.get_security_group", return_value=self.fake_sg
        ):

            acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(), fake_port_sg, {}, {})
            self.assertEqual(expected_acls, acls)

        # Test with security groups disabled
        with mock.patch("networking_ovn.common.acl.is_sg_enabled", return_value=False):
            acls = ovn_acl.add_acls(
                self.mech_driver._plugin, mock.Mock(), fake_port_sg, self.sg_cache, self.subnet_cache
            )
            self.assertEqual([], acls)

        # Test with multiple fixed IPs on the same subnet.
        fake_port_sg["fixed_ips"].append({"subnet_id": self.fake_subnet["id"], "ip_address": "10.10.10.21"})
        acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(), fake_port_sg, self.sg_cache, self.subnet_cache)
        self.assertEqual(expected_acls, acls)
    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 = {}
        sg_ports_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, sg_ports_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
                and len(original_port.get('fixed_ips')) == 0):
            # No need to process remote security group if the port
            # didn't have any IP Addresses.
            return port

        for sg_id in (attached_sg_ids | detached_sg_ids):
            ovn_acl.refresh_remote_security_group(self._plugin, admin_context,
                                                  self._nb_ovn, sg_id,
                                                  sg_cache, sg_ports_cache,
                                                  subnet_cache, [port['id']])

        # Refresh remote security groups if remote_group_match_ip is set
        if original_port.get('fixed_ips') != port.get('fixed_ips'):
            # We have refreshed 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:
                ovn_acl.refresh_remote_security_group(
                    self._plugin, admin_context, self._nb_ovn, sg_id, sg_cache,
                    sg_ports_cache, subnet_cache, [port['id']])
Exemple #10
0
    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,
                                )
                            )
Exemple #11
0
    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))
Exemple #12
0
    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)
Exemple #13
0
    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 _validate_acls(self, should_match=True):
        # Get the neutron DB ACLs.
        db_acls = []
        sg_cache = {}
        subnet_cache = {}
        for db_port in self._list('ports')['ports']:
            acls = acl_utils.add_acls(self.plugin,
                                      context.get_admin_context(),
                                      db_port,
                                      sg_cache,
                                      subnet_cache)
            for acl in acls:
                acl.pop('lport')
                acl.pop('lswitch')
                db_acls.append(acl)

        # Get the list of ACLs stored in the OVN plugin IDL.
        _plugin_nb_ovn = self.mech_driver._nb_ovn
        plugin_acls = []
        for row in _plugin_nb_ovn._tables['Logical_Switch'].rows.values():
            for acl in getattr(row, 'acls', []):
                plugin_acls.append(self._build_acl_to_compare(acl))

        # Get the list of ACLs stored in the OVN monitor IDL.
        monitor_nb_ovn = self.monitor_nb_db_idl
        monitor_acls = []
        for row in monitor_nb_ovn.tables['Logical_Switch'].rows.values():
            for acl in getattr(row, 'acls', []):
                monitor_acls.append(self._build_acl_to_compare(acl))

        if should_match:
            self.assertItemsEqual(db_acls, plugin_acls)
            self.assertItemsEqual(db_acls, monitor_acls)
        else:
            self.assertRaises(
                AssertionError, self.assertItemsEqual,
                db_acls, plugin_acls)
            self.assertRaises(
                AssertionError, self.assertItemsEqual,
                db_acls, monitor_acls)
Exemple #15
0
    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)
Exemple #16
0
    def sync_acls(self, ctx):
        """Sync ACLs 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
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' % str(datetime.now()))

        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in six.iteritems(db_ports):
            if port['security_groups']:
                acl_list = acl_utils.add_acls(self.core_plugin, ctx, port,
                                              sg_cache, subnet_cache)
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(acl_list)
                else:
                    neutron_acls[port_id] = acl_list

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        num_acls_to_add = \
            len(list(itertools.chain(*six.itervalues(neutron_acls))))
        num_acls_to_remove = \
            len(list(itertools.chain(*six.itervalues(nb_acls))))
        if 0 != num_acls_to_add or 0 != num_acls_to_remove:
            LOG.warning(
                _LW('ACLs-to-be-added %(add)d '
                    'ACLs-to-be-removed %(remove)d'), {
                        'add': num_acls_to_add,
                        'remove': num_acls_to_remove
                    })

        if self.mode == SYNC_MODE_REPAIR:
            with self.ovn_api.transaction(check_error=True) as txn:
                for acla in list(
                        itertools.chain(*six.itervalues(neutron_acls))):
                    LOG.warning(
                        _LW('ACL found in Neutron but not in '
                            'OVN DB for port %s'), acla['lport'])
                    txn.add(self.ovn_api.add_acl(**acla))

            # TODO(rtheis): Each delete must be done in a separate
            # transaction until bug 1629099 is fixed. Otherwise, ACLs may
            # not be deleted because of previous row mutations on a logical
            # switch.
            for aclr in list(itertools.chain(*six.itervalues(nb_acls))):
                # Both lswitch and lport aren't needed within the ACL.
                lswitchr = aclr.pop('lswitch').replace('neutron-', '')
                lportr = aclr.pop('lport')
                aclr_dict = {lportr: aclr}
                LOG.warning(
                    _LW('ACLs found in OVN DB but not in '
                        'Neutron for port %s'), lportr)
                self.ovn_api.update_acls(
                    [lswitchr], [lportr],
                    aclr_dict,
                    need_compare=False,
                    is_add_acl=False).execute(check_error=True)

        LOG.debug('ACL-SYNC: finished @ %s' % str(datetime.now()))
    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 test_add_acls_no_sec_group(self):
     acls = acl_utils.add_acls(self.plugin, self.context,
                               port={'security_groups': []},
                               sg_cache={}, sg_ports_cache={},
                               subnet_cache={})
     self.assertEqual(acls, [])
    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))
    def sync_acls(self, ctx):
        """Sync ACLs 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
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' %
                  str(datetime.now()))

        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in six.iteritems(db_ports):
            if port['security_groups']:
                acl_list = acl_utils.add_acls(self.core_plugin,
                                              ctx,
                                              port,
                                              sg_cache,
                                              subnet_cache)
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(acl_list)
                else:
                    neutron_acls[port_id] = acl_list

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        num_acls_to_add = \
            len(list(itertools.chain(*six.itervalues(neutron_acls))))
        num_acls_to_remove = \
            len(list(itertools.chain(*six.itervalues(nb_acls))))
        if 0 != num_acls_to_add or 0 != num_acls_to_remove:
            LOG.warning(_LW('ACLs-to-be-added %(add)d '
                            'ACLs-to-be-removed %(remove)d'),
                        {'add': num_acls_to_add,
                         'remove': num_acls_to_remove})

        if self.mode == SYNC_MODE_REPAIR:
            with self.ovn_api.transaction(check_error=True) as txn:
                for acla in list(itertools.chain(
                                 *six.itervalues(neutron_acls))):
                    LOG.warning(_LW('ACL found in Neutron but not in '
                                    'OVN DB for port %s'), acla['lport'])
                    txn.add(self.ovn_api.add_acl(**acla))

            with self.ovn_api.transaction(check_error=True) as txn:
                for aclr in list(itertools.chain(*six.itervalues(nb_acls))):
                    # Both lswitch and lport aren't needed within the ACL.
                    lswitchr = aclr.pop('lswitch').replace('neutron-', '')
                    lportr = aclr.pop('lport')
                    aclr_dict = {lportr: aclr}
                    LOG.warning(_LW('ACLs found in OVN DB but not in '
                                    'Neutron for port %s'), lportr)
                    txn.add(self.ovn_api.update_acls(
                        [lswitchr],
                        [lportr],
                        aclr_dict,
                        need_compare=False,
                        is_add_acl=False
                    ))

        LOG.debug('ACL-SYNC: finished @ %s' %
                  str(datetime.now()))
    def _test_add_acls_with_sec_group_helper(self, native_dhcp=True):
        fake_port_sg = fakes.FakePort.create_one_port(
            attrs={'security_groups': [self.fake_sg['id']],
                   'fixed_ips': [{'subnet_id': self.fake_subnet['id'],
                                  'ip_address': '10.10.10.20'}]}
        ).info()

        expected_acls = []
        expected_acls += ovn_acl.drop_all_ip_traffic_for_port(
            fake_port_sg)
        if not native_dhcp:
            expected_acls += ovn_acl.add_acl_dhcp(
                fake_port_sg, self.fake_subnet)
        sg_rule_acl = ovn_acl.add_sg_rule_acl_for_port(
            fake_port_sg, self.fake_sg_rule,
            'outport == "' + fake_port_sg['id'] + '" ' +
            '&& ip4 && ip4.src == 0.0.0.0/0 ' +
            '&& tcp && tcp.dst == 22')
        expected_acls.append(sg_rule_acl)

        # Test with caches
        acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                mock.Mock(),
                                fake_port_sg,
                                self.sg_cache,
                                self.subnet_cache)
        self.assertEqual(expected_acls, acls)

        # Test without caches
        with mock.patch('neutron.db.db_base_plugin_v2.'
                        'NeutronDbPluginV2.get_subnet',
                        return_value=self.fake_subnet), \
            mock.patch('neutron.db.securitygroups_db.'
                       'SecurityGroupDbMixin.get_security_group',
                       return_value=self.fake_sg):

            acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                    mock.Mock(),
                                    fake_port_sg,
                                    {}, {})
            self.assertEqual(expected_acls, acls)

        # Test with security groups disabled
        with mock.patch('networking_ovn.common.acl.is_sg_enabled',
                        return_value=False):
            acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                    mock.Mock(),
                                    fake_port_sg,
                                    self.sg_cache,
                                    self.subnet_cache)
            self.assertEqual([], acls)

        # Test with multiple fixed IPs on the same subnet.
        fake_port_sg['fixed_ips'].append({'subnet_id': self.fake_subnet['id'],
                                          'ip_address': '10.10.10.21'})
        acls = ovn_acl.add_acls(self.mech_driver._plugin,
                                mock.Mock(),
                                fake_port_sg,
                                self.sg_cache,
                                self.subnet_cache)
        self.assertEqual(expected_acls, acls)
    def sync_acls(self, ctx):
        """Sync ACLs between neutron and NB.

        @param ctx: neutron_lib.context
        @type  ctx: object of type neutron_lib.context.Context
        @var   db_ports: List of ports from neutron DB
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' % str(datetime.now()))

        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in db_ports.items():
            if utils.get_lsp_security_groups(port):
                acl_list = acl_utils.add_acls(self.core_plugin, ctx, port,
                                              sg_cache, subnet_cache,
                                              self.ovn_api)
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(acl_list)
                else:
                    neutron_acls[port_id] = acl_list

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        num_acls_to_add = len(list(itertools.chain(*neutron_acls.values())))
        num_acls_to_remove = len(list(itertools.chain(*nb_acls.values())))
        if 0 != num_acls_to_add or 0 != num_acls_to_remove:
            LOG.warning(
                'ACLs-to-be-added %(add)d '
                'ACLs-to-be-removed %(remove)d', {
                    'add': num_acls_to_add,
                    'remove': num_acls_to_remove
                })

        if self.mode == SYNC_MODE_REPAIR:
            with self.ovn_api.transaction(check_error=True) as txn:
                for acla in list(itertools.chain(*neutron_acls.values())):
                    LOG.warning(
                        'ACL found in Neutron but not in '
                        'OVN DB for port %s', acla['lport'])
                    txn.add(self.ovn_api.add_acl(**acla))

            with self.ovn_api.transaction(check_error=True) as txn:
                for aclr in list(itertools.chain(*nb_acls.values())):
                    # Both lswitch and lport aren't needed within the ACL.
                    lswitchr = aclr.pop('lswitch').replace('neutron-', '')
                    lportr = aclr.pop('lport')
                    aclr_dict = {lportr: aclr}
                    LOG.warning(
                        'ACLs found in OVN DB but not in '
                        'Neutron for port %s', lportr)
                    txn.add(
                        self.ovn_api.update_acls([lswitchr], [lportr],
                                                 aclr_dict,
                                                 need_compare=False,
                                                 is_add_acl=False))

        LOG.debug('ACL-SYNC: finished @ %s' % str(datetime.now()))
    def sync_acls(self, ctx):
        """Sync ACLs between neutron and NB.

        @param ctx: neutron context
        @type  ctx: object of type neutron.context.Context
        @var   db_secs: List of SGs from neutron DB
        @var   db_ports: List of ports from neutron DB
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   sg_ports_cache: cache for sg_ports
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' %
                  str(datetime.now()))
        db_secs = {}
        for sg in self.core_plugin.get_security_groups(ctx):
            db_secs[sg['id']] = sg

        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        sg_ports_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in db_ports.items():
            if port['security_groups']:
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(
                        acl_utils.add_acls(self.core_plugin,
                                           ctx,
                                           port,
                                           sg_cache,
                                           sg_ports_cache,
                                           subnet_cache))
                else:
                    neutron_acls[port_id] = \
                        acl_utils.add_acls(self.core_plugin,
                                           ctx,
                                           port,
                                           sg_cache,
                                           sg_ports_cache,
                                           subnet_cache)

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        LOG.debug('ACLs-to-be-addded %d ACLs-to-be-removed %d' %
                  (len(list(itertools.chain(*six.itervalues(neutron_acls)))),
                   len(list(itertools.chain(*six.itervalues(nb_acls))))))

        LOG.debug('ACL-SYNC: transaction started @ %s' % str(datetime.now()))
        with self.ovn_api.transaction(check_error=True) as txn:
            for acla in list(itertools.chain(*six.itervalues(neutron_acls))):
                txn.add(self.ovn_api.add_acl(**acla))
            for aclr in list(itertools.chain(*six.itervalues(nb_acls))):
                txn.add(self.ovn_api.delete_acl(aclr['lswitch'],
                                                aclr['lport']))
        LOG.debug('ACL-SYNC: transaction finished @ %s' % str(datetime.now()))
 def test_add_acls_no_sec_group(self):
     acls = ovn_acl.add_acls(self.mech_driver._plugin,
                             mock.Mock(),
                             self.fake_port_no_sg,
                             {}, {}, {})
     self.assertEqual([], acls)
Exemple #25
0
    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 sync_acls(self, ctx):
        """Sync ACLs 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
        @var   neutron_acls: neutron dictionary of port
               vs list-of-acls
        @var   nb_acls: NB dictionary of port
               vs list-of-acls
        @var   sg_ports_cache: cache for sg_ports
        @var   subnet_cache: cache for subnets
        @return: Nothing
        """
        LOG.debug('ACL-SYNC: started @ %s' %
                  str(datetime.now()))
        db_ports = {}
        for port in self.core_plugin.get_ports(ctx):
            db_ports[port['id']] = port

        sg_cache = {}
        sg_ports_cache = {}
        subnet_cache = {}
        neutron_acls = {}
        for port_id, port in db_ports.items():
            if port['security_groups']:
                if port_id in neutron_acls:
                    neutron_acls[port_id].extend(
                        acl_utils.add_acls(self.core_plugin,
                                           ctx,
                                           port,
                                           sg_cache,
                                           sg_ports_cache,
                                           subnet_cache))
                else:
                    neutron_acls[port_id] = \
                        acl_utils.add_acls(self.core_plugin,
                                           ctx,
                                           port,
                                           sg_cache,
                                           sg_ports_cache,
                                           subnet_cache)

        nb_acls = self.get_acls(ctx)

        self.remove_common_acls(neutron_acls, nb_acls)

        LOG.debug('ACLs-to-be-addded %d ACLs-to-be-removed %d' %
                  (len(list(itertools.chain(*six.itervalues(neutron_acls)))),
                   len(list(itertools.chain(*six.itervalues(nb_acls))))))

        if self.mode == SYNC_MODE_REPAIR:
            LOG.debug('ACL-SYNC: transaction started @ %s' %
                      str(datetime.now()))
            with self.ovn_api.transaction(check_error=True) as txn:
                for acla in list(itertools.chain(
                                 *six.itervalues(neutron_acls))):
                    txn.add(self.ovn_api.add_acl(**acla))
                for aclr in list(itertools.chain(*six.itervalues(nb_acls))):
                    # Both lswitch and lport aren't needed within the ACL.
                    lswitchr = aclr.pop('lswitch').replace('neutron-', '')
                    lportr = aclr.pop('lport')
                    aclr_dict = {lportr: aclr}
                    txn.add(self.ovn_api.update_acls([lswitchr],
                                                     [lportr],
                                                     aclr_dict,
                                                     need_compare=False,
                                                     is_add_acl=False))
            LOG.debug('ACL-SYNC: transaction finished @ %s' %
                      str(datetime.now()))
Exemple #27
0
 def test_add_acls_no_sec_group(self):
     acls = ovn_acl.add_acls(self.mech_driver._plugin, mock.Mock(),
                             self.fake_port_no_sg, {}, {})
     self.assertEqual([], acls)