Beispiel #1
0
    def __init__(self,
                 simulation_cfg,
                 superlog_path_or_dag,
                 create_event_scheduler=None,
                 **kwargs):
        ControlFlow.__init__(self, simulation_cfg)
        self.sync_callback = ReplaySyncCallback(self.get_interpolated_time)

        if type(superlog_path_or_dag) == str:
            superlog_path = superlog_path_or_dag
            # The dag is codefied as a list, where each element has
            # a list of its dependents
            self.dag = EventDag(superlog_parser.parse_path(superlog_path))
        else:
            self.dag = superlog_path_or_dag

        # compute interpolate to time to be just before first event
        self.compute_interpolated_time(self.dag.events[0])

        if create_event_scheduler:
            self.create_event_scheduler = create_event_scheduler
        else:
            self.create_event_scheduler = \
              lambda simulation: EventScheduler(simulation,
                  **{ k: v for k,v in kwargs.items()
                      if k in EventScheduler.kwargs })
Beispiel #2
0
 def setup_simulation(self):
   # TODO(cs): currently assumes that STSSyncProto is not used alongside
   # snapshotting.
   # N.B. bootstrap() does not connect switches to controllers.
   # ConnectionToControllers is an input event, which we peek() for like
   # any other input event.
   simulation = self.simulation_cfg.bootstrap(ReplaySyncCallback(None))
   simulation.openflow_buffer.pass_through_whitelisted_packets = self.kwargs['pass_through_whitelisted_messages']
   controller = simulation.controller_manager.controllers[0]
   return (simulation, controller)
Beispiel #3
0
    def __init__(self,
                 simulation_cfg,
                 superlog_path_or_dag,
                 create_event_scheduler=None,
                 print_buffers=True,
                 wait_on_deterministic_values=False,
                 default_dp_permit=False,
                 fail_to_interactive=False,
                 fail_to_interactive_on_persistent_violations=False,
                 end_in_interactive=False,
                 input_logger=None,
                 allow_unexpected_messages=False,
                 expected_message_round_window=3,
                 pass_through_whitelisted_messages=False,
                 delay_flow_mods=False,
                 invariant_check_name="",
                 bug_signature="",
                 end_wait_seconds=0.5,
                 transform_dag=None,
                 pass_through_sends=False,
                 fail_fast=False,
                 check_interval=5,
                 **kwargs):
        '''
     - If invariant_check_name is not None, check it at the end for the
       execution
     - If bug_signature is not None, check whether this particular signature
       appears in the output of the invariant check at the end of the
       execution
    '''
        ControlFlow.__init__(self, simulation_cfg)
        # Label uniquely identifying this replay, set in init_results()
        self.replay_id = "N/A"
        self.logical_time = 0
        if wait_on_deterministic_values:
            self.sync_callback = ReplaySyncCallback()
        else:
            self.sync_callback = ReplaySyncCallback(self.get_interpolated_time)

        if type(superlog_path_or_dag) == str:
            superlog_path = superlog_path_or_dag
            # The dag is codefied as a list, where each element has
            # a list of its dependents
            self.dag = EventDag(log_parser.parse_path(superlog_path))
        else:
            self.dag = superlog_path_or_dag

        if len(self.dag.events) == 0:
            raise ValueError("No events to replay!")

        self.default_dp_permit = default_dp_permit
        self.dp_checker = self._setup_dp_checker(default_dp_permit)
        if self.default_dp_permit:
            # Set DataplanePermit and DataplaneDrop to passive if permit is set
            # to default
            # TODO(cs): rather than setting these to passive (which still causes them to
            # be scheduled as regular events) should these just be removed from the
            # event dag altogether?
            for event in [e for e in self.dag.events if type(e) in dp_events]:
                event.passive = default_dp_permit

        self.print_buffers_flag = print_buffers
        self.fail_fast = fail_fast
        self.check_interval = check_interval

        # compute interpolate to time to be just before first event
        self.compute_interpolated_time(self.dag.events[0])
        # String repesentations of unexpected state changes we've passed through, for
        # statistics purposes.
        self.unexpected_state_changes = []
        self.early_state_changes = []
        self.event_scheduler_stats = None
        self.end_in_interactive = end_in_interactive
        self.fail_to_interactive = fail_to_interactive
        self.fail_to_interactive_on_persistent_violations =\
          fail_to_interactive_on_persistent_violations
        self._input_logger = input_logger
        self.allow_unexpected_messages = allow_unexpected_messages
        self.expected_message_round_window = expected_message_round_window
        self.pass_through_whitelisted_messages = pass_through_whitelisted_messages
        self.pass_through_sends = pass_through_sends
        # How many logical rounds to peek ahead when deciding if a message is
        # expected or not.
        # String repesentations of unexpected messages we've passed through, for
        # statistics purposes.
        self.passed_unexpected_messages = []
        self.delay_flow_mods = delay_flow_mods
        self.end_wait_seconds = end_wait_seconds
        self.transform_dag = transform_dag
        self.bug_signature = bug_signature
        self.invariant_check_name = invariant_check_name
        self.invariant_check = None
        if self.invariant_check_name:
            if self.invariant_check_name not in name_to_invariant_check:
                raise ValueError(
                    '''Unknown invariant check %s.\n'''
                    '''Invariant check name must be defined in config.invariant_checks''',
                    self.invariant_check_name)
            self.invariant_check = name_to_invariant_check[
                self.invariant_check_name]

        if self.pass_through_whitelisted_messages:
            for event in self.dag.events:
                if hasattr(event, "ignore_whitelisted_packets"):
                    event.ignore_whitelisted_packets = True

        if self.simulation_cfg.ignore_interposition:
            self._ignore_interposition()

        if create_event_scheduler:
            self.create_event_scheduler = create_event_scheduler
        else:
            if self.default_dp_permit:
                # Tell EventScheduler to use call into us whenever it wants to sleep or
                # select, so that we can keep forwarding dataplane packets.
                kwargs[
                    'sleep_continuation'] = self._sleep_with_dataplane_passthrough
                kwargs[
                    'select_continuation'] = self._select_with_dataplane_passthrough

            self.create_event_scheduler = \
              lambda simulation: EventScheduler(simulation,
                  **{ k: v for k,v in kwargs.items()
                      if k in EventScheduler.kwargs })

        unknown_kwargs = [
            k for k in kwargs.keys() if k not in EventScheduler.kwargs
        ]
        if unknown_kwargs != []:
            raise ValueError("Unknown kwargs %s" % str(unknown_kwargs))
