Exemplo n.º 1
0
 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
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
 def check_config(self):
     super(Router, self).check_config()
     if self.bgp:
         self._check_conf_types(self.bgp, self.bgp_defaults_types)
         self.bgp = self._set_unknown_conf(self.bgp, self.bgp_defaults_types)
         if not self.bgp_connect_mode():
             self.bgp['bgp']['connect_mode'] = 'passive'
         for field in self.ipaddress_fields:
             if field in self.bgp:
                 self.bgp[field] = frozenset([
                     self._check_ip_str(ip_str) for ip_str in self.bgp[field]])
         for accessor_val, required_field in (
                 (self.bgp_ipvs(), 'server_addresses'),
                 (self.bgp_as(), 'as'),
                 (self.bgp_port(), 'port'),
                 (self.bgp_connect_mode(), 'connect_mode'),
                 (self.bgp_routerid(), 'routerid'),
                 (self.bgp_neighbor_addresses(), 'neighbor_addresses'),
                 (self.bgp_neighbor_as(), 'neighbor_as')):
             test_config_condition(not accessor_val, 'BGP %s must be specified' % required_field)
         test_config_condition(
             self.bgp_connect_mode() != 'passive', 'BGP connect_mode must be passive')
         for ipv in self.bgp_ipvs():
             test_config_condition(
                 len(self.bgp_server_addresses_by_ipv(ipv)) != 1,
                 'Only one BGP server address per IP version supported')
         if not self.bgp_vlan():
             test_config_condition(
                 len(self.vlans) != 1,
                 'If routing more than one VLAN, must specify BGP VLAN')
             self.set_bgp_vlan(self.vlans[0])
     else:
         test_config_condition(
             not self.vlans, 'A router must have least one VLAN specified at top level')
Exemplo n.º 4
0
 def __init__(self, _id, dp_id, conf):
     self.rules = []
     self.exact_match = None
     self.meter = False
     self.matches = {}
     self.set_fields = set()
     for match_fields in (MATCH_FIELDS, OLD_MATCH_FIELDS):
         self.rule_types.update({match: (str, int) for match in match_fields.keys()})
     conf = copy.deepcopy(conf)
     if isinstance(conf, dict):
         rules = conf.get('rules', [])
     elif isinstance(conf, list):
         rules = conf
         conf = {}
     else:
         raise InvalidConfigError(
             'ACL conf is an invalid type %s' % _id)
     conf['rules'] = []
     for rule in rules:
         normalized_rule = rule
         if isinstance(rule, dict):
             normalized_rule = rule.get('rule', rule)
             if normalized_rule is None:
                 normalized_rule = {k: v for k, v in rule.items() if v is not None}
         test_config_condition(not isinstance(normalized_rule, dict), (
             'ACL rule is %s not %s (%s)' % (type(normalized_rule), dict, rules)))
         conf['rules'].append(normalized_rule)
     super(ACL, self).__init__(_id, dp_id, conf)
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
 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
Exemplo n.º 7
0
 def _map_port_num_to_port(ports_conf):
     port_num_to_port_conf = {}
     for port_key, port_conf in list(ports_conf.items()):
         test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config')
         port_num = port_conf.get('number', port_key)
         try:
             port_num_to_port_conf[port_num] = (port_key, port_conf)
         except TypeError:
             raise InvalidConfigError('Invalid syntax in port config')
     return port_num_to_port_conf
Exemplo n.º 8
0
def _get_vlan_by_key(dp_id, vlan_key, vlans):
    test_config_condition(not isinstance(vlan_key, (str, int)), (
        'VLAN key must not be type %s' % type(vlan_key)))
    if vlan_key in vlans:
        return vlans[vlan_key]
    for vlan in list(vlans.values()):
        if vlan_key == str(vlan.vid):
            return vlan
    # Create VLAN with VID, if not defined.
    return vlans.setdefault(vlan_key, VLAN(vlan_key, dp_id))
Exemplo n.º 9
0
def _dp_add_ports(dp, dp_conf, dp_id, vlans):
    ports_conf = dp_conf.get('interfaces', {})
    port_ranges_conf = dp_conf.get('interface_ranges', {})
    # as users can config port VLAN by using VLAN name, we store vid in
    # Port instance instead of VLAN name for data consistency
    test_config_condition(not isinstance(ports_conf, dict), (
        'Invalid syntax in interface config'))
    test_config_condition(not isinstance(port_ranges_conf, dict), (
        'Invalid syntax in interface ranges config'))

    def _map_port_num_to_port(ports_conf):
        port_num_to_port_conf = {}
        for port_key, port_conf in list(ports_conf.items()):
            test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config')
            port_num = port_conf.get('number', port_key)
            try:
                port_num_to_port_conf[port_num] = (port_key, port_conf)
            except TypeError:
                raise InvalidConfigError('Invalid syntax in port config')
        return port_num_to_port_conf

    def _parse_port_ranges(port_ranges_conf, port_num_to_port_conf):
        for port_range, port_conf in list(port_ranges_conf.items()):
            # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9
            test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config')
            port_nums = set()
            if 'number' in port_conf:
                del port_conf['number']
            for range_ in re.findall(r'(\d+-\d+)', str(port_range)):
                start_num, end_num = [int(num) for num in range_.split('-')]
                test_config_condition(start_num >= end_num, (
                    'Incorrect port range (%d - %d)' % (start_num, end_num)))
                port_nums.update(list(range(start_num, end_num + 1)))
                port_range = re.sub(range_, '', port_range)
            other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))]
            port_nums.update(other_nums)
            test_config_condition(not port_nums, 'interface-ranges contain invalid config')
            for port_num in port_nums:
                if port_num in port_num_to_port_conf:
                    # port range config has lower priority than individual port config
                    for attr, value in list(port_conf.items()):
                        port_num_to_port_conf[port_num][1].setdefault(attr, value)
                else:
                    port_num_to_port_conf[port_num] = (port_num, port_conf)

    port_num_to_port_conf = _map_port_num_to_port(ports_conf)
    _parse_port_ranges(port_ranges_conf, port_num_to_port_conf)

    for port_num, port_conf in list(port_num_to_port_conf.values()):
        port = _dp_parse_port(dp_id, port_num, port_conf, vlans)
        dp.add_port(port)
    dp.reset_refs(vlans=vlans)
Exemplo n.º 10
0
def _parse_dp(dp_key, dp_conf, acls_conf, meters_conf, routers_conf, vlans_conf):
    test_config_condition(not isinstance(dp_conf, dict), '')
    dp = DP(dp_key, dp_conf.get('dp_id', None), dp_conf)
    test_config_condition(dp.name != dp_key, (
        'DP key %s and DP name must match' % dp_key))
    dp_id = dp.dp_id
    vlans = {}
    vids = set()
    for vlan_key, vlan_conf in list(vlans_conf.items()):
        vlan = VLAN(vlan_key, dp_id, vlan_conf)
        test_config_condition(str(vlan_key) not in (str(vlan.vid), vlan.name), (
            'VLAN %s key must match VLAN name or VLAN VID' % vlan_key))
        test_config_condition(vlan.vid in vids, (
            'VLAN VID %u multiply configured' % vlan.vid))
        vlans[vlan_key] = vlan
        vids.add(vlan.vid)
    for acl_key, acl_conf in list(acls_conf.items()):
        acl = ACL(acl_key, dp_id, acl_conf)
        dp.add_acl(acl_key, acl)
    for router_key, router_conf in list(routers_conf.items()):
        router = Router(router_key, dp_id, router_conf)
        dp.add_router(router_key, router)
    for meter_key, meter_conf in list(meters_conf.items()):
        meter = Meter(meter_key, dp_id, meter_conf)
        dp.meters[meter_key] = meter
    _dp_add_ports(dp, dp_conf, dp_id, vlans)
    return dp
Exemplo n.º 11
0
 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
Exemplo n.º 12
0
    def _generate_acl_tables(self):
        all_acls = {}
        if self.dot1x:
            all_acls['port_acl'] = [PORT_ACL_8021X]

        for vlan in self.vlans.values():
            if vlan.acls_in:
                all_acls.setdefault('vlan_acl', [])
                all_acls['vlan_acl'].extend(vlan.acls_in)
        if self.dp_acls:
            test_config_condition(self.dot1x, (
                'DP ACLs and 802.1x cannot be configured together'))
            for acl in self.dp_acls:
                all_acls['port_acl'] = self.dp_acls
        else:
            for port in self.ports.values():
                if port.acls_in:
                    test_config_condition(port.dot1x, (
                        'port ACLs and 802.1x cannot be configured together'))
                    all_acls.setdefault('port_acl', [])
                    all_acls['port_acl'].extend(port.acls_in)

        table_config = {}
        for table_name, acls in all_acls.items():
            matches = {}
            set_fields = set()
            meter = False
            exact_match = False
            default = faucet_pipeline.DEFAULT_CONFIGS[table_name]
            for acl in acls:
                for field, has_mask in acl.matches.items():
                    if has_mask or field not in matches:
                        matches[field] = has_mask
                set_fields.update(acl.set_fields)
                meter = meter or acl.meter
                exact_match = acl.exact_match
            matches = set(matches.items())
            table_config[table_name] = ValveTableConfig(
                table_name,
                default.table_id,
                exact_match=exact_match,
                meter=meter,
                output=True,
                match_types=matches,
                set_fields=tuple(set_fields),
                next_tables=default.next_tables)
        # TODO: dynamically configure output attribue
        return table_config
Exemplo n.º 13
0
def match_from_dict(match_dict):
    for old_match, new_match in list(OLD_MATCH_FIELDS.items()):
        if old_match in match_dict:
            match_dict[new_match] = match_dict[old_match]
            del match_dict[old_match]

    kwargs = {}
    for of_match, field in list(match_dict.items()):
        test_config_condition(of_match not in MATCH_FIELDS, 'Unknown match field: %s' % of_match)
        try:
            encoded_field = MATCH_FIELDS[of_match](field)
        except TypeError:
            raise InvalidConfigError('%s cannot be type %s' % (of_match, type(field)))
        kwargs[of_match] = encoded_field

    return parser.OFPMatch(**kwargs)
Exemplo n.º 14
0
    def build(self, meters, vid, port_num):
        """Check that ACL can be built from config."""

        class NullRyuDatapath:
            """Placeholder Ryu Datapath."""
            ofproto = valve_of.ofp

        self.matches = {}
        self.set_fields = set()
        self.meter = False
        if self.rules:
            try:
                ofmsgs = valve_acl.build_acl_ofmsgs(
                    [self], wildcard_table,
                    [valve_of.goto_table(wildcard_table)],
                    [valve_of.goto_table(wildcard_table)],
                    2**16-1, meters, self.exact_match,
                    vlan_vid=vid, port_num=port_num)
            except (netaddr.core.AddrFormatError, KeyError, ValueError) as err:
                raise InvalidConfigError(err)
            test_config_condition(not ofmsgs, 'OF messages is empty')
            for ofmsg in ofmsgs:
                ofmsg.datapath = NullRyuDatapath()
                ofmsg.set_xid(0)
                try:
                    ofmsg.serialize()
                except (KeyError, ValueError) as err:
                    raise InvalidConfigError(err)
                except Exception as err:
                    print(ofmsg)
                    raise err
                if valve_of.is_flowmod(ofmsg):
                    apply_actions = []
                    for inst in ofmsg.instructions:
                        if valve_of.is_apply_actions(inst):
                            apply_actions.extend(inst.actions)
                        elif valve_of.is_meter(inst):
                            self.meter = True
                    for action in apply_actions:
                        if valve_of.is_set_field(action):
                            self.set_fields.add(action.key)
                    for match, value in ofmsg.match.items():
                        has_mask = isinstance(value, (tuple, list))
                        if has_mask or match not in self.matches:
                            self.matches[match] = has_mask
        return (self.matches, self.set_fields, self.meter)
