control_flow Package

control_flow Package

base Module

class sts.control_flow.base.ControlFlow(simulation_cfg)[source]

Bases: object

Superclass of ControlFlow types

__init__(simulation_cfg)[source]
get_sync_callback()[source]
init_results(results_dir)[source]

Set up event log files

simulate()[source]

Move the simulation forward!

class sts.control_flow.base.RecordingSyncCallback(input_logger, record_deterministic_values=False)[source]

Bases: sts.syncproto.sts_syncer.STSSyncCallback

__init__(input_logger, record_deterministic_values=False)[source]
get_deterministic_value(controller, name, xid)[source]
state_change(sync_type, xid, controller, time, fingerprint, name, value)[source]
class sts.control_flow.base.ReplaySyncCallback(get_interpolated_time=None)[source]

Bases: sts.syncproto.sts_syncer.STSSyncCallback, pox.lib.revent.revent.EventMixin

__init__(get_interpolated_time=None)[source]

If get_interpolated_time is None, will always wait on deterministic values. If not None, will always invoke get_interpolated_time and respond immediately

ack_pending_state_change(pending_state_change)[source]

ACK the pending state change, and collect the PendingStateChange from our buffer

flush()[source]

ACK any pending state changes

get_deterministic_value(controller, name, xid)[source]
pending_deterministic_value_request(controller_id)[source]
pending_state_changes()[source]

Return any pending state changes

pending_state_changes_with_counts()[source]

Return any pending state changes

send_deterministic_value(controller_id, value)[source]
set_pass_through()[source]

Cause all pending state changes to pass through without being buffered

state_change(sync_type, xid, controller, time, fingerprint, name, value)[source]
state_change_pending(pending_state_change)[source]

Return whether the PendingStateChange has been observed

unset_pass_through()[source]

Unset pass through mode, and return any events that were passed through since pass through mode was set

class sts.control_flow.base.StateChange(pending_state_change)[source]

Bases: pox.lib.revent.revent.Event

__init__(pending_state_change)[source]

event_scheduler Module

class sts.control_flow.event_scheduler.DumbEventScheduler(simulation, epsilon_seconds=0.0, sleep_interval_seconds=0.2)[source]

Bases: sts.control_flow.event_scheduler.EventSchedulerBase

__init__(simulation, epsilon_seconds=0.0, sleep_interval_seconds=0.2)[source]
kwargs = set(['epsilon_seconds', 'sleep_interval_seconds'])
schedule(event)[source]
class sts.control_flow.event_scheduler.EventScheduler(simulation, speedup=1.0, delay_input_events=True, initial_wait=0.5, epsilon_seconds=0.5, sleep_interval_seconds=0.2)[source]

Bases: sts.control_flow.event_scheduler.EventSchedulerBase

an EventWatchers schedules events. It controls their admission, and any post-event delay

__init__(simulation, speedup=1.0, delay_input_events=True, initial_wait=0.5, epsilon_seconds=0.5, sleep_interval_seconds=0.2)[source]
inject_input(event)[source]
kwargs = set(['initial_wait', 'delay_input_events', 'epsilon_seconds', 'speedup', 'sleep_interval_seconds'])
schedule(event)[source]
update_event_time(event)[source]

update our bearing on where we currently our in the timeline

wait_for_internal(event)[source]
wait_time(event)[source]

returns how long to wait in seconds for an event to occur or be injected.

class sts.control_flow.event_scheduler.EventSchedulerBase[source]

Bases: object

__init__()[source]
set_input_logger(input_logger)[source]
class sts.control_flow.event_scheduler.EventSchedulerStats[source]

Bases: object

__init__()[source]
event_matched(event)[source]
event_timed_out(event)[source]
sorted_match_counts()[source]
sorted_timeout_counts()[source]
start_replay(event)[source]
time(event)[source]
sts.control_flow.event_scheduler.format_time(time)[source]

fuzzer Module

Three control flow types for running the simulation forward.
  • Fuzzer: injects input events at random intervals, periodically checking for invariant violations
  • Interactive: presents an interactive prompt for injecting events and checking for invariants at the users’ discretion
