Example #1
0
    def test_check_for_igmp_snooping_enabled(self):
        cfg.CONF.set_override('igmp_snooping_enable', False, group='OVS')
        net = self._create_network('net')
        ls = self.nb_api.db_find('Logical_Switch',
                                 ('name', '=', utils.ovn_name(
                                     net['id']))).execute(check_error=True)[0]

        self.assertEqual('false', ls['other_config'][ovn_const.MCAST_SNOOP])
        self.assertEqual(
            'false', ls['other_config'][ovn_const.MCAST_FLOOD_UNREGISTERED])

        # Change the value of the configuration
        cfg.CONF.set_override('igmp_snooping_enable', True, group='OVS')

        # Call the maintenance task and check that the value has been
        # updated in the Logical Switch
        self.assertRaises(periodics.NeverAgain,
                          self.maint.check_for_igmp_snoop_support)

        ls = self.nb_api.db_find('Logical_Switch',
                                 ('name', '=', utils.ovn_name(
                                     net['id']))).execute(check_error=True)[0]

        self.assertEqual('true', ls['other_config'][ovn_const.MCAST_SNOOP])
        self.assertEqual(
            'true', ls['other_config'][ovn_const.MCAST_FLOOD_UNREGISTERED])
Example #2
0
 def _get_update_data_without_compare(self):
     lswitch_ovsdb_dict = {}
     for switch_name in self.lswitch_names:
         switch_name = utils.ovn_name(switch_name)
         lswitch = idlutils.row_by_value(self.api.idl, 'Logical_Switch',
                                         'name', switch_name)
         lswitch_ovsdb_dict[switch_name] = lswitch
     if self.is_add_acl:
         acl_add_values_dict = {}
         for port in self.port_list:
             switch_name = utils.ovn_name(port['network_id'])
             if switch_name not in acl_add_values_dict:
                 acl_add_values_dict[switch_name] = []
             if port['id'] in self.acl_new_values_dict:
                 acl_add_values_dict[switch_name].append(
                     self.acl_new_values_dict[port['id']])
         acl_del_objs_dict = {}
     else:
         acl_add_values_dict = {}
         acl_del_objs_dict = {}
         del_acl_extids = []
         for acl_dict in self.acl_new_values_dict.values():
             del_acl_extids.append({acl_dict['match']:
                                    acl_dict['external_ids']})
         for switch_name, lswitch in lswitch_ovsdb_dict.items():
             if switch_name not in acl_del_objs_dict:
                 acl_del_objs_dict[switch_name] = []
             acls = getattr(lswitch, 'acls', [])
             for acl in acls:
                 match = getattr(acl, 'match')
                 acl_extids = {match: getattr(acl, 'external_ids')}
                 if acl_extids in del_acl_extids:
                     acl_del_objs_dict[switch_name].append(acl)
     return lswitch_ovsdb_dict, acl_del_objs_dict, acl_add_values_dict
Example #3
0
def add_acl_dhcp(port, subnet, ovn_dhcp=True):
    # Allow DHCP requests for OVN native DHCP service, while responses are
    # allowed in ovn-northd.
    # Allow both DHCP requests and responses to pass for other DHCP services.
    # We do this even if DHCP isn't enabled for the subnet
    acl_list = []
    if not ovn_dhcp:
        acl = {"lswitch": utils.ovn_name(port['network_id']),
               "lport": port['id'],
               "priority": ovn_const.ACL_PRIORITY_ALLOW,
               "action": ovn_const.ACL_ACTION_ALLOW,
               "log": False,
               "name": [],
               "severity": [],
               "direction": 'to-lport',
               "match": ('outport == "%s" && ip4 && ip4.src == %s && '
                         'udp && udp.src == 67 && udp.dst == 68'
                         ) % (port['id'], subnet['cidr']),
               "external_ids": {'neutron:lport': port['id']}}
        acl_list.append(acl)
    acl = {"lswitch": utils.ovn_name(port['network_id']),
           "lport": port['id'],
           "priority": ovn_const.ACL_PRIORITY_ALLOW,
           "action": ovn_const.ACL_ACTION_ALLOW,
           "log": False,
           "name": [],
           "severity": [],
           "direction": 'from-lport',
           "match": ('inport == "%s" && ip4 && '
                     'ip4.dst == {255.255.255.255, %s} && '
                     'udp && udp.src == 68 && udp.dst == 67'
                     ) % (port['id'], subnet['cidr']),
           "external_ids": {'neutron:lport': port['id']}}
    acl_list.append(acl)
    return acl_list
Example #4
0
    def test_overlap_net_logs(self):
        log_data1 = self._log_data(sg_id=self.sg3, port_id=self.port3)
        log_obj1 = self.log_plugin.create_log(self.ctxt, log_data1)
        self._check_sgrs(sgrs=self.sg1rs, is_enabled=False)
        self._check_sgrs(sgrs=self.sg2rs, is_enabled=False)
        self._check_sgrs(sgrs=self.sg3rs, is_enabled=True)

        log_data2 = self._log_data(port_id=self.port2)
        log_obj2 = self.log_plugin.create_log(self.ctxt, log_data2)
        self._check_sgrs(sgrs=self.sg1rs, is_enabled=False)

        # port 2 uses sg2 and sg3. However, sg3 is in use by log_obj1
        # so only acls for 2 would be associated with log_obj2
        for sgr in self.sg2rs:
            acl = self._check_acl_log(sgr)
            self.assertEqual(utils.ovn_name(log_obj2['id']), acl.name[0])
        for sgr in self.sg3rs:
            acl = self._check_acl_log(sgr)
            self.assertEqual(utils.ovn_name(log_obj1['id']), acl.name[0])

        # Next, delete log_obj1 and make sure that lob_obj2 gets to
        # claim what it could not use before
        self.log_plugin.delete_log(self.ctxt, log_obj1['id'])
        self._check_sgrs(sgrs=self.sg1rs, is_enabled=False)
        for sgr in self.sg2rs + self.sg3rs:
            acl = self._check_acl_log(sgr)
            self.assertEqual(utils.ovn_name(log_obj2['id']), acl.name[0])

        # Delete log_obj2 and ensure that logs are off and meter is no
        # longer used
        self.log_plugin.delete_log(self.ctxt, log_obj2['id'])
        self._check_sgrs(is_enabled=False)
        self.assertEqual([],
                         self.nb_api.meter_list().execute(check_error=True))
Example #5
0
 def test_get_all_logical_switches_with_ports(self):
     # Test empty
     mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
     self.assertItemsEqual(mapping, {})
     # Test loaded values
     self._load_nb_db()
     mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
     expected = [{
         'name': utils.ovn_name('ls-id-1'),
         'ports': ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1'],
         'provnet_port': 'provnet-ls-id-1'
     }, {
         'name': utils.ovn_name('ls-id-2'),
         'ports': ['lsp-id-21', 'lsp-rp-id-2'],
         'provnet_port': 'provnet-ls-id-2'
     }, {
         'name':
         utils.ovn_name('ls-id-3'),
         'ports': ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'],
         'provnet_port':
         None
     }, {
         'name':
         utils.ovn_name('ls-id-5'),
         'ports': ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'],
         'provnet_port':
         None
     }]
     self.assertItemsEqual(mapping, expected)
Example #6
0
    def get_acls_for_lswitches(self, lswitch_names):
        """Get the existing set of acls that belong to the logical switches

        @param lswitch_names: List of logical switch names
        @type lswitch_names: []
        @var acl_values_dict: A dictionary indexed by port_id containing the
                              list of acl values in string format that belong
                              to that port
        @var acl_obj_dict: A dictionary indexed by acl value containing the
                           corresponding acl idl object.
        @var lswitch_ovsdb_dict: A dictionary mapping from logical switch
                                 name to lswitch idl object
        @return: (acl_values_dict, acl_obj_dict, lswitch_ovsdb_dict)
        """
        acl_values_dict = {}
        acl_obj_dict = {}
        lswitch_ovsdb_dict = {}
        for lswitch_name in lswitch_names:
            try:
                lswitch = idlutils.row_by_value(self.idl, 'Logical_Switch',
                                                'name',
                                                utils.ovn_name(lswitch_name))
            except idlutils.RowNotFound:
                # It is possible for the logical switch to be deleted
                # while we are searching for it by name in idl.
                continue
            lswitch_ovsdb_dict[lswitch_name] = lswitch
            acls = getattr(lswitch, 'acls', [])

            # Iterate over each acl in a lswitch and store the acl in
            # a key:value representation for e.g. acl_string. This
            # key:value representation can invoke the code -
            # self._ovn.add_acl(**acl_string)
            for acl in acls:
                ext_ids = getattr(acl, 'external_ids', {})
                port_id = ext_ids.get('neutron:lport')
                acl_list = acl_values_dict.setdefault(port_id, [])
                acl_string = {
                    'lport': port_id,
                    'lswitch': utils.ovn_name(lswitch_name)
                }
                for acl_key in getattr(acl, "_data", {}):
                    try:
                        acl_string[acl_key] = getattr(acl, acl_key)
                    except AttributeError:
                        pass
                acl_obj_dict[str(acl_string)] = acl
                acl_list.append(acl_string)
        return acl_values_dict, acl_obj_dict, lswitch_ovsdb_dict
