def main(): s = sys.stdin.read() file_name = create_config_file(s) try: cp.dp_parser(file_name, LOGNAME) except cp.InvalidConfigError as err: pass
def main(): logging.disable(logging.CRITICAL) while afl.loop(ROUNDS): # pylint: disable=c-extension-no-member config = sys.stdin.read() file_name = create_config_file(config) try: cp.dp_parser(file_name, LOGNAME) except cp.InvalidConfigError: pass
def main(): """Runs the py-AFL fuzzer with the faucet config parser""" logging.disable(logging.CRITICAL) while afl.loop(ROUNDS): # pylint: disable=c-extension-no-member config = sys.stdin.read() file_name = create_config_file(config) try: cp.dp_parser(file_name, LOGNAME) except InvalidConfigError: pass
def setUp(self): self.tmpdir = tempfile.mkdtemp() self.config_file = os.path.join(self.tmpdir, 'valve_reload_unit.yaml') self.table = FakeOFTable(7) with open(self.config_file, 'w') as f: f.write(self.OLD_CONFIG) _, dps = dp_parser(self.config_file, 'test_valve') self.valve = valve_factory(dps[0])(dps[0], 'test_valve') # establish connection to datapath ofmsgs = self.valve.datapath_connect( self.DP_ID, range(1, self.NUM_PORTS + 1) ) self.table.apply_ofmsgs(ofmsgs) # learn some mac addresses self.rcv_packet(1, 100, { 'eth_src': self.P1_V100_MAC, 'eth_dst': self.UNKNOWN_MAC }) self.rcv_packet(2, 100, { 'eth_src': self.P2_V200_MAC, 'eth_dst': self.P3_V200_MAC, 'vid': 200 }) self.rcv_packet(3, 100, { 'eth_src': self.P3_V200_MAC, 'eth_dst': self.P2_V200_MAC, 'vid': 200 }) # reload the config with open(self.config_file, 'w') as f: f.write(self.CONFIG) _, new_dps = dp_parser(self.config_file, 'test_valve') ofmsgs = self.valve.reload_config(new_dps[0]) self.table.apply_ofmsgs(ofmsgs) # relearn some mac addresses self.rcv_packet(1, 100, { 'eth_src': self.P1_V100_MAC, 'eth_dst': self.UNKNOWN_MAC }) self.rcv_packet(2, 200, { 'eth_src': self.P2_V200_MAC, 'eth_dst': self.P3_V200_MAC, 'vid': 200 }) self.rcv_packet(3, 200, { 'eth_src': self.P3_V200_MAC, 'eth_dst': self.P2_V200_MAC, 'vid': 200 })
def __init__(self, *args, **kwargs): super(Faucet, self).__init__(*args, **kwargs) # There doesnt seem to be a sensible method of getting command line # options into ryu apps. Instead I am using the environment variable # FAUCET_CONFIG to allow this to be set, if it is not set it will # default to valve.yaml sysprefix = get_sys_prefix() self.config_file = os.getenv('FAUCET_CONFIG', sysprefix + '/etc/ryu/faucet/faucet.yaml') self.logfile = os.getenv('FAUCET_LOG', sysprefix + '/var/log/ryu/faucet/faucet.log') self.exc_logfile = os.getenv( 'FAUCET_EXCEPTION_LOG', sysprefix + '/var/log/ryu/faucet/faucet_exception.log') # Set the signal handler for reloading config file signal.signal(signal.SIGHUP, self.signal_handler) # Create dpset object for querying Ryu's DPSet application self.dpset = kwargs['dpset'] # Setup logging self.logger = get_logger(self.logname, self.logfile, logging.DEBUG, 0) # Set up separate logging for exceptions self.exc_logger = get_logger(self.exc_logname, self.exc_logfile, logging.DEBUG, 1) # TODO: metrics instance can be passed to Valves also, # for DP specific instrumentation. self.metrics = FaucetMetrics() prom_port = int(os.getenv('FAUCET_PROMETHEUS_PORT', '9244')) start_http_server(prom_port) # Set up a valve object for each datapath self.valves = {} self.config_hashes, valve_dps = dp_parser(self.config_file, self.logname) for valve_dp in valve_dps: # pylint: disable=no-member valve_cl = valve_factory(valve_dp) if valve_cl is None: self.logger.error('Hardware type not supported for DP: %s', valve_dp.name) else: valve = valve_cl(valve_dp, self.logname) self.valves[valve_dp.dp_id] = valve valve.update_config_metrics(self.metrics) self.gateway_resolve_request_thread = hub.spawn( self.gateway_resolve_request) self.host_expire_request_thread = hub.spawn(self.host_expire_request) self.dp_bgp_speakers = {} self._reset_bgp() # Register to API api = kwargs['faucet_api'] api._register(self) self.send_event_to_observers(EventFaucetAPIRegistered())
def check_config(conf_files, debug_level, check_output_file): """Return True and successful config dict, if all config can be parsed.""" logname = os.devnull logger = logging.getLogger('%s.config' % logname) logger_handler = logging.StreamHandler(stream=sys.stderr) logger.addHandler(logger_handler) logger.propagate = 0 logger.setLevel(debug_level) check_output = [] for conf_file in conf_files: check_result = False try: _, dps = dp_parser(conf_file, logname) if dps is not None: dps_conf = [(valve.valve_factory(dp), dp.to_conf()) for dp in dps] check_output.extend([conf for _, conf in dps_conf]) check_result = True continue except InvalidConfigError as config_err: check_output = [config_err] break pprint.pprint(check_output, stream=check_output_file) return check_result
def test_port_range_valid_config(self): """Test if port range config applied correctly""" config = """ vlans: office: vid: 100 guest: vid: 200 dps: sw1: dp_id: 0x1 interface_ranges: 1-4,6,port8: native_vlan: office max_hosts: 2 permanent_learn: True port10-11: native_vlan: guest max_hosts: 2 interfaces: 1: max_hosts: 4 description: "video conf" """ conf_file = self.create_config_file(config) _, dps = cp.dp_parser(conf_file, LOGNAME) dp = dps[0] self.assertEqual(len(dp.ports), 8) self.assertTrue(all([p.permanent_learn for p in dp.ports.values() if p.number < 9])) self.assertTrue(all([p.max_hosts == 2 for p in dp.ports.values() if p.number > 1])) self.assertTrue(dp.ports[1].max_hosts == 4) self.assertEqual(dp.ports[1].description, "video conf")
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" self.metrics.faucet_config_hash_func.labels(algorithm=CONFIG_HASH_FUNC) try: new_conf_hashes, new_config_content, new_dps, top_conf = dp_parser( new_config_file, self.logname, self.meta_dp_state) new_present_conf_hashes = [ (conf_file, conf_hash) for conf_file, conf_hash in sorted(new_conf_hashes.items()) if conf_hash is not None] conf_files = [conf_file for conf_file, _ in new_present_conf_hashes] conf_hashes = [conf_hash for _, conf_hash in new_present_conf_hashes] self.config_watcher.update(new_config_file, new_conf_hashes) self.meta_dp_state.top_conf = top_conf self.meta_dp_state.last_good_config = new_config_content self.meta_dp_state.config_hash_info = dict( config_files=','.join(conf_files), hashes=','.join(conf_hashes), error='') self.metrics.faucet_config_hash.info(self.meta_dp_state.config_hash_info) self.metrics.faucet_config_load_error.set(0) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) # If the config was reverted, let the watcher notice. if self.config_auto_revert: self.revert_config() self.config_watcher.update(new_config_file) self.meta_dp_state.config_hash_info = dict( config_files=new_config_file, hashes='', error=str(err)) self.metrics.faucet_config_hash.info(self.meta_dp_state.config_hash_info) self.metrics.faucet_config_load_error.set(1) new_dps = None return new_dps
def check_config(conf_files, debug_level, check_output_file): """Return True and successful config dict, if all config can be parsed.""" logname = os.devnull logger = logging.getLogger('%s.config' % logname) logger_handler = logging.StreamHandler(stream=sys.stderr) logger.addHandler(logger_handler) logger.propagate = 0 logger.setLevel(debug_level) check_output = '' check_result = False for conf_file in conf_files: try: _, dps = dp_parser(conf_file, logname) for dp in dps: valve_dp = valve.valve_factory(dp) if valve_dp is None: check_result = False break check_output = dp.to_conf() check_result = True except InvalidConfigError as config_err: check_output = config_err check_output_file.write(str(check_output)) return check_result
def check_config(conf_files, debug_level, check_output_file): """Return True and successful config dict, if all config can be parsed.""" logname = os.devnull logger = logging.getLogger('%s.config' % logname) logger_handler = logging.StreamHandler(stream=sys.stderr) logger.addHandler(logger_handler) logger.propagate = 0 logger.setLevel(debug_level) check_output = [] if conf_files: for conf_file in conf_files: check_result = False try: _, dps = dp_parser(conf_file, logname) if dps is not None: dps_conf = [(valve.valve_factory(dp), dp.to_conf()) for dp in dps] check_output.extend([conf for _, conf in dps_conf]) check_result = True continue except InvalidConfigError as config_err: check_output = [config_err] break else: check_result = False check_output = ['no files specified'] pprint.pprint(check_output, stream=check_output_file) return check_result
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" self.metrics.faucet_config_hash_func.labels(algorithm=CONFIG_HASH_FUNC) try: new_conf_hashes, new_dps, top_conf = dp_parser( new_config_file, self.logname, self.meta_dp_state) self.config_watcher.update(new_config_file, new_conf_hashes) new_present_conf_hashes = [ (conf_file, conf_hash) for conf_file, conf_hash in sorted(new_conf_hashes.items()) if conf_hash is not None ] conf_files = [ conf_file for conf_file, _ in new_present_conf_hashes ] conf_hashes = [ conf_hash for _, conf_hash in new_present_conf_hashes ] self.metrics.faucet_config_hash.info( dict(config_files=','.join(conf_files), hashes=','.join(conf_hashes))) self.metrics.faucet_config_load_error.set(0) self.meta_dp_state.top_conf = top_conf except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) self.config_watcher.update(new_config_file) self.metrics.faucet_config_hash.info( dict(config_files=new_config_file, hashes='')) self.metrics.faucet_config_load_error.set(1) new_dps = None return new_dps
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" try: new_config_hashes, new_dps = dp_parser(new_config_file, self.logname) self.config_watcher.update(new_config_file, new_config_hashes) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) return None return new_dps
def _load_configs(self, new_config_file): try: new_config_hashes, new_dps = dp_parser(new_config_file, self.logname) self.config_file = new_config_file self.config_hashes = new_config_hashes self._apply_configs(new_dps) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) return
def _get_faucet_config(self): try: (new_conf_hashes, _, new_dps, top_conf) = config_parser.dp_parser(self._faucet_config_file, 'fconfig') config_hash_info = self._get_faucet_config_hash_info( new_conf_hashes) return config_hash_info, new_dps, top_conf except Exception as e: LOGGER.error('Cannot read faucet config: %s', e) raise e
def setUp(self): """Setup fixture for each test method""" self._temp_dir = tempfile.mkdtemp() _, temp_faucet_config_file = tempfile.mkstemp(dir=self._temp_dir) with open(temp_faucet_config_file, 'w') as file: file.write(self.FAUCET_CONFIG) _, _, dps_config, _ = config_parser.dp_parser(temp_faucet_config_file, 'fconfig') switches_config = {str(dp): dp for dp in dps_config} self._acl_collector = AclStateCollector() self._acl_collector.update_switch_configs(switches_config)
def _get_faucet_config(self): try: (new_conf_hashes, _, new_dps, top_conf) = config_parser.dp_parser( self._behavioral_config_file, 'fconfig') config_hash_info = self._get_faucet_config_hash_info(new_conf_hashes) self._faucet_config_summary = SystemState.ConfigSummary() for file_name, file_hash in new_conf_hashes.items(): LOGGER.info('Loaded conf %s as %s', file_name, file_hash) self._faucet_config_summary.hashes[file_name] = file_hash for warning, message in self._validate_config(top_conf): LOGGER.warning('Config warning %s: %s', warning, message) self._faucet_config_summary.warnings[warning] = message return config_hash_info, new_dps, top_conf except Exception as e: LOGGER.error('Cannot read faucet config: %s', e) raise
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" self.metrics.faucet_config_hash_func.labels(algorithm=CONFIG_HASH_FUNC) try: new_config_hashes, new_dps = dp_parser(new_config_file, self.logname) self.config_watcher.update(new_config_file, new_config_hashes) config_files = sorted(new_config_hashes.keys()) hashes = [new_config_hashes[config] for config in config_files] self.metrics.faucet_config_hash.info( dict(config_files=','.join(config_files), hashes=','.join(hashes))) self.metrics.faucet_config_load_error.set(0) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) self.metrics.faucet_config_load_error.set(1) return None return new_dps
def test_single_range_valid_config(self): """Test if port range with single port config applied correctly""" config = """ vlans: office: vid: 100 dps: sw1: dp_id: 0x1 interface_ranges: 1: native_vlan: office """ conf_file = self.create_config_file(config) _, dps = cp.dp_parser(conf_file, LOGNAME) dp = dps[0] self.assertEqual(len(dp.ports), 1)
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" self.metrics.faucet_config_hash_func.labels(algorithm=CONFIG_HASH_FUNC) try: new_config_hashes, new_dps = dp_parser(new_config_file, self.logname) quoted_new_config_hashes = { quote_label(filename): filehash for filename, filehash in new_config_hashes.items() } self.config_watcher.update(new_config_file, new_config_hashes) self.metrics.faucet_config_hash.info(quoted_new_config_hashes) self.metrics.faucet_config_load_error.set(0) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) self.metrics.faucet_config_load_error.set(1) return None return new_dps
def _load_configs(self, new_config_file): self.config_file = new_config_file self.config_hashes, new_dps = dp_parser(new_config_file, self.logname) if new_dps is None: self.logger.error('new config bad - rejecting') return deleted_valve_dpids = (set(list(self.valves.keys())) - set([valve.dp_id for valve in new_dps])) for new_dp in new_dps: dp_id = new_dp.dp_id if dp_id in self.valves: valve = self.valves[dp_id] cold_start, flowmods = valve.reload_config(new_dp) # pylint: disable=no-member if flowmods: self._send_flow_msgs(new_dp.dp_id, flowmods) if cold_start: self.metrics.faucet_config_reload_cold.labels( dp_id=hex(dp_id)).inc() else: self.metrics.faucet_config_reload_warm.labels( dp_id=hex(dp_id)).inc() else: # pylint: disable=no-member valve_cl = valve_factory(new_dp) if valve_cl is None: self.logger.error('%s hardware %s must be one of %s', new_dp.name, new_dp.hardware, sorted(list(SUPPORTED_HARDWARE.keys()))) continue else: valve = valve_cl(new_dp, self.logname) self.valves[dp_id] = valve self.logger.info('Add new datapath %s', dpid_log(dp_id)) self.metrics.reset_dpid(dp_id) valve.update_config_metrics(self.metrics) for deleted_valve_dpid in deleted_valve_dpids: self.logger.info('Deleting de-configured %s', dpid_log(deleted_valve_dpid)) del self.valves[deleted_valve_dpid] ryu_dp = self.dpset.get(deleted_valve_dpid) if ryu_dp is not None: ryu_dp.close() self._bgp.reset(self.valves, self.metrics)
def setUp(self): logname = 'test_config' logger = logging.getLogger('%s.config' % logname) logger_handler = logging.StreamHandler(stream=sys.stderr) log_fmt = '%(asctime)s %(name)-6s %(levelname)-8s %(message)s' logger_handler.setFormatter( logging.Formatter(log_fmt, '%b %d %H:%M:%S')) logger.addHandler(logger_handler) logger.propagate = 0 logger.setLevel(logging.CRITICAL) self.v2_config_hashes, v2_dps = dp_parser('config/testconfigv2.yaml', logname) self.v2_dps_by_id = {} for dp in v2_dps: self.v2_dps_by_id[dp.dp_id] = dp self.v2_dp = self.v2_dps_by_id[0xcafef00d] self.v2_watchers = watcher_parser( 'config/testgaugeconfig.yaml', logname)
def parse_configs(self, new_config_file): """Return parsed configs for Valves, or None.""" self.metrics.faucet_config_hash_func.labels(algorithm=CONFIG_HASH_FUNC) try: new_config_hashes, new_dps = dp_parser(new_config_file, self.logname) self.config_watcher.update(new_config_file, new_config_hashes) config_files = sorted(new_config_hashes.keys()) hashes = [new_config_hashes[config] for config in config_files] self.metrics.faucet_config_hash.info( dict(config_files=','.join(config_files), hashes=','.join(hashes))) self.metrics.faucet_config_load_error.set(0) except InvalidConfigError as err: self.logger.error('New config bad (%s) - rejecting', err) self.metrics.faucet_config_hash.info( dict(config_files=new_config_file, hashes='')) self.metrics.faucet_config_load_error.set(1) return None return new_dps
def check_config(conf_files): logname = '/dev/null' logger = logging.getLogger('%s.config' % logname) logger_handler = logging.StreamHandler(stream=sys.stderr) logger.addHandler(logger_handler) logger.propagate = 0 logger.setLevel(logging.DEBUG) for conf_file in conf_files: parse_result = dp_parser(conf_file, logname) if parse_result is None: return False else: _, dps = parse_result for dp in dps: valve_dp = valve.valve_factory(dp) if valve_dp is None: return False print((dp.to_conf())) return True
def _validate_faucet_config(self, config_dir): logname = os.devnull try: root_config = os.path.join(config_dir, self.default_config) _, _, dps, top_confs = dp_parser(root_config, logname) dps_conf = None valve_cls = None acls_conf = None if dps is not None: dps_conf = {dp.name: dp for dp in dps} valve_cls = [valve.valve_factory(dp) for dp in dps] acls_conf = top_confs.get('acls', {}) if dps_conf: if not valve_cls: raise InvalidConfigError('no valid DPs defined') else: dps_conf = {} return (dps_conf, acls_conf) except InvalidConfigError as err: raise _ServerError(f'Invalid config: {err}') # pylint: disable=raise-missing-from
def reload_config(self, ryu_event): """Handle a request to reload configuration. Args: ryu_event (ryu.controller.event.EventReplyBase): triggering event. """ new_config_file = os.getenv('FAUCET_CONFIG', self.config_file) if self._config_changed(new_config_file): self.config_file = new_config_file self.config_hashes, new_dps = dp_parser(new_config_file, self.logname) for new_dp in new_dps: valve = self.valves[new_dp.dp_id] flowmods = valve.reload_config(new_dp) ryudp = self.dpset.get(new_dp.dp_id) if ryudp is not None: self._send_flow_msgs(ryudp, flowmods) self._reset_bgp() valve.update_config_metrics(self.metrics) else: self.logger.info('configuration is unchanged, not reloading') # pylint: disable=no-member self.metrics.faucet_config_reload_requests.inc()
def update_config(self, config): with open(self.config_file, 'w') as f: f.write(config) _, dps = dp_parser(self.config_file, 'test_valve') return dps[0]
#!/usr/bin/env python3 import logging import tempfile import os import sys from faucet import config_parser as cp LOGNAME = 'FAUCETLOG' logging.disable(logging.CRITICAL) tmpdir = tempfile.mkdtemp() def create_config_file(config): conf_file_name = os.path.join(tmpdir, 'faucet.yaml') with open(conf_file_name, 'w') as conf_file: conf_file.write(config) return conf_file_name import afl while afl.loop(500): data = sys.stdin.read() file_name = create_config_file(data) try: cp.dp_parser(file_name, LOGNAME) except cp.InvalidConfigError as err: pass os._exit(0)
def _reload_faucet_config(self): _, _, dps_config, _ = config_parser.dp_parser(self._faucet_config_file, 'fconfig') switches_config = {str(dp): dp for dp in dps_config} self._acl_state_collector.update_switch_configs(switches_config)
def update_config(self, config, dp_name): """Update FAUCET config with config as text.""" with open(self.config_file, 'w') as config_file: config_file.write(config) _, dps = dp_parser(self.config_file, 'test_valve') return [dp for dp in dps if dp.name == dp_name][0]
def update_config(self, config): with open(self.config_file, 'w') as config_file: config_file.write(config) _, dps = dp_parser(self.config_file, 'test_valve') return [dp for dp in dps if dp.name == 's1'][0]