Beispiel #1
0
 def new_valve(self, new_dp):
     valve_cl = valve_factory(new_dp)
     if valve_cl is not None:
         return valve_cl(new_dp, self.logname, self.metrics, self.notifier)
     self.logger.error('%s hardware %s must be one of %s', new_dp.name,
                       new_dp.hardware,
                       sorted(list(SUPPORTED_HARDWARE.keys())))
     return None
Beispiel #2
0
 def _apply_configs_new(self, dp_id, new_dp):
     self.logger.info('Add new datapath %s', dpid_log(dp_id))
     valve_cl = valve_factory(new_dp)
     if valve_cl is not None:
         return valve_cl(new_dp, self.logname, self.notifier)
     self.logger.error('%s hardware %s must be one of %s', new_dp.name,
                       new_dp.hardware,
                       sorted(list(SUPPORTED_HARDWARE.keys())))
     return None
Beispiel #3
0
 def new_valve(self, new_dp):
     valve_cl = valve_factory(new_dp)
     if valve_cl is not None:
         return valve_cl(new_dp, self.logname, self.metrics, self.notifier, self.dot1x)
     self.logger.error(
         '%s hardware %s must be one of %s',
         new_dp.name,
         new_dp.hardware,
         sorted(list(SUPPORTED_HARDWARE.keys())))
     return None
Beispiel #4
0
 def _load_configs(self, new_config_file):
     self.config_file = new_config_file
     self.config_hashes, new_dps = dp_parser(new_config_file, self.logname)
     if new_dps is None:
         self.logger.error('new config bad - rejecting')
         return
     deleted_valve_dpids = (set(list(self.valves.keys())) -
                            set([valve.dp_id for valve in new_dps]))
     for new_dp in new_dps:
         dp_id = new_dp.dp_id
         if dp_id in self.valves:
             valve = self.valves[dp_id]
             cold_start, flowmods = valve.reload_config(new_dp)
             # pylint: disable=no-member
             if flowmods:
                 self._send_flow_msgs(new_dp.dp_id, flowmods)
                 if cold_start:
                     self.metrics.faucet_config_reload_cold.labels(
                         dp_id=hex(dp_id)).inc()
                 else:
                     self.metrics.faucet_config_reload_warm.labels(
                         dp_id=hex(dp_id)).inc()
         else:
             # pylint: disable=no-member
             valve_cl = valve_factory(new_dp)
             if valve_cl is None:
                 self.logger.error('%s hardware %s must be one of %s',
                                   new_dp.name, new_dp.hardware,
                                   sorted(list(SUPPORTED_HARDWARE.keys())))
                 continue
             else:
                 valve = valve_cl(new_dp, self.logname)
                 self.valves[dp_id] = valve
             self.logger.info('Add new datapath %s', dpid_log(dp_id))
         self.metrics.reset_dpid(dp_id)
         valve.update_config_metrics(self.metrics)
     for deleted_valve_dpid in deleted_valve_dpids:
         self.logger.info('Deleting de-configured %s',
                          dpid_log(deleted_valve_dpid))
         del self.valves[deleted_valve_dpid]
         ryu_dp = self.dpset.get(deleted_valve_dpid)
         if ryu_dp is not None:
             ryu_dp.close()
     self._bgp.reset(self.valves, self.metrics)