class sts.control_flow.fuzzer.Fuzzer(simulation_cfg, fuzzer_params='config.fuzzer_params', check_interval=None, traffic_inject_interval=10, random_seed=None, delay=0.1, steps=None, input_logger=None, invariant_check_name='InvariantChecker.check_correspondence', halt_on_violation=False, log_invariant_checks=True, delay_startup=True, print_buffers=True, record_deterministic_values=False, mock_link_discovery=False, initialization_rounds=0)[source]

Bases: sts.control_flow.base.ControlFlow

Injects input events at random intervals, periodically checking for invariant violations. (Not the proper use of the term Fuzzer)

__init__(simulation_cfg, fuzzer_params='config.fuzzer_params', check_interval=None, traffic_inject_interval=10, random_seed=None, delay=0.1, steps=None, input_logger=None, invariant_check_name='InvariantChecker.check_correspondence', halt_on_violation=False, log_invariant_checks=True, delay_startup=True, print_buffers=True, record_deterministic_values=False, mock_link_discovery=False, initialization_rounds=0)[source]
Options:
  • fuzzer_params: path to event probabilities
  • check_interval: the period for checking invariants, in terms of logical rounds
  • traffic_inject_interval: how often to inject dataplane trace packets
  • random_seed: optionally set the seed of the random number generator
  • delay: how long to sleep between each logical round
  • input_logger: None, or a InputLogger instance
  • invariant_check_name: the name of the invariant check, from config/invariant_checks.py
  • halt_on_violation: whether to stop after a bug has been detected
  • log_invariant_checks: whether to log InvariantCheck events
  • delay_startup: whether to until the first OpenFlow message is received before proceeding with fuzzing
  • print_buffers: whether to print the remaining contents of the dataplane/controlplane buffers at the end of the execution
  • record_deterministic_values: whether to record gettimeofday requests for replay
  • mock_link_discovery: optional module for POX to experiment with better determinism – tell POX exactly when links should be discovered
  • initialization_rounds: if non-zero, will wait the specified rounds to let the controller discover the topology before injecting inputs
check_controllers()[source]
check_dataplane(pass_through=False)[source]

Decide whether to delay, drop, or deliver packets

check_migrations()[source]
check_pending_messages(pass_through=False)[source]
check_switch_crashes()[source]

Decide whether to crash or restart switches, links and controllers

check_tcp_connections()[source]

Decide whether to block or unblock control channels

fuzz_traffic()[source]
init_results(results_dir)[source]
loop()[source]
maybe_check_invariant()[source]
maybe_inject_trace_event()[source]
simulate()[source]

Precondition: simulation.patch_panel is a buffered patch panel

trigger_events()[source]

interactive Module

control flow type for running the simulation forward.
  • Interactive: presents an interactive prompt for injecting events and checking for invariants at the users’ discretion
class sts.control_flow.interactive.Interactive(simulation_cfg, input_logger=None)[source]

Bases: sts.control_flow.base.ControlFlow

Presents an interactive prompt for injecting events and checking for invariants at the users’ discretion

__init__(simulation_cfg, input_logger=None)[source]
dataplane_delay(event=None)[source]
dataplane_drop(event=None)[source]
dataplane_forward(event=None)[source]
dataplane_trace_feed()[source]
default_command()[source]
init_results(results_dir)[source]
invariant_check(kind)[source]
kill_controller(label)[source]
kill_switch(dpid)[source]
list_controllers()[source]
list_hosts()[source]
list_switches()[source]
migrate_host(hid, dpid)[source]
next_step()[source]
quit()[source]
show_flow_table(dpid)[source]
show_queued_events()[source]
simulate(simulation=None, bound_objects=())[source]
start_controller(label)[source]
start_switch(dpid)[source]
class sts.control_flow.interactive.STSCommand(func, name, alias, help_msg)[source]

Bases: object

__init__(func, name, alias, help_msg)[source]
arg(name, help_msg=None, values=None)[source]
arg_help()[source]
get_help()[source]
class sts.control_flow.interactive.STSCommandArg(name, help_msg=None, values=None)[source]

Bases: object

__init__(name, help_msg=None, values=None)[source]
arg_help()[source]
values()[source]
class sts.control_flow.interactive.STSConsole(default_command=None)[source]

Bases: object