Exemplo n.º 15
0
 def _resolve_output_ports(self, action_conf, resolve_port_cb, resolve_tunnel_objects):
     result = {}
     for output_action, output_action_values in action_conf.items():
         if output_action == 'tunnel':
             tunnel = output_action_values
             self._check_conf_types(tunnel, self.tunnel_types)
             src_dp, src_port, dst_dp, dst_port, tunnel_id = resolve_tunnel_objects(
                 tunnel['dp'], tunnel['port'], tunnel['tunnel_id'])
             tunnel_dict = {
                 'src_dp': src_dp,
                 'src_port': src_port,
                 'dst_dp': dst_dp,
                 'dst_port': dst_port,
                 'tunnel_id': tunnel_id,
                 'type': tunnel['type'],
             }
             self.tunnel_info[tunnel_id] = tunnel_dict
             result[output_action] = tunnel_id
         elif output_action == 'port':
             port_name = output_action_values
             port = resolve_port_cb(port_name)
             test_config_condition(
                 not port,
                 ('ACL (%s) output port undefined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = port
         elif output_action == 'ports':
             resolved_ports = [
                 resolve_port_cb(p) for p in output_action_values]
             test_config_condition(
                 None in resolved_ports,
                 ('ACL (%s) output port(s) not defined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = resolved_ports
         elif output_action == 'failover':
             failover = output_action_values
             test_config_condition(not isinstance(failover, dict), (
                 'failover is not a dictionary'))
             result[output_action] = {}
             for failover_name, failover_values in failover.items():
                 if failover_name == 'ports':
                     resolved_ports = [
                         resolve_port_cb(p) for p in failover_values]
                     test_config_condition(
                         None in resolved_ports,
                         ('ACL (%s) failover port(s) not defined in DP: %s'\
                         % (self._id, self.dp_id))
                         )
                     result[output_action][failover_name] = resolved_ports
                 else:
                     result[output_action][failover_name] = failover_values
         else:
             result[output_action] = output_action_values
     return result
Exemplo n.º 16
0
    def __init__(self, _id, dp_id, conf):
        self.rules = []
        self.exact_match = None
        self.meter = False
        self.matches = {}
        self.set_fields = set()

        #TODO: Would be possible to save the names instead of the DP and port objects
        # TUNNEL:
        #   src_port: PORT object / port number
        #       source port
        #   src_dp: DP object
        #       source dp
        #   dst_port: PORT object / port number
        #       final destination port
        #   dst_dp: DP object
        #       final destination dp
        #   tunnel_id: int
        #       ID to represent the tunnel
        #   tunnel_type: str ('vlan')
        #       tunnel type specification
        self.tunnel_info = {}

        for match_fields in (MATCH_FIELDS, OLD_MATCH_FIELDS):
            self.rule_types.update({match: (str, int) for match in match_fields})
        conf = copy.deepcopy(conf)
        if isinstance(conf, dict):
            rules = conf.get('rules', [])
        elif isinstance(conf, list):
            rules = conf
            conf = {}
        else:
            raise InvalidConfigError(
                'ACL conf is an invalid type %s' % _id)
        conf['rules'] = []
        for rule in rules:
            normalized_rule = rule
            if isinstance(rule, dict):
                normalized_rule = rule.get('rule', rule)
                if normalized_rule is None:
                    normalized_rule = {k: v for k, v in rule.items() if v is not None}
            test_config_condition(not isinstance(normalized_rule, dict), (
                'ACL rule is %s not %s (%s)' % (type(normalized_rule), dict, rules)))
            conf['rules'].append(normalized_rule)
        super(ACL, self).__init__(_id, dp_id, conf)
Exemplo n.º 17
0
        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
Exemplo n.º 18
0
def _dp_parse_port(dp_id, port_key, port_conf, vlans):

    def _dp_parse_native_port_vlan():
        if port.native_vlan is not None:
            vlan = _get_vlan_by_key(dp_id, port.native_vlan, vlans)
            port.native_vlan = vlan

    def _dp_parse_tagged_port_vlans():
        if port.tagged_vlans:
            port_tagged_vlans = [
                _get_vlan_by_key(dp_id, vlan_key, vlans) for vlan_key in port.tagged_vlans]
            port.tagged_vlans = port_tagged_vlans

    port = Port(port_key, dp_id, port_conf)
    test_config_condition(str(port_key) not in (str(port.number), port.name), (
        'Port key %s match port name or port number' % port_key))
    _dp_parse_native_port_vlan()
    _dp_parse_tagged_port_vlans()
    return port
Exemplo n.º 19
0
def _dp_parser_v2(acls_conf, dps_conf, meters_conf,
                  routers_conf, vlans_conf):

    dps = [_parse_dp(dp_key, dp_conf, acls_conf, meters_conf, routers_conf, vlans_conf)
           for dp_key, dp_conf in list(dps_conf.items())]
    for dp in dps:
        dp.finalize_config(dps)
    for dp in dps:
        dp.resolve_stack_topology(dps)

    router_ref_dps = collections.defaultdict(set)
    for dp in dps:
        for router in list(dp.routers.keys()):
            router_ref_dps[router].add(dp)
    for router in list(routers_conf.keys()):
        test_config_condition(not router_ref_dps[router], (
            'router %s configured but not used by any DP' % router))

    return dps
Exemplo n.º 20
0
        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)
Exemplo n.º 21
0
 def __init__(self, _id, dp_id, conf):
     self.rules = []
     self.exact_match = None
     self.meter = False
     self.matches = {}
     self.set_fields = set()
     conf = copy.deepcopy(conf)
     if isinstance(conf, dict):
         rules = conf.get('rules', [])
     elif isinstance(conf, list):
         rules = conf
         conf = {}
     else:
         raise InvalidConfigError(
             'ACL conf is an invalid type %s' % self._id)
     conf['rules'] = []
     for rule in rules:
         test_config_condition(not isinstance(rule, dict), (
             'ACL rule is %s not %s' % (type(rule), dict)))
         conf['rules'].append(rule.get('rule', rule))
     super(ACL, self).__init__(_id, dp_id, conf)
Exemplo n.º 22
0
def dp_parser(config_file, logname):
    """Parse a config file into DP configuration objects with hashes of config include/files."""
    conf = config_parser_util.read_config(config_file, logname)
    config_hashes = None
    dps = None

    test_config_condition(conf is None, 'Config file is empty')
    test_config_condition(not isinstance(conf, dict), 'Config file does not have valid syntax')
    version = conf.pop('version', 2)
    test_config_condition(version != 2, 'Only config version 2 is supported')
    config_hashes, dps = _config_parser_v2(config_file, logname)
    test_config_condition(dps is None, 'no DPs are not defined')

    return config_hashes, dps
Exemplo n.º 23
0
 def resolve_ports(self, resolve_port_cb, resolve_tunnel_objects):
     for rule_conf in self.rules:
         if 'actions' in rule_conf:
             actions_conf = rule_conf['actions']
             resolved_actions = {}
             test_config_condition(not isinstance(actions_conf, dict), (
                 'actions value is not a dictionary'))
             for action_name, action_conf in actions_conf.items():
                 if action_name == 'mirror':
                     resolved_port = resolve_port_cb(action_conf)
                     test_config_condition(
                         resolved_port is None,
                         ('ACL (%s) mirror port is not defined in DP: %s'\
                         % (self._id, self.dp_id))
                         )
                     resolved_actions[action_name] = resolved_port
                 elif action_name == 'output':
                     resolved_action = self._resolve_output_ports(
                         action_conf, resolve_port_cb, resolve_tunnel_objects)
                     resolved_actions[action_name] = resolved_action
                 else:
                     resolved_actions[action_name] = action_conf
             rule_conf['actions'] = resolved_actions
Exemplo n.º 24
0
 def finalize(self):
     test_config_condition(not (self.vlans() or self.stack or self.output_only), (
         '%s must have a VLAN, be a stack port, or have output_only: True' % self))
     test_config_condition(self.vlans() and self.stack, (
         '%s cannot have stack and VLANs on same port' % self))
     if self.native_vlan:
         test_config_condition(self.native_vlan in self.tagged_vlans, (
             'cannot have same native and tagged VLAN on same port'))
     self.tagged_vlans = tuple(self.tagged_vlans)
     super(Port, self).finalize()
Exemplo n.º 25
0
 def _resolve_output_ports(self, action_conf, resolve_port_cb):
     result = {}
     for output_action, output_action_values in list(action_conf.items()):
         if output_action == 'port':
             port_name = output_action_values
             port = resolve_port_cb(port_name)
             test_config_condition(
                 not port,
                 ('ACL (%s) output port undefined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = port
         elif output_action == 'ports':
             resolved_ports = [
                 resolve_port_cb(p) for p in output_action_values]
             test_config_condition(
                 None in resolved_ports,
                 ('ACL (%s) output port(s) not defined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = resolved_ports
         elif output_action == 'failover':
             failover = output_action_values
             test_config_condition(not isinstance(failover, dict), (
                 'failover is not a dictionary'))
             result[output_action] = {}
             for failover_name, failover_values in list(failover.items()):
                 if failover_name == 'ports':
                     resolved_ports = [
                         resolve_port_cb(p) for p in failover_values]
                     test_config_condition(
                         None in resolved_ports,
                         ('ACL (%s) failover port(s) not defined in DP: %s'\
                         % (self._id, self.dp_id))
                         )
                     result[output_action][failover_name] = resolved_ports
                 else:
                     result[output_action][failover_name] = failover_values
         else:
             result[output_action] = output_action_values
     return result
Exemplo n.º 26
0
 def check_config(self):
     test_config_condition(
         not self.rules, 'no rules found for ACL %s' % self._id)
     for rule in self.rules:
         self._check_conf_types(rule, self.rule_types)
         for rule_field, rule_conf in rule.items():
             if rule_field == 'cookie':
                 test_config_condition(
                     rule_conf < 0 or rule_conf > 2**16,
                     'rule cookie value must be 0-2**16')
             elif rule_field == 'actions':
                 test_config_condition(
                     not rule_conf,
                     'Missing rule actions in ACL %s' % self._id)
                 self._check_conf_types(rule_conf, self.actions_types)
                 for action_name, action_conf in rule_conf.items():
                     if action_name == 'output':
                         self._check_conf_types(
                             action_conf, self.output_actions_types)
Exemplo n.º 27
0
 def check_config(self):
     test_config_condition(not self.rules,
                           'no rules found for ACL %s' % self._id)
     for match_fields in (MATCH_FIELDS, OLD_MATCH_FIELDS):
         for match in list(match_fields.keys()):
             self.rule_types[match] = (str, int)
     for rule in self.rules:
         self._check_conf_types(rule, self.rule_types)
         for rule_field, rule_conf in list(rule.items()):
             if rule_field == 'cookie':
                 test_config_condition(
                     rule_conf < 0 or rule_conf > 2**16,
                     ('rule cookie value must be 0-2**16'))
             elif rule_field == 'actions':
                 test_config_condition(
                     not rule_conf,
                     'Missing rule actions in ACL %s' % self._id)
                 self._check_conf_types(rule_conf, self.actions_types)
                 for action_name, action_conf in list(rule_conf.items()):
                     if action_name == 'output':
                         self._check_conf_types(action_conf,
                                                self.output_actions_types)
Exemplo n.º 28
0
 def check_config(self):
     test_config_condition(
         not self.rules, 'no rules found for ACL %s' % self._id)
     for match_fields in (MATCH_FIELDS, OLD_MATCH_FIELDS):
         for match in list(match_fields.keys()):
             self.rule_types[match] = (str, int)
     for rule in self.rules:
         self._check_conf_types(rule, self.rule_types)
         for rule_field, rule_conf in list(rule.items()):
             if rule_field == 'cookie':
                 test_config_condition(rule_conf < 0 or rule_conf > 2**16, (
                     'rule cookie value must be 0-2**16'))
             elif rule_field == 'actions':
                 test_config_condition(
                     not rule_conf,
                     'Missing rule actions in ACL %s' % self._id
                     )
                 self._check_conf_types(rule_conf, self.actions_types)
                 for action_name, action_conf in list(rule_conf.items()):
                     if action_name == 'output':
                         self._check_conf_types(
                             action_conf, self.output_actions_types)
Exemplo n.º 29
0
 def _parse_port_ranges(port_ranges_conf, port_num_to_port_conf):
     for port_range, port_conf in list(port_ranges_conf.items()):
         # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9
         test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config')
         port_nums = set()
         if 'number' in port_conf:
             del port_conf['number']
         for range_ in re.findall(r'(\d+-\d+)', str(port_range)):
             start_num, end_num = [int(num) for num in range_.split('-')]
             test_config_condition(start_num >= end_num, (
                 'Incorrect port range (%d - %d)' % (start_num, end_num)))
             port_nums.update(list(range(start_num, end_num + 1)))
             port_range = re.sub(range_, '', port_range)
         other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))]
         port_nums.update(other_nums)
         test_config_condition(not port_nums, 'interface-ranges contain invalid config')
         for port_num in port_nums:
             if port_num in port_num_to_port_conf:
                 # port range config has lower priority than individual port config
                 for attr, value in list(port_conf.items()):
                     port_num_to_port_conf[port_num][1].setdefault(attr, value)
             else:
                 port_num_to_port_conf[port_num] = (port_num, port_conf)
Exemplo n.º 30
0
 def _parse_port_ranges(port_ranges_conf, port_num_to_port_conf):
     for port_range, port_conf in port_ranges_conf.items():
         # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9
         test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config')
         port_nums = set()
         if 'number' in port_conf:
             del port_conf['number']
         for range_ in re.findall(r'(\d+-\d+)', str(port_range)):
             start_num, end_num = [int(num) for num in range_.split('-')]
             test_config_condition(start_num >= end_num, (
                 'Incorrect port range (%d - %d)' % (start_num, end_num)))
             port_nums.update(range(start_num, end_num + 1))
             port_range = re.sub(range_, '', port_range)
         other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))]
         port_nums.update(other_nums)
         test_config_condition(not port_nums, 'interface-ranges contain invalid config')
         for port_num in port_nums:
             if port_num in port_num_to_port_conf:
                 # port range config has lower priority than individual port config
                 for attr, value in port_conf.items():
                     port_num_to_port_conf[port_num][1].setdefault(attr, value)
             else:
                 port_num_to_port_conf[port_num] = (port_num, port_conf)
Exemplo n.º 31
0
    def check_config(self):
        super(VLAN, self).check_config()
        test_config_condition(not self.vid_valid(self.vid),
                              'invalid VID %s' % self.vid)
        test_config_condition(not netaddr.valid_mac(self.faucet_mac),
                              ('invalid MAC address %s' % self.faucet_mac))

        test_config_condition(
            self.acl_in and self.acls_in,
            'found both acl_in and acls_in, use only acls_in')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [
                self.acl_in,
            ]
            self.acl_in = None
        if self.acls_in:
            for acl in self.acls_in:
                test_config_condition(not isinstance(acl, (int, str)),
                                      'acl names must be int or str')

        if self.max_hosts:
            if not self.proactive_arp_limit:
                self.proactive_arp_limit = 2 * self.max_hosts
            if not self.proactive_nd_limit:
                self.proactive_nd_limit = 2 * self.max_hosts

        if self.faucet_vips:
            self.faucet_vips = frozenset([
                self._check_ip_str(ip_str, ip_method=ipaddress.ip_interface)
                for ip_str in self.faucet_vips
            ])

        if self.bgp_neighbor_addresses or self.bgp_neighbour_addresses:
            neigh_addresses = frozenset(self.bgp_neighbor_addresses +
                                        self.bgp_neighbour_addresses)
            self.bgp_neighbor_addresses = frozenset(
                [self._check_ip_str(ip_str) for ip_str in neigh_addresses])

        if self.bgp_server_addresses:
            self.bgp_server_addresses = frozenset([
                self._check_ip_str(ip_str)
                for ip_str in self.bgp_server_addresses
            ])
            for ipv in self.bgp_ipvs():
                test_config_condition(
                    len(self.bgp_server_addresses_by_ipv(ipv)) != 1,
                    'Only one BGP server address per IP version supported')

        if self.bgp_as:
            test_config_condition(not isinstance(self.bgp_port, int),
                                  ('BGP port must be %s not %s' %
                                   (int, type(self.bgp_port))))
            test_config_condition(self.bgp_connect_mode not in ('passive'),
                                  ('BGP connect mode %s must be passive' %
                                   self.bgp_connect_mode))
            test_config_condition(
                not ipaddress.IPv4Address(btos(self.bgp_routerid)),
                ('%s is not a valid IPv4 address' % (self.bgp_routerid)))
            test_config_condition(not self.bgp_neighbor_as,
                                  'No BGP neighbor AS')
            test_config_condition(not self.bgp_neighbor_addresses,
                                  'No BGP neighbor addresses')
            test_config_condition(
                len(self.bgp_neighbor_addresses) != len(
                    self.bgp_neighbor_addresses),
                ('Must be as many BGP neighbor addresses as BGP server addresses'
                 ))

        if self.routes:
            test_config_condition(not isinstance(self.routes, list),
                                  'invalid VLAN routes format')
            try:
                self.routes = [route['route'] for route in self.routes]
            except TypeError:
                raise InvalidConfigError('%s is not a valid routes value' %
                                         self.routes)
            except KeyError:
                pass
            for route in self.routes:
                test_config_condition(not isinstance(route, dict),
                                      'invalid VLAN route format')
                test_config_condition('ip_gw' not in route,
                                      'missing ip_gw in VLAN route')
                test_config_condition('ip_dst' not in route,
                                      'missing ip_dst in VLAN route')
                ip_gw = self._check_ip_str(route['ip_gw'])
                ip_dst = self._check_ip_str(route['ip_dst'],
                                            ip_method=ipaddress.ip_network)
                test_config_condition(
                    ip_gw.version != ip_dst.version,
                    'ip_gw version does not match the ip_dst version')
                self.add_route(ip_dst, ip_gw)
Exemplo n.º 32
0
    def check_config(self):
        super(VLAN, self).check_config()
        test_config_condition(not self.vid_valid(self.vid),
                              'invalid VID %s' % self.vid)
        test_config_condition(not netaddr.valid_mac(self.faucet_mac),
                              ('invalid MAC address %s' % self.faucet_mac))

        test_config_condition(
            self.acl_in and self.acls_in,
            'found both acl_in and acls_in, use only acls_in')
        test_config_condition(
            self.acl_out and self.acls_out,
            'found both acl_out and acls_out, use only acls_out')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [
                self.acl_in,
            ]
            self.acl_in = None
        if self.acl_out and not isinstance(self.acl_out, list):
            self.acls_out = [
                self.acl_out,
            ]
            self.acl_out = None
        all_acls = []
        if self.acls_in:
            all_acls.extend(self.acls_in)
        if self.acls_out:
            all_acls.extend(self.acls_out)
        for acl in all_acls:
            test_config_condition(not isinstance(acl, (int, str)),
                                  'acl names must be int or str')

        if self.max_hosts:
            if not self.proactive_arp_limit:
                self.proactive_arp_limit = 2 * self.max_hosts
            if not self.proactive_nd_limit:
                self.proactive_nd_limit = 2 * self.max_hosts

        if self.faucet_vips:
            self.faucet_vips = frozenset([
                self._check_ip_str(ip_str, ip_method=ipaddress.ip_interface)
                for ip_str in self.faucet_vips
            ])

        if self.routes:
            test_config_condition(not isinstance(self.routes, list),
                                  'invalid VLAN routes format')
            try:
                self.routes = [route['route'] for route in self.routes]
            except TypeError:
                raise InvalidConfigError('%s is not a valid routes value' %
                                         self.routes)
            except KeyError:
                pass
            for route in self.routes:
                test_config_condition(not isinstance(route, dict),
                                      'invalid VLAN route format')
                test_config_condition('ip_gw' not in route,
                                      'missing ip_gw in VLAN route')
                test_config_condition('ip_dst' not in route,
                                      'missing ip_dst in VLAN route')
                ip_gw = self._check_ip_str(route['ip_gw'])
                ip_dst = self._check_ip_str(route['ip_dst'],
                                            ip_method=ipaddress.ip_network)
                test_config_condition(
                    ip_gw.version != ip_dst.version,
                    'ip_gw version does not match the ip_dst version')
                self.add_route(ip_dst, ip_gw)
Exemplo n.º 33
0
 def check_config(self):
     super().check_config()
     test_config_condition(self.meter_id < 0, 'meter_id is than 0')
     test_config_condition(
         self.meter_id > 4294901760,
         'DP meter_id cannot exceed 4294901760 per OF13 specification')
Exemplo n.º 34
0
Arquivo: dp.py Projeto: lantz/faucet2
 def resolve_meter(_acl, action_conf):
     meter_name = action_conf
     test_config_condition(
         meter_name not in self.meters,
         ('meter %s is not configured' % meter_name))
     return action_conf
Exemplo n.º 35
0
 def _resolve_ordered_output_ports(self, output_list, resolve_port_cb, resolve_tunnel_objects):
     """Resolve output actions in the ordered list format"""
     result = []
     for action in output_list:
         for key, value in action.items():
             if key == 'tunnel':
                 tunnel = value
                 # Fetch tunnel items from the tunnel output dict
                 test_config_condition(
                     'dp' not in tunnel,
                     'ACL (%s) tunnel DP not defined' % self._id)
                 tunnel_dp = tunnel['dp']
                 tunnel_port = tunnel.get('port', None)
                 tunnel_id = tunnel.get('tunnel_id', None)
                 tunnel_type = tunnel.get('type', 'vlan')
                 tunnel_exit_instructions = tunnel.get('exit_instructions', [])
                 tunnel_direction = tunnel.get('bi_directional', False)
                 tunnel_maintain = tunnel.get('maintain_encapsulation', False)
                 tunnel_reverse = tunnel.get('reverse', False)
                 test_config_condition(
                     tunnel_reverse and tunnel_direction,
                     ('Tunnel ACL %s cannot contain values for the fields'
                      '`bi_directional` and `reverse` at the same time' % self._id))
                 # Resolve the tunnel items
                 dst_dp, dst_port, tunnel_id = resolve_tunnel_objects(
                     tunnel_dp, tunnel_port, tunnel_id)
                 # Compile the tunnel into an easy-access dictionary
                 tunnel_dict = {
                     'dst_dp': dst_dp,
                     'dst_port': dst_port,
                     'tunnel_id': tunnel_id,
                     'type': tunnel_type,
                     'exit_instructions': tunnel_exit_instructions,
                     'bi_directional': tunnel_direction,
                     'maintain_encapsulation': tunnel_maintain,
                     'reverse': tunnel_reverse,
                 }
                 self.tunnel_dests[tunnel_id] = tunnel_dict
                 result.append({key: tunnel_id})
             elif key == 'port':
                 port_name = value
                 port = resolve_port_cb(port_name)
                 test_config_condition(
                     not port,
                     'ACL (%s) output port undefined in DP: %s' % (self._id, self.dp_id))
                 result.append({key: port})
             elif key == 'ports':
                 resolved_ports = [
                     resolve_port_cb(p) for p in value]
                 test_config_condition(
                     None in resolved_ports,
                     'ACL (%s) output port(s) not defined in DP: %s' % (self._id, self.dp_id))
                 result.append({key: resolved_ports})
             elif key == 'failover':
                 failover = value
                 test_config_condition(not isinstance(failover, dict), (
                     'failover is not a dictionary'))
                 failover_dict = {}
                 for failover_name, failover_values in failover.items():
                     if failover_name == 'ports':
                         resolved_ports = [
                             resolve_port_cb(p) for p in failover_values]
                         test_config_condition(
                             None in resolved_ports,
                             'ACL (%s) failover port(s) not defined in DP: %s' % (
                                 self._id, self.dp_id))
                         failover_dict[failover_name] = resolved_ports
                     else:
                         failover_dict[failover_name] = failover_values
                 result.append({key: failover_dict})
             else:
                 result.append(action)
     return result
Exemplo n.º 36
0
Arquivo: acl.py Projeto: mubix/faucet
 def _resolve_output_ports(self, action_conf, resolve_port_cb, resolve_tunnel_objects):
     """Resolve the values for output actions in the ACL"""
     if isinstance(action_conf, (list, tuple)):
         return self._resolve_ordered_output_ports(
             action_conf, resolve_port_cb, resolve_tunnel_objects)
     result = {}
     test_config_condition(
         'vlan_vid' in action_conf and 'vlan_vids' in action_conf,
         'ACL %s has both vlan_vid and vlan_vids defined' % self._id)
     test_config_condition(
         'port' in action_conf and 'ports' in action_conf,
         'ACL %s has both port and ports defined' % self._id)
     for output_action, output_action_values in action_conf.items():
         if output_action == 'tunnel':
             tunnel = output_action_values
             # Fetch tunnel items from the tunnel output dict
             test_config_condition(
                 'dp' not in tunnel,
                 'ACL (%s) tunnel DP not defined' % self._id)
             tunnel_dp = tunnel['dp']
             test_config_condition(
                 'port' not in tunnel,
                 'ACL (%s) tunnel port not defined' % self._id)
             tunnel_port = tunnel['port']
             tunnel_id = tunnel.get('tunnel_id', None)
             tunnel_type = tunnel.get('type', 'vlan')
             # Resolve the tunnel items
             dst_dp, dst_port, tunnel_id = resolve_tunnel_objects(
                 tunnel_dp, tunnel_port, tunnel_id)
             # Compile the tunnel into an easy-access dictionary
             tunnel_dict = {
                 'dst_dp': dst_dp,
                 'dst_port': dst_port,
                 'tunnel_id': tunnel_id,
                 'type': tunnel_type
             }
             self.tunnel_info[tunnel_id] = tunnel_dict
             result[output_action] = tunnel_id
         elif output_action == 'port':
             port_name = output_action_values
             port = resolve_port_cb(port_name)
             test_config_condition(
                 not port,
                 ('ACL (%s) output port undefined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = port
         elif output_action == 'ports':
             resolved_ports = [
                 resolve_port_cb(p) for p in output_action_values]
             test_config_condition(
                 None in resolved_ports,
                 ('ACL (%s) output port(s) not defined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = resolved_ports
         elif output_action == 'failover':
             failover = output_action_values
             test_config_condition(not isinstance(failover, dict), (
                 'failover is not a dictionary'))
             result[output_action] = {}
             for failover_name, failover_values in failover.items():
                 if failover_name == 'ports':
                     resolved_ports = [
                         resolve_port_cb(p) for p in failover_values]
                     test_config_condition(
                         None in resolved_ports,
                         ('ACL (%s) failover port(s) not defined in DP: %s'\
                         % (self._id, self.dp_id))
                         )
                     result[output_action][failover_name] = resolved_ports
                 else:
                     result[output_action][failover_name] = failover_values
         else:
             result[output_action] = output_action_values
     return result
Exemplo n.º 37
0
    def check_config(self):
        super(VLAN, self).check_config()
        test_config_condition(not self.vid_valid(self.vid), 'invalid VID %s' % self.vid)
        test_config_condition(not netaddr.valid_mac(self.faucet_mac), (
            'invalid MAC address %s' % self.faucet_mac))

        test_config_condition(
            self.acl_in and self.acls_in, 'found both acl_in and acls_in, use only acls_in')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [self.acl_in,]
            self.acl_in = None
        if self.acls_in:
            for acl in self.acls_in:
                test_config_condition(
                    not isinstance(acl, (int, str)), 'acl names must be int or str')

        if self.max_hosts:
            if not self.proactive_arp_limit:
                self.proactive_arp_limit = 2 * self.max_hosts
            if not self.proactive_nd_limit:
                self.proactive_nd_limit = 2 * self.max_hosts

        if self.faucet_vips:
            self.faucet_vips = frozenset([
                self._check_ip_str(ip_str, ip_method=ipaddress.ip_interface)
                for ip_str in self.faucet_vips])

        if self.routes:
            test_config_condition(not isinstance(self.routes, list), 'invalid VLAN routes format')
            try:
                self.routes = [route['route'] for route in self.routes]
            except TypeError:
                raise InvalidConfigError('%s is not a valid routes value' % self.routes)
            except KeyError:
                pass
            for route in self.routes:
                test_config_condition(not isinstance(route, dict), 'invalid VLAN route format')
                test_config_condition('ip_gw' not in route, 'missing ip_gw in VLAN route')
                test_config_condition('ip_dst' not in route, 'missing ip_dst in VLAN route')
                ip_gw = self._check_ip_str(route['ip_gw'])
                ip_dst = self._check_ip_str(route['ip_dst'], ip_method=ipaddress.ip_network)
                test_config_condition(
                    ip_gw.version != ip_dst.version,
                    'ip_gw version does not match the ip_dst version')
                self.add_route(ip_dst, ip_gw)
Exemplo n.º 38
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()
Exemplo n.º 39
0
 def __init__(self, _id, dp_id, conf):
     super(ACL, self).__init__(_id, dp_id, conf)
     rules = conf
     if isinstance(conf, dict):
         if 'exact_match' in conf and conf['exact_match']:
             self.exact_match = True
         test_config_condition('rules' not in conf, 'no rules found for ACL %s' % _id)
         rules = conf['rules']
     self.rules = []
     test_config_condition(not isinstance(rules, list), (
         "ACL rules is %s not %s" % (type(rules), dict)))
     for match_fields in (MATCH_FIELDS, OLD_MATCH_FIELDS):
         for match in list(match_fields.keys()):
             self.rule_types[match] = (str, int)
     for rule in rules:
         test_config_condition(not isinstance(rule, dict), (
             "ACL rule is %s not %s" % (type(rule), dict)))
         for rule_key, rule_content in list(rule.items()):
             test_config_condition(rule_key != 'rule', "Incorrect ACL rule key")
             test_config_condition(not isinstance(rule_content, dict), (
                 "ACL rule content is %s not %s") % (type(rule_content), dict))
             self._check_conf_types(rule_content, self.rule_types)
             for rule_field, rule_conf in list(rule_content.items()):
                 if rule_field == 'cookie':
                     test_config_condition(rule_conf < 0 or rule_conf > 2**16, (
                         'rule cookie value must be 0-2**16'))
                 elif rule_field == 'actions':
                     test_config_condition(not rule_conf, "Missing rule actions in ACL %s" % _id)
                     self._check_conf_types(rule_conf, self.actions_types)
                     for action_name, action_conf in list(rule_conf.items()):
                         if action_name == 'output':
                             self._check_conf_types(action_conf, self.output_actions_types)
             self.rules.append(rule_content)
Exemplo n.º 40
0
Arquivo: dp.py Projeto: vmastar/faucet
    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()
Exemplo n.º 41
0
    def resolve_stack_topology(self, dps):
        """Resolve inter-DP config for stacking."""
        def canonical_edge(dp, port):
            peer_dp = port.stack['dp']
            peer_port = port.stack['port']
            sort_edge_a = (dp.name, port.name, dp, port)
            sort_edge_z = (peer_dp.name, peer_port.name, peer_dp, peer_port)
            sorted_edge = sorted((sort_edge_a, sort_edge_z))
            edge_a, edge_b = sorted_edge[0][2:], sorted_edge[1][2:]
            return edge_a, edge_b

        def make_edge_name(edge_a, edge_z):
            edge_a_dp, edge_a_port = edge_a
            edge_z_dp, edge_z_port = edge_z
            return '%s:%s-%s:%s' % (edge_a_dp.name, edge_a_port.name,
                                    edge_z_dp.name, edge_z_port.name)

        def make_edge_attr(edge_a, edge_z):
            edge_a_dp, edge_a_port = edge_a
            edge_z_dp, edge_z_port = edge_z
            return {
                'dp_a': edge_a_dp,
                'port_a': edge_a_port,
                'dp_z': edge_z_dp,
                'port_z': edge_z_port
            }

        root_dp = None
        stack_dps = []
        for dp in dps:
            if dp.stack is not None:
                stack_dps.append(dp)
                if 'priority' in dp.stack:
                    test_config_condition(dp.stack['priority'] <= 0,
                                          ('stack priority must be > 0'))
                    test_config_condition(root_dp is not None,
                                          'cannot have multiple stack roots')
                    root_dp = dp
                    for vlan in list(dp.vlans.values()):
                        test_config_condition(
                            vlan.faucet_vips != [],
                            ('routing + stacking not supported'))

        if root_dp is None:
            test_config_condition(stack_dps, 'stacking enabled but no root_dp')
            return

        edge_count = {}

        graph = networkx.MultiGraph()
        for dp in dps:
            if dp.stack_ports:
                graph.add_node(dp.name)
                for port in dp.stack_ports:
                    edge = canonical_edge(dp, port)
                    edge_a, edge_z = edge
                    edge_name = make_edge_name(edge_a, edge_z)
                    edge_attr = make_edge_attr(edge_a, edge_z)
                    edge_a_dp, _ = edge_a
                    edge_z_dp, _ = edge_z
                    if edge_name not in edge_count:
                        edge_count[edge_name] = 0
                    edge_count[edge_name] += 1
                    graph.add_edge(edge_a_dp.name,
                                   edge_z_dp.name,
                                   key=edge_name,
                                   port_map=edge_attr)
        if graph.size():
            for edge_name, count in list(edge_count.items()):
                test_config_condition(
                    count != 2, '%s defined only in one direction' % edge_name)
            if self.name in graph:
                if self.stack is None:
                    self.stack = {}
                self.stack['root_dp'] = root_dp
                self.stack['graph'] = graph
Exemplo n.º 42
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_port_numbers(port_names):
            """Resolve list of ports to numbers, by port by name or number."""
            return [port.number for port in resolve_ports(port_names)]

        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]
            elif 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):
            """Resolve an individual ACL."""
            test_config_condition(acl_in not in self.acls,
                                  ('missing ACL %s on %s' %
                                   (self.name, acl_in)))
            acl = self.acls[acl_in]
            mirror_destinations = set()

            def resolve_meter(_acl, action_conf):
                meter_name = action_conf
                test_config_condition(
                    meter_name not in self.meters,
                    ('meter %s is not configured' % meter_name))
                return action_conf

            def resolve_mirror(_acl, action_conf):
                port_name = action_conf
                port = self.resolve_port(port_name)
                # If this DP does not have this port, do nothing.
                if port is not None:
                    action_conf = port.number
                    mirror_destinations.add(port.number)
                    return action_conf
                return None

            def resolve_output(_acl, action_conf):
                resolved_action_conf = {}
                test_config_condition(not isinstance(action_conf, dict),
                                      ('action conf is not a dictionary'))
                for output_action, output_action_values in list(
                        action_conf.items()):
                    if output_action == 'port':
                        port_name = output_action_values
                        port = self.resolve_port(port_name)
                        test_config_condition(
                            not port,
                            ('output port not defined in DP: %s' % self.name))
                        resolved_action_conf[output_action] = port.number  # pytype: disable=attribute-error
                    elif output_action == 'ports':
                        resolved_ports = resolve_port_numbers(
                            output_action_values)
                        test_config_condition(
                            len(resolved_ports) != len(output_action_values),
                            ('output port(s) not defined in DP: %s' %
                             self.name))
                        resolved_action_conf[output_action] = resolved_ports
                    elif output_action == 'failover':
                        failover = output_action_values
                        test_config_condition(not isinstance(failover, dict),
                                              ('failover is not a dictionary'))
                        resolved_action_conf[output_action] = {}
                        for failover_name, failover_values in list(
                                failover.items()):
                            if failover_name == 'ports':
                                resolved_failover_values = resolve_port_numbers(
                                    failover_values)
                                test_config_condition(
                                    len(resolved_failover_values) !=
                                    len(failover_values),
                                    ('failover port(s) not defined in DP: %s' %
                                     self.name))
                                failover_values = resolved_failover_values
                            resolved_action_conf[output_action][
                                failover_name] = failover_values
                    else:
                        resolved_action_conf[
                            output_action] = output_action_values
                if resolved_action_conf:
                    return resolved_action_conf
                return None

            def resolve_noop(_acl, action_conf):
                return action_conf

            action_resolvers = {
                'meter': resolve_meter,
                'mirror': resolve_mirror,
                'output': resolve_output,
                'allow': resolve_noop,
                'force_port_vlan': resolve_noop,
            }

            def build_acl(acl, vid=None):
                """Check that ACL can be built from config and mark mirror destinations."""
                if acl.rules:
                    try:
                        ofmsgs = valve_acl.build_acl_ofmsgs(
                            [acl],
                            self.wildcard_table,
                            valve_of.goto_table(self.wildcard_table),
                            valve_of.goto_table(self.wildcard_table),
                            2**16 - 1,
                            self.meters,
                            acl.exact_match,
                            vlan_vid=vid)
                        test_config_condition(not ofmsgs,
                                              'of messages is empty')
                        for ofmsg in ofmsgs:
                            ofmsg.datapath = NullRyuDatapath()
                            ofmsg.set_xid(0)
                            ofmsg.serialize()
                    except (AddrFormatError, KeyError, ValueError) as err:
                        raise InvalidConfigError(err)
                    for port_no in mirror_destinations:
                        port = self.ports[port_no]
                        port.output_only = True

            for rule_conf in acl.rules:
                for attrib, attrib_value in list(rule_conf.items()):
                    if attrib == 'actions':
                        resolved_actions = {}
                        test_config_condition(
                            not isinstance(attrib_value, dict),
                            ('attrib_value is not a dictionary'))
                        for action_name, action_conf in list(
                                attrib_value.items()):
                            resolved_action_conf = action_resolvers[
                                action_name](acl, action_conf)
                            test_config_condition(
                                resolved_action_conf is None,
                                ('cannot resolve ACL rule %s' % rule_conf))
                            resolved_actions[
                                action_name] = resolved_action_conf
                        rule_conf[attrib] = resolved_actions

            build_acl(acl, vid=1)

        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)
                        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)
                        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)
                    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
            self.routers = dp_routers

        test_config_condition(
            not self.vlans,
            'no VLANs referenced by interfaces in %s' % self.name)

        for dp in dps:
            dp_by_name[dp.name] = dp
        for vlan in list(self.vlans.values()):
            vlan_by_name[vlan.name] = vlan

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

        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 = set([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 = set([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()
Exemplo n.º 43
0
 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'
              ))
Exemplo n.º 44
0
 def check_config(self):
     super(Router, self).check_config()
     test_config_condition(
         not (isinstance(self.vlans, list) and len(self.vlans) > 1),
         ('router %s must have at least 2 VLANs configured' % self))
Exemplo n.º 45
0
    def check_config(self):
        super(VLAN, self).check_config()
        test_config_condition(not self.vid_valid(self.vid), 'invalid VID %s' % self.vid)
        test_config_condition(not netaddr.valid_mac(self.faucet_mac), (
            'invalid MAC address %s' % self.faucet_mac))

        test_config_condition(self.acl_in and self.acls_in, 'found both acl_in and acls_in, use only acls_in')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [self.acl_in,]
            self.acl_in = None
        if self.acls_in:
            for acl in self.acls_in:
                test_config_condition(not isinstance(acl, (int, str)), 'acl names must be int or str')

        if self.max_hosts:
            if not self.proactive_arp_limit:
                self.proactive_arp_limit = 2 * self.max_hosts
            if not self.proactive_nd_limit:
                self.proactive_nd_limit = 2 * self.max_hosts

        if self.faucet_vips:
            self.faucet_vips = frozenset([
                self._check_ip_str(ip_str, ip_method=ipaddress.ip_interface) for ip_str in self.faucet_vips])

        if self.bgp_neighbor_addresses or self.bgp_neighbour_addresses:
            neigh_addresses = frozenset(self.bgp_neighbor_addresses + self.bgp_neighbour_addresses)
            self.bgp_neighbor_addresses = frozenset([
                self._check_ip_str(ip_str) for ip_str in neigh_addresses])

        if self.bgp_server_addresses:
            self.bgp_server_addresses = frozenset([
                self._check_ip_str(ip_str) for ip_str in self.bgp_server_addresses])
            for ipv in self.bgp_ipvs():
                test_config_condition(
                    len(self.bgp_server_addresses_by_ipv(ipv)) != 1,
                    'Only one BGP server address per IP version supported')

        if self.bgp_as:
            test_config_condition(not isinstance(self.bgp_port, int), (
                'BGP port must be %s not %s' % (int, type(self.bgp_port))))
            test_config_condition(self.bgp_connect_mode not in ('passive'), (
                'BGP connect mode %s must be passive' % self.bgp_connect_mode))
            test_config_condition(not ipaddress.IPv4Address(self.bgp_routerid), (
                '%s is not a valid IPv4 address' % (self.bgp_routerid)))
            test_config_condition(not self.bgp_neighbor_as, 'No BGP neighbor AS')
            test_config_condition(not self.bgp_neighbor_addresses, 'No BGP neighbor addresses')
            test_config_condition(len(self.bgp_neighbor_addresses) != len(self.bgp_neighbor_addresses), (
                'Must be as many BGP neighbor addresses as BGP server addresses'))

        if self.routes:
            test_config_condition(not isinstance(self.routes, list), 'invalid VLAN routes format')
            try:
                self.routes = [route['route'] for route in self.routes]
            except TypeError:
                raise InvalidConfigError('%s is not a valid routes value' % self.routes)
            except KeyError:
                pass
            for route in self.routes:
                test_config_condition(not isinstance(route, dict), 'invalid VLAN route format')
                test_config_condition('ip_gw' not in route, 'missing ip_gw in VLAN route')
                test_config_condition('ip_dst' not in route, 'missing ip_dst in VLAN route')
                ip_gw = self._check_ip_str(route['ip_gw'])
                ip_dst = self._check_ip_str(route['ip_dst'], ip_method=ipaddress.ip_network)
                test_config_condition(
                    ip_gw.version != ip_dst.version,
                    'ip_gw version does not match the ip_dst version')
                self.add_route(ip_dst, ip_gw)
Exemplo n.º 46
0
 def finalize(self):
     if self.native_vlan:
         test_config_condition(self.native_vlan in self.tagged_vlans, (
             'cannot have same native and tagged VLAN on same port'))
     self.tagged_vlans = tuple(self.tagged_vlans)
     super(Port, self).finalize()
Exemplo n.º 47
0
Arquivo: dp.py Projeto: vmastar/faucet
 def check_config(self):
     super(DP, self).check_config()
     test_config_condition(not isinstance(self.dp_id, int),
                           ('dp_id must be %s not %s' %
                            (int, type(self.dp_id))))
     test_config_condition(self.dp_id < 0 or self.dp_id > 2**64 - 1,
                           ('DP ID %s not in valid range' % self.dp_id))
     test_config_condition(not netaddr.valid_mac(self.faucet_dp_mac),
                           ('invalid MAC address %s' % self.faucet_dp_mac))
     test_config_condition(
         not (self.interfaces or self.interface_ranges),
         ('DP %s must have at least one interface' % self))
     test_config_condition(self.timeout < 15, ('timeout must be > 15'))
     # To prevent L2 learning from timing out before L3 can refresh
     test_config_condition(
         not (self.arp_neighbor_timeout < (self.timeout / 2)),
         ('L2 timeout must be > ARP timeout * 2'))
     test_config_condition(
         not (self.nd_neighbor_timeout < (self.timeout / 2)),
         ('L2 timeout must be > ND timeout * 2'))
     if self.cache_update_guard_time == 0:
         self.cache_update_guard_time = int(self.timeout / 2)
     if self.learn_jitter == 0:
         self.learn_jitter = int(max(math.sqrt(self.timeout) * 3, 1))
     if self.learn_ban_timeout == 0:
         self.learn_ban_timeout = self.learn_jitter
     if self.lldp_beacon:
         self._check_conf_types(self.lldp_beacon,
                                self.lldp_beacon_defaults_types)
         test_config_condition('send_interval' not in self.lldp_beacon,
                               ('lldp_beacon send_interval not set'))
         test_config_condition('max_per_interval' not in self.lldp_beacon,
                               ('lldp_beacon max_per_interval not set'))
         self.lldp_beacon = self._set_unknown_conf(
             self.lldp_beacon, self.lldp_beacon_defaults_types)
         if self.lldp_beacon['system_name'] is None:
             self.lldp_beacon['system_name'] = self.name
     if self.stack:
         self._check_conf_types(self.stack, self.stack_defaults_types)
     if self.dot1x:
         self._check_conf_types(self.dot1x, self.dot1x_defaults_types)
     self._check_conf_types(self.table_sizes,
                            self.default_table_sizes_types)
Exemplo n.º 48
0
    def build(self, meters, vid, port_num):
        """Check that ACL can be built from config."""

        self.matches = {}
        self.set_fields = set()
        self.meter = False
        if self.rules:
            try:
                ofmsgs = valve_acl.build_acl_ofmsgs(
                    [self], wildcard_table,
                    [valve_of.goto_table(wildcard_table)],
                    [valve_of.goto_table(wildcard_table)],
                    2**16-1, meters, self.exact_match,
                    vlan_vid=vid, port_num=port_num)
            except (netaddr.core.AddrFormatError, KeyError, ValueError) as err:
                raise InvalidConfigError from err
            test_config_condition(not ofmsgs, 'OF messages is empty')
            for ofmsg in ofmsgs:
                try:
                    valve_of.verify_flowmod(ofmsg)
                except (KeyError, ValueError) as err:
                    raise InvalidConfigError from err
                except Exception as err:
                    raise err
                if valve_of.is_flowmod(ofmsg):
                    apply_actions = []
                    for inst in ofmsg.instructions:
                        if valve_of.is_apply_actions(inst):
                            apply_actions.extend(inst.actions)
                        elif valve_of.is_meter(inst):
                            self.meter = True
                    for action in apply_actions:
                        if valve_of.is_set_field(action):
                            self.set_fields.add(action.key)
                    for match, value in ofmsg.match.items():
                        has_mask = isinstance(value, (tuple, list))
                        if has_mask or match not in self.matches:
                            self.matches[match] = has_mask
        for tunnel_rules in self.tunnel_dests.values():
            if 'exit_instructions' in tunnel_rules:
                exit_inst = tunnel_rules['exit_instructions']
                try:
                    ofmsgs = valve_acl.build_tunnel_ofmsgs(
                        exit_inst, wildcard_table, 1)
                except (netaddr.core.AddrFormatError, KeyError, ValueError) as err:
                    raise InvalidConfigError from err
                test_config_condition(not ofmsgs, 'OF messages is empty')
                for ofmsg in ofmsgs:
                    try:
                        valve_of.verify_flowmod(ofmsg)
                    except (KeyError, ValueError) as err:
                        raise InvalidConfigError from err
                    except Exception as err:
                        raise err
                    if valve_of.is_flowmod(ofmsg):
                        apply_actions = []
                        for inst in ofmsg.instructions:
                            if valve_of.is_apply_actions(inst):
                                apply_actions.extend(inst.actions)
                            elif valve_of.is_meter(inst):
                                self.meter = True
                        for action in apply_actions:
                            if valve_of.is_set_field(action):
                                self.set_fields.add(action.key)
                        for match, value in ofmsg.match.items():
                            has_mask = isinstance(value, (tuple, list))
                            if has_mask or match not in self.matches:
                                self.matches[match] = has_mask
        return (self.matches, self.set_fields, self.meter)
Exemplo n.º 49
0
 def check_config(self):
     super(Port, self).check_config()
     test_config_condition(not (isinstance(self.number, int) and self.number > 0 and (
         not valve_of.ignore_port(self.number))), ('Port number invalid: %s' % self.number))
     non_vlan_options = {'stack', 'mirror', 'coprocessor', 'output_only'}
     vlan_agnostic_options = {'enabled', 'number', 'name', 'description', 'max_lldp_lost'}
     vlan_port = self.tagged_vlans or self.native_vlan
     non_vlan_port_options = {option for option in non_vlan_options if getattr(self, option)}
     test_config_condition(
         vlan_port and non_vlan_port_options,
         'cannot have VLANs configured on non-VLAN ports: %s' % self)
     if self.output_only:
         test_config_condition(
             not non_vlan_port_options.issubset({'mirror', 'output_only'}),
             'output_only can only coexist with mirror option on same port %s' % self)
     elif self.mirror:
         test_config_condition(
             not non_vlan_port_options.issubset({'mirror', 'coprocessor'}),
             'coprocessor can only coexist with mirror option on same port %s' % self)
     else:
         test_config_condition(
             len(non_vlan_port_options) > 1,
             'cannot have multiple non-VLAN port options %s on same port: %s' % (
                 non_vlan_port_options, self))
     if non_vlan_port_options:
         for key, default_val in self.defaults.items():
             if key in vlan_agnostic_options or key in non_vlan_port_options:
                 continue
             if key.startswith('acl') and (self.stack or self.coprocessor):
                 continue
             val = getattr(self, key)
             test_config_condition(
                 val != default_val and val,
                 'Cannot have VLAN option %s: %s on non-VLAN port %s' % (key, val, self))
     test_config_condition(
         self.hairpin and self.hairpin_unicast,
         'Cannot have both hairpin and hairpin_unicast enabled')
     dot1x_features = {
         dot1x_feature for dot1x_feature, dot1x_config in self.defaults.items()
         if dot1x_feature.startswith('dot1x_') and dot1x_config}
     test_config_condition(
         dot1x_features and not self.dot1x,
         '802.1x features %s require port to have dot1x enabled' % dot1x_features)
     if self.dot1x:
         test_config_condition(self.number > 65535, (
             '802.1x not supported on ports > 65535'))
         if self.dot1x_mab:
             test_config_condition(self.dot1x_dyn_acl, (
                 '802.1x_MAB cannot be used with 802.1x_DYN_ACL'))
         if self.dot1x_dyn_acl:
             test_config_condition(self.dot1x_acl, (
                 '802.1x_DYN_ACL cannot be used with 802.1x_ACL'))
     if self.coprocessor:
         self._check_conf_types(self.coprocessor, self.coprocessor_defaults_types)
         test_config_condition(
             self.coprocessor.get('strategy', None) != 'vlan_vid',
             'coprocessor only supports vlan_vid strategy')
         self.coprocessor['vlan_vid_base'] = self.coprocessor.get('vlan_vid_base', 1000)
     if self.stack:
         self._check_conf_types(self.stack, self.stack_defaults_types)
         for stack_config in list(self.stack_defaults_types.keys()):
             test_config_condition(stack_config not in self.stack, (
                 'stack %s must be defined' % stack_config))
         # LLDP always enabled for stack ports.
         self.receive_lldp = True
         if not self.lldp_beacon_enabled():
             self.lldp_beacon.update({'enable': True})
     if self.lacp_resp_interval is not None:
         test_config_condition(
             self.lacp_resp_interval > 65535 or self.lacp_resp_interval < 0.3,
             ('interval must be at least 0.3 and less than 65536'))
     if self.lacp_port_priority is not None:
         test_config_condition(
             self.lacp_port_priority > 255 or self.lacp_port_priority < 0,
             ('lacp port priority must be at least 0 and less than 256'))
     if self.lldp_peer_mac:
         test_config_condition(not netaddr.valid_mac(self.lldp_peer_mac), (
             'invalid MAC address %s' % self.lldp_peer_mac))
     if self.lldp_beacon:
         self._check_conf_types(
             self.lldp_beacon, self.lldp_beacon_defaults_types)
         self.lldp_beacon = self._set_unknown_conf(
             self.lldp_beacon, self.lldp_beacon_defaults_types)
         if self.lldp_beacon_enabled():
             if self.lldp_beacon['port_descr'] is None:
                 self.lldp_beacon['port_descr'] = self.description
             org_tlvs = []
             for org_tlv in self.lldp_beacon['org_tlvs']:
                 self._check_conf_types(org_tlv, self.lldp_org_tlv_defaults_types)
                 test_config_condition(len(org_tlv) != len(self.lldp_org_tlv_defaults_types), (
                     'missing org_tlv config'))
                 if not isinstance(org_tlv['info'], bytearray):
                     try:
                         org_tlv['info'] = bytearray.fromhex(
                             org_tlv['info']) # pytype: disable=missing-parameter
                     except ValueError:
                         org_tlv['info'] = org_tlv['info'].encode('utf-8')
                 if not isinstance(org_tlv['oui'], bytearray):
                     org_tlv['oui'] = bytearray.fromhex(
                         '%6.6x' % org_tlv['oui']) # pytype: disable=missing-parameter
                 org_tlvs.append(org_tlv)
             self.lldp_beacon['org_tlvs'] = org_tlvs
     test_config_condition(
         self.acl_in and self.acls_in,
         'Found both acl_in and acls_in, use only acls_in')
     if self.acl_in and not isinstance(self.acl_in, list):
         self.acls_in = [self.acl_in]
         self.acl_in = None
     if self.acls_in:
         for acl in self.acls_in:
             test_config_condition(not isinstance(acl, (int, str)),
                                   'ACL names must be int or str')
     lacp_options = [self.lacp_selected, self.lacp_unselected, self.lacp_standby]
     test_config_condition(
         lacp_options.count(True) > 1,
         'Cannot force multiple LACP port selection states')
Exemplo n.º 50
0
Arquivo: dp.py Projeto: lantz/faucet2
 def check_config(self):
     test_config_condition(not isinstance(self.dp_id, int),
                           ('dp_id must be %s not %s' %
                            (int, type(self.dp_id))))
     test_config_condition(self.dp_id < 0 or self.dp_id > 2**64 - 1,
                           ('DP ID %s not in valid range' % self.dp_id))
     test_config_condition(not netaddr.valid_mac(self.faucet_dp_mac),
                           ('invalid MAC address %s' % self.faucet_dp_mac))
     test_config_condition(self.group_table and self.group_table_routing, (
         'groups for routing and other functions simultaneously not supported'
     ))
     test_config_condition(
         not (self.interfaces or self.interface_ranges),
         ('DP %s must have at least one interface' % self))
     # To prevent L2 learning from timing out before L3 can refresh
     test_config_condition(self.timeout < self.arp_neighbor_timeout,
                           ('L2 timeout must be >= L3 timeout'))
     if self.lldp_beacon:
         self._check_conf_types(self.lldp_beacon,
                                self.lldp_beacon_defaults_types)
         test_config_condition('send_interval' not in self.lldp_beacon,
                               ('lldp_beacon send_interval not set'))
         test_config_condition('max_per_interval' not in self.lldp_beacon,
                               ('lldp_beacon max_per_interval not set'))
         self.lldp_beacon = self._set_unknown_conf(
             self.lldp_beacon, self.lldp_beacon_defaults_types)
         if self.lldp_beacon['system_name'] is None:
             self.lldp_beacon['system_name'] = self.name
     if self.stack:
         self._check_conf_types(self.stack, self.stack_defaults_types)
     if self.dot1x:
         self._check_conf_types(self.dot1x, self.dot1x_defaults_types)
     if self.table_sizes:
         self._check_conf_types(self.table_sizes, self.table_sizes_types)
Exemplo n.º 51
0
    def check_config(self):
        super(Port, self).check_config()
        test_config_condition(
            not (isinstance(self.number, int) and self.number > 0 and
                 (not valve_of.ignore_port(self.number))),
            ('Port number invalid: %s' % self.number))
        test_config_condition(
            self.hairpin and self.hairpin_unicast,
            'Cannot have both hairpin and hairpin_unicast enabled')
        if self.dot1x:
            test_config_condition(self.number > 65535,
                                  ('802.1x not supported on ports > 65535'))
        if self.dot1x_acl:
            test_config_condition(
                not self.dot1x,
                ('802.1x_ACL requires dot1x to be enabled also'))
        if self.mirror:
            test_config_condition(
                self.tagged_vlans or self.native_vlan,
                ('mirror port %s cannot have any VLANs assigned' % self))
        if self.stack:
            self._check_conf_types(self.stack, self.stack_defaults_types)
            for stack_config in list(self.stack_defaults_types.keys()):
                test_config_condition(
                    stack_config not in self.stack,
                    ('stack %s must be defined' % stack_config))
            # LLDP always enabled for stack ports.
            self.receive_lldp = True
            if not self.lldp_beacon_enabled():
                self.lldp_beacon.update({'enable': True})

        if self.lldp_beacon:
            self._check_conf_types(self.lldp_beacon,
                                   self.lldp_beacon_defaults_types)
            self.lldp_beacon = self._set_unknown_conf(
                self.lldp_beacon, self.lldp_beacon_defaults_types)
            if self.lldp_beacon_enabled():
                if self.lldp_beacon['port_descr'] is None:
                    self.lldp_beacon['port_descr'] = self.description

                org_tlvs = []
                for org_tlv in self.lldp_beacon['org_tlvs']:
                    self._check_conf_types(org_tlv,
                                           self.lldp_org_tlv_defaults_types)
                    test_config_condition(
                        len(org_tlv) != len(self.lldp_org_tlv_defaults_types),
                        ('missing org_tlv config'))
                    if not isinstance(org_tlv['info'], bytearray):
                        try:
                            org_tlv['info'] = bytearray.fromhex(
                                org_tlv['info'])  # pytype: disable=missing-parameter
                        except ValueError:
                            org_tlv['info'] = org_tlv['info'].encode('utf-8')
                    if not isinstance(org_tlv['oui'], bytearray):
                        org_tlv['oui'] = bytearray.fromhex(
                            '%6.6x' % org_tlv['oui'])  # pytype: disable=missing-parameter
                    org_tlvs.append(org_tlv)
                self.lldp_beacon['org_tlvs'] = org_tlvs
        if self.acl_in and self.acls_in:
            raise InvalidConfigError(
                'found both acl_in and acls_in, use only acls_in')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [
                self.acl_in,
            ]
            self.acl_in = None
        if self.acls_in:
            for acl in self.acls_in:
                test_config_condition(not isinstance(acl, (int, str)),
                                      'ACL names must be int or str')
Exemplo n.º 52
0
Arquivo: dp.py Projeto: lantz/faucet2
    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_port_numbers(port_names):
            """Resolve list of ports to numbers, by port by name or number."""
            return [port.number for port in resolve_ports(port_names)]

        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]
            mirror_destinations = set()

            def resolve_meter(_acl, action_conf):
                meter_name = action_conf
                test_config_condition(
                    meter_name not in self.meters,
                    ('meter %s is not configured' % meter_name))
                return action_conf

            def resolve_mirror(_acl, action_conf):
                port_name = action_conf
                port = self.resolve_port(port_name)
                # If this DP does not have this port, do nothing.
                if port is not None:
                    action_conf = port.number
                    mirror_destinations.add(port.number)
                    return action_conf
                return None

            def resolve_output(_acl, action_conf):
                resolved_action_conf = {}
                test_config_condition(not isinstance(action_conf, dict),
                                      ('action conf is not a dictionary'))
                for output_action, output_action_values in list(
                        action_conf.items()):
                    if output_action == 'port':
                        port_name = output_action_values
                        port = self.resolve_port(port_name)
                        test_config_condition(
                            not port,
                            ('output port not defined in DP: %s' % self.name))
                        resolved_action_conf[output_action] = port.number  # pytype: disable=attribute-error
                    elif output_action == 'ports':
                        resolved_ports = resolve_port_numbers(
                            output_action_values)
                        test_config_condition(
                            len(resolved_ports) != len(output_action_values),
                            ('output port(s) not defined in DP: %s' %
                             self.name))
                        resolved_action_conf[output_action] = resolved_ports
                    elif output_action == 'failover':
                        failover = output_action_values
                        test_config_condition(not isinstance(failover, dict),
                                              ('failover is not a dictionary'))
                        resolved_action_conf[output_action] = {}
                        for failover_name, failover_values in list(
                                failover.items()):
                            if failover_name == 'ports':
                                resolved_failover_values = resolve_port_numbers(
                                    failover_values)
                                test_config_condition(
                                    len(resolved_failover_values) !=
                                    len(failover_values),
                                    ('failover port(s) not defined in DP: %s' %
                                     self.name))
                                failover_values = resolved_failover_values
                            resolved_action_conf[output_action][
                                failover_name] = failover_values
                    else:
                        resolved_action_conf[
                            output_action] = output_action_values
                if resolved_action_conf:
                    return resolved_action_conf
                return None

            def resolve_noop(_acl, action_conf):
                return action_conf

            action_resolvers = {
                'meter': resolve_meter,
                'mirror': resolve_mirror,
                'output': resolve_output,
                'allow': resolve_noop,
                'force_port_vlan': resolve_noop,
            }

            def build_acl(acl, vid):
                """Check that ACL can be built from config and mark mirror destinations."""
                matches = {}
                set_fields = set()
                meter = False
                if acl.rules:
                    try:
                        ofmsgs = valve_acl.build_acl_ofmsgs(
                            [acl],
                            self.wildcard_table,
                            valve_of.goto_table(self.wildcard_table),
                            valve_of.goto_table(self.wildcard_table),
                            2**16 - 1,
                            self.meters,
                            acl.exact_match,
                            vlan_vid=vid)
                    except (netaddr.core.AddrFormatError, KeyError,
                            ValueError) as err:
                        raise InvalidConfigError(err)
                    test_config_condition(not ofmsgs, 'OF messages is empty')
                    for ofmsg in ofmsgs:
                        ofmsg.datapath = NullRyuDatapath()
                        ofmsg.set_xid(0)
                        try:
                            ofmsg.serialize()
                        except (KeyError, ValueError) as err:
                            raise InvalidConfigError(err)
                        if valve_of.is_flowmod(ofmsg):
                            apply_actions = []
                            for inst in ofmsg.instructions:
                                if valve_of.is_apply_actions(inst):
                                    apply_actions.extend(inst.actions)
                                elif valve_of.is_meter(inst):
                                    meter = True
                            for action in apply_actions:
                                if valve_of.is_set_field(action):
                                    set_fields.add(action.key)
                            for match, value in list(ofmsg.match.items()):
                                has_mask = isinstance(value, (tuple, list))
                                if has_mask or match not in matches:
                                    matches[match] = has_mask
                    for port_no in mirror_destinations:
                        port = self.ports[port_no]
                        port.output_only = True
                return (matches, set_fields, meter)

            for rule_conf in acl.rules:
                for attrib, attrib_value in list(rule_conf.items()):
                    if attrib == 'actions':
                        resolved_actions = {}
                        test_config_condition(
                            not isinstance(attrib_value, dict),
                            ('attrib_value is not a dictionary'))
                        for action_name, action_conf in list(
                                attrib_value.items()):
                            resolved_action_conf = action_resolvers[
                                action_name](acl, action_conf)
                            test_config_condition(
                                resolved_action_conf is None,
                                ('cannot resolve ACL rule %s' % rule_conf))
                            resolved_actions[
                                action_name] = resolved_action_conf
                        rule_conf[attrib] = resolved_actions

            return build_acl(acl, vid)

        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():
            """Resolve config references in ACLs."""
            # TODO: move this config validation to ACL object.
            port_acl_matches = {}
            port_acl_set_fields = set()
            port_acl_exact_match = False
            port_acl_matches.update({'in_port': 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)
            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_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 in valve_packet.IPV4_LINK_LOCAL
                                or vip.ip in valve_packet.IPV6_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)

        for dp in dps:
            dp_by_name[dp.name] = dp
        for vlan in list(self.vlans.values()):
            vlan_by_name[vlan.name] = vlan

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

        # 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')

        self._configure_tables(override_table_config)

        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()
Exemplo n.º 53
0
Arquivo: dp.py Projeto: lantz/faucet2
    def resolve_stack_topology(self, dps):
        """Resolve inter-DP config for stacking."""
        root_dp = None
        stack_dps = []
        for dp in dps:
            if dp.stack is not None:
                stack_dps.append(dp)
                if 'priority' in dp.stack:
                    test_config_condition(dp.stack['priority'] <= 0,
                                          ('stack priority must be > 0'))
                    test_config_condition(root_dp is not None,
                                          'cannot have multiple stack roots')
                    root_dp = dp
                    for vlan in list(dp.vlans.values()):
                        test_config_condition(
                            vlan.faucet_vips,
                            ('routing + stacking not supported'))

        if root_dp is None:
            test_config_condition(stack_dps, 'stacking enabled but no root_dp')
            return

        edge_count = {}

        graph = networkx.MultiGraph()
        for dp in dps:
            if dp.stack_ports:
                graph.add_node(dp.name)
                for port in dp.stack_ports:
                    edge_name = self.add_stack_link(graph, dp, port)
                    if edge_name not in edge_count:
                        edge_count[edge_name] = 0
                    edge_count[edge_name] += 1
        if graph.size():
            for edge_name, count in list(edge_count.items()):
                test_config_condition(
                    count != 2, '%s defined only in one direction' % edge_name)
            if self.name in graph:
                if self.stack is None:
                    self.stack = {}
                self.stack['root_dp'] = root_dp
                self.stack['graph'] = graph
                longest_path_to_root_len = 0
                for dp in graph.nodes():
                    path_to_root_len = len(
                        self.shortest_path(root_dp.name, src_dp=dp))
                    test_config_condition(path_to_root_len == 0,
                                          '%s not connected to stack' % dp)
                    longest_path_to_root_len = max(path_to_root_len,
                                                   longest_path_to_root_len)
                self.stack[
                    'longest_path_to_root_len'] = longest_path_to_root_len
Exemplo n.º 54
0
 def check_config(self):
     super(WatcherConf, self).check_config()
     test_config_condition(self.all_dps and self.dps is not None,
                           'all_dps and dps cannot be set together')
Exemplo n.º 55
0
Arquivo: dp.py Projeto: lantz/faucet2
        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]
            mirror_destinations = set()

            def resolve_meter(_acl, action_conf):
                meter_name = action_conf
                test_config_condition(
                    meter_name not in self.meters,
                    ('meter %s is not configured' % meter_name))
                return action_conf

            def resolve_mirror(_acl, action_conf):
                port_name = action_conf
                port = self.resolve_port(port_name)
                # If this DP does not have this port, do nothing.
                if port is not None:
                    action_conf = port.number
                    mirror_destinations.add(port.number)
                    return action_conf
                return None

            def resolve_output(_acl, action_conf):
                resolved_action_conf = {}
                test_config_condition(not isinstance(action_conf, dict),
                                      ('action conf is not a dictionary'))
                for output_action, output_action_values in list(
                        action_conf.items()):
                    if output_action == 'port':
                        port_name = output_action_values
                        port = self.resolve_port(port_name)
                        test_config_condition(
                            not port,
                            ('output port not defined in DP: %s' % self.name))
                        resolved_action_conf[output_action] = port.number  # pytype: disable=attribute-error
                    elif output_action == 'ports':
                        resolved_ports = resolve_port_numbers(
                            output_action_values)
                        test_config_condition(
                            len(resolved_ports) != len(output_action_values),
                            ('output port(s) not defined in DP: %s' %
                             self.name))
                        resolved_action_conf[output_action] = resolved_ports
                    elif output_action == 'failover':
                        failover = output_action_values
                        test_config_condition(not isinstance(failover, dict),
                                              ('failover is not a dictionary'))
                        resolved_action_conf[output_action] = {}
                        for failover_name, failover_values in list(
                                failover.items()):
                            if failover_name == 'ports':
                                resolved_failover_values = resolve_port_numbers(
                                    failover_values)
                                test_config_condition(
                                    len(resolved_failover_values) !=
                                    len(failover_values),
                                    ('failover port(s) not defined in DP: %s' %
                                     self.name))
                                failover_values = resolved_failover_values
                            resolved_action_conf[output_action][
                                failover_name] = failover_values
                    else:
                        resolved_action_conf[
                            output_action] = output_action_values
                if resolved_action_conf:
                    return resolved_action_conf
                return None

            def resolve_noop(_acl, action_conf):
                return action_conf

            action_resolvers = {
                'meter': resolve_meter,
                'mirror': resolve_mirror,
                'output': resolve_output,
                'allow': resolve_noop,
                'force_port_vlan': resolve_noop,
            }

            def build_acl(acl, vid):
                """Check that ACL can be built from config and mark mirror destinations."""
                matches = {}
                set_fields = set()
                meter = False
                if acl.rules:
                    try:
                        ofmsgs = valve_acl.build_acl_ofmsgs(
                            [acl],
                            self.wildcard_table,
                            valve_of.goto_table(self.wildcard_table),
                            valve_of.goto_table(self.wildcard_table),
                            2**16 - 1,
                            self.meters,
                            acl.exact_match,
                            vlan_vid=vid)
                    except (netaddr.core.AddrFormatError, KeyError,
                            ValueError) as err:
                        raise InvalidConfigError(err)
                    test_config_condition(not ofmsgs, 'OF messages is empty')
                    for ofmsg in ofmsgs:
                        ofmsg.datapath = NullRyuDatapath()
                        ofmsg.set_xid(0)
                        try:
                            ofmsg.serialize()
                        except (KeyError, ValueError) as err:
                            raise InvalidConfigError(err)
                        if valve_of.is_flowmod(ofmsg):
                            apply_actions = []
                            for inst in ofmsg.instructions:
                                if valve_of.is_apply_actions(inst):
                                    apply_actions.extend(inst.actions)
                                elif valve_of.is_meter(inst):
                                    meter = True
                            for action in apply_actions:
                                if valve_of.is_set_field(action):
                                    set_fields.add(action.key)
                            for match, value in list(ofmsg.match.items()):
                                has_mask = isinstance(value, (tuple, list))
                                if has_mask or match not in matches:
                                    matches[match] = has_mask
                    for port_no in mirror_destinations:
                        port = self.ports[port_no]
                        port.output_only = True
                return (matches, set_fields, meter)

            for rule_conf in acl.rules:
                for attrib, attrib_value in list(rule_conf.items()):
                    if attrib == 'actions':
                        resolved_actions = {}
                        test_config_condition(
                            not isinstance(attrib_value, dict),
                            ('attrib_value is not a dictionary'))
                        for action_name, action_conf in list(
                                attrib_value.items()):
                            resolved_action_conf = action_resolvers[
                                action_name](acl, action_conf)
                            test_config_condition(
                                resolved_action_conf is None,
                                ('cannot resolve ACL rule %s' % rule_conf))
                            resolved_actions[
                                action_name] = resolved_action_conf
                        rule_conf[attrib] = resolved_actions

            return build_acl(acl, vid)
