<commit_before>'''
Three control flow types for running the simulation forward.
  - Replayer: takes as input a `superlog` with causal dependencies, and
    iteratively prunes until the MCS has been found
  - 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
'''

import pox.openflow.libopenflow_01 as of
from invariant_checker import InvariantChecker
from topology import BufferedPatchPanel
from traffic_generator import TrafficGenerator
from sts.console import msg
from sts.event import EventDag
import log_parsing.superlog_parser as superlog_parser

import os
import time
import sys
import threading
import random
import logging

log = logging.getLogger("control_flow")

class ControlFlow(object):
  ''' Superclass of ControlFlow types '''
  def __init__(self):
    self.invariant_checker = InvariantChecker()

  def simulate(self, simulation):
    ''' Move the simulation forward! Take the state of the system as a
    parameter'''
    pass

class Replayer(ControlFlow):
  '''
  Replay events from a `superlog` with causal dependencies, pruning as we go
  '''
  def __init__(self, superlog_path):
    ControlFlow.__init__(self)
    # 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))

  def increment_round(self):
    # TODO(cs): complete this method
    pass

  def simulate(self, simulation):
    self.simulation = simulation

    # First, run through without pruning to verify that the violation exists
    self.simulation.bootstrap()
    for event_watcher in self.dag.event_watchers():
      event_watcher.run(simulation)
      self.increment_round()
      # TODO(cs): check correspondence

    # Now start pruning
    return self.find_mcs()

  def find_mcs(self):
    mcs = []
    for pruned_event in self.dag.events():
      self.simulation.bootstrap()
      for event_watcher in self.dag.event_watchers(pruned_event):
        event_watcher.run(self.simulation)
        # TODO(cs): check correspondence
        self.increment_round()
    return mcs

class Fuzzer(ControlFlow):
  '''
  Injects input events at random intervals, periodically checking
  for invariant violations. (Not the proper use of the term `Fuzzer`)
  '''
  def __init__(self, fuzzer_params="config.fuzzer_params",
               check_interval=35, trace_interval=10, random_seed=0.0,
               delay=0.1, steps=None):
    ControlFlow.__init__(self)

    self.check_interval = check_interval
    self.trace_interval = trace_interval
    # Make execution deterministic to allow the user to easily replay
    self.seed = random_seed
    self.random = random.Random(self.seed)
    self.traffic_generator = TrafficGenerator(self.random)

    self.delay = delay
    self.steps = steps
    self.params = object()
    self._load_fuzzer_params(fuzzer_params)

    # Logical time (round #) for the simulation execution
    self.logical_time = 0

  def _load_fuzzer_params(self, fuzzer_params_path):
    try:
      self.params = __import__(fuzzer_params_path, globals(), locals(), ["*"])
    except:
      raise IOError("Could not find logging config file: %s" %
                    fuzzer_params_path)

  def simulate(self, simulation):
    """Precondition: simulation.patch_panel is a buffered patch panel"""
    assert(isinstance(simulation.patch_panel, BufferedPatchPanel))
    self.simulation = simulation
    self.simulation.bootstrap()
    self.loop()

  def loop(self):
    if self.steps:
      end_time = self.logical_time + self.steps
    else:
      end_time = sys.maxint

    while self.logical_time < end_time:
      self.logical_time += 1
      self.trigger_events()
      msg.event("Round %d completed." % self.logical_time)

      if (self.logical_time % self.check_interval) == 0:
        # Time to run correspondence!
        # spawn a thread for running correspondence. Make sure the controller doesn't
        # think we've gone idle though: send OFP_ECHO_REQUESTS every few seconds
        # TODO(cs): this is a HACK
        def do_correspondence():
          any_policy_violations = self.invariant_checker\
                                      .check_correspondence(self.simulation)

          if any_policy_violations:
            msg.fail("There were policy-violations!")
          else:
            msg.interactive("No policy-violations!")
        thread = threading.Thread(target=do_correspondence)
        thread.start()
        while thread.isAlive():
          for switch in self.simulation.topology.live_switches:
            # connection -> deferred io worker -> io worker
            switch.send(of.ofp_echo_request().pack())
          thread.join(2.0)

      if (self.simulation.dataplane_trace and
          (self.logical_time % self.trace_interval) == 0):
        self.inject_trace_event()

      time.sleep(self.delay)

  def trigger_events(self):
    self.check_dataplane()
    self.check_controlplane()
    self.check_switch_crashes()
    self.check_timeouts()
    self.fuzz_traffic()

  def check_dataplane(self):
    ''' Decide whether to delay, drop, or deliver packets '''
    for dp_event in self.simulation.patch_panel.queued_dataplane_events:
      if self.random.random() < self.params.dataplane_delay_rate:
        self.simulation.delay_dp_event(dp_event)
      elif self.random.random() < self.params.dataplane_drop_rate:<commit_msg>Minor refactoring to Fuzzer<commit_after>'''
Three control flow types for running the simulation forward.
  - Replayer: takes as input a `superlog` with causal dependencies, and
    iteratively prunes until the MCS has been found
  - 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
'''