Example #7
0
    def from_neutron_router(router):

        def _get_subnet_id(gw_info):
            subnet_id = ''
            ext_ips = gw_info.get('external_fixed_ips', [])
            if ext_ips:
                subnet_id = ext_ips[0]['subnet_id']
            return subnet_id

        external_ids = {
            ovn_const.OVN_GW_PORT_EXT_ID_KEY: router.get('gw_port_id') or '',
            ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY:
                router.get('name', 'no_router_name')}

        # Get the routes
        routes = []
        for r in router.get('routes', []):
            routes.append(FakeStaticRoute(ip_prefix=r['destination'],
                                          nexthop=r['nexthop'],
                                          external_ids={}))

        gw_info = router.get(l3.EXTERNAL_GW_INFO)
        if gw_info:
            external_ids = {
                ovn_const.OVN_ROUTER_IS_EXT_GW: 'true',
                ovn_const.OVN_SUBNET_EXT_ID_KEY: _get_subnet_id(gw_info)}
            routes.append(FakeStaticRoute(
                ip_prefix='0.0.0.0/0', nexthop='',
                external_ids=external_ids))

        return FakeOVNRouter.create_one_router(
            {'external_ids': external_ids,
             'enabled': router.get('admin_state_up') or False,
             'name': ovn_utils.ovn_name(router['id']),
             'static_routes': routes})
Example #8
0
    def _test_external_port_update(self, vnic_type):
        net_id = self.n1['network']['id']
        port_data = {
            'port': {
                'network_id': net_id,
                'tenant_id': self._tenant_id
            }
        }

        port_req = self.new_create_request('ports', port_data, self.fmt)
        port_res = port_req.get_response(self.api)
        port = self.deserialize(self.fmt, port_res)['port']

        ovn_port = self._find_port_row_by_name(port['id'])
        self.assertEqual('', ovn_port.type)
        self.assertEqual([], ovn_port.ha_chassis_group)

        port_upt_data = {'port': {portbindings.VNIC_TYPE: vnic_type}}
        port_req = self.new_update_request('ports', port_upt_data, port['id'],
                                           self.fmt)
        port_res = port_req.get_response(self.api)
        port = self.deserialize(self.fmt, port_res)['port']

        ovn_port = self._find_port_row_by_name(port['id'])
        self.assertEqual(ovn_const.LSP_TYPE_EXTERNAL, ovn_port.type)
        self.assertEqual(1, len(ovn_port.ha_chassis_group))
        self.assertEqual(utils.ovn_name(net_id),
                         str(ovn_port.ha_chassis_group[0].name))
 def _find_pf_lb(self, router_id, fip_id=None):
     lbs = self.nb_api.get_router_floatingip_lbs(utils.ovn_name(router_id))
     return [
         lb for lb in lbs
         if (not fip_id
             or fip_id == lb.external_ids[ovn_const.OVN_FIP_EXT_ID_KEY])
     ]
Example #10
0
    def test_get_all_chassis_gateway_bindings(self):
        self._load_nb_db()
        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings()
        expected = {
            'host-1': [
                utils.ovn_lrouter_port_name('orp-id-a1'),
                utils.ovn_lrouter_port_name('orp-id-a2')
            ],
            'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')],
            ovn_const.OVN_GATEWAY_INVALID_CHASSIS:
            [utils.ovn_name('orp-id-a3')]
        }
        self.assertItemsEqual(bindings, expected)

        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([])
        self.assertItemsEqual(bindings, expected)

        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings(['host-1'])
        expected = {
            'host-1': [
                utils.ovn_lrouter_port_name('orp-id-a1'),
                utils.ovn_lrouter_port_name('orp-id-a2')
            ]
        }
        self.assertItemsEqual(bindings, expected)
Example #11
0
    def update_floatingip(self, txn, floatingip):
        router_id = floatingip.get('router_id')
        qos_policy_id = floatingip.get('qos_policy_id')
        if floatingip['floating_network_id']:
            lswitch_name = utils.ovn_name(floatingip['floating_network_id'])
            txn.add(
                self._driver._nb_idl.qos_del_ext_ids(
                    lswitch_name,
                    {ovn_const.OVN_FIP_EXT_ID_KEY: floatingip['id']}))

        if not (router_id and qos_policy_id):
            return

        admin_context = n_context.get_admin_context()
        router_db = self._plugin_l3._get_router(admin_context, router_id)
        gw_port_id = router_db.get('gw_port_id')
        if not gw_port_id:
            return

        qos_rules = self._qos_rules(admin_context, qos_policy_id)
        for direction, rules in qos_rules.items():
            ovn_rule = self._ovn_qos_rule(
                direction,
                rules,
                gw_port_id,
                floatingip['floating_network_id'],
                fip_id=floatingip['id'],
                ip_address=floatingip['floating_ip_address'])
            if ovn_rule:
                txn.add(self._driver._nb_idl.qos_add(**ovn_rule))
Example #12
0
    def _check_rules(self, rules, port_id, network_id):
        egress_ovn_rule = self.qos_driver._ovn_qos_rule(
            constants.EGRESS_DIRECTION, rules.get(constants.EGRESS_DIRECTION),
            port_id, network_id)
        ingress_ovn_rule = self.qos_driver._ovn_qos_rule(
            constants.INGRESS_DIRECTION,
            rules.get(constants.INGRESS_DIRECTION), port_id, network_id)

        with self.nb_api.transaction(check_error=True):
            ls = self.qos_driver._driver._nb_idl.lookup(
                'Logical_Switch', ovn_utils.ovn_name(self.network_1))
            self.assertEqual(len(rules), len(ls.qos_rules))
            for rule in ls.qos_rules:
                ref_rule = (egress_ovn_rule if rule.direction == 'from-lport'
                            else ingress_ovn_rule)
                action = {}
                if 'dscp' in ref_rule:
                    action = {'dscp': ref_rule['dscp']}
                bandwidth = {}
                if 'rate' in ref_rule:
                    bandwidth['rate'] = ref_rule['rate']
                    if ref_rule.get('burst'):
                        bandwidth['burst'] = ref_rule['burst']
                self.assertIn(port_id, rule.match)
                self.assertEqual(action, rule.action)
                self.assertEqual(bandwidth, rule.bandwidth)
Example #13
0
 def _delete_gateway_ip_qos_rules(self, txn, router_id, network_id):
     if network_id:
         lswitch_name = utils.ovn_name(network_id)
         txn.add(
             self.nb_idl.qos_del_ext_ids(
                 lswitch_name,
                 {ovn_const.OVN_ROUTER_ID_EXT_ID_KEY: router_id}))
Example #14
0
 def get_lrouter(self, lrouter_name):
     if uuidutils.is_uuid_like(lrouter_name):
         lrouter_name = utils.ovn_name(lrouter_name)
     try:
         return self.lr_get(lrouter_name).execute(check_error=True)
     except idlutils.RowNotFound:
         return None
