def _print_buffers(self): # TODO(cs): this method should also be added to Interactive. # Note that there shouldn't be any pending state changes in record mode, # only pending message sends/receives. buffered_events = [] log.info("Pending Receives:") of_buf = self.simulation.openflow_buffer for (dpid, controller_id) in of_buf.conns_with_pending_receives(): for p in of_buf.get_pending_receives(dpid, controller_id): log.info("- %r", p) message = of_buf.get_message_receipt(p) b64_packet = base64_encode(message) event = ControlMessageReceive(p.dpid, p.controller_id, p.fingerprint, b64_packet=b64_packet) buffered_events.append(event) log.info("Pending Sends:") for (dpid, controller_id) in of_buf.conns_with_pending_sends(): for p in of_buf.get_pending_sends(dpid, controller_id): log.info("- %r", p) message = of_buf.get_message_send(p) b64_packet = base64_encode(message) event = ControlMessageSend(p.dpid, p.controller_id, p.fingerprint, b64_packet=b64_packet) buffered_events.append(event) if self._input_logger is not None: self._input_logger.dump_buffered_events(buffered_events)
def check_pending_messages(self, pass_through=False): of_buf = self.simulation.openflow_buffer for (dpid, controller_id) in of_buf.conns_with_pending_receives(): for pending_receipt in of_buf.get_pending_receives(dpid, controller_id): if (not pass_through and self.random.random() > self.params.ofp_message_receipt_rate): break message = of_buf.get_message_receipt(pending_receipt) b64_packet = base64_encode(message) self._log_input_event(ControlMessageReceive(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) of_buf.schedule(pending_receipt) for (dpid, controller_id) in of_buf.conns_with_pending_sends(): for pending_send in of_buf.get_pending_sends(dpid, controller_id): if (not pass_through and self.random.random() > self.params.ofp_message_send_rate): break message = of_buf.get_message_send(pending_send) b64_packet = base64_encode(message) self._log_input_event(ControlMessageSend(pending_send.dpid, pending_send.controller_id, pending_send.fingerprint, b64_packet=b64_packet)) of_buf.schedule(pending_send)
def check_pending_messages(self, pass_through=False): for pending_receipt in self.simulation.openflow_buffer.pending_receives( ): # TODO(cs): this is a really dumb way to fuzz packet receipt scheduling if (self.random.random() < self.params.ofp_message_receipt_rate or pass_through): message = self.simulation.openflow_buffer.schedule( pending_receipt) b64_packet = base64_encode(message) self._log_input_event( ControlMessageReceive(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) for pending_send in self.simulation.openflow_buffer.pending_sends(): if (self.random.random() < self.params.ofp_message_send_rate or pass_through): message = self.simulation.openflow_buffer.schedule( pending_send) b64_packet = base64_encode(message) self._log_input_event( ControlMessageSend(pending_send.dpid, pending_send.controller_id, pending_send.fingerprint, b64_packet=b64_packet))
def check_pending_messages(self, pass_through=False): of_buf = self.simulation.openflow_buffer for (dpid, controller_id) in of_buf.conns_with_pending_receives(): for pending_receipt in of_buf.get_pending_receives( dpid, controller_id): if (not pass_through and self.random.random() > self.params.ofp_message_receipt_rate): break message = of_buf.get_message_receipt(pending_receipt) b64_packet = base64_encode(message) self._log_input_event( ControlMessageReceive(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) of_buf.schedule(pending_receipt) for (dpid, controller_id) in of_buf.conns_with_pending_sends(): for pending_send in of_buf.get_pending_sends(dpid, controller_id): if (not pass_through and self.random.random() > self.params.ofp_message_send_rate): break message = of_buf.get_message_send(pending_send) b64_packet = base64_encode(message) self._log_input_event( ControlMessageSend(pending_send.dpid, pending_send.controller_id, pending_send.fingerprint, b64_packet=b64_packet)) of_buf.schedule(pending_send)
def check_pending_commands(self): ''' If Fuzzer is configured to delay flow mods, this decides whether each switch is allowed to process a buffered flow mod ''' def should_fail_flow_mod(command): # super simple filter to tell whether to apply or actively fail a flow_mod return self.random.random() < self.params.ofp_flow_mod_failure_rate if self.delay_flow_mods: for switch in self.simulation.topology.switches: assert(isinstance(switch, FuzzSoftwareSwitch)) # first decide if we should try to process the next command from the switch if switch.has_pending_commands() and (self.random.random() < self.params.ofp_cmd_passthrough_rate): (cmd, pending_receipt) = switch.get_next_command() # then check whether we should make the attempt to process the next command fail if should_fail_flow_mod(cmd): eventclass = FailFlowMod else: eventclass = ProcessFlowMod switch.process_delayed_command(pending_receipt) b64_packet = base64_encode(cmd) self._log_input_event(eventclass(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet))
def check_pending_commands(self): ''' If Fuzzer is configured to delay flow mods, this decides whether each switch is allowed to process a buffered flow mod ''' def should_fail_flow_mod(command): # super simple filter to tell whether to apply or actively fail a flow_mod return self.random.random() < self.params.ofp_flow_mod_failure_rate if self.delay_flow_mods: for switch in self.simulation.topology.switches: assert (isinstance(switch, FuzzSoftwareSwitch)) # first decide if we should try to process the next command from the switch if (self.random.random() < self.params.ofp_cmd_passthrough_rate ) and switch.has_pending_commands(): (cmd, pending_receipt) = switch.get_next_command() # then check whether we should make the attempt to process the next command fail if should_fail_flow_mod(cmd): eventclass = FailFlowMod else: eventclass = ProcessFlowMod switch.process_delayed_command(pending_receipt) b64_packet = base64_encode(cmd) self._log_input_event( eventclass(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet))
def _check_unexpected_cp_messages(self, dag, current_index): ''' If throughout replay we observe new messages that weren't in the original trace, we (usually) want to let them through. This is especially true for messages that are related to timers, such as LLDP, since timings will often change during replay, and we don't want to unnecessarily change the controller's behavior. ''' if not self.allow_unexpected_messages: return # TODO(cs): evaluate whether _check_unexpected_cp_messages is more or less # effective than whitelisting cp message types (in OpenflowBuffer). # Compare executions with visualization tool. # Currently it appears that this method is too liberal, and ends up # causing timouts as a result of letting messages through. # First, build a set of expected ControlMessageSends/Receives fingerprints # within the next expected_message_round_window rounds. start_round = dag.events[current_index].round expected_receive_fingerprints = set() expected_send_fingerprints = set() for i in xrange(current_index, len(dag.events)): event = dag.events[i] if event.round - start_round > self.expected_message_round_window: break if type(event) == ControlMessageReceive: (_, of_fingerprint, dpid, cid) = event.fingerprint expected_receive_fingerprints.add((of_fingerprint, dpid, cid)) if type(event) == ControlMessageSend: (_, of_fingerprint, dpid, cid) = event.fingerprint expected_send_fingerprints.add((of_fingerprint, dpid, cid)) # Now check pending messages. for expected_fingerprints, messages in [ (expected_receive_fingerprints, self.simulation.openflow_buffer.pending_receives), (expected_send_fingerprints, self.simulation.openflow_buffer.pending_sends) ]: for pending_message in messages: fingerprint = (pending_message.fingerprint, pending_message.dpid, pending_message.controller_id) if fingerprint not in expected_fingerprints: message = self.simulation.openflow_buffer.schedule( pending_message) log.debug("Allowed unexpected message %s" % message) b64_packet = base64_encode(message) # Monkeypatch a "new internal event" marker to be logged to the JSON trace # (All fields picked up by event.to_json()) event_type = ControlMessageReceive if type( pending_message ) == PendingReceive else ControlMessageSend log_event = event_type(pending_message.dpid, pending_message.controller_id, pending_message.fingerprint, b64_packet=b64_packet) log_event.new_internal_event = True log_event.replay_time = SyncTime.now() self.passed_unexpected_messages.append(repr(log_event)) self._log_input_event(log_event)
def check_pending_messages(self, pass_through=False): for pending_receipt in self.simulation.openflow_buffer.pending_receives(): # TODO(cs): this is a really dumb way to fuzz packet receipt scheduling if (self.random.random() < self.params.ofp_message_receipt_rate or pass_through): message = self.simulation.openflow_buffer.schedule(pending_receipt) b64_packet = base64_encode(message) self._log_input_event(ControlMessageReceive(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) for pending_send in self.simulation.openflow_buffer.pending_sends(): if (self.random.random() < self.params.ofp_message_send_rate or pass_through): message = self.simulation.openflow_buffer.schedule(pending_send) b64_packet = base64_encode(message) self._log_input_event(ControlMessageSend(pending_send.dpid, pending_send.controller_id, pending_send.fingerprint, b64_packet=b64_packet))
def insert_pending_send(self, dpid, controller_id, ofp_message, conn): ''' Called by DeferredOFConnection to insert messages into our buffer ''' fingerprint = OFFingerprint.from_pkt(ofp_message) if self.pass_through_whitelisted_packets and self.in_whitelist(fingerprint): conn.allow_message_send(ofp_message) return conn_message = (conn, ofp_message) pending_send = PendingSend(dpid, controller_id, fingerprint) self.pendingsend2conn_messages[pending_send].append(conn_message) b64_packet = base64_encode(ofp_message) self.raiseEventNoErrors(PendingMessage(pending_send, b64_packet, send_event=True)) return pending_send
def insert_pending_receipt(self, dpid, controller_id, ofp_message, conn): ''' Called by DeferredOFConnection to insert messages into our buffer ''' fingerprint = OFFingerprint.from_pkt(ofp_message) if self.pass_through_whitelisted_packets and self.in_whitelist(fingerprint): conn.allow_message_receipt(ofp_message) return conn_message = (conn, ofp_message) message_id = PendingReceive(dpid, controller_id, fingerprint) self.pending_receives.insert(message_id, conn_message) b64_packet = base64_encode(ofp_message) self.raiseEventNoErrors(PendingMessage(message_id, b64_packet)) return message_id
def insert_pending_receipt(self, dpid, controller_id, ofp_message, conn): ''' Called by DeferredOFConnection to insert messages into our buffer ''' fingerprint = OFFingerprint.from_pkt(ofp_message) if self.pass_through_whitelisted_packets and self.in_whitelist( fingerprint): conn.allow_message_receipt(ofp_message) return conn_message = (conn, ofp_message) message_id = PendingReceive(dpid, controller_id, fingerprint) self.pending_receives.insert(message_id, conn_message) b64_packet = base64_encode(ofp_message) self.raiseEventNoErrors(PendingMessage(message_id, b64_packet)) return message_id
def _check_unexpected_dp_messages(self, dag, current_index): ''' If throughout replay we observe new messages that weren't in the original trace, we (usually) want to let them through. This is especially true for messages that are related to timers, such as LLDP, since timings will often change during replay, and we don't want to unnecessarily change the controller's behavior. ''' if not self.allow_unexpected_messages: return # TODO(cs): evaluate whether _check_unexpected_dp_messages is more or less # effective than _check_whitelisted_dp_messages. Compare executions with # visualization tool. Currently it appears that this method is too # liberal, and ends up causing timouts as a result of letting messages # through. # First, build a set of expected ControlMessageSends/Receives fingerprints # within the next expected_message_round_window rounds. start_round = dag.events[current_index].round expected_receive_fingerprints = set() expected_send_fingerprints = set() for i in xrange(current_index, len(dag.events)): event = dag.events[i] if event.round - start_round > self.expected_message_round_window: break if type(event) == ControlMessageReceive: (_, of_fingerprint, dpid, cid) = event.fingerprint expected_receive_fingerprints.add((of_fingerprint, dpid, cid)) if type(event) == ControlMessageSend: (_, of_fingerprint, dpid, cid) = event.fingerprint expected_send_fingerprints.add((of_fingerprint, dpid, cid)) # Now check pending messages. for expected_fingerprints, messages in [ (expected_receive_fingerprints, self.simulation.openflow_buffer.pending_receives()), (expected_send_fingerprints, self.simulation.openflow_buffer.pending_sends())]: for pending_message in messages: fingerprint = (pending_message.fingerprint, pending_message.dpid, pending_message.controller_id) if fingerprint not in expected_fingerprints: message = self.simulation.openflow_buffer.schedule(pending_message) log.debug("Sending unexpected %s" % message) b64_packet = base64_encode(message) # Monkeypatch a "new internal event" marker to be logged to the JSON trace # (All fields picked up by event.to_json()) event_type = ControlMessageReceive if type(pending_message) == PendingReceive else ControlMessageSend log_event = event_type(pending_message.dpid, pending_message.controller_id, pending_message.fingerprint, b64_packet=b64_packet) log_event.new_internal_event = True log_event.replay_time = SyncTime.now() self.passed_unexpected_messages.append(repr(log_event)) self._log_input_event(log_event)
def insert_pending_send(self, dpid, controller_id, ofp_message, conn): ''' Called by DeferredOFConnection to insert messages into our buffer ''' fingerprint = OFFingerprint.from_pkt(ofp_message) if self.pass_through_whitelisted_packets and self.in_whitelist( fingerprint): conn.allow_message_send(ofp_message) return conn_message = (conn, ofp_message) pending_send = PendingSend(dpid, controller_id, fingerprint) self.pendingsend2conn_messages[pending_send].append(conn_message) b64_packet = base64_encode(ofp_message) self.raiseEventNoErrors( PendingMessage(pending_send, b64_packet, send_event=True)) return pending_send
def check_pending_commands(self): ''' If Fuzzer is configured to delay flow mods, this decides whether each switch is allowed to process a buffered flow mod ''' if self.delay_flow_mods: for switch in self.simulation.topology.switches: assert(isinstance(switch, FuzzSoftwareSwitch)) if (self.random.random() < self.params.ofp_cmd_passthrough_rate): if switch.has_pending_commands(): (message, pending_receipt) = switch.process_delayed_command() b64_packet = base64_encode(message) self._log_input_event(ProcessFlowMod(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet))
def insert_pending_send(self, dpid, controller_id, ofp_message, conn): ''' Called by DeferredOFConnection to insert messages into our buffer ''' fingerprint = OFFingerprint.from_pkt(ofp_message) if (self.pass_through_sends or (self.pass_through_whitelisted_packets and self.in_whitelist(fingerprint))): conn.allow_message_send(ofp_message) return conn_message = (conn, ofp_message) message_id = PendingSend(dpid, controller_id, fingerprint) self.pending_sends.insert(message_id, conn_message) log.info("--- insert pending send: %s", message_id) b64_packet = base64_encode(ofp_message) self.raiseEventNoErrors(PendingMessage(message_id, b64_packet, send_event=True)) return message_id
def check_pending_commands(self): ''' If Fuzzer is configured to delay flow mods, this decides whether each switch is allowed to process a buffered flow mod ''' if self.delay_flow_mods: for switch in self.simulation.topology.switches: assert(isinstance(switch, FuzzSoftwareSwitch)) # first decide if we should try to process the next command from the switch if switch.has_pending_commands() and (self.random.random() < self.params.ofp_cmd_passthrough_rate): (cmd, pending_receipt) = switch.get_next_command() eventclass = ProcessFlowMod b64_packet = base64_encode(cmd) self._log_input_event(eventclass(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) switch.process_delayed_command(pending_receipt)
def _print_buffers(self): # TODO(cs): this method should also be added to Interactive. # Note that there shouldn't be any pending state changes in record mode, # only pending message sends/receives. buffered_events = [] log.info("Pending Messages:") for event_type, pending2conn_messages in [ (ControlMessageReceive, self.simulation.openflow_buffer.pendingreceive2conn_messages), (ControlMessageSend, self.simulation.openflow_buffer.pendingsend2conn_messages)]: for p, conn_messages in pending2conn_messages.iteritems(): log.info("- %r", p) for _, ofp_message in conn_messages: b64_packet = base64_encode(ofp_message) event = event_type(p.dpid, p.controller_id, p.fingerprint, b64_packet=b64_packet) buffered_events.append(event) if self._input_logger is not None: self._input_logger.dump_buffered_events(buffered_events)
def check_pending_commands(self): ''' If Fuzzer is configured to delay flow mods, this decides whether each switch is allowed to process a buffered flow mod ''' if self.delay_flow_mods: for switch in self.simulation.topology.switches: assert (isinstance(switch, FuzzSoftwareSwitch)) # first decide if we should try to process the next command from the switch if switch.has_pending_commands() and ( self.random.random() < self.params.ofp_cmd_passthrough_rate): (cmd, pending_receipt) = switch.get_next_command() eventclass = ProcessFlowMod b64_packet = base64_encode(cmd) self._log_input_event( eventclass(pending_receipt.dpid, pending_receipt.controller_id, pending_receipt.fingerprint, b64_packet=b64_packet)) switch.process_delayed_command(pending_receipt)
def _print_buffers(self): # TODO(cs): this method should also be added to Interactive. # Note that there shouldn't be any pending state changes in record mode, # only pending message sends/receives. buffered_events = [] log.info("Pending Messages:") for event_type, pending2conn_messages in [ (ControlMessageReceive, self.simulation.openflow_buffer.pendingreceive2conn_messages), (ControlMessageSend, self.simulation.openflow_buffer.pendingsend2conn_messages) ]: for p, conn_messages in pending2conn_messages.iteritems(): log.info("- %r", p) for _, ofp_message in conn_messages: b64_packet = base64_encode(ofp_message) event = event_type(p.dpid, p.controller_id, p.fingerprint, b64_packet=b64_packet) buffered_events.append(event) if self._input_logger is not None: self._input_logger.dump_buffered_events(buffered_events)
def _send_command(self, command): b64_pkt = base64_encode(command) self.json_worker.send(b64_pkt)