import pox.openflow.libopenflow_01 as of
from invariant_checker import InvariantChecker
from topology import BufferedPatchPanel
from traffic_generator import TrafficGenerator
from sts.console import msg
from sts.event import EventDag
import log_parsing.superlog_parser as superlog_parser

import os
import time
import sys
import threading
import random
import logging

log = logging.getLogger("control_flow")

class ControlFlow(object):
  ''' Superclass of ControlFlow types '''
  def __init__(self):
    self.invariant_checker = InvariantChecker()

  def simulate(self, simulation):
    ''' Move the simulation forward! Take the state of the system as a
    parameter'''
    pass

class Replayer(ControlFlow):
  '''
  Replay events from a `superlog` with causal dependencies, pruning as we go
  '''
  def __init__(self, superlog_path):
    ControlFlow.__init__(self)
    # 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))

  def increment_round(self):
    # TODO(cs): complete this method
    pass

  def simulate(self, simulation):
    self.simulation = simulation

    # First, run through without pruning to verify that the violation exists
    self.simulation.bootstrap()
    for event_watcher in self.dag.event_watchers():
      event_watcher.run(simulation)
      self.increment_round()
      # TODO(cs): check correspondence

    # Now start pruning
    return self.find_mcs()

  def find_mcs(self):
    mcs = []
    for pruned_event in self.dag.events():
      self.simulation.bootstrap()
      for event_watcher in self.dag.event_watchers(pruned_event):
        event_watcher.run(self.simulation)
        # TODO(cs): check correspondence
        self.increment_round()
    return mcs

class Fuzzer(ControlFlow):
  '''
  Injects input events at random intervals, periodically checking
  for invariant violations. (Not the proper use of the term `Fuzzer`)
  '''
  def __init__(self, fuzzer_params="config.fuzzer_params",
               check_interval=35, trace_interval=10, random_seed=0.0,
               delay=0.1, steps=None):
    ControlFlow.__init__(self)

    self.check_interval = check_interval
    self.trace_interval = trace_interval
    # Make execution deterministic to allow the user to easily replay
    self.seed = random_seed
    self.random = random.Random(self.seed)
    self.traffic_generator = TrafficGenerator(self.random)

    self.delay = delay
    self.steps = steps
    self.params = object()
    self._load_fuzzer_params(fuzzer_params)

    # Logical time (round #) for the simulation execution
    self.logical_time = 0

  def _load_fuzzer_params(self, fuzzer_params_path):
    try:
      self.params = __import__(fuzzer_params_path, globals(), locals(), ["*"])
    except:
      raise IOError("Could not find logging config file: %s" %
                    fuzzer_params_path)

  def simulate(self, simulation):
    """Precondition: simulation.patch_panel is a buffered patch panel"""
    assert(isinstance(simulation.patch_panel, BufferedPatchPanel))
    self.simulation = simulation
    self.simulation.bootstrap()
    self.loop()

  def loop(self):
    if self.steps:
      end_time = self.logical_time + self.steps
    else:
      end_time = sys.maxint

    while self.logical_time < end_time:
      self.logical_time += 1
      self.trigger_events()
      msg.event("Round %d completed." % self.logical_time)
      self.maybe_check_correspondence()
      self.maybe_inject_trace_event()
      time.sleep(self.delay)

  def maybe_check_correspondence(self):
    if (self.logical_time % self.check_interval) == 0:
      # Time to run correspondence!
      # spawn a thread for running correspondence. Make sure the controller doesn't
      # think we've gone idle though: send OFP_ECHO_REQUESTS every few seconds
      # TODO(cs): this is a HACK
      def do_correspondence():
        any_policy_violations = self.invariant_checker\
                                    .check_correspondence(self.simulation)

        if any_policy_violations:
          msg.fail("There were policy-violations!")
        else:
          msg.interactive("No policy-violations!")
      thread = threading.Thread(target=do_correspondence)
      thread.start()
      while thread.isAlive():
        for switch in self.simulation.topology.live_switches:
          # connection -> deferred io worker -> io worker
          switch.send(of.ofp_echo_request().pack())
        thread.join(2.0)

  def maybe_inject_trace_event(self):
    if (self.simulation.dataplane_trace and
        (self.logical_time % self.trace_interval) == 0):
      self.inject_trace_event()

  def trigger_events(self):
    self.check_dataplane()
    self.check_controlplane()
    self.check_switch_crashes()
    self.check_timeouts()
    self.fuzz_traffic()

  def check_dataplane(self):
    ''' Decide whether to delay, drop, or deliver packets '''
    for dp_event in self.simulation.patch_panel.queued_dataplane_events:
      if self.random.random() < self.params.dataplane_delay_rate:
        self.simulation.delay_dp_event(dp_event)
      elif self.random.random() < self.params.dataplane_drop_rate:
{'fraction_non_alphanumeric': 0.08469579201286519, 'fraction_numerical': 0.002858929688197981, 'mean_word_length': 3.3471844660194177, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5731142', 'n_tokens_mistral': 3338, 'n_tokens_neox': 3212, 'n_words': 884}