def do_flow_mod(self, event=None): """ If the event is not specified, then issues a flow mod with random src and dst ports; all the other fields will match against the trigger event saved earlier. Does not issue pkt_out. Otherwise, does a normal flow_mod. """ msg = of.ofp_flow_mod() # Normal flow-mod if event: msg.match = of.ofp_match.from_packet(event.parse()) msg.actions.append(of.ofp_action_output(port=get_the_other_port(event.port))) msg.buffer_id = event.ofp.buffer_id # Save the trigger event for later matching. if msg.match.tp_dst == TRIGGER_PORT: with self.lock: self.trigger_event = event mylog('Received trigger event. Trigger event.parse() =', pretty_dict(dictify(event.parse()))) mylog('Installed flow:', pretty_dict(dictify(msg.match))) # Special flow-mod that generates random source/dst ports. else: with self.lock: assert self.trigger_event trigger_packet = func_cache(self.trigger_event.parse) msg.match = of.ofp_match.from_packet(trigger_packet) msg.actions.append(of.ofp_action_output(port=get_the_other_port(self.trigger_event.port))) msg.match.tp_dst = random.randint(10, 65000) msg.match.tp_src = random.randint(10, 65000) current_time = time.time() with self.lock: (count, start, _) = self.flow_mod_stat if start is None: start = current_time self.flow_mod_stat = (count + 1, start, current_time) msg.idle_timeout = IDLE_TIMEOUT msg.hard_timeout = HARD_TIMEOUT if (not USE_LIMITER) or (USE_LIMITER and self.flow_mod_limiter.to_forward_packet()): self._of_send(msg) self.flow_mod_queue.put((current_time, event.parse()))
def _install_rule(self, event, packet, outport, tp_dst=None, idle_timeout=IDLE_TIMEOUT): """ Installs a rule for any incoming packet, doing what a learning switch should do. """ msg = of.ofp_flow_mod() msg.match = of.ofp_match.from_packet(packet) msg.idle_timeout = idle_timeout msg.hard_timeout = HARD_TIMEOUT msg.actions.append(of.ofp_action_output(port=outport)) with exp_control.lock: exp_control.flow_mod_count += 1 install_bogus_rules = exp_control.install_bogus_rules # Install a rule with a randomly generated dest mac address that no # one will ever match against. if install_bogus_rules: # mac_addr_list = ['0' + str(random.randint(1,9)) for _ in range(6)] # msg.match.dl_src = EthAddr(':'.join(mac_addr_list)) msg.match.tp_dst = random.randint(10, 65000) msg.match.tp_src = random.randint(10, 65000) msg.buffer_id = event.ofp.buffer_id mylog("Installing a bogus flow.") # Create a rule that matches with the incoming packet. When buffer ID is # specified, the flow mod command is automatically followed by a packet- # out command. elif tp_dst is None: msg.buffer_id = event.ofp.buffer_id with exp_control.lock: exp_control.pkt_out_count += 1 mylog("installing flow for %s.%i -> %s.%i" % (packet.src, event.port, packet.dst, outport)) # Create a rule with a specific dest port. else: msg.match.tp_dst = tp_dst mylog("Installing rule for tp_dst =", tp_dst) current_time = time.time() with exp_control.lock: if exp_control.flow_mod_start_time is None: exp_control.flow_mod_start_time = current_time exp_control.flow_mod_end_time = current_time mylog("Flow_mod:", pretty_dict(dictify(msg))) self.connection.send(msg)
def _is_relevant_packet(self, event, packet): """ Sanity check to make sure we deal with experimental traffic only. Otherwise, returns False. """ mylog('zzzz inport =', event.port) if not self.transparent: if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered(): mylog('pkt_in: Rejected packet LLDP or BridgeFiltered:', packet, repr(packet), dictify(packet)) self._drop(event) return False if event.port not in SWITCH_PORT_LIST: mylog('pkt_in: Rejected packet: invalid port', packet, repr(packet), dictify(packet)) self._drop(event) return False if packet.dst.isMulticast(): self.do_pkt_out(event) return False return True
def _handle_pkt_in_helper(self, event): packet = event.parse() current_time = time.time() with exp_control.lock: flow_stat_interval = exp_control.flow_stat_interval # Obtain flow stats once in a while. if flow_stat_interval: if current_time - self.last_flow_stat_time > flow_stat_interval: self.last_flow_stat_time = current_time self.connection.send(of.ofp_stats_request(body=of.ofp_flow_stats_request())) # There are just packets that we don't care. if not self._is_relevant_packet(event, packet): mylog("pkt_in: Rejected packet:", packet, repr(packet), dictify(packet)) return # Throttle packet-in events if need be. if exp_control.emulate_hp_switch: if not self.limiter_pkt_in.to_forward_packet(): return # Count packet-in events. with exp_control.lock: learning_switch = exp_control.learning exp_control.pkt_in_count += 1 if exp_control.pkt_in_start_time is None: exp_control.pkt_in_start_time = current_time exp_control.pkt_in_end_time = current_time # Count number of packet-out events if the switch does not install # rules. if not learning_switch: with exp_control.lock: exp_control.pkt_out_count += 1 self._drop(event) return outport = get_the_other_port(event.port) # Throttle flow-mod events and pkt-out events if need be. if exp_control.emulate_hp_switch: if self.limiter_flow_mod.to_forward_packet(): # flow-mod and pkt-out at 50 pps pass else: # pkt-out at 50 pps, so regardless, total pkt-out at 100 pps if self.limiter_pkt_out.to_forward_packet(): self._packet_out(event) return # Automatically learns new flows, as a normal learning switch would do. if exp_control.auto_install_rules: self._install_rule(event, packet, outport) return # Manually install rules in the port range. with exp_control.lock: tp_dst_range = exp_control.manual_install_tp_dst_range[:] gap_ms = exp_control.manual_install_gap_ms for tp_dst in range(*tp_dst_range): # Keep going until the exp_control client decides to stop it. with exp_control.lock: manual_active = exp_control.manual_install_active if not manual_active: break self._install_rule(event, packet, outport, tp_dst) time.sleep(gap_ms / 1000.0)