Example #15
0
    def _ovn_qos_rule(self,
                      rules_direction,
                      rules,
                      port_id,
                      network_id,
                      delete=False):
        """Generate an OVN QoS register based on several Neutron QoS rules

        A OVN QoS register can contain "bandwidth" and "action" parameters.
        "bandwidth" defines the rate speed limitation; "action" contains the
        DSCP value to apply. Both are not exclusive.
        Only one rule per port and direction can be applied; that's why
        two rules (bandwidth limit and DSCP) in the same direction must be
        combined in one OVN QoS register.
        http://www.openvswitch.org/support/dist-docs/ovn-nb.5.html

        :param rules_direction: (string) rules direction (egress, ingress).
        :param rules: (dict) {bw_limit: {max_kbps, max_burst_kbps},
                              dscp: {dscp_mark}}
        :param port_id: (string) port ID.
        :param network_id: (string) network ID.
        :param delete: (bool) defines if this rule if going to be a partial
                       one (without any bandwidth or DSCP information) to be
                       used only as deletion rule.
        :return: (dict) OVN QoS rule register to be used with QoSAddCommand
                 and QoSDelCommand.
        """
        if not delete and not rules:
            return

        lswitch_name = utils.ovn_name(network_id)

        if rules_direction == constants.EGRESS_DIRECTION:
            direction = 'from-lport'
            match = 'inport == "{}"'.format(port_id)
        else:
            direction = 'to-lport'
            match = 'outport == "{}"'.format(port_id)

        ovn_qos_rule = {
            'switch': lswitch_name,
            'direction': direction,
            'priority': OVN_QOS_DEFAULT_RULE_PRIORITY,
            'match': match
        }

        if delete:
            # Any specific rule parameter is left undefined.
            return ovn_qos_rule

        for rule_type, rule in rules.items():
            if rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT:
                ovn_qos_rule['rate'] = rule['max_kbps']
                if rule.get('max_burst_kbps'):
                    ovn_qos_rule['burst'] = rule['max_burst_kbps']
            elif rule_type == qos_consts.RULE_TYPE_DSCP_MARKING:
                ovn_qos_rule.update({'dscp': rule['dscp_mark']})

        return ovn_qos_rule
Example #16
0
 def _find_nat_rule(self, router_id, external_ip, logical_ip=None,
                    nat_type='dnat_and_snat'):
     rules = self.nb_api.get_lrouter_nat_rules(utils.ovn_name(router_id))
     return next((r for r in rules
                  if r['type'] == nat_type and
                  r['external_ip'] == external_ip and
                  (not logical_ip or r['logical_ip'] == logical_ip)),
                 None)
Example #17
0
    def get_lrouter(self, lrouter_name):
        if uuidutils.is_uuid_like(lrouter_name):
            lrouter_name = utils.ovn_name(lrouter_name)

        # TODO(lucasagomes): Use lr_get() once we start refactoring this
        # API to use methods from ovsdbapp.
        lr = self.db_find_rows('Logical_Router', ('name', '=', lrouter_name))
        result = lr.execute(check_error=True)
        return result[0] if result else None
Example #18
0
    def get_floatingip_by_ips(self, router_id, logical_ip, external_ip):
        if not all([router_id, logical_ip, external_ip]):
            return

        for nat in self.get_lrouter_nat_rules(utils.ovn_name(router_id)):
            if (nat['type'] == 'dnat_and_snat'
                    and nat['logical_ip'] == logical_ip
                    and nat['external_ip'] == external_ip):
                return nat
Example #19
0
    def _get_lbs_and_ls(self, nb_ovn, payload):
        rtr_name = ovn_utils.ovn_name(payload.resource_id)
        ovn_lr = nb_ovn.get_lrouter(rtr_name)
        if ovn_lr:
            ext_id_key = ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY
            # Filter only lbs managed by port forwarding plugin
            lr_lbs = [
                lr for lr in ovn_lr.load_balancer if lr.external_ids.get(
                    ext_id_key) == pf_const.PORT_FORWARDING_PLUGIN
            ]
            r_port = payload.metadata.get('port')

            if r_port:
                ls_name = ovn_utils.ovn_name(r_port['network_id'])
                ovn_ls = nb_ovn.get_lswitch(ls_name)
                ls_lbs = ovn_ls.load_balancer
                return lr_lbs, ls_lbs, ls_name
        return [], [], None
Example #20
0
    def test_add_and_remove(self):
        self._check_sgrs(is_enabled=False)
        self.assertEqual([],
                         self.nb_api.meter_list().execute(check_error=True))

        log_obj = self.log_plugin.create_log(self.ctxt, self._log_data())
        for sgr in self.sgrs:
            acl = self._check_acl_log(sgr)
            self.assertEqual(utils.ovn_name(log_obj['id']), acl.name[0])
            meter = self.nb_api.meter_get(
                acl.meter[0]).execute(check_error=True)
            self.assertEqual([True], meter.fair)
            self.assertEqual('pktps', meter.unit)
            self.assertEqual(1, len(meter.bands))
            self.assertEqual(
                {
                    ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
                    log_const.LOGGING_PLUGIN
                }, meter.external_ids)

        self.log_plugin.delete_log(self.ctxt, log_obj['id'])
        self._check_sgrs(is_enabled=False)
        self.assertEqual([],
                         self.nb_api.meter_list().execute(check_error=True))

        log_objs = []
        for sg in self.sgs:
            log_data = self._log_data(sg_id=sg)
            log_objs.append(self.log_plugin.create_log(self.ctxt, log_data))
        self.assertEqual(len(log_objs),
                         len(self.log_plugin.get_logs(self.ctxt)))
        self._check_sgrs(is_enabled=True)

        # Attempt to delete non-existing row
        self.assertRaises(log_exc.LogResourceNotFound,
                          self.log_plugin.delete_log, self.ctxt, log_obj['id'])

        self.log_plugin.delete_log(self.ctxt, log_objs[1]['id'])
        self._check_sgrs(sgrs=self.sg1rs, is_enabled=True)
        self._check_sgrs(sgrs=self.sg2rs, is_enabled=False)
        self._check_sgrs(sgrs=self.sg3rs, is_enabled=True)

        self.log_plugin.delete_log(self.ctxt, log_objs[2]['id'])
        self._check_sgrs(sgrs=self.sg1rs, is_enabled=True)
        self._check_sgrs(sgrs=self.sg2rs, is_enabled=False)
        self._check_sgrs(sgrs=self.sg3rs, is_enabled=False)

        self.log_plugin.delete_log(self.ctxt, log_objs[0]['id'])
        self.assertEqual([], self.log_plugin.get_logs(self.ctxt))
        self._check_sgrs(is_enabled=False)

        # Attempt to delete from empty table
        self.assertRaises(log_exc.LogResourceNotFound,
                          self.log_plugin.delete_log, self.ctxt,
                          log_objs[0]['id'])
Example #21
0
    def get_lswitch(self, lswitch_name):
        # FIXME(lucasagomes): We should refactor those get_*()
        # methods. Some of 'em require the name, others IDs etc... It can
        # be confusing.
        if uuidutils.is_uuid_like(lswitch_name):
            lswitch_name = utils.ovn_name(lswitch_name)

        try:
            return self.lookup('Logical_Switch', lswitch_name)
        except idlutils.RowNotFound:
            return None
Example #22
0
    def update_log(self, context, log_obj):
        """Update a log_obj invocation.

        :param context: current running context information
        :param log_obj: a log object being updated

        """
        LOG.debug("Update_log %s", log_obj)

        pgs = self._pgs_from_log_obj(context, log_obj)
        actions_enabled = self._acl_actions_enabled(log_obj)
        with self.ovn_nb.transaction(check_error=True) as ovn_txn:
            self._set_acls_log(pgs, ovn_txn, actions_enabled,
                               utils.ovn_name(log_obj.id))
Example #23
0
def add_sg_rule_acl_for_port(port, r, match):
    dir_map = {const.INGRESS_DIRECTION: 'to-lport',
               const.EGRESS_DIRECTION: 'from-lport'}
    acl = {"lswitch": utils.ovn_name(port['network_id']),
           "lport": port['id'],
           "priority": ovn_const.ACL_PRIORITY_ALLOW,
           "action": ovn_const.ACL_ACTION_ALLOW_RELATED,
           "log": False,
           "name": [],
           "severity": [],
           "direction": dir_map[r['direction']],
           "match": match,
           "external_ids": {'neutron:lport': port['id'],
                            ovn_const.OVN_SG_RULE_EXT_ID_KEY: r['id']}}
    return acl
Example #24
0
 def get_gateway_chassis_az_hints(self, gateway_name):
     lrp = self.lookup('Logical_Router_Port', gateway_name, default=None)
     if not lrp:
         return []
     router_id = lrp.external_ids.get(ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY,
                                      "")
     lrouter = self.lookup('Logical_Router',
                           utils.ovn_name(router_id),
                           default=None)
     if not lrouter:
         return []
     az_string = lrouter.external_ids.get(ovn_const.OVN_AZ_HINTS_EXT_ID_KEY,
                                          "")
     if not az_string:
         return []
     return az_string.split(",")