Exemplo n.º 56
0
def _dp_parser_v2(acls_conf, dps_conf, meters_conf, routers_conf, vlans_conf):
    dps = []

    def _get_vlan_by_key(dp_id, vlan_key, vlans):
        test_config_condition(
            not isinstance(vlan_key, (str, int)),
            ('VLAN key must not be type %s' % type(vlan_key)))
        if vlan_key in vlans:
            return vlans[vlan_key]
        for vlan in list(vlans.values()):
            if vlan_key == str(vlan.vid):
                return vlan
        # Create VLAN with VID, if not defined.
        return vlans.setdefault(vlan_key, VLAN(vlan_key, dp_id))

    def _dp_parse_port(dp_id, port_key, port_conf, vlans):
        port = Port(port_key, dp_id, port_conf)
        test_config_condition(
            str(port_key) not in (str(port.number), port.name),
            ('Port key %s match port name or port number' % port_key))

        def _dp_parse_native_port_vlan():
            if port.native_vlan is not None:
                vlan = _get_vlan_by_key(dp_id, port.native_vlan, vlans)
                port.native_vlan = vlan

        def _dp_parse_tagged_port_vlans():
            if port.tagged_vlans:
                port_tagged_vlans = [
                    _get_vlan_by_key(dp_id, vlan_key, vlans)
                    for vlan_key in port.tagged_vlans
                ]
                port.tagged_vlans = port_tagged_vlans

        _dp_parse_native_port_vlan()
        _dp_parse_tagged_port_vlans()
        return port

    def _dp_add_ports(dp, dp_conf, dp_id, vlans):
        ports_conf = dp_conf.get('interfaces', {})
        port_ranges_conf = dp_conf.get('interface_ranges', {})
        # as users can config port vlan by using vlan name, we store vid in
        # Port instance instead of vlan name for data consistency
        test_config_condition(not isinstance(ports_conf, dict),
                              ('Invalid syntax in interface config'))
        test_config_condition(not isinstance(port_ranges_conf, dict),
                              ('Invalid syntax in interface ranges config'))
        port_num_to_port_conf = {}
        for port_key, port_conf in list(ports_conf.items()):
            test_config_condition(not isinstance(port_conf, dict),
                                  'Invalid syntax in port config')
            if 'number' in port_conf:
                port_num = port_conf['number']
            else:
                port_num = port_key
            try:
                port_num_to_port_conf[port_num] = (port_key, port_conf)
            except TypeError:
                raise InvalidConfigError('Invalid syntax in port config')
        for port_range, port_conf in list(port_ranges_conf.items()):
            # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9
            test_config_condition(not isinstance(port_conf, dict),
                                  'Invalid syntax in port config')
            port_nums = set()
            if 'number' in port_conf:
                del port_conf['number']
            for range_ in re.findall(r'(\d+-\d+)', str(port_range)):
                start_num, end_num = [int(num) for num in range_.split('-')]
                test_config_condition(start_num >= end_num,
                                      ('Incorrect port range (%d - %d)' %
                                       (start_num, end_num)))
                port_nums.update(list(range(start_num, end_num + 1)))
                port_range = re.sub(range_, '', port_range)
            other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))]
            port_nums.update(other_nums)
            test_config_condition(not port_nums,
                                  'interface-ranges contain invalid config')
            for port_num in port_nums:
                if port_num in port_num_to_port_conf:
                    # port range config has lower priority than individual port config
                    for attr, value in list(port_conf.items()):
                        port_num_to_port_conf[port_num][1].setdefault(
                            attr, value)
                else:
                    port_num_to_port_conf[port_num] = (port_num, port_conf)
        for port_num, port_conf in list(port_num_to_port_conf.values()):
            port = _dp_parse_port(dp_id, port_num, port_conf, vlans)
            dp.add_port(port)
        dp.reset_refs(vlans=vlans)

    for dp_key, dp_conf in list(dps_conf.items()):
        test_config_condition(not isinstance(dp_conf, dict), '')
        dp = DP(dp_key, dp_conf.get('dp_id', None), dp_conf)
        test_config_condition(dp.name != dp_key,
                              ('DP key %s and DP name must match' % dp_key))
        dp_id = dp.dp_id

        vlans = {}
        for vlan_key, vlan_conf in list(vlans_conf.items()):
            vlan = VLAN(vlan_key, dp_id, vlan_conf)
            vlans[vlan_key] = vlan
            test_config_condition(
                str(vlan_key) not in (str(vlan.vid), vlan.name),
                ('VLAN %s key must match VLAN name or VLAN VID' % vlan_key))
        for acl_key, acl_conf in list(acls_conf.items()):
            acl = ACL(acl_key, dp_id, acl_conf)
            dp.add_acl(acl_key, acl)
        for router_key, router_conf in list(routers_conf.items()):
            router = Router(router_key, dp_id, router_conf)
            dp.add_router(router_key, router)
        for meter_key, meter_conf in list(meters_conf.items()):
            meter = Meter(meter_key, dp_id, meter_conf)
            dp.meters[meter_key] = meter
        _dp_add_ports(dp, dp_conf, dp_id, vlans)
        dps.append(dp)

    for dp in dps:
        dp.finalize_config(dps)
    for dp in dps:
        dp.resolve_stack_topology(dps)

    router_ref_dps = collections.defaultdict(set)
    for dp in dps:
        for router in list(dp.routers.keys()):
            router_ref_dps[router].add(dp)
    for router in list(routers_conf.keys()):
        test_config_condition(
            not router_ref_dps[router],
            ('router %s configured but not used by any DP' % router))

    return dps