Beispiel #4
0
  def __init__(self, simulation_cfg, superlog_path_or_dag, create_event_scheduler=None,
               print_buffers=True, wait_on_deterministic_values=False, default_dp_permit=False,
               fail_to_interactive=False, fail_to_interactive_on_persistent_violations=False,
               end_in_interactive=False, input_logger=None,
               allow_unexpected_messages=False,
               pass_through_whitelisted_messages=True,
               delay_flow_mods=False,
               **kwargs):
    ControlFlow.__init__(self, simulation_cfg)
    if wait_on_deterministic_values:
      self.sync_callback = ReplaySyncCallback()
    else:
      self.sync_callback = ReplaySyncCallback(self.get_interpolated_time)

    if type(superlog_path_or_dag) == str:
      superlog_path = superlog_path_or_dag
      # The dag is codefied as a list, where each element has
      # a list of its dependents
      self.dag = EventDag(log_parser.parse_path(superlog_path))
    else:
      self.dag = superlog_path_or_dag

    if len(self.dag.events) == 0:
      raise ValueError("No events to replay!")

    self.default_dp_permit = default_dp_permit
    # Set DataplanePermit and DataplaneDrop to passive if permit is set
    # to default
    for event in [ e for e in self.dag.events if type(e) in dp_events ]:
      event.passive = default_dp_permit

    self.dp_checker = None
    if default_dp_permit:
      self.dp_checker = DataplaneChecker(self.dag)

    self.print_buffers_flag = print_buffers

    # compute interpolate to time to be just before first event
    self.compute_interpolated_time(self.dag.events[0])
    # String repesentations of unexpected state changes we've passed through, for
    # statistics purposes.
    self.unexpected_state_changes = []
    self.early_state_changes = []
    self.event_scheduler_stats = None
    self.end_in_interactive = end_in_interactive
    self.fail_to_interactive = fail_to_interactive
    self.fail_to_interactive_on_persistent_violations =\
      fail_to_interactive_on_persistent_violations
    self._input_logger = input_logger
    self.allow_unexpected_messages = allow_unexpected_messages
    self.pass_through_whitelisted_messages = pass_through_whitelisted_messages
    # How many logical rounds to peek ahead when deciding if a message is
    # expected or not.
    self.expected_message_round_window = 3
    # String repesentations of unexpected messages we've passed through, for
    # statistics purposes.
    self.passed_unexpected_messages = []
    self.delay_flow_mods = delay_flow_mods

    if self.pass_through_whitelisted_messages:
      for event in self.dag.events:
        if hasattr(event, "ignore_whitelisted_packets"):
          event.ignore_whitelisted_packets = True

    if create_event_scheduler:
      self.create_event_scheduler = create_event_scheduler
    else:
      self.create_event_scheduler = \
        lambda simulation: EventScheduler(simulation,
            **{ k: v for k,v in kwargs.items()
                if k in EventScheduler.kwargs })