Beispiel #5
0
    def finalize_config(self, dps):
        """Perform consistency checks after initial config parsing."""

        dp_by_name = {}
        vlan_by_name = {}

        def resolve_ports(port_names):
            """Resolve list of ports, by port by name or number."""
            resolved_ports = []
            for port_name in port_names:
                port = self.resolve_port(port_name)
                if port is not None:
                    resolved_ports.append(port)
            return resolved_ports

        def resolve_vlan(vlan_name):
            """Resolve VLAN by name or VID."""
            test_config_condition(not isinstance(vlan_name, (str, int)),
                                  ('VLAN must be type %s or %s not %s' %
                                   (str, int, type(vlan_name))))
            if vlan_name in vlan_by_name:
                return vlan_by_name[vlan_name]
            if vlan_name in self.vlans:
                return self.vlans[vlan_name]
            return None

        def resolve_stack_dps():
            """Resolve DP references in stacking config."""
            port_stack_dp = {}
            for port in self.stack_ports:
                stack_dp = port.stack['dp']
                test_config_condition(stack_dp not in dp_by_name,
                                      ('stack DP %s not defined' % stack_dp))
                port_stack_dp[port] = dp_by_name[stack_dp]
            for port, dp in list(port_stack_dp.items()):
                port.stack['dp'] = dp
                stack_port = dp.resolve_port(port.stack['port'])
                test_config_condition(stack_port is None,
                                      ('stack port %s not defined in DP %s' %
                                       (port.stack['port'], dp.name)))
                port.stack['port'] = stack_port

        def resolve_mirror_destinations():
            """Resolve mirror port references and destinations."""
            mirror_from_port = defaultdict(list)
            for mirror_port in list(self.ports.values()):
                if mirror_port.mirror is not None:
                    mirrored_ports = resolve_ports(mirror_port.mirror)
                    test_config_condition(
                        len(mirrored_ports) != len(mirror_port.mirror),
                        ('port mirror not defined in DP %s' % self.name))
                    for mirrored_port in mirrored_ports:
                        mirror_from_port[mirrored_port].append(mirror_port)

            # TODO: confusingly, mirror at config time means what ports to mirror from.
            # But internally we use as a list of ports to mirror to.
            for mirrored_port, mirror_ports in list(mirror_from_port.items()):
                mirrored_port.mirror = []
                for mirror_port in mirror_ports:
                    mirrored_port.mirror.append(mirror_port.number)
                    mirror_port.output_only = True

        def resolve_override_output_ports():
            """Resolve override output ports."""
            for port_no, port in list(self.ports.items()):
                if port.override_output_port:
                    port.override_output_port = self.resolve_port(
                        port.override_output_port)
                    test_config_condition(
                        not port.override_output_port,
                        ('override_output_port port not defined'))
                    self.ports[port_no] = port

        def resolve_acl(acl_in, vid):
            """Resolve an individual ACL."""
            test_config_condition(acl_in not in self.acls,
                                  ('missing ACL %s in DP: %s' %
                                   (acl_in, self.name)))
            acl = self.acls[acl_in]

            def resolve_port_cb(port_name):
                port = self.resolve_port(port_name)
                if port:
                    return port.number
                return port

            acl.resolve_ports(resolve_port_cb)

            for meter_name in acl.get_meters():
                test_config_condition(
                    meter_name not in self.meters,
                    ('meter %s is not configured' % meter_name))
            for port_no in acl.get_mirror_destinations():
                port = self.ports[port_no]
                port.output_only = True
            return acl.build(vid, self.meters)

        def verify_acl_exact_match(acls):
            for acl in acls:
                test_config_condition(
                    acl.exact_match != acls[0].exact_match,
                    ('ACLs when used together must have consistent exact_match'
                     ))
            return acls[0].exact_match

        def resolve_acls(valve_cl):
            """Resolve config references in ACLs."""
            # TODO: move this config validation to ACL object.
            port_acl_enabled = valve_cl.STATIC_TABLE_IDS
            port_acl_matches = {}
            port_acl_set_fields = set()
            port_acl_exact_match = False
            port_acl_meter = False
            vlan_acl_matches = {}
            vlan_acl_exact_match = False
            vlan_acl_set_fields = set()
            vlan_acl_meter = False

            def merge_matches(matches, new_matches):
                for field, has_mask in list(new_matches.items()):
                    if has_mask or field not in matches:
                        matches[field] = has_mask

            for vlan in list(self.vlans.values()):
                if vlan.acls_in:
                    acls = []
                    for acl in vlan.acls_in:
                        matches, set_fields, meter = resolve_acl(acl, vlan.vid)
                        merge_matches(vlan_acl_matches, matches)
                        vlan_acl_set_fields = vlan_acl_set_fields.union(
                            set_fields)
                        if meter:
                            vlan_acl_meter = True
                        acls.append(self.acls[acl])
                    vlan.acls_in = acls
                    vlan_acl_exact_match = verify_acl_exact_match(acls)
            for port in list(self.ports.values()):
                if port.acls_in:
                    test_config_condition(
                        self.dp_acls,
                        ('dataplane ACLs cannot be used with port ACLs.'))
                    acls = []
                    for acl in port.acls_in:
                        matches, set_fields, meter = resolve_acl(acl, None)
                        merge_matches(port_acl_matches, matches)
                        port_acl_set_fields = port_acl_set_fields.union(
                            set_fields)
                        if meter:
                            port_acl_meter = True
                        acls.append(self.acls[acl])
                    port.acls_in = acls
                    port_acl_exact_match = verify_acl_exact_match(acls)
                    port_acl_enabled = True
            if self.dp_acls:
                acls = []
                for acl in self.acls:
                    matches, set_fields, meter = resolve_acl(acl, None)
                    merge_matches(port_acl_matches, matches)
                    port_acl_set_fields = port_acl_set_fields.union(set_fields)
                    if meter:
                        port_acl_meter = True
                    acls.append(self.acls[acl])
                self.dp_acls = acls
                port_acl_enabled = True
            if port_acl_enabled:
                port_acl_matches.update({'in_port': False})
            port_acl_matches = {
                (field, mask)
                for field, mask in list(port_acl_matches.items())
            }
            vlan_acl_matches = {
                (field, mask)
                for field, mask in list(vlan_acl_matches.items())
            }

            # TODO: skip port_acl table if not configured.
            # TODO: dynamically configure output attribue
            override_table_config = {
                'port_acl':
                ValveTableConfig('port_acl',
                                 exact_match=port_acl_exact_match,
                                 meter=port_acl_meter,
                                 output=True,
                                 match_types=port_acl_matches,
                                 set_fields=tuple(port_acl_set_fields)),
                'vlan_acl':
                ValveTableConfig('vlan_acl',
                                 exact_match=vlan_acl_exact_match,
                                 meter=vlan_acl_meter,
                                 output=True,
                                 match_types=vlan_acl_matches,
                                 set_fields=tuple(vlan_acl_set_fields)),
            }
            return override_table_config

        def resolve_vlan_names_in_routers():
            """Resolve VLAN references in routers."""
            dp_routers = {}
            for router_name, router in list(self.routers.items()):
                vlans = []
                for vlan_name in router.vlans:
                    vlan = resolve_vlan(vlan_name)
                    if vlan is not None:
                        vlans.append(vlan)
                if len(vlans) > 1:
                    dp_router = copy.copy(router)
                    dp_router.vlans = vlans
                    dp_routers[router_name] = dp_router
                vips = set()
                for vlan in vlans:
                    for vip in vlan.faucet_vips:
                        if vip.ip.is_link_local:
                            continue
                        vips.add(vip)
                for vip in vips:
                    for other_vip in vips - set([vip]):
                        test_config_condition(
                            vip.ip in other_vip.network,
                            'VIPs %s and %s overlap in router %s' %
                            (vip, other_vip, router_name))
            self.routers = dp_routers

        test_config_condition(
            not self.vlans,
            'no VLANs referenced by interfaces in %s' % self.name)
        valve_cl = SUPPORTED_HARDWARE.get(self.hardware, None)
        test_config_condition(
            not valve_cl, 'hardware %s must be in %s' %
            (self.hardware, list(SUPPORTED_HARDWARE.keys())))

        for dp in dps:
            dp_by_name[dp.name] = dp
        for vlan in list(self.vlans.values()):
            vlan_by_name[vlan.name] = vlan
            if self.global_vlan:
                test_config_condition(
                    self.global_vlan == vlan.vid,
                    'VLAN %u is reserved by global_vlan' % vlan.vid)

        resolve_stack_dps()
        resolve_mirror_destinations()
        resolve_override_output_ports()
        resolve_vlan_names_in_routers()
        override_table_config = resolve_acls(valve_cl)

        # Only configure IP routing tables if enabled.
        ipvs = set()
        for vlan in list(self.vlans.values()):
            ipvs = ipvs.union(vlan.ipvs())
        for ipv in (4, 6):
            if ipv not in ipvs:
                table_name = 'ipv%u_fib' % ipv
                override_table_config[table_name] = ValveTableConfig(
                    table_name)
        if not ipvs:
            override_table_config['vip'] = ValveTableConfig('vip')

        vlan_port_factor = len(self.vlans) * len(self.ports)
        self._configure_tables(override_table_config, valve_cl,
                               vlan_port_factor)

        bgp_vlans = self.bgp_vlans()
        if bgp_vlans:
            for vlan in bgp_vlans:
                vlan_dps = [dp for dp in dps if vlan.vid in dp.vlans]
                test_config_condition(
                    len(vlan_dps) != 1,
                    ('DPs %s sharing a BGP speaker VLAN is unsupported'))
            router_ids = {vlan.bgp_routerid for vlan in bgp_vlans}
            test_config_condition(
                len(router_ids) != 1, 'BGP router IDs must all be the same')
            bgp_ports = {vlan.bgp_port for vlan in bgp_vlans}
            test_config_condition(
                len(bgp_ports) != 1, 'BGP ports must all be the same')
            for vlan in bgp_vlans:
                test_config_condition(
                    vlan.bgp_server_addresses !=
                    (bgp_vlans[0].bgp_server_addresses),
                    ('BGP server addresses must all be the same'))

        for port in list(self.ports.values()):
            port.finalize()
        for vlan in list(self.vlans.values()):
            vlan.finalize()
        for acl in list(self.acls.values()):
            acl.finalize()
        for router in list(self.routers.values()):
            router.finalize()
        self.finalize()