Exemplo n.º 57
0
Arquivo: dp.py Projeto: lantz/faucet2
        def resolve_acls():
            """Resolve config references in ACLs."""
            # TODO: move this config validation to ACL object.
            port_acl_matches = {}
            port_acl_set_fields = set()
            port_acl_exact_match = False
            port_acl_matches.update({'in_port': 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)
            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_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
Exemplo n.º 58
0
    def check_config(self):
        super(VLAN, self).check_config()
        test_config_condition(not self.vid_valid(self.vid),
                              'invalid VID %s' % self.vid)
        test_config_condition(not netaddr.valid_mac(self.faucet_mac),
                              ('invalid MAC address %s' % self.faucet_mac))
        if self.max_hosts:
            if not self.proactive_arp_limit:
                self.proactive_arp_limit = 2 * self.max_hosts
            if not self.proactive_nd_limit:
                self.proactive_nd_limit = 2 * self.max_hosts
        if self.faucet_vips:
            try:
                self.faucet_vips = [
                    ipaddress.ip_interface(btos(ip)) for ip in self.faucet_vips
                ]
            except (ValueError, AttributeError, TypeError) as err:
                raise InvalidConfigError(
                    'Invalid IP address in faucet_vips: %s' % err)
            for faucet_vip in self.faucet_vips:
                self.dyn_faucet_vips_by_ipv[faucet_vip.version].append(
                    faucet_vip)
            self.dyn_ipvs = list(self.dyn_faucet_vips_by_ipv.keys())
        if self.bgp_neighbor_addresses or self.bgp_neighbour_addresses:
            neigh_addresses = set(self.bgp_neighbor_addresses +
                                  self.bgp_neighbour_addresses)
            try:
                self.bgp_neighbor_addresses = [
                    ipaddress.ip_address(btos(ip)) for ip in neigh_addresses
                ]
            except (ValueError, AttributeError, TypeError) as err:
                raise InvalidConfigError(
                    'Invalid IP address in bgp_neighbor_addresses: %s' % err)
            for bgp_neighbor_address in self.bgp_neighbor_addresses:
                self.dyn_bgp_neighbor_addresses_by_ipv[
                    bgp_neighbor_address.version].append(bgp_neighbor_address)
        if self.bgp_server_addresses:
            try:
                self.bgp_server_addresses = [
                    ipaddress.ip_address(btos(ip))
                    for ip in self.bgp_server_addresses
                ]
            except (ValueError, AttributeError, TypeError) as err:
                raise InvalidConfigError(
                    'Invalid IP address in bgp_server_addresses: %s' % err)
            for bgp_server_address in self.bgp_server_addresses:
                self.dyn_bgp_server_addresses_by_ipv[
                    bgp_server_address.version].append(bgp_server_address)
            self.dyn_bgp_ipvs = list(
                self.dyn_bgp_server_addresses_by_ipv.keys())

        if self.bgp_as:
            test_config_condition(not isinstance(self.bgp_port, int),
                                  ('BGP port must be %s not %s' %
                                   (int, type(self.bgp_port))))
            test_config_condition(
                self.bgp_connect_mode not in ('active', 'passive', 'both'),
                ('%s must be active, passive or both' % self.bgp_connect_mode))
            test_config_condition(
                not ipaddress.IPv4Address(btos(self.bgp_routerid)),
                ('%s is not a valid IPv4 address' % (self.bgp_routerid)))
            test_config_condition(not self.bgp_neighbor_as,
                                  'No BGP neighbor AS')
            test_config_condition(not self.bgp_neighbor_addresses,
                                  'No BGP neighbor addresses')
            neighbor_ips = self.bgp_neighbor_addresses
            test_config_condition(
                len(neighbor_ips) != len(self.bgp_neighbor_addresses),
                ('Neighbor IPs is not the same length as BGP neighbor addresses'
                 ))
            peer_versions = [ip.version for ip in neighbor_ips]
            test_config_condition(
                len(peer_versions) != 1 and self.bgp_connect_mode != 'active',
                ('if using multiple address families bgp_connect_mode must be active'
                 ))

        if self.routes:
            try:
                self.routes = [route['route'] for route in self.routes]
                for route in self.routes:
                    try:
                        ip_gw = ipaddress.ip_address(btos(route['ip_gw']))
                        ip_dst = ipaddress.ip_network(btos(route['ip_dst']))
                    except (ValueError, AttributeError, TypeError) as err:
                        raise InvalidConfigError(
                            'Invalid IP address in route: %s' % err)
                    test_config_condition(
                        ip_gw.version != ip_dst.version,
                        'ip_gw version does not match the ip_dst version')
                    self.add_route(ip_dst, ip_gw)
            except KeyError as err:
                raise InvalidConfigError('missing route config %s' % err)
            except TypeError:
                raise InvalidConfigError('%s is not a valid routes value' %
                                         self.routes)
        test_config_condition(
            self.acl_in and self.acls_in,
            'found both acl_in and acls_in, use only acls_in')
        if self.acl_in and not isinstance(self.acl_in, list):
            self.acls_in = [
                self.acl_in,
            ]
            self.acl_in = None
        if self.acls_in:
            for acl in self.acls_in:
                test_config_condition(not isinstance(acl, (int, str)),
                                      'acl names must be int or str')
Exemplo n.º 59
0
 def _dp_add_ports(dp, dp_conf, dp_id, vlans):
     ports_conf = dp_conf.get('interfaces', {})
     port_ranges_conf = dp_conf.get('interface_ranges', {})
     # as users can config port vlan by using vlan name, we store vid in
     # Port instance instead of vlan name for data consistency
     test_config_condition(not isinstance(ports_conf, dict),
                           ('Invalid syntax in interface config'))
     test_config_condition(not isinstance(port_ranges_conf, dict),
                           ('Invalid syntax in interface ranges config'))
     port_num_to_port_conf = {}
     for port_key, port_conf in list(ports_conf.items()):
         test_config_condition(not isinstance(port_conf, dict),
                               'Invalid syntax in port config')
         if 'number' in port_conf:
             port_num = port_conf['number']
         else:
             port_num = port_key
         try:
             port_num_to_port_conf[port_num] = (port_key, port_conf)
         except TypeError:
             raise InvalidConfigError('Invalid syntax in port config')
     for port_range, port_conf in list(port_ranges_conf.items()):
         # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9
         test_config_condition(not isinstance(port_conf, dict),
                               'Invalid syntax in port config')
         port_nums = set()
         if 'number' in port_conf:
             del port_conf['number']
         for range_ in re.findall(r'(\d+-\d+)', str(port_range)):
             start_num, end_num = [int(num) for num in range_.split('-')]
             test_config_condition(start_num >= end_num,
                                   ('Incorrect port range (%d - %d)' %
                                    (start_num, end_num)))
             port_nums.update(list(range(start_num, end_num + 1)))
             port_range = re.sub(range_, '', port_range)
         other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))]
         port_nums.update(other_nums)
         test_config_condition(not port_nums,
                               'interface-ranges contain invalid config')
         for port_num in port_nums:
             if port_num in port_num_to_port_conf:
                 # port range config has lower priority than individual port config
                 for attr, value in list(port_conf.items()):
                     port_num_to_port_conf[port_num][1].setdefault(
                         attr, value)
             else:
                 port_num_to_port_conf[port_num] = (port_num, port_conf)
     for port_num, port_conf in list(port_num_to_port_conf.values()):
         port = _dp_parse_port(dp_id, port_num, port_conf, vlans)
         dp.add_port(port)
     dp.reset_refs(vlans=vlans)
