def __init__(self, dpid, connection=None, features=None): """Contructor of switches have the below parameters. Args: dpid (|DPID|): datapath_id of the switch connection (:class:`~.Connection`): Connection used by switch. features (|features_reply|): FeaturesReply instance. """ self.dpid = dpid self.connection = connection self.features = features self.firstseen = now() self.lastseen = now() self.sent_xid = None self.waiting_for_reply = False self.request_timestamp = 0 #: Dict associating mac addresses to switch ports. #: the key of this dict is a mac_address, and the value is a set #: containing the ports of this switch in which that mac can be #: found. self.mac2port = {} #: This flood_table will keep track of flood packets to avoid over #: flooding on the network. Its key is a hash composed by #: (eth_type, mac_src, mac_dst) and the value is the timestamp of #: the last flood. self.flood_table = {} self.interfaces = {} self.flows = [] self.description = {} if connection: connection.switch = self super().__init__()
def update_flood_table(self, ethernet_frame): """Update a flood table using the given ethernet frame. Args: ethernet_frame (|ethernet|): Ethernet frame to be updated. """ self.flood_table[ethernet_frame.get_hash()] = now()
def start_controller(self): """Start the controller. Starts the KytosServer (TCP Server) coroutine. Starts a thread for each buffer handler. Load the installed apps. """ self.log.info("Starting Kytos - Kytos Controller") self.server = KytosServer((self.options.listen, int(self.options.port)), KytosServerProtocol, self, self.options.protocol_name) self.log.info("Starting TCP server: %s", self.server) self.server.serve_forever() def _stop_loop(_): loop = asyncio.get_event_loop() # print(_.result()) threads = threading.enumerate() self.log.debug("%s threads before loop.stop: %s", len(threads), threads) loop.stop() async def _run_api_server_thread(executor): log = logging.getLogger('controller.api_server_thread') log.debug('starting') # log.debug('creating tasks') loop = asyncio.get_event_loop() blocking_tasks = [ loop.run_in_executor(executor, self.api_server.run) ] # log.debug('waiting for tasks') completed, pending = await asyncio.wait(blocking_tasks) # results = [t.result() for t in completed] # log.debug('results: {!r}'.format(results)) log.debug('completed: %d, pending: %d', len(completed), len(pending)) task = self._loop.create_task(self.raw_event_handler()) task = self._loop.create_task(self.msg_in_event_handler()) task = self._loop.create_task(self.msg_out_event_handler()) task = self._loop.create_task(self.app_event_handler()) task = self._loop.create_task(_run_api_server_thread(self._pool)) task.add_done_callback(_stop_loop) self.log.info("ThreadPool started: %s", self._pool) # ASYNC TODO: ensure all threads started correctly # This is critical, if any of them failed starting we should exit. # sys.exit(error_msg.format(thread, exception)) self.log.info("Loading Kytos NApps...") self.napp_dir_listener.start() self.pre_install_napps(self.options.napps_pre_installed) self.load_napps() self.started_at = now()
def add_endpoint(self, endpoint): """Create a new endpoint to Interface instance. Args: endpoint(|hw_address|, :class:`.Interface`): A target endpoint. """ exists = self.get_endpoint(endpoint) if not exists: self.endpoints.append((endpoint, now()))
def start_controller(self): """Start the controller. Starts the KytosServer (TCP Server) coroutine. Starts a thread for each buffer handler. Load the installed apps. """ self.log.info("Starting Kytos - Kytos Controller") self.server = KytosServer( (self.options.listen, int(self.options.port)), KytosServerProtocol, self, self.options.protocol_name) self.log.info("Starting TCP server: %s", self.server) self.server.serve_forever() def _stop_loop(_): loop = asyncio.get_event_loop() # print(_.result()) threads = threading.enumerate() self.log.debug("%s threads before loop.stop: %s", len(threads), threads) loop.stop() async def _run_api_server_thread(executor): log = logging.getLogger('kytos.core.controller.api_server_thread') log.debug('starting') # log.debug('creating tasks') loop = asyncio.get_event_loop() blocking_tasks = [ loop.run_in_executor(executor, self.api_server.run) ] # log.debug('waiting for tasks') completed, pending = await asyncio.wait(blocking_tasks) # results = [t.result() for t in completed] # log.debug('results: {!r}'.format(results)) log.debug('completed: %d, pending: %d', len(completed), len(pending)) task = self._loop.create_task(self.raw_event_handler()) task = self._loop.create_task(self.msg_in_event_handler()) task = self._loop.create_task(self.msg_out_event_handler()) task = self._loop.create_task(self.app_event_handler()) task = self._loop.create_task(_run_api_server_thread(self._pool)) task.add_done_callback(_stop_loop) self.log.info("ThreadPool started: %s", self._pool) # ASYNC TODO: ensure all threads started correctly # This is critical, if any of them failed starting we should exit. # sys.exit(error_msg.format(thread, exception)) self.log.info("Loading Kytos NApps...") self.napp_dir_listener.start() self.pre_install_napps(self.options.napps_pre_installed) self.load_napps() self.started_at = now()
def add_endpoint(self, endpoint): """Create a new endpoint to Interface instance. Args: endpoint(|hw_address|, :class:`.Interface`): A target endpoint. """ exists = self.get_endpoint(endpoint) if not exists: self.endpoints.append((endpoint, now()))
def __init__(self, name=None, content=None): """Create an event to be published. Args: name (string): The name of the event. You should prepend it with the name of the napp. content (dict): Dictionary with any extra data for the event. """ self.name = name self.content = content if content is not None else {} self.timestamp = now()
def __init__(self, name=None, content=None): """Constructor of KytosEvent receive the parameters below. Args: name (string): The name of the event. You should prepend with the name of the napp. content (dict): Dictionary with all event informations. """ self.name = name self.content = content if content is not None else {} self.timestamp = now()
def uptime(self): """Return the uptime of kytos server. This method should return: - 0 if Kytos Server is stopped. - (kytos.start_at - datetime.now) if Kytos Server is running. Returns: datetime.timedelta: The uptime interval. """ return now() - self.started_at if self.started_at else 0
def circuit_deploy(self, circuit): """Add a new circuit deploy event.""" seconds = (circuit.creation_time - now()).total_seconds() if not circuit.is_enabled(): log.debug(f'{circuit} is not enabled') if not circuit.is_active(): log.debug(f'{circuit} is not active') if circuit.is_enabled() and not circuit.is_active(): self.scheduler.enter(seconds, circuit.priority, circuit.deploy) log.debug(f'{circuit} scheduled to be activated.')
def should_flood(self, ethernet_frame): """Verify if the ethernet frame should flood. Args: ethernet_frame (|ethernet|): Ethernet instance to be verified. Returns: bool: True if the ethernet_frame should flood. """ last_flood = self.last_flood(ethernet_frame) diff = (now() - last_flood).microseconds return last_flood is None or diff > FLOOD_TIMEOUT
def uptime(self): """Return the uptime of kytos server. This method should return: - 0 if Kytos Server is stopped. - (kytos.start_at - datetime.now) if Kytos Server is running. Returns: datetime.timedelta: The uptime interval. """ return now() - self.started_at if self.started_at else 0
def __init__(self, dpid, connection=None, ofp_version='0x01', features=None): """Contructor of switches have the below parameters. Args: dpid (|DPID|): datapath_id of the switch connection (:class:`~.Connection`): Connection used by switch. ofp_version (string): Current talked OpenFlow version. features (|features_reply|): FeaturesReply instance. """ self.dpid = dpid self.connection = connection self.ofp_version = ofp_version self.features = features self.firstseen = now() self.lastseen = now() self.sent_xid = None self.waiting_for_reply = False self.request_timestamp = 0 #: Dict associating mac addresses to switch ports. #: the key of this dict is a mac_address, and the value is a set #: containing the ports of this switch in which that mac can be #: found. self.mac2port = {} #: This flood_table will keep track of flood packets to avoid over #: flooding on the network. Its key is a hash composed by #: (eth_type, mac_src, mac_dst) and the value is the timestamp of #: the last flood. self.flood_table = {} self.interfaces = {} self.flows = [] self.description = {} if connection: connection.switch = self
def should_flood(self, ethernet_frame): """Verify if the ethernet frame should flood. Args: ethernet_frame (|ethernet|): Ethernet instance to be verified. Returns: bool: True if the ethernet_frame should flood. """ last_flood = self.last_flood(ethernet_frame) diff = (now() - last_flood).microseconds return last_flood is None or diff > FLOOD_TIMEOUT
def start_controller(self): """Start the controller. Starts a thread with the KytosServer (TCP Server). Starts a thread for each buffer handler. Load the installed apps. """ self.log.info("Starting Kytos - Kytos Controller") self.server = KytosServer( (self.options.listen, int(self.options.port)), KytosRequestHandler, self, self.options.protocol_name) raw_event_handler = self.raw_event_handler msg_in_event_handler = self.msg_in_event_handler msg_out_event_handler = self.msg_out_event_handler app_event_handler = self.app_event_handler thrds = { 'tcp_server': Thread(name='TCP server', target=self.server.serve_forever), 'api_server': Thread(name='API server', target=self.api_server.run), 'raw_event_handler': Thread(name='RawEvent Handler', target=raw_event_handler), 'msg_in_event_handler': Thread(name='MsgInEvent Handler', target=msg_in_event_handler), 'msg_out_event_handler': Thread(name='MsgOutEvent Handler', target=msg_out_event_handler), 'app_event_handler': Thread(name='AppEvent Handler', target=app_event_handler) } self._threads = thrds # This is critical, if any of them started we should exit. for thread in self._threads.values(): try: thread.start() except OSError as exception: error_msg = "Error starting thread {}: {}." sys.exit(error_msg.format(thread, exception)) self.log.info("Loading Kytos NApps...") self.napp_dir_listener.start() self.load_napps() self.started_at = now()
def __init__(self, name=None, content=None, trace_parent=None, priority=0): """Create an event to be published. Args: name (string): The name of the event. You should prepend it with the name of the napp. content (dict): Dictionary with any extra data for the event. trace_parent (object): APM TraceParent for distributed tracing, if you have APM enabled, @listen_to will set the root parent, and then you have to pass the trace_parent to subsequent correlated KytosEvent(s). priority (int): Priority of this event if a PriorityQueue is being used, the lower the number the higher the priority. """ self.name = name self.content = content if content is not None else {} self.timestamp = now() self.reinjections = 0 self.priority = priority # pylint: disable=invalid-name self.id = uuid4() self.trace_parent = trace_parent
def __init__(self, controller, **kwargs): """Create an EVC instance with the provided parameters. Args: id(str): EVC identifier. Whether it's None an ID will be genereted. Only the first 14 bytes passed will be used. name: represents an EVC name.(Required) uni_a (UNI): Endpoint A for User Network Interface.(Required) uni_z (UNI): Endpoint Z for User Network Interface.(Required) start_date(datetime|str): Date when the EVC was registred. Default is now(). end_date(datetime|str): Final date that the EVC will be fineshed. Default is None. bandwidth(int): Bandwidth used by EVC instance. Default is 0. primary_links(list): Primary links used by evc. Default is [] backup_links(list): Backups links used by evc. Default is [] current_path(list): Circuit being used at the moment if this is an active circuit. Default is []. primary_path(list): primary circuit offered to user IF one or more links were provided. Default is []. backup_path(list): backup circuit offered to the user IF one or more links were provided. Default is []. dynamic_backup_path(bool): Enable computer backup path dynamically. Dafault is False. creation_time(datetime|str): datetime when the circuit should be activated. default is now(). enabled(Boolean): attribute to indicate the administrative state; default is False. active(Boolean): attribute to indicate the operational state; default is False. archived(Boolean): indicate the EVC has been deleted and is archived; default is False. owner(str): The EVC owner. Default is None. priority(int): Service level provided in the request. Default is 0. Raises: ValueError: raised when object attributes are invalid. """ self._validate(**kwargs) super().__init__() # required attributes self._id = kwargs.get('id', uuid4().hex)[:14] self.uni_a = kwargs.get('uni_a') self.uni_z = kwargs.get('uni_z') self.name = kwargs.get('name') # optional attributes self.start_date = get_time(kwargs.get('start_date')) or now() self.end_date = get_time(kwargs.get('end_date')) or None self.queue_id = kwargs.get('queue_id', None) self.bandwidth = kwargs.get('bandwidth', 0) self.primary_links = Path(kwargs.get('primary_links', [])) self.backup_links = Path(kwargs.get('backup_links', [])) self.current_path = Path(kwargs.get('current_path', [])) self.primary_path = Path(kwargs.get('primary_path', [])) self.backup_path = Path(kwargs.get('backup_path', [])) self.dynamic_backup_path = kwargs.get('dynamic_backup_path', False) self.creation_time = get_time(kwargs.get('creation_time')) or now() self.owner = kwargs.get('owner', None) self.priority = kwargs.get('priority', 0) self.circuit_scheduler = kwargs.get('circuit_scheduler', []) self.current_links_cache = set() self.primary_links_cache = set() self.backup_links_cache = set() self.lock = Lock() self.archived = kwargs.get('archived', False) self._storehouse = StoreHouse(controller) if kwargs.get('active', False): self.activate() else: self.deactivate() if kwargs.get('enabled', False): self.enable() else: self.disable() # datetime of user request for a EVC (or datetime when object was # created) self.request_time = kwargs.get('request_time', now()) # dict with the user original request (input) self._requested = kwargs
def is_connected(self): """Verify if the switch is connected to a socket.""" return (self.connection is not None and self.connection.is_alive() and self.connection.is_established() and (now() - self.lastseen).seconds <= CONNECTION_TIMEOUT)
def update_lastseen(self): """Update the lastseen attribute.""" self.lastseen = now()
def is_active(self): """Return true if the switch connection is alive.""" return (now() - self.lastseen).seconds <= CONNECTION_TIMEOUT
def update_lastseen(self): """Update the lastseen attribute.""" self.lastseen = now()
def is_active(self): """Return true if the switch connection is alive.""" return (now() - self.lastseen).seconds <= CONNECTION_TIMEOUT