Beispiel #6
0
    def finalize_config(self, dps):
        """Perform consistency checks after initial config parsing."""

        dp_by_name = {}
        vlan_by_name = {}

        def resolve_ports(port_names):
            """Resolve list of ports, by port by name or number."""
            resolved_ports = []
            for port_name in port_names:
                port = self.resolve_port(port_name)
                if port is not None:
                    resolved_ports.append(port)
            return resolved_ports

        def resolve_vlan(vlan_name):
            """Resolve VLAN by name or VID."""
            test_config_condition(not isinstance(vlan_name, (str, int)),
                                  ('VLAN must be type %s or %s not %s' %
                                   (str, int, type(vlan_name))))
            if vlan_name in vlan_by_name:
                return vlan_by_name[vlan_name]
            if vlan_name in self.vlans:
                return self.vlans[vlan_name]
            return None

        def resolve_stack_dps():
            """Resolve DP references in stacking config."""
            port_stack_dp = {}
            for port in self.stack_ports:
                stack_dp = port.stack['dp']
                test_config_condition(stack_dp not in dp_by_name,
                                      ('stack DP %s not defined' % stack_dp))
                port_stack_dp[port] = dp_by_name[stack_dp]
            for port, dp in port_stack_dp.items():
                port.stack['dp'] = dp
                stack_port = dp.resolve_port(port.stack['port'])
                test_config_condition(stack_port is None,
                                      ('stack port %s not defined in DP %s' %
                                       (port.stack['port'], dp.name)))
                port.stack['port'] = stack_port

        def resolve_mirror_destinations():
            """Resolve mirror port references and destinations."""
            mirror_from_port = defaultdict(list)
            for mirror_port in self.ports.values():
                if mirror_port.mirror is not None:
                    mirrored_ports = resolve_ports(mirror_port.mirror)
                    test_config_condition(
                        len(mirrored_ports) != len(mirror_port.mirror),
                        ('port mirror not defined in DP %s' % self.name))
                    for mirrored_port in mirrored_ports:
                        mirror_from_port[mirrored_port].append(mirror_port)

            # TODO: confusingly, mirror at config time means what ports to mirror from.
            # But internally we use as a list of ports to mirror to.
            for mirrored_port, mirror_ports in mirror_from_port.items():
                mirrored_port.mirror = []
                for mirror_port in mirror_ports:
                    mirrored_port.mirror.append(mirror_port.number)
                    mirror_port.output_only = True

        def resolve_override_output_ports():
            """Resolve override output ports."""
            for port_no, port in self.ports.items():
                if port.override_output_port:
                    port.override_output_port = self.resolve_port(
                        port.override_output_port)
                    test_config_condition(
                        not port.override_output_port,
                        ('override_output_port port not defined'))
                    self.ports[port_no] = port

        def resolve_acl(acl_in, vid=None, port_num=None):
            """Resolve an individual ACL."""
            test_config_condition(acl_in not in self.acls,
                                  ('missing ACL %s in DP: %s' %
                                   (acl_in, self.name)))
            acl = self.acls[acl_in]

            def resolve_port_cb(port_name):
                port = self.resolve_port(port_name)
                if port:
                    return port.number
                return port

            acl.resolve_ports(resolve_port_cb)

            for meter_name in acl.get_meters():
                test_config_condition(
                    meter_name not in self.meters,
                    ('meter %s is not configured' % meter_name))
            for port_no in acl.get_mirror_destinations():
                port = self.ports[port_no]
                port.output_only = True
            return acl.build(self.meters, vid, port_num)

        def verify_acl_exact_match(acls):
            for acl in acls:
                test_config_condition(
                    acl.exact_match != acls[0].exact_match,
                    ('ACLs when used together must have consistent exact_match'
                     ))

        def resolve_acls():
            """Resolve config references in ACLs."""
            # TODO: move this config validation to ACL object.
            for vlan in self.vlans.values():
                if vlan.acls_in:
                    acls = []
                    for acl in vlan.acls_in:
                        resolve_acl(acl, vlan.vid)
                        acls.append(self.acls[acl])
                    vlan.acls_in = acls
                    verify_acl_exact_match(acls)
            for port in self.ports.values():
                if port.acls_in:
                    test_config_condition(
                        self.dp_acls,
                        ('dataplane ACLs cannot be used with port ACLs.'))
                    acls = []
                    for acl in port.acls_in:
                        resolve_acl(acl, port_num=port.number)
                        acls.append(self.acls[acl])
                    port.acls_in = acls
                    verify_acl_exact_match(acls)
            if self.dp_acls:
                acls = []
                for acl in self.acls:
                    resolve_acl(acl, None)
                    acls.append(self.acls[acl])
                self.dp_acls = acls

        def resolve_vlan_names_in_routers():
            """Resolve VLAN references in routers."""
            dp_routers = {}
            for router_name, router in self.routers.items():
                vlans = []
                for vlan_name in router.vlans:
                    vlan = resolve_vlan(vlan_name)
                    if vlan is not None:
                        vlans.append(vlan)
                if len(vlans) > 1:
                    dp_router = copy.copy(router)
                    dp_router.vlans = vlans
                    dp_routers[router_name] = dp_router
                vips = set()
                for vlan in vlans:
                    for vip in vlan.faucet_vips:
                        if vip.ip.is_link_local:
                            continue
                        vips.add(vip)
                for vip in vips:
                    for other_vip in vips - set([vip]):
                        test_config_condition(
                            vip.ip in other_vip.network,
                            'VIPs %s and %s overlap in router %s' %
                            (vip, other_vip, router_name))
            self.routers = dp_routers

        test_config_condition(
            not self.vlans,
            'no VLANs referenced by interfaces in %s' % self.name)
        valve_cl = SUPPORTED_HARDWARE.get(self.hardware, None)
        test_config_condition(
            not valve_cl, 'hardware %s must be in %s' %
            (self.hardware, SUPPORTED_HARDWARE.keys()))

        for dp in dps:
            dp_by_name[dp.name] = dp
        for vlan in self.vlans.values():
            vlan_by_name[vlan.name] = vlan
            if self.global_vlan:
                test_config_condition(
                    self.global_vlan == vlan.vid,
                    'VLAN %u is reserved by global_vlan' % vlan.vid)

        resolve_stack_dps()
        resolve_mirror_destinations()
        resolve_override_output_ports()
        resolve_vlan_names_in_routers()
        resolve_acls()

        self._configure_tables(valve_cl)

        bgp_vlans = self.bgp_vlans()
        if bgp_vlans:
            for vlan in bgp_vlans:
                vlan_dps = [dp for dp in dps if vlan.vid in dp.vlans]
                test_config_condition(
                    len(vlan_dps) != 1,
                    ('DPs %s sharing a BGP speaker VLAN is unsupported'))
            router_ids = {vlan.bgp_routerid for vlan in bgp_vlans}
            test_config_condition(
                len(router_ids) != 1, 'BGP router IDs must all be the same')
            bgp_ports = {vlan.bgp_port for vlan in bgp_vlans}
            test_config_condition(
                len(bgp_ports) != 1, 'BGP ports must all be the same')
            for vlan in bgp_vlans:
                test_config_condition(
                    vlan.bgp_server_addresses !=
                    (bgp_vlans[0].bgp_server_addresses),
                    ('BGP server addresses must all be the same'))

        for port in self.ports.values():
            port.finalize()
        for vlan in self.vlans.values():
            vlan.finalize()
        for acl in self.acls.values():
            acl.finalize()
        for router in self.routers.values():
            router.finalize()
        self.finalize()