__init__(default_command=None)[source]
autocomplete_matches(text, index)[source]
cmd(func, name, alias=None, help_msg=None)[source]
cmd_group(name)[source]
default_command[source]
register_obj(obj, name, alias=None, help_msg=None)[source]
run()[source]
show_help(command=None)[source]
class sts.control_flow.interactive.STSRegisteredObject(obj, name, alias, help_msg)[source]

Bases: object

__init__(obj, name, alias, help_msg)[source]
get_help()[source]

mcs_finder Module

An orchestrating control flow that invokes replayer several times to find the minimal causal sequence (MCS) of a failure.

class sts.control_flow.mcs_finder.EfficientMCSFinder(simulation_cfg, superlog_path_or_dag, invariant_check_name=None, transform_dag=None, end_wait_seconds=0.5, mcs_trace_path=None, extra_log=None, runtime_stats_file=None, wait_on_deterministic_values=False, no_violation_verification_runs=1, optimized_filtering=False, forker=<sts.util.rpc_forker.LocalForker object at 0x59ce610>, replay_final_trace=False, **kwargs)[source]

Bases: sts.control_flow.mcs_finder.MCSFinder

Exactly the same functionality as MCSFinder, but assumes that indeterminate results cannot occur. Worst-case runtime of O(n) as opposed to O(n^2) replays. Taken from the predecessor paper:

Section 4

class sts.control_flow.mcs_finder.MCSFinder(simulation_cfg, superlog_path_or_dag, invariant_check_name=None, transform_dag=None, end_wait_seconds=0.5, mcs_trace_path=None, extra_log=None, runtime_stats_file=None, wait_on_deterministic_values=False, no_violation_verification_runs=1, optimized_filtering=False, forker=<sts.util.rpc_forker.LocalForker object at 0x59ce610>, replay_final_trace=False, **kwargs)[source]

Bases: sts.control_flow.base.ControlFlow

__init__(simulation_cfg, superlog_path_or_dag, invariant_check_name=None, transform_dag=None, end_wait_seconds=0.5, mcs_trace_path=None, extra_log=None, runtime_stats_file=None, wait_on_deterministic_values=False, no_violation_verification_runs=1, optimized_filtering=False, forker=<sts.util.rpc_forker.LocalForker object at 0x59ce610>, replay_final_trace=False, **kwargs)[source]
init_results(results_dir)[source]
log(s)[source]

Output a message to both self._log and self._extra_log

log_no_violation(s)[source]

Output a message to both self._log and self._extra_log

log_violation(s)[source]

Output a message to both self._log and self._extra_log

replay(new_dag, label)[source]
simulate(check_reproducability=True)[source]
class sts.control_flow.mcs_finder.MCSLogTracker(results_dir, mcs_trace_path, runtime_stats, simulation_cfg, peeker_exists)[source]

Bases: object

Logs intermedate and final MCS results that are the outcome(s) of delta debugging

__init__(results_dir, mcs_trace_path, runtime_stats, simulation_cfg, peeker_exists)[source]
dump_mcs_trace(dag, control_flow, mcs_trace_path=None)[source]
dump_runtime_stats(runtime_stats_file=None)[source]
maybe_dump_intermediate_mcs(dag, label, control_flow)[source]
class sts.control_flow.mcs_finder.ReplayLogTracker(results_dir)[source]

Bases: object

Logs intermediate and final replay traces chosen by delta debugging

__init__(results_dir)[source]
static create_replay_logger_dir(results_dir)[source]
get_replay_logger_dir(label)[source]
class sts.control_flow.mcs_finder.RuntimeStats(runtime_stats_file)[source]

Bases: object

Tracks statistics and configuration information of the delta debugging runs

__init__(runtime_stats_file)[source]
client_dict()[source]

Return a serializable dict

clone()[source]
merge_client_dict(client_dict)[source]
record_early_internal_events(early_internal_events)[source]
record_global_stats()[source]
record_iteration_size(iteration_size)[source]
record_matched_events(matched_events)[source]
record_new_internal_events(new_internal_events)[source]
record_prune_end()[source]
record_prune_start()[source]
record_replay_end()[source]
record_replay_start()[source]
record_timed_out_events(timed_out_events)[source]
record_violation_found(verification_iteration)[source]
set_config(config)[source]
set_dag_stats(dag)[source]
set_initial_verification_runs_needed(verification_runs)[source]
set_peeker(peeker)[source]
write_runtime_stats()[source]