Beispiel #5
0
  def bootstrap(self, sync_callback=None, boot_controllers=default_boot_controllers):
    '''Return a simulation object encapsulating the state of
       the system in its initial starting point:
       - boots controllers
       - connects switches to controllers

       May be invoked multiple times!
    '''
    if sync_callback is None:
      sync_callback = ReplaySyncCallback(None)

    def initialize_io_loop():
      ''' boot the IOLoop (needed for the controllers) '''
      _io_master = IOMaster()
      # monkey patch time.sleep for all our friends
      _io_master.monkey_time_sleep()
      # tell sts.console to use our io_master
      msg.set_io_master(_io_master)
      return _io_master

    def wire_controller_patch_panel(controller_manager, create_io_worker):
      patch_panel = None
      if not self.interpose_on_controllers:
        return patch_panel
      # N.B. includes local controllers in network namespaces or VMs.
      remote_controllers = controller_manager.remote_controllers
      if len(remote_controllers) != 0:
        patch_panel = self.controller_patch_panel_class(create_io_worker)
        for c in remote_controllers:
          patch_panel.register_controller(c.cid, c.guest_eth_addr, c.host_device)
      return patch_panel

    def instantiate_topology(create_io_worker):
      '''construct a clean topology object from topology_class and
      topology_params'''
      log.info("Creating topology...")
      # If you want to shoot yourself in the foot, feel free :)
      comma = "" if self._topology_params == "" else ","
      topology = eval("%s(%s%screate_io_worker=create_io_worker)" %
                      (self._topology_class.__name__,
                       self._topology_params, comma))
      return topology

    def monkeypatch_select(multiplex_sockets, controller_manager):
      mux_select = None
      demuxers = []
      if multiplex_sockets:
        log.debug("Monkeypatching STS select")
        revert_select_monkeypatch()
        # Monkey patch select to use our deterministic version
        mux_select = MultiplexedSelect()
        for c in controller_manager.controller_configs:
          # Connect the true sockets
          true_socket = connect_socket_with_backoff(address=c.address, port=c.port)
          true_socket.setblocking(0)
          io_worker = mux_select.create_worker_for_socket(true_socket)
          demux = STSSocketDemultiplexer(io_worker, c.server_info)
          demuxers.append(demux)

        # Monkey patch select.select
        select._old_select = select.select
        select.select = mux_select.select

      return (mux_select, demuxers)

    # Instantiate the pieces needed for Simulation's constructor
    revert_select_monkeypatch()
    io_master = initialize_io_loop()
    sync_connection_manager = STSSyncConnectionManager(io_master,
                                                       sync_callback)
    controller_manager = boot_controllers(self.controller_configs,
                                          self.snapshot_service,
                                          sync_connection_manager,
                                          multiplex_sockets=self.multiplex_sockets)
    controller_patch_panel = wire_controller_patch_panel(controller_manager,
                                                         io_master.create_worker_for_socket)
    topology = instantiate_topology(io_master.create_worker_for_socket)
    patch_panel = self._patch_panel_class(topology.switches, topology.hosts,
                                          topology.get_connected_port)
    openflow_buffer = OpenFlowBuffer()
    dataplane_trace = None
    if self._dataplane_trace_path is not None:
      dataplane_trace = Trace(self._dataplane_trace_path, topology)
    if self._violation_persistence_threshold is not None:
      violation_tracker = ViolationTracker(self._violation_persistence_threshold)
    else:
      violation_tracker = ViolationTracker()

    # Connect up MuxSelect if enabled
    (mux_select, demuxers) = monkeypatch_select(self.multiplex_sockets,
                                                controller_manager)

    simulation = Simulation(topology, controller_manager, dataplane_trace,
                            openflow_buffer, io_master, controller_patch_panel,
                            patch_panel, sync_callback, mux_select, demuxers,
                            violation_tracker, self._kill_controllers_on_exit)
    if self.ignore_interposition:
      simulation.set_pass_through()
    self.current_simulation = simulation
    return simulation