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 do_pkt_out(self, event=None): msg = of.ofp_packet_out() # Normal pkt-out if event: if event.ofp.buffer_id == -1: mylog("Not flooding unbuffered packet on", dpidToStr(event.dpid)) return msg.actions.append(of.ofp_action_output(port=get_the_other_port(event.port))) msg.buffer_id = event.ofp.buffer_id msg.in_port = event.port mylog('Normal packet-out: ', msg) # Special pkt-out that generates a packet that is exactly the same as # the trigger packet. Unfortunately, only 114 bytes of the original # ingress packet are forwarded into the controller as pkt-in. We need to # make up for the truncated length, if needed. The checksum will be # wrong, but screw that. else: raw_data = func_cache(self.trigger_event.parse).raw if len(raw_data) < self.pkt_out_length: raw_data += 'z' * (self.pkt_out_length - len(raw_data)) msg._data = raw_data msg.buffer_id = -1 with self.lock: assert self.trigger_event msg.actions.append(of.ofp_action_output(port=get_the_other_port(self.trigger_event.port))) msg.in_port = self.trigger_event.port # Stat collection for special pkt-out only. current_time = time.time() with self.lock: (count, start, _) = self.pkt_out_stat if start is None: start = current_time self.pkt_out_stat = (count + 1, start, current_time) if (not USE_LIMITER) or (USE_LIMITER and self.dyn_limiter.to_forward_packet(DynamicLimiter.PacketType.PktOut)): self._of_send(msg)