Example #25
0
 def from_neutron_port(port):
     """Create a fake ovn port based on a neutron port."""
     external_ids = {
         ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY:
             ovn_utils.ovn_name(port['network_id']),
         ovn_const.OVN_SG_IDS_EXT_ID_KEY:
             ' '.join(port['security_groups']),
         ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
             port.get('device_owner', '')}
     addresses = [port['mac_address'], ]
     addresses += [x['ip_address'] for x in port.get('fixed_ips', [])]
     port_security = (
         addresses + [x['ip_address'] for x in
                      port.get('allowed_address_pairs', [])])
     return FakeOVNPort.create_one_port(
         {'external_ids': external_ids, 'addresses': addresses,
          'port_security': port_security})
Example #26
0
def drop_all_ip_traffic_for_port(port):
    acl_list = []
    for direction, p in (('from-lport', 'inport'),
                         ('to-lport', 'outport')):
        lswitch = utils.ovn_name(port['network_id'])
        lport = port['id']
        acl = {"lswitch": lswitch, "lport": lport,
               "priority": ovn_const.ACL_PRIORITY_DROP,
               "action": ovn_const.ACL_ACTION_DROP,
               "log": False,
               "name": [],
               "severity": [],
               "direction": direction,
               "match": '%s == "%s" && ip' % (p, port['id']),
               "external_ids": {'neutron:lport': port['id']}}
        acl_list.append(acl)
    return acl_list
Example #27
0
    def _test_external_port_update_switchdev(self, vnic_type):
        net_id = self.n1['network']['id']
        port_data = {
            'port': {
                'network_id': net_id,
                'tenant_id': self._tenant_id,
                portbindings.VNIC_TYPE: vnic_type
            }
        }

        # Create a VNIC_DIRECT[_PHYSICAL] type port without the "switchdev"
        # capability and assert that it's an "external" port
        port_req = self.new_create_request('ports', port_data, self.fmt)
        port_res = port_req.get_response(self.api)
        port = self.deserialize(self.fmt, port_res)['port']

        ovn_port = self._find_port_row_by_name(port['id'])
        self.assertEqual(ovn_const.LSP_TYPE_EXTERNAL, ovn_port.type)
        self.assertEqual(1, len(ovn_port.ha_chassis_group))
        self.assertEqual(utils.ovn_name(net_id),
                         str(ovn_port.ha_chassis_group[0].name))

        # Now, update the port to add a "switchdev" capability and make
        # sure it's not treated as an "external" port anymore nor it's
        # included in a HA Chassis Group
        port_upt_data = {
            'port': {
                ovn_const.OVN_PORT_BINDING_PROFILE: {
                    'capabilities': [ovn_const.PORT_CAP_SWITCHDEV]
                }
            }
        }
        port_req = self.new_update_request('ports', port_upt_data, port['id'],
                                           self.fmt)
        port_res = port_req.get_response(self.api)
        port = self.deserialize(self.fmt, port_res)['port']

        ovn_port = self._find_port_row_by_name(port['id'])
        # When "switchdev" is set, we should treat it as a normal
        # port instead of "external" type
        self.assertEqual("", ovn_port.type)
        # Assert the poer hasn't been added to any HA Chassis Group either
        self.assertEqual(0, len(ovn_port.ha_chassis_group))
Example #28
0
    def update_floatingip(self, txn, floatingip):
        router_id = floatingip.get('router_id')
        qos_policy_id = floatingip.get('qos_policy_id')
        if floatingip['floating_network_id']:
            lswitch_name = utils.ovn_name(floatingip['floating_network_id'])
            txn.add(
                self._driver._nb_idl.qos_del_ext_ids(
                    lswitch_name,
                    {ovn_const.OVN_FIP_EXT_ID_KEY: floatingip['id']}))

        if not (router_id and qos_policy_id):
            return

        admin_context = n_context.get_admin_context()
        router_db = self._plugin_l3._get_router(admin_context, router_id)
        gw_port_id = router_db.get('gw_port_id')
        if not gw_port_id:
            return

        if ovn_conf.is_ovn_distributed_floating_ip():
            # DVR, floating IP GW is in the same compute node as private port.
            resident_port = floatingip['port_id']
        else:
            # Non-DVR, floating IP GW is located where chassisredirect lrp is.
            resident_port = utils.ovn_cr_lrouter_port_name(gw_port_id)

        qos_rules = self._qos_rules(admin_context, qos_policy_id)
        for direction, rules in qos_rules.items():
            ovn_rule = self._ovn_qos_rule(
                direction,
                rules,
                gw_port_id,
                floatingip['floating_network_id'],
                fip_id=floatingip['id'],
                ip_address=floatingip['floating_ip_address'],
                resident_port=resident_port)
            if ovn_rule:
                txn.add(self._driver._nb_idl.qos_add(**ovn_rule))
Example #29
0
    def delete_log(self, context, log_obj):
        """Delete a log_obj invocation.

        :param context: current running context information
        :param log_obj: a log_object being deleted

        """
        LOG.debug("Delete_log %s", log_obj)

        # If we are removing the last log_obj, let's clear log from all acls.
        # This is a simple way of ensuring that no acl logs are left behind!
        log_objs = self._get_logs(context)
        if not log_objs or (len(log_objs) == 1
                            and log_objs[0].id == log_obj.id):
            pgs = self._pgs_all()
            with self.ovn_nb.transaction(check_error=True) as ovn_txn:
                self._remove_acls_log(pgs, ovn_txn)
                ovn_txn.add(
                    self.ovn_nb.meter_del(self.meter_name, if_exists=True))
            LOG.info("All ACL logs cleared after deletion of log_obj %s",
                     log_obj.id)
            return

        # Remove log_obj and revisit all remaining ones, since the acls that
        # were serving the removed log_obj may be usable by the remaining
        # log_objs.
        pgs = self._pgs_from_log_obj(context, log_obj)
        with self.ovn_nb.transaction(check_error=True) as ovn_txn:
            self._remove_acls_log(pgs, ovn_txn, utils.ovn_name(log_obj.id))

        # TODO(flaviof): We needed to break this second part into a separate
        # transaction because logic that determines the value of the 'freed up'
        # acl rows will not see the modified rows unless it was inside an an
        # idl command.
        with self.ovn_nb.transaction(check_error=True) as ovn_txn:
            self._update_log_objs(
                context, ovn_txn,
                [lo for lo in log_objs if lo.id != log_obj.id])