Exemplo n.º 60
0
 def _resolve_output_ports(self, action_conf, resolve_port_cb, resolve_tunnel_objects):
     """Resolve the values for output actions in the ACL"""
     if isinstance(action_conf, (list, tuple)):
         return self._resolve_ordered_output_ports(
             action_conf, resolve_port_cb, resolve_tunnel_objects)
     result = {}
     test_config_condition(
         'vlan_vid' in action_conf and 'vlan_vids' in action_conf,
         'ACL %s has both vlan_vid and vlan_vids defined' % self._id)
     test_config_condition(
         'port' in action_conf and 'ports' in action_conf,
         'ACL %s has both port and ports defined' % self._id)
     for output_action, output_action_values in action_conf.items():
         if output_action == 'tunnel':
             tunnel = output_action_values
             # Fetch tunnel items from the tunnel output dict
             test_config_condition(
                 'dp' not in tunnel,
                 'ACL (%s) tunnel DP not defined' % self._id)
             tunnel_dp = tunnel['dp']
             tunnel_port = tunnel.get('port', None)
             tunnel_id = tunnel.get('tunnel_id', None)
             tunnel_type = tunnel.get('type', 'vlan')
             tunnel_exit_instructions = tunnel.get('exit_instructions', [])
             tunnel_direction = tunnel.get('bi_directional', False)
             tunnel_maintain = tunnel.get('maintain_encapsulation', False)
             tunnel_reverse = tunnel.get('reverse', False)
             test_config_condition(
                 tunnel_reverse and tunnel_direction,
                 ('Tunnel ACL %s cannot contain values for the fields'
                  '`bi_directional` and `reverse` at the same time' % self._id))
             # Resolve the tunnel items
             dst_dp, dst_port, tunnel_id = resolve_tunnel_objects(
                 tunnel_dp, tunnel_port, tunnel_id)
             # Compile the tunnel into an easy-access dictionary
             tunnel_dict = {
                 'dst_dp': dst_dp,
                 'dst_port': dst_port,
                 'tunnel_id': tunnel_id,
                 'type': tunnel_type,
                 'exit_instructions': tunnel_exit_instructions,
                 'bi_directional': tunnel_direction,
                 'maintain_encapsulation': tunnel_maintain,
                 'reverse': tunnel_reverse,
             }
             self.tunnel_dests[tunnel_id] = tunnel_dict
             result[output_action] = tunnel_id
         elif output_action == 'port':
             port_name = output_action_values
             port = resolve_port_cb(port_name)
             test_config_condition(
                 not port,
                 ('ACL (%s) output port undefined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = port
         elif output_action == 'ports':
             resolved_ports = [
                 resolve_port_cb(p) for p in output_action_values]
             test_config_condition(
                 None in resolved_ports,
                 ('ACL (%s) output port(s) not defined in DP: %s'\
                 % (self._id, self.dp_id))
                 )
             result[output_action] = resolved_ports
         elif output_action == 'failover':
             failover = output_action_values
             test_config_condition(not isinstance(failover, dict), (
                 'failover is not a dictionary'))
             result[output_action] = {}
             for failover_name, failover_values in failover.items():
                 if failover_name == 'ports':
                     resolved_ports = [
                         resolve_port_cb(p) for p in failover_values]
                     test_config_condition(
                         None in resolved_ports,
                         ('ACL (%s) failover port(s) not defined in DP: %s'\
                         % (self._id, self.dp_id))
                         )
                     result[output_action][failover_name] = resolved_ports
                 else:
                     result[output_action][failover_name] = failover_values
         else:
             result[output_action] = output_action_values
     return result