Beispiel #7
0
    def finalize_config(self, dps):
        """Perform consistency checks after initial config parsing."""

        dp_by_name = {}
        vlan_by_name = {}

        def resolve_ports(port_names):
            """Resolve list of ports, by port by name or number."""
            resolved_ports = []
            for port_name in port_names:
                port = self.resolve_port(port_name)
                if port is not None:
                    resolved_ports.append(port)
            return resolved_ports

        def resolve_vlan(vlan_name):
            """Resolve VLAN by name or VID."""
            test_config_condition(not isinstance(vlan_name, (str, int)), (
                'VLAN must be type %s or %s not %s' % (str, int, type(vlan_name))))
            if vlan_name in vlan_by_name:
                return vlan_by_name[vlan_name]
            if vlan_name in self.vlans:
                return self.vlans[vlan_name]
            return None

        def resolve_stack_dps():
            """Resolve DP references in stacking config."""
            port_stack_dp = {}
            for port in self.stack_ports:
                stack_dp = port.stack['dp']
                test_config_condition(stack_dp not in dp_by_name, (
                    'stack DP %s not defined' % stack_dp))
                port_stack_dp[port] = dp_by_name[stack_dp]
            for port, dp in list(port_stack_dp.items()):
                port.stack['dp'] = dp
                stack_port = dp.resolve_port(port.stack['port'])
                test_config_condition(stack_port is None, (
                    'stack port %s not defined in DP %s' % (port.stack['port'], dp.name)))
                port.stack['port'] = stack_port

        def resolve_mirror_destinations():
            """Resolve mirror port references and destinations."""
            mirror_from_port = defaultdict(list)
            for mirror_port in list(self.ports.values()):
                if mirror_port.mirror is not None:
                    mirrored_ports = resolve_ports(mirror_port.mirror)
                    test_config_condition(len(mirrored_ports) != len(mirror_port.mirror), (
                        'port mirror not defined in DP %s' % self.name))
                    for mirrored_port in mirrored_ports:
                        mirror_from_port[mirrored_port].append(mirror_port)

            # TODO: confusingly, mirror at config time means what ports to mirror from.
            # But internally we use as a list of ports to mirror to.
            for mirrored_port, mirror_ports in list(mirror_from_port.items()):
                mirrored_port.mirror = []
                for mirror_port in mirror_ports:
                    mirrored_port.mirror.append(mirror_port.number)
                    mirror_port.output_only = True

        def resolve_override_output_ports():
            """Resolve override output ports."""
            for port_no, port in list(self.ports.items()):
                if port.override_output_port:
                    port.override_output_port = self.resolve_port(port.override_output_port)
                    test_config_condition(not port.override_output_port, (
                        'override_output_port port not defined'))
                    self.ports[port_no] = port

        def resolve_acl(acl_in, vid=None, port_num=None):
            """Resolve an individual ACL."""
            test_config_condition(acl_in not in self.acls, (
                'missing ACL %s in DP: %s' % (acl_in, self.name)))
            acl = self.acls[acl_in]
            def resolve_port_cb(port_name):
                port = self.resolve_port(port_name)
                if port:
                    return port.number
                return port

            acl.resolve_ports(resolve_port_cb)

            for meter_name in acl.get_meters():
                test_config_condition(meter_name not in self.meters, (
                    'meter %s is not configured' % meter_name))
            for port_no in acl.get_mirror_destinations():
                port = self.ports[port_no]
                port.output_only = True
            return acl.build(self.meters, vid, port_num)

        def verify_acl_exact_match(acls):
            for acl in acls:
                test_config_condition(acl.exact_match != acls[0].exact_match, (
                    'ACLs when used together must have consistent exact_match'))

        def resolve_acls():
            """Resolve config references in ACLs."""
            # TODO: move this config validation to ACL object.
            for vlan in list(self.vlans.values()):
                if vlan.acls_in:
                    acls = []
                    for acl in vlan.acls_in:
                        resolve_acl(acl, vlan.vid)
                        acls.append(self.acls[acl])
                    vlan.acls_in = acls
                    verify_acl_exact_match(acls)
            for port in list(self.ports.values()):
                if port.acls_in:
                    test_config_condition(self.dp_acls, (
                        'dataplane ACLs cannot be used with port ACLs.'))
                    acls = []
                    for acl in port.acls_in:
                        resolve_acl(acl, port_num=port.number)
                        acls.append(self.acls[acl])
                    port.acls_in = acls
                    verify_acl_exact_match(acls)
            if self.dp_acls:
                acls = []
                for acl in self.acls:
                    resolve_acl(acl, None)
                    acls.append(self.acls[acl])
                self.dp_acls = acls

        def resolve_vlan_names_in_routers():
            """Resolve VLAN references in routers."""
            dp_routers = {}
            for router_name, router in list(self.routers.items()):
                vlans = []
                for vlan_name in router.vlans:
                    vlan = resolve_vlan(vlan_name)
                    if vlan is not None:
                        vlans.append(vlan)
                if len(vlans) > 1:
                    dp_router = copy.copy(router)
                    dp_router.vlans = vlans
                    dp_routers[router_name] = dp_router
                vips = set()
                for vlan in vlans:
                    for vip in vlan.faucet_vips:
                        if vip.ip.is_link_local:
                            continue
                        vips.add(vip)
                for vip in vips:
                    for other_vip in vips - set([vip]):
                        test_config_condition(
                            vip.ip in other_vip.network,
                            'VIPs %s and %s overlap in router %s' % (
                                vip, other_vip, router_name))
            self.routers = dp_routers

        test_config_condition(not self.vlans, 'no VLANs referenced by interfaces in %s' % self.name)
        valve_cl = SUPPORTED_HARDWARE.get(self.hardware, None)
        test_config_condition(
            not valve_cl, 'hardware %s must be in %s' % (
                self.hardware, list(SUPPORTED_HARDWARE.keys())))

        for dp in dps:
            dp_by_name[dp.name] = dp
        for vlan in list(self.vlans.values()):
            vlan_by_name[vlan.name] = vlan
            if self.global_vlan:
                test_config_condition(
                    self.global_vlan == vlan.vid, 'VLAN %u is reserved by global_vlan' % vlan.vid)

        resolve_stack_dps()
        resolve_mirror_destinations()
        resolve_override_output_ports()
        resolve_vlan_names_in_routers()
        resolve_acls()

        self._configure_tables(valve_cl)

        bgp_vlans = self.bgp_vlans()
        if bgp_vlans:
            for vlan in bgp_vlans:
                vlan_dps = [dp for dp in dps if vlan.vid in dp.vlans]
                test_config_condition(len(vlan_dps) != 1, (
                    'DPs %s sharing a BGP speaker VLAN is unsupported'))
            router_ids = {vlan.bgp_routerid for vlan in bgp_vlans}
            test_config_condition(len(router_ids) != 1, 'BGP router IDs must all be the same')
            bgp_ports = {vlan.bgp_port for vlan in bgp_vlans}
            test_config_condition(len(bgp_ports) != 1, 'BGP ports must all be the same')
            for vlan in bgp_vlans:
                test_config_condition(vlan.bgp_server_addresses != (
                    bgp_vlans[0].bgp_server_addresses), (
                        'BGP server addresses must all be the same'))

        for port in list(self.ports.values()):
            port.finalize()
        for vlan in list(self.vlans.values()):
            vlan.finalize()
        for acl in list(self.acls.values()):
            acl.finalize()
        for router in list(self.routers.values()):
            router.finalize()
        self.finalize()