Example #30
0
class TestNBImplIdlOvn(TestDBImplIdlOvn):

    fake_set = {
        'lswitches': [{
            'name': utils.ovn_name('ls-id-1'),
            'external_ids': {
                ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-1'
            }
        }, {
            'name': utils.ovn_name('ls-id-2'),
            'external_ids': {
                ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-2'
            }
        }, {
            'name': utils.ovn_name('ls-id-3'),
            'external_ids': {
                ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-3'
            }
        }, {
            'name': 'ls-id-4',
            'external_ids': {
                'not-neutron:network_name': 'ls-name-4'
            }
        }, {
            'name': utils.ovn_name('ls-id-5'),
            'external_ids': {
                ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'ls-name-5'
            }
        }],
        'lswitch_ports': [{
            'name': 'lsp-id-11',
            'addresses': ['10.0.1.1'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-11'
            }
        }, {
            'name': 'lsp-id-12',
            'addresses': ['10.0.1.2'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-12'
            }
        }, {
            'name': 'lsp-rp-id-1',
            'addresses': ['10.0.1.254'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-1'
            },
            'options': {
                'router-port': utils.ovn_lrouter_port_name('orp-id-a1')
            }
        }, {
            'name': 'provnet-ls-id-1',
            'addresses': ['unknown'],
            'external_ids': {},
            'options': {
                'network_name': 'physnet1'
            }
        }, {
            'name': 'lsp-id-21',
            'addresses': ['10.0.2.1'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-21'
            }
        }, {
            'name': 'lsp-id-22',
            'addresses': ['10.0.2.2'],
            'external_ids': {}
        }, {
            'name': 'lsp-id-23',
            'addresses': ['10.0.2.3'],
            'external_ids': {
                'not-neutron:port_name': 'lsp-name-23'
            }
        }, {
            'name': 'lsp-rp-id-2',
            'addresses': ['10.0.2.254'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-2'
            },
            'options': {
                'router-port': utils.ovn_lrouter_port_name('orp-id-a2')
            }
        }, {
            'name': 'provnet-ls-id-2',
            'addresses': ['unknown'],
            'external_ids': {},
            'options': {
                'network_name': 'physnet2'
            }
        }, {
            'name': 'lsp-id-31',
            'addresses': ['10.0.3.1'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-31'
            }
        }, {
            'name': 'lsp-id-32',
            'addresses': ['10.0.3.2'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-32'
            }
        }, {
            'name': 'lsp-rp-id-3',
            'addresses': ['10.0.3.254'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-3'
            },
            'options': {
                'router-port': utils.ovn_lrouter_port_name('orp-id-a3')
            }
        }, {
            'name': 'lsp-vpn-id-3',
            'addresses': ['10.0.3.253'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-3'
            }
        }, {
            'name': 'lsp-id-41',
            'addresses': ['20.0.1.1'],
            'external_ids': {
                'not-neutron:port_name': 'lsp-name-41'
            }
        }, {
            'name': 'lsp-rp-id-4',
            'addresses': ['20.0.1.254'],
            'external_ids': {},
            'options': {
                'router-port': 'xrp-id-b1'
            }
        }, {
            'name': 'lsp-id-51',
            'addresses': ['20.0.2.1'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-51'
            }
        }, {
            'name': 'lsp-id-52',
            'addresses': ['20.0.2.2'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-name-52'
            }
        }, {
            'name': 'lsp-rp-id-5',
            'addresses': ['20.0.2.254'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-rp-name-5'
            },
            'options': {
                'router-port': utils.ovn_lrouter_port_name('orp-id-b2')
            }
        }, {
            'name': 'lsp-vpn-id-5',
            'addresses': ['20.0.2.253'],
            'external_ids': {
                ovn_const.OVN_PORT_NAME_EXT_ID_KEY: 'lsp-vpn-name-5'
            }
        }],
        'lrouters': [{
            'name': utils.ovn_name('lr-id-a'),
            'external_ids': {
                ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-a'
            }
        }, {
            'name': utils.ovn_name('lr-id-b'),
            'external_ids': {
                ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-b'
            }
        }, {
            'name': utils.ovn_name('lr-id-c'),
            'external_ids': {
                ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-c'
            }
        }, {
            'name': utils.ovn_name('lr-id-d'),
            'external_ids': {
                ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-d'
            }
        }, {
            'name': utils.ovn_name('lr-id-e'),
            'external_ids': {
                ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-name-e'
            }
        }],
        'lrouter_ports': [{
            'name': utils.ovn_lrouter_port_name('orp-id-a1'),
            'external_ids': {},
            'networks': ['10.0.1.0/24'],
            'options': {
                ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1'
            }
        }, {
            'name': utils.ovn_lrouter_port_name('orp-id-a2'),
            'external_ids': {},
            'networks': ['10.0.2.0/24'],
            'options': {
                ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-1'
            }
        }, {
            'name': utils.ovn_lrouter_port_name('orp-id-a3'),
            'external_ids': {},
            'networks': ['10.0.3.0/24'],
            'options': {
                ovn_const.OVN_GATEWAY_CHASSIS_KEY:
                ovn_const.OVN_GATEWAY_INVALID_CHASSIS
            }
        }, {
            'name': 'xrp-id-b1',
            'external_ids': {},
            'networks': ['20.0.1.0/24']
        }, {
            'name': utils.ovn_lrouter_port_name('orp-id-b2'),
            'external_ids': {},
            'networks': ['20.0.2.0/24'],
            'options': {
                ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'
            }
        }, {
            'name': utils.ovn_lrouter_port_name('orp-id-b3'),
            'external_ids': {},
            'networks': ['20.0.3.0/24'],
            'options': {}
        }],
        'static_routes': [{
            'ip_prefix': '20.0.0.0/16',
            'nexthop': '10.0.3.253'
        }, {
            'ip_prefix': '10.0.0.0/16',
            'nexthop': '20.0.2.253'
        }],
        'nats': [{
            'external_ip': '10.0.3.1',
            'logical_ip': '20.0.0.0/16',
            'type': 'snat'
        }, {
            'external_ip': '20.0.2.1',
            'logical_ip': '10.0.0.0/24',
            'type': 'snat'
        }, {
            'external_ip': '20.0.2.4',
            'logical_ip': '10.0.0.4',
            'type': 'dnat_and_snat',
            'external_mac': [],
            'logical_port': []
        }, {
            'external_ip': '20.0.2.5',
            'logical_ip': '10.0.0.5',
            'type': 'dnat_and_snat',
            'external_mac': ['00:01:02:03:04:05'],
            'logical_port': ['lsp-id-001']
        }],
        'acls': [{
            'unit_test_id': 1,
            'action': 'allow-related',
            'direction': 'from-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-11'
            },
            'match': 'inport == "lsp-id-11" && ip4'
        }, {
            'unit_test_id': 2,
            'action': 'allow-related',
            'direction': 'to-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-11'
            },
            'match': 'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1'
        }, {
            'unit_test_id': 3,
            'action': 'allow-related',
            'direction': 'from-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-12'
            },
            'match': 'inport == "lsp-id-12" && ip4'
        }, {
            'unit_test_id': 4,
            'action': 'allow-related',
            'direction': 'to-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-12'
            },
            'match': 'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1'
        }, {
            'unit_test_id': 5,
            'action': 'allow-related',
            'direction': 'from-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-21'
            },
            'match': 'inport == "lsp-id-21" && ip4'
        }, {
            'unit_test_id': 6,
            'action': 'allow-related',
            'direction': 'to-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-21'
            },
            'match': 'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2'
        }, {
            'unit_test_id': 7,
            'action': 'allow-related',
            'direction': 'from-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-41'
            },
            'match': 'inport == "lsp-id-41" && ip4'
        }, {
            'unit_test_id': 8,
            'action': 'allow-related',
            'direction': 'to-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-41'
            },
            'match': 'outport == "lsp-id-41" && ip4.src == $as_ip4_id_4'
        }, {
            'unit_test_id': 9,
            'action': 'allow-related',
            'direction': 'from-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-52'
            },
            'match': 'inport == "lsp-id-52" && ip4'
        }, {
            'unit_test_id': 10,
            'action': 'allow-related',
            'direction': 'to-lport',
            'external_ids': {
                'neutron:lport': 'lsp-id-52'
            },
            'match': 'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5'
        }],
        'dhcp_options': [{
            'cidr': '10.0.1.0/24',
            'external_ids': {
                'subnet_id': 'subnet-id-10-0-1-0'
            },
            'options': {
                'mtu': '1442',
                'router': '10.0.1.254'
            }
        }, {
            'cidr': '10.0.2.0/24',
            'external_ids': {
                'subnet_id': 'subnet-id-10-0-2-0'
            },
            'options': {
                'mtu': '1442',
                'router': '10.0.2.254'
            }
        }, {
            'cidr': '10.0.1.0/26',
            'external_ids': {
                'subnet_id': 'subnet-id-10-0-1-0',
                'port_id': 'lsp-vpn-id-3'
            },
            'options': {
                'mtu': '1442',
                'router': '10.0.1.1'
            }
        }, {
            'cidr': '20.0.1.0/24',
            'external_ids': {
                'subnet_id': 'subnet-id-20-0-1-0'
            },
            'options': {
                'mtu': '1442',
                'router': '20.0.1.254'
            }
        }, {
            'cidr': '20.0.2.0/24',
            'external_ids': {
                'subnet_id': 'subnet-id-20-0-2-0',
                'port_id': 'lsp-vpn-id-5'
            },
            'options': {
                'mtu': '1442',
                'router': '20.0.2.254'
            }
        }, {
            'cidr': '2001:dba::/64',
            'external_ids': {
                'subnet_id': 'subnet-id-2001-dba',
                'port_id': 'lsp-vpn-id-5'
            },
            'options': {
                'server_id': '12:34:56:78:9a:bc'
            }
        }, {
            'cidr': '30.0.1.0/24',
            'external_ids': {
                'port_id': 'port-id-30-0-1-0'
            },
            'options': {
                'mtu': '1442',
                'router': '30.0.2.254'
            }
        }, {
            'cidr': '30.0.2.0/24',
            'external_ids': {},
            'options': {}
        }],
        'address_sets': [{
            'name': '$as_ip4_id_1',
            'addresses': ['10.0.1.1', '10.0.1.2'],
            'external_ids': {
                ovn_const.OVN_SG_EXT_ID_KEY: 'id_1'
            }
        }, {
            'name': '$as_ip4_id_2',
            'addresses': ['10.0.2.1'],
            'external_ids': {
                ovn_const.OVN_SG_EXT_ID_KEY: 'id_2'
            }
        }, {
            'name': '$as_ip4_id_3',
            'addresses': ['10.0.3.1', '10.0.3.2'],
            'external_ids': {
                ovn_const.OVN_SG_EXT_ID_KEY: 'id_3'
            }
        }, {
            'name': '$as_ip4_id_4',
            'addresses': ['20.0.1.1', '20.0.1.2'],
            'external_ids': {}
        }, {
            'name': '$as_ip4_id_5',
            'addresses': ['20.0.2.1', '20.0.2.2'],
            'external_ids': {
                ovn_const.OVN_SG_EXT_ID_KEY: 'id_5'
            }
        }],
    }

    fake_associations = {
        'lstolsp': {
            utils.ovn_name('ls-id-1'):
            ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1', 'provnet-ls-id-1'],
            utils.ovn_name('ls-id-2'): [
                'lsp-id-21', 'lsp-id-22', 'lsp-id-23', 'lsp-rp-id-2',
                'provnet-ls-id-2'
            ],
            utils.ovn_name('ls-id-3'):
            ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'],
            'ls-id-4': ['lsp-id-41', 'lsp-rp-id-4'],
            utils.ovn_name('ls-id-5'):
            ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5']
        },
        'lrtolrp': {
            utils.ovn_name('lr-id-a'): [
                utils.ovn_lrouter_port_name('orp-id-a1'),
                utils.ovn_lrouter_port_name('orp-id-a2'),
                utils.ovn_lrouter_port_name('orp-id-a3')
            ],
            utils.ovn_name('lr-id-b'):
            ['xrp-id-b1',
             utils.ovn_lrouter_port_name('orp-id-b2')]
        },
        'lrtosroute': {
            utils.ovn_name('lr-id-a'): ['20.0.0.0/16'],
            utils.ovn_name('lr-id-b'): ['10.0.0.0/16']
        },
        'lrtonat': {
            utils.ovn_name('lr-id-a'): ['10.0.3.1'],
            utils.ovn_name('lr-id-b'): ['20.0.2.1', '20.0.2.4', '20.0.2.5'],
        },
        'lstoacl': {
            utils.ovn_name('ls-id-1'): [1, 2, 3, 4],
            utils.ovn_name('ls-id-2'): [5, 6],
            'ls-id-4': [7, 8],
            utils.ovn_name('ls-id-5'): [9, 10]
        }
    }

    def setUp(self):
        super(TestNBImplIdlOvn, self).setUp()

        self.lswitch_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.lsp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.lrouter_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.lrp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.sroute_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.nat_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.acl_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.dhcp_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self.address_set_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()

        self._tables = {}
        self._tables['Logical_Switch'] = self.lswitch_table
        self._tables['Logical_Switch_Port'] = self.lsp_table
        self._tables['Logical_Router'] = self.lrouter_table
        self._tables['Logical_Router_Port'] = self.lrp_table
        self._tables['Logical_Router_Static_Route'] = self.sroute_table
        self._tables['ACL'] = self.acl_table
        self._tables['DHCP_Options'] = self.dhcp_table
        self._tables['Address_Set'] = self.address_set_table

        with mock.patch.object(impl_idl_ovn,
                               'get_connection',
                               return_value=mock.Mock()):
            with mock.patch.object(ovs_idl.Backend,
                                   'autocreate_indices',
                                   create=True):
                impl_idl_ovn.OvsdbNbOvnIdl.ovsdb_connection = None
                self.nb_ovn_idl = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock())

        self.nb_ovn_idl.idl.tables = self._tables

    def _load_nb_db(self):
        # Load Switches and Switch Ports
        fake_lswitches = TestNBImplIdlOvn.fake_set['lswitches']
        self._load_ovsdb_fake_rows(self.lswitch_table, fake_lswitches)
        fake_lsps = TestNBImplIdlOvn.fake_set['lswitch_ports']
        self._load_ovsdb_fake_rows(self.lsp_table, fake_lsps)
        # Associate switches and ports
        self._construct_ovsdb_references(
            TestNBImplIdlOvn.fake_associations['lstolsp'], self.lswitch_table,
            self.lsp_table, 'name', 'name', 'ports')
        # Load Routers and Router Ports
        fake_lrouters = TestNBImplIdlOvn.fake_set['lrouters']
        self._load_ovsdb_fake_rows(self.lrouter_table, fake_lrouters)
        fake_lrps = TestNBImplIdlOvn.fake_set['lrouter_ports']
        self._load_ovsdb_fake_rows(self.lrp_table, fake_lrps)
        # Associate routers and router ports
        self._construct_ovsdb_references(
            TestNBImplIdlOvn.fake_associations['lrtolrp'], self.lrouter_table,
            self.lrp_table, 'name', 'name', 'ports')
        # Load static routes
        fake_sroutes = TestNBImplIdlOvn.fake_set['static_routes']
        self._load_ovsdb_fake_rows(self.sroute_table, fake_sroutes)
        # Associate routers and static routes
        self._construct_ovsdb_references(
            TestNBImplIdlOvn.fake_associations['lrtosroute'],
            self.lrouter_table, self.sroute_table, 'name', 'ip_prefix',
            'static_routes')
        # Load nats
        fake_nats = TestNBImplIdlOvn.fake_set['nats']
        self._load_ovsdb_fake_rows(self.nat_table, fake_nats)
        # Associate routers and nats
        self._construct_ovsdb_references(
            TestNBImplIdlOvn.fake_associations['lrtonat'], self.lrouter_table,
            self.nat_table, 'name', 'external_ip', 'nat')
        # Load acls
        fake_acls = TestNBImplIdlOvn.fake_set['acls']
        self._load_ovsdb_fake_rows(self.acl_table, fake_acls)
        # Associate switches and acls
        self._construct_ovsdb_references(
            TestNBImplIdlOvn.fake_associations['lstoacl'], self.lswitch_table,
            self.acl_table, 'name', 'unit_test_id', 'acls')
        # Load dhcp options
        fake_dhcp_options = TestNBImplIdlOvn.fake_set['dhcp_options']
        self._load_ovsdb_fake_rows(self.dhcp_table, fake_dhcp_options)
        # Load address sets
        fake_address_sets = TestNBImplIdlOvn.fake_set['address_sets']
        self._load_ovsdb_fake_rows(self.address_set_table, fake_address_sets)

    @mock.patch.object(ovs_idl.Backend,
                       'autocreate_indices',
                       mock.Mock(),
                       create=True)
    @mock.patch.object(impl_idl_ovn.OvsdbNbOvnIdl, 'ovsdb_connection', None)
    @mock.patch.object(impl_idl_ovn, 'get_connection', mock.Mock())
    def test_setting_ovsdb_probe_timeout_default_value(self):
        inst = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock())
        inst.idl._session.reconnect.set_probe_interval.assert_called_with(
            60000)

    @mock.patch.object(ovs_idl.Backend,
                       'autocreate_indices',
                       mock.Mock(),
                       create=True)
    @mock.patch.object(impl_idl_ovn.OvsdbNbOvnIdl, 'ovsdb_connection', None)
    @mock.patch.object(impl_idl_ovn, 'get_connection', mock.Mock())
    @mock.patch.object(ovn_conf, 'get_ovn_ovsdb_probe_interval')
    def test_setting_ovsdb_probe_timeout(self, mock_get_probe_interval):
        mock_get_probe_interval.return_value = 5000
        inst = impl_idl_ovn.OvsdbNbOvnIdl(mock.Mock())
        inst.idl._session.reconnect.set_probe_interval.assert_called_with(5000)

    def test_get_all_logical_switches_with_ports(self):
        # Test empty
        mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
        self.assertItemsEqual(mapping, {})
        # Test loaded values
        self._load_nb_db()
        mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
        expected = [{
            'name': utils.ovn_name('ls-id-1'),
            'ports': ['lsp-id-11', 'lsp-id-12', 'lsp-rp-id-1'],
            'provnet_port': 'provnet-ls-id-1'
        }, {
            'name': utils.ovn_name('ls-id-2'),
            'ports': ['lsp-id-21', 'lsp-rp-id-2'],
            'provnet_port': 'provnet-ls-id-2'
        }, {
            'name':
            utils.ovn_name('ls-id-3'),
            'ports': ['lsp-id-31', 'lsp-id-32', 'lsp-rp-id-3', 'lsp-vpn-id-3'],
            'provnet_port':
            None
        }, {
            'name':
            utils.ovn_name('ls-id-5'),
            'ports': ['lsp-id-51', 'lsp-id-52', 'lsp-rp-id-5', 'lsp-vpn-id-5'],
            'provnet_port':
            None
        }]
        self.assertItemsEqual(mapping, expected)

    def test_get_all_logical_routers_with_rports(self):
        # Test empty
        mapping = self.nb_ovn_idl.get_all_logical_switches_with_ports()
        self.assertItemsEqual(mapping, {})
        # Test loaded values
        self._load_nb_db()
        mapping = self.nb_ovn_idl.get_all_logical_routers_with_rports()
        expected = [{
            'name':
            'lr-id-a',
            'ports': {
                'orp-id-a1': ['10.0.1.0/24'],
                'orp-id-a2': ['10.0.2.0/24'],
                'orp-id-a3': ['10.0.3.0/24']
            },
            'static_routes': [{
                'destination': '20.0.0.0/16',
                'nexthop': '10.0.3.253'
            }],
            'snats': [{
                'external_ip': '10.0.3.1',
                'logical_ip': '20.0.0.0/16',
                'type': 'snat'
            }],
            'dnat_and_snats': []
        }, {
            'name':
            'lr-id-b',
            'ports': {
                'xrp-id-b1': ['20.0.1.0/24'],
                'orp-id-b2': ['20.0.2.0/24']
            },
            'static_routes': [{
                'destination': '10.0.0.0/16',
                'nexthop': '20.0.2.253'
            }],
            'snats': [{
                'external_ip': '20.0.2.1',
                'logical_ip': '10.0.0.0/24',
                'type': 'snat'
            }],
            'dnat_and_snats': [{
                'external_ip': '20.0.2.4',
                'logical_ip': '10.0.0.4',
                'type': 'dnat_and_snat'
            }, {
                'external_ip': '20.0.2.5',
                'logical_ip': '10.0.0.5',
                'type': 'dnat_and_snat',
                'external_mac': '00:01:02:03:04:05',
                'logical_port': 'lsp-id-001'
            }]
        }, {
            'name': 'lr-id-c',
            'ports': {},
            'static_routes': [],
            'snats': [],
            'dnat_and_snats': []
        }, {
            'name': 'lr-id-d',
            'ports': {},
            'static_routes': [],
            'snats': [],
            'dnat_and_snats': []
        }, {
            'name': 'lr-id-e',
            'ports': {},
            'static_routes': [],
            'snats': [],
            'dnat_and_snats': []
        }]
        self.assertItemsEqual(mapping, expected)

    def test_get_acls_for_lswitches(self):
        self._load_nb_db()
        # Test neutron switches
        lswitches = ['ls-id-1', 'ls-id-2', 'ls-id-3', 'ls-id-5']
        acl_values, acl_objs, lswitch_ovsdb_dict = \
            self.nb_ovn_idl.get_acls_for_lswitches(lswitches)
        excepted_acl_values = {
            'lsp-id-11': [{
                'action': 'allow-related',
                'lport': 'lsp-id-11',
                'lswitch': 'neutron-ls-id-1',
                'external_ids': {
                    'neutron:lport': 'lsp-id-11'
                },
                'direction': 'from-lport',
                'match': 'inport == "lsp-id-11" && ip4'
            }, {
                'action':
                'allow-related',
                'lport':
                'lsp-id-11',
                'lswitch':
                'neutron-ls-id-1',
                'external_ids': {
                    'neutron:lport': 'lsp-id-11'
                },
                'direction':
                'to-lport',
                'match':
                'outport == "lsp-id-11" && ip4.src == $as_ip4_id_1'
            }],
            'lsp-id-12': [{
                'action': 'allow-related',
                'lport': 'lsp-id-12',
                'lswitch': 'neutron-ls-id-1',
                'external_ids': {
                    'neutron:lport': 'lsp-id-12'
                },
                'direction': 'from-lport',
                'match': 'inport == "lsp-id-12" && ip4'
            }, {
                'action':
                'allow-related',
                'lport':
                'lsp-id-12',
                'lswitch':
                'neutron-ls-id-1',
                'external_ids': {
                    'neutron:lport': 'lsp-id-12'
                },
                'direction':
                'to-lport',
                'match':
                'outport == "lsp-id-12" && ip4.src == $as_ip4_id_1'
            }],
            'lsp-id-21': [{
                'action': 'allow-related',
                'lport': 'lsp-id-21',
                'lswitch': 'neutron-ls-id-2',
                'external_ids': {
                    'neutron:lport': 'lsp-id-21'
                },
                'direction': 'from-lport',
                'match': 'inport == "lsp-id-21" && ip4'
            }, {
                'action':
                'allow-related',
                'lport':
                'lsp-id-21',
                'lswitch':
                'neutron-ls-id-2',
                'external_ids': {
                    'neutron:lport': 'lsp-id-21'
                },
                'direction':
                'to-lport',
                'match':
                'outport == "lsp-id-21" && ip4.src == $as_ip4_id_2'
            }],
            'lsp-id-52': [{
                'action': 'allow-related',
                'lport': 'lsp-id-52',
                'lswitch': 'neutron-ls-id-5',
                'external_ids': {
                    'neutron:lport': 'lsp-id-52'
                },
                'direction': 'from-lport',
                'match': 'inport == "lsp-id-52" && ip4'
            }, {
                'action':
                'allow-related',
                'lport':
                'lsp-id-52',
                'lswitch':
                'neutron-ls-id-5',
                'external_ids': {
                    'neutron:lport': 'lsp-id-52'
                },
                'direction':
                'to-lport',
                'match':
                'outport == "lsp-id-52" && ip4.src == $as_ip4_id_5'
            }]
        }
        self.assertItemsEqual(acl_values, excepted_acl_values)
        self.assertEqual(len(acl_objs), 8)
        self.assertEqual(len(lswitch_ovsdb_dict), len(lswitches))

        # Test non-neutron switches
        lswitches = ['ls-id-4']
        acl_values, acl_objs, lswitch_ovsdb_dict = \
            self.nb_ovn_idl.get_acls_for_lswitches(lswitches)
        self.assertItemsEqual(acl_values, {})
        self.assertEqual(len(acl_objs), 0)
        self.assertEqual(len(lswitch_ovsdb_dict), 0)

    def test_get_all_chassis_gateway_bindings(self):
        self._load_nb_db()
        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings()
        expected = {
            'host-1': [
                utils.ovn_lrouter_port_name('orp-id-a1'),
                utils.ovn_lrouter_port_name('orp-id-a2')
            ],
            'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')],
            ovn_const.OVN_GATEWAY_INVALID_CHASSIS:
            [utils.ovn_name('orp-id-a3')]
        }
        self.assertItemsEqual(bindings, expected)

        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([])
        self.assertItemsEqual(bindings, expected)

        bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings(['host-1'])
        expected = {
            'host-1': [
                utils.ovn_lrouter_port_name('orp-id-a1'),
                utils.ovn_lrouter_port_name('orp-id-a2')
            ]
        }
        self.assertItemsEqual(bindings, expected)

    def test_get_gateway_chassis_binding(self):
        self._load_nb_db()
        chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
            utils.ovn_lrouter_port_name('orp-id-a1'))
        self.assertEqual(chassis, ['host-1'])
        chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
            utils.ovn_lrouter_port_name('orp-id-b2'))
        self.assertEqual(chassis, ['host-2'])
        chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
            utils.ovn_lrouter_port_name('orp-id-a3'))
        self.assertEqual(chassis, ['neutron-ovn-invalid-chassis'])
        chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
            utils.ovn_lrouter_port_name('orp-id-b3'))
        self.assertEqual([], chassis)
        chassis = self.nb_ovn_idl.get_gateway_chassis_binding('bad')
        self.assertEqual([], chassis)

    def test_get_unhosted_gateways(self):
        self._load_nb_db()
        # Port physnet-dict
        port_physnet_dict = {
            'orp-id-a1': 'physnet1',  # scheduled
            'orp-id-a2': 'physnet1',  # scheduled
            'orp-id-a3': 'physnet1',  # not scheduled
            'orp-id-b6': 'physnet2'
        }  # not scheduled
        # Test only that orp-id-a3 is to be scheduled.
        # Rest ports don't have required chassis (physnet2)
        # or are already scheduled.
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet3'
            }, ['host-1', 'host-2'])
        expected = ['lrp-orp-id-a3']
        self.assertItemsEqual(unhosted_gateways, expected)
        # Test both host-1, host-2 in valid list
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet2'
            }, ['host-1', 'host-2'])
        expected = ['lrp-orp-id-a3', 'lrp-orp-id-b6']
        self.assertItemsEqual(unhosted_gateways, expected)

    def test_get_unhosted_gateways_deleted_physnet(self):
        self._load_nb_db()
        # The LRP is on host-2 now
        router_row = self._find_ovsdb_fake_row(self.lrp_table, 'name',
                                               'lrp-orp-id-a1')
        setattr(router_row, 'options',
                {ovn_const.OVN_GATEWAY_CHASSIS_KEY: 'host-2'})
        port_physnet_dict = {'orp-id-a1': 'physnet1'}
        # Lets spoof that physnet1 is deleted from host-2.
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet3'
            }, ['host-1', 'host-2'])
        # Make sure that lrp is rescheduled, because host-1 has physet1
        expected = ['lrp-orp-id-a1']
        self.assertItemsEqual(unhosted_gateways, expected)
        # Spoof that there is no valid host with required physnet.
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            port_physnet_dict, {
                'host-1': 'physnet4',
                'host-2': 'physnet3'
            }, ['host-1', 'host-2'])
        self.assertItemsEqual(unhosted_gateways, [])

    def _test_get_unhosted_gateway_max_chassis(self, r):
        gw_chassis_table = fakes.FakeOvsdbTable.create_one_ovsdb_table()
        self._tables['Gateway_Chassis'] = gw_chassis_table
        gw_chassis = collections.namedtuple('gw_chassis',
                                            'chassis_name priority')
        TestNBImplIdlOvn.fake_set['lrouter_ports'][0]['gateway_chassis'] = [
            gw_chassis(chassis_name='host-%s' % x, priority=x) for x in r
        ]
        self._load_nb_db()
        self.port_physnet_dict = {'orp-id-a1': 'physnet1'}

    def test_get_unhosted_gateway_max_chassis_lack_of_chassis(self):
        self._test_get_unhosted_gateway_max_chassis(r=(1, 3, 5))
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            self.port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet2',
                'host-3': 'physnet1',
                'host-4': 'physnet2',
                'host-5': 'physnet1',
                'host-6': 'physnet2'
            }, ['host-%s' % x for x in range(1, 7)])
        # We don't have required number of chassis
        expected = []
        self.assertItemsEqual(unhosted_gateways, expected)

    def test_get_unhosted_gateway_max_chassis(self):
        # We have required number of chassis, and lrp
        # is hosted everywhere.
        self._test_get_unhosted_gateway_max_chassis(r=range(1, 6))
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            self.port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet1',
                'host-3': 'physnet1',
                'host-4': 'physnet1',
                'host-5': 'physnet1',
                'host-6': 'physnet1'
            }, ['host-%s' % x for x in range(1, 7)])
        expected = []
        self.assertItemsEqual(unhosted_gateways, expected)

    def test_get_unhosed_gateway_schedule_to_max(self):
        # The LRP is not yet scheduled on all chassis
        # but we can schedule on new chassis now.
        self._test_get_unhosted_gateway_max_chassis(r=range(1, 4))
        unhosted_gateways = self.nb_ovn_idl.get_unhosted_gateways(
            self.port_physnet_dict, {
                'host-1': 'physnet1',
                'host-2': 'physnet1',
                'host-3': 'physnet1',
                'host-4': 'physnet1',
                'host-5': 'physnet1',
                'host-6': 'physnet1'
            }, ['host-%s' % x for x in range(1, 7)])
        expected = ['lrp-orp-id-a1']
        self.assertItemsEqual(unhosted_gateways, expected)

    def test_get_subnet_dhcp_options(self):
        self._load_nb_db()
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-10-0-2-0')
        expected_row = self._find_ovsdb_fake_row(self.dhcp_table, 'cidr',
                                                 '10.0.2.0/24')
        self.assertEqual(
            {
                'subnet': {
                    'cidr': expected_row.cidr,
                    'external_ids': expected_row.external_ids,
                    'options': expected_row.options,
                    'uuid': expected_row.uuid
                },
                'ports': []
            }, subnet_options)
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-11-0-2-0')['subnet']
        self.assertIsNone(subnet_options)
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'port-id-30-0-1-0')['subnet']
        self.assertIsNone(subnet_options)

    def test_get_subnet_dhcp_options_with_ports(self):
        # Test empty
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-10-0-1-0', with_ports=True)
        self.assertItemsEqual({'subnet': None, 'ports': []}, subnet_options)
        # Test loaded values
        self._load_nb_db()
        # Test getting both subnet and port dhcp options
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-10-0-1-0', with_ports=True)
        dhcp_rows = [
            self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.1.0/24'),
            self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.1.0/26')
        ]
        expected_rows = [{
            'cidr': dhcp_row.cidr,
            'external_ids': dhcp_row.external_ids,
            'options': dhcp_row.options,
            'uuid': dhcp_row.uuid
        } for dhcp_row in dhcp_rows]
        self.assertItemsEqual(expected_rows, [subnet_options['subnet']] +
                              subnet_options['ports'])
        # Test getting only subnet dhcp options
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-10-0-2-0', with_ports=True)
        dhcp_rows = [
            self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '10.0.2.0/24')
        ]
        expected_rows = [{
            'cidr': dhcp_row.cidr,
            'external_ids': dhcp_row.external_ids,
            'options': dhcp_row.options,
            'uuid': dhcp_row.uuid
        } for dhcp_row in dhcp_rows]
        self.assertItemsEqual(expected_rows, [subnet_options['subnet']] +
                              subnet_options['ports'])
        # Test getting no dhcp options
        subnet_options = self.nb_ovn_idl.get_subnet_dhcp_options(
            'subnet-id-11-0-2-0', with_ports=True)
        self.assertItemsEqual({'subnet': None, 'ports': []}, subnet_options)

    def test_get_subnets_dhcp_options(self):
        self._load_nb_db()

        def get_row_dict(row):
            return {
                'cidr': row.cidr,
                'external_ids': row.external_ids,
                'options': row.options,
                'uuid': row.uuid
            }

        subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options(
            ['subnet-id-10-0-1-0', 'subnet-id-10-0-2-0'])
        expected_rows = [
            get_row_dict(
                self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', cidr))
            for cidr in ('10.0.1.0/24', '10.0.2.0/24')
        ]
        self.assertItemsEqual(expected_rows, subnets_options)

        subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options(
            ['subnet-id-11-0-2-0', 'subnet-id-20-0-1-0'])
        expected_row = get_row_dict(
            self._find_ovsdb_fake_row(self.dhcp_table, 'cidr', '20.0.1.0/24'))
        self.assertItemsEqual([expected_row], subnets_options)

        subnets_options = self.nb_ovn_idl.get_subnets_dhcp_options(
            ['port-id-30-0-1-0', 'fake-not-exist'])
        self.assertEqual([], subnets_options)

    def test_get_all_dhcp_options(self):
        self._load_nb_db()
        dhcp_options = self.nb_ovn_idl.get_all_dhcp_options()
        self.assertEqual(len(dhcp_options['subnets']), 3)
        self.assertEqual(len(dhcp_options['ports_v4']), 2)

    def test_get_address_sets(self):
        self._load_nb_db()
        address_sets = self.nb_ovn_idl.get_address_sets()
        self.assertEqual(len(address_sets), 4)

    def test_get_port_group_not_supported(self):
        self._load_nb_db()
        # Make sure that PG tables doesn't exist in fake db.
        self._tables.pop('Port_Group', None)
        port_group = self.nb_ovn_idl.get_port_group(str(uuid.uuid4()))
        self.assertIsNone(port_group)

    def test_get_port_groups_not_supported(self):
        self._load_nb_db()
        # Make sure that PG tables doesn't exist in fake db.
        self._tables.pop('Port_Group', None)
        port_groups = self.nb_ovn_idl.get_port_groups()
        self.assertEqual({}, port_groups)