def repair_links(cut_this_round): for link in set(self.cut_links): if link in cut_this_round: continue if self.random.random() < self.link_recovery_rate: msg.event("Restoring link %s" % str(link)) link.start_switch_impl.bring_port_up(link.start_port) self.cut_links.remove(link)
def restart_switches(crashed_this_round): for switch_impl in set(self.failed_switches): if switch_impl in crashed_this_round: continue if self.random.random() < self.switch_recovery_rate: msg.event("Rebooting switch_impl %s" % str(switch_impl)) switch_impl.recover() self.failed_switches.remove(switch_impl)
def crash_switches(): crashed_this_round = set() for switch_impl in self.live_switches: if self.random.random() < self.switch_failure_rate: msg.event("Crashing switch_impl %s" % str(switch_impl)) switch_impl.fail() crashed_this_round.add(switch_impl) self.failed_switches.add(switch_impl) return crashed_this_round
def fuzz_traffic(self): if not self.dataplane_trace: # randomly generate messages from switches for switch_impl in self.live_switches: if self.random.random() < self.traffic_generation_rate: if len(switch_impl.ports) > 0: msg.event("injecting a random packet") traffic_type = "icmp_ping" # Generates a packet, and feeds it to the switch_impl self.traffic_generator.generate(traffic_type, switch_impl)
def sever_links(): # TODO: model administratively down links? (OFPPC_PORT_DOWN) cut_this_round = set() for link in self.live_links: if self.random.random() < self.link_failure_rate: msg.event("Cutting link %s" % str(link)) self.cut_links.add(link) link.start_switch_impl.take_port_down(link.start_port) cut_this_round.add(link) return cut_this_round
def loop(self, steps=None): self.running = True end_time = self.logical_time + steps if steps else sys.maxint while self.running and self.logical_time < end_time: self.logical_time += 1 self.trigger_events() msg.event("Round %d completed." % self.logical_time) if self.interactive: # TODO: print out the state of the network at each timestep? Take a # verbose flag.. self.invariant_check_prompt() self.dataplane_trace_prompt() answer = msg.raw_input('Continue to next round? [Yn]').strip() if answer != '' and answer.lower() != 'y': self.stop() break else: # not self.interactive 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: this is a HACK def do_correspondence(): any_policy_violations = self.invariant_checker.check_correspondence(self.live_switches, self.live_links, self.access_links) 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.live_switches: # connection -> deferred io worker -> io worker switch.send(of.ofp_echo_request().pack()) thread.join(2.0) if self.dataplane_trace and (self.logical_time % self.trace_interval) == 0: self.inject_trace_event() time.sleep(self.delay)
def check_dataplane(self): ''' Decide whether to delay, drop, or deliver packets ''' for dp_event in set(self.panel.get_buffered_dp_events()): if self.random.random() < self.dataplane_delay_rate: msg.event("Delaying dataplane event") # (Monkey patch on a delay counter) if not hasattr(dp_event, "delayed_rounds"): dp_event.delayed_rounds = 0 dp_event.delayed_rounds += 1 elif self.random.random() < self.dataplane_drop_rate: msg.event("Dropping dataplane event") # Drop the message self.panel.drop_dp_event(dp_event) self.dropped_dp_events.append(dp_event) else: (next_hop, next_port) = self.panel.get_connected_port(dp_event.switch, dp_event.port) if type(dp_event.node) == Host or type(next_hop) == Host: # TODO: model access link failures: self.panel.permit_dp_event(dp_event) else: link = Link(dp_event.switch, dp_event.port, next_hop, next_port) if not link in self.cut_links: msg.event("Forwarding dataplane event") # Forward the message self.panel.permit_dp_event(dp_event)