peeker Module

class sts.control_flow.peeker.Peeker(simulation_cfg, default_wait_time_seconds=0.5, epsilon_time=0.2)[source]

Bases: object

__init__(simulation_cfg, default_wait_time_seconds=0.5, epsilon_time=0.2)[source]
ambiguous_counts = Counter()
ambiguous_events = Counter()
find_internal_events(replay_dag, wait_time_seconds)[source]

Replay the replay_dag, then wait for wait_time_seconds and collect internal events that occur. Return the list of internal events.

get_wait_time_seconds(first_event, second_event)[source]
match_and_filter(newly_inferred_events, expected_internal_events)[source]
peek(dag)[source]

Infer which internal events are/aren’t going to occur,

sts.control_flow.peeker.correct_timestamps(new_events, old_events)[source]

Set new_events’ timestamps to approximately the same timestamp as old_events.

Precondition: old_events != []

sts.control_flow.peeker.count_overlapping_fingerprints(newly_inferred_events, expected_internal_events)[source]

Track # of instances where an expected event matches 2 or more inferred events. Mutates Peeker.ambiguous_counts and Peeker.ambiguous_events

sts.control_flow.peeker.get_expected_internal_events(left_input, right_input, events_list)[source]

Return previously observed internal events between the left_input and the right_input event

left_input may be None case we return events from the beginning of events_list

right_input may also be None, in which case we return all events following left_input

sts.control_flow.peeker.match_fingerprints(newly_inferred_events, expected_internal_events)[source]

replayer Module

control flow for running the simulation forward.
  • Replayer: takes as input a superlog with causal dependencies, and iteratively prunes until the MCS has been found
class sts.control_flow.replayer.DataplaneChecker(event_dag, slop_buffer=10)[source]

Bases: object

Dataplane permits are the default, unless they were explicitly dropped in the initial run. This class keeps track of whether pending dataplane events should be dropped or forwarded during replay

__init__(event_dag, slop_buffer=10)[source]

Consider the round i of a DataplaneDrop in the original event ordering. slop_buffer defines how tolerant we are to differences in the position of the correspdonding DataplaneDrop event in the pruned run. A slop_buffer of 4 says that we will tolerate the same DataplaneDrop in the pruned run occuring in the range [i-4,i+4]. If the corresponding DataplaneDrop occurs outside of this window, we won’t detect it, and will treat it as a default DataplanePermit

check_dataplane(current_round, simulation)[source]

Check dataplane events for before playing then next event. - current_event_idx allows us to adjust our current slop buffer

decide_drop(dp_event)[source]

Returns True if this event should be dropped, False otherwise

update_window(current_round)[source]

Update the current slop buffer (“the dp_events we expect to see”)

class sts.control_flow.replayer.DataplaneCheckerStats(events)[source]

Bases: object

Tracks how many drops we actually performed vs. how many we expected to perform

__init__(events)[source]
record_drop(fingerprint)[source]
class sts.control_flow.replayer.Replayer(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, input_logger=None, **kwargs)[source]

Bases: sts.control_flow.base.ControlFlow

Replay events from a trace

To set the event scheduling parameters, pass them as keyword args to the constructor of this class, which will pass them on to the EventScheduler object it creates.

__init__(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, input_logger=None, **kwargs)[source]
compute_interpolated_time(current_event)[source]
get_interpolated_time()[source]

During divergence, the controller may ask for the current time more or less times than they did in the original run. We control the time, so we need to give them some answer. The answers we give them should be (i) monotonically increasing, and (ii) between the time of the last recorded (“landmark”) event and the next landmark event, and (iii) as close to the recorded times as possible

Our temporary solution is to always return the time right before the next landmark

increment_round()[source]
run_simulation_forward(dag, post_bootstrap_hook=None)[source]
simulate(post_bootstrap_hook=None)[source]

Caller must call simulation.clean_up()

time_epsilon_microseconds = 500
total_inputs_replayed = 0
total_replays = 0

Table Of Contents

Previous topic

sts Package

Next topic

dataplane_traces Package

This Page