def rx_packet (self, packet, in_port, packet_data = None): """ process a dataplane packet packet: an instance of ethernet in_port: the integer port number packet_data: packed version of packet if available """ assert assert_type("packet", packet, ethernet, none_ok=False) assert assert_type("in_port", in_port, int, none_ok=False) port = self.ports.get(in_port) if port is None: self.log.warn("Got packet on missing port %i", in_port) return is_stp = packet.dst == _STP_MAC if (port.config & OFPPC_NO_RECV) and not is_stp: # Drop all except STP return if (port.config & OFPPC_NO_RECV_STP) and is_stp: # Drop STP return if self.config_flags & OFPC_FRAG_MASK: ipp = packet.find(ipv4) if ipp: if (ipp.flags & ipv4.MF_FLAG) or ipp.frag != 0: frag_mode = self.config_flags & OFPC_FRAG_MASK if frag_mode == OFPC_FRAG_DROP: # Drop fragment return elif frag_mode == OFPC_FRAG_REASM: if self.features.cap_ip_reasm: #TODO: Implement fragment reassembly self.log.info("Can't reassemble fragment: not implemented") else: self.log.warn("Illegal fragment processing mode: %i", frag_mode) self.port_stats[in_port].rx_packets += 1 if packet_data is not None: self.port_stats[in_port].rx_bytes += len(packet_data) else: self.port_stats[in_port].rx_bytes += len(packet.pack()) # Expensive self._lookup_count += 1 entry = self.table.entry_for_packet(packet, in_port) if entry is not None: self._matched_count += 1 entry.touch_packet(len(packet)) self._process_actions_for_packet(entry.actions, packet, in_port) else: # no matching entry if port.config & OFPPC_NO_PACKET_IN: return buffer_id = self._buffer_packet(packet, in_port) if packet_data is None: packet_data = packet.pack() self.send_packet_in(in_port, buffer_id, packet_data, reason=OFPR_NO_MATCH, data_length=self.miss_send_len)
def __init__(self, host, interface, switch, switch_port): assert_type("interface", interface, HostInterface, none_ok=False) assert_type("switch_port", switch_port, ofp_phy_port, none_ok=False) self.host = host self.interface = interface self.switch = switch self.switch_port = switch_port
def rx_packet (self, packet, in_port): """ process a dataplane packet packet: an instance of ethernet in_port: the integer port number """ assert assert_type("packet", packet, ethernet, none_ok=False) assert assert_type("in_port", in_port, int, none_ok=False) port = self.ports.get(in_port) if port is None: self.log.warn("Got packet on missing port %i", in_port) return if port.config & OFPPC_NO_RECV: return self._lookup_count += 1 entry = self.table.entry_for_packet(packet, in_port) if entry is not None: self._matched_count += 1 entry.touch_packet(len(packet)) self._process_actions_for_packet(entry.actions, packet, in_port) else: # no matching entry if port.config & OFPPC_NO_PACKET_IN: return buffer_id = self._buffer_packet(packet, in_port) self.send_packet_in(in_port, buffer_id, packet, reason=OFPR_NO_MATCH, data_length=self.miss_send_len)
def _output_packet(self, packet, out_port, in_port): """ send a packet out some port. packet: instance of ethernet out_port, in_port: the integer port number """ assert_type("packet", packet, ethernet, none_ok=False) def real_send(port_no): if type(port_no) == ofp_phy_port: port_no = port_no.port_no if port_no not in self.ports: raise RuntimeError("Invalid physical output port: %x" % port_no) if self.ports[port_no].state & OFPPS_LINK_DOWN: self.log.debug("Sending packet on a port which is down!") else: self.raiseEvent(DpPacketOut(self, packet, self.ports[port_no])) if out_port < OFPP_MAX: real_send(out_port) elif out_port == OFPP_IN_PORT: real_send(in_port) elif out_port == OFPP_FLOOD or out_port == OFPP_ALL: # no support for spanning tree yet -> flood=all for (no,port) in self.ports.iteritems(): if no != in_port: real_send(port) elif out_port == OFPP_CONTROLLER: buffer_id = self._buffer_packet(packet, in_port) self.send_packet_in(in_port, buffer_id, packet, self.xid_count(), reason=OFPR_ACTION) else: raise("Unsupported virtual output port: %x" % out_port)
def __init__(self, start_switch_impl, start_port, end_switch_impl, end_port): assert_type("start_port", start_port, ofp_phy_port, none_ok=False) assert_type("end_port", end_port, ofp_phy_port, none_ok=False) self.start_switch_impl = start_switch_impl self.start_port = start_port self.end_switch_impl = end_switch_impl self.end_port = end_port
def __init__ (self, node, packet, port): assert_type("packet", packet, ethernet, none_ok=False) Event.__init__(self) self.node = node self.packet = packet self.port = port # For backwards compatability: self.switch = node
def _process_actions_for_packet(self, actions, packet, in_port): """ process the output actions for a packet """ assert_type("packet", packet, [ethernet, str], none_ok=False) if not isinstance(packet, ethernet): packet = ethernet.unpack(packet) def output_packet(action, packet): self._output_packet(packet, action.port, in_port) def set_vlan_id(action, packet): if not isinstance(packet, vlan): packet = vlan(packet) packet.id = action.vlan_id def set_vlan_pcp(action, packet): if not isinstance(packet, vlan): packet = vlan(packet) packet.pcp = action.vlan_pcp def strip_vlan(action, packet): if not isinstance(packet, vlan): packet = vlan(packet) packet.pcp = action.vlan_pcp def set_dl_src(action, packet): packet.src = action.dl_addr def set_dl_dst(action, packet): packet.dst = action.dl_addr def set_nw_src(action, packet): if(isinstance(packet, ipv4)): packet.nw_src = action.nw_addr def set_nw_dst(action, packet): if(isinstance(packet, ipv4)): packet.nw_dst = action.nw_addr def set_nw_tos(action, packet): if(isinstance(packet, ipv4)): packet.tos = action.nw_tos def set_tp_src(action, packet): if(isinstance(packet, udp) or isinstance(packet, tcp)): packet.srcport = action.tp_port def set_tp_dst(action, packet): if(isinstance(packet, udp) or isinstance(packet, tcp)): packet.dstport = action.tp_port def enqueue(action, packet): self.log.warn("output_enqueue not supported yet. Performing regular output") output_packet(action.tp_port, packet) handler_map = { OFPAT_OUTPUT: output_packet, OFPAT_SET_VLAN_VID: set_vlan_id, OFPAT_SET_VLAN_PCP: set_vlan_pcp, OFPAT_STRIP_VLAN: strip_vlan, OFPAT_SET_DL_SRC: set_dl_src, OFPAT_SET_DL_DST: set_dl_dst, OFPAT_SET_NW_SRC: set_nw_src, OFPAT_SET_NW_DST: set_nw_dst, OFPAT_SET_NW_TOS: set_nw_tos, OFPAT_SET_TP_SRC: set_tp_src, OFPAT_SET_TP_DST: set_tp_dst, OFPAT_ENQUEUE: enqueue } for action in actions: if(action.type not in handler_map): raise NotImplementedError("Unknown action type: %x " % type) handler_map[action.type](action, packet)
def send_port_status(self, port, reason): ''' port is an ofp_phy_port reason is one of 'OFPPR_ADD', 'OFPPR_DELETE', 'OFPPR_MODIFY' ''' assert_type("port", port, ofp_phy_port, none_ok=False) assert(reason in ofp_port_reason_rev_map.values()) msg = ofp_port_status(desc=port, reason=reason) self.send(msg)
def __init__(self, start_software_switch, start_port, end_software_switch, end_port): if type(start_port) == int: assert(start_port in start_software_switch.ports) start_port = start_software_switch.ports[start_port] if type(end_port) == int: assert(end_port in start_software_switch.ports) end_port = end_software_switch.ports[end_port] super(Link, self).__init__(start_software_switch, start_port, end_software_switch, end_port) assert_type("start_port", start_port, ofp_phy_port, none_ok=False) assert_type("end_port", end_port, ofp_phy_port, none_ok=False) self.start_software_switch = start_software_switch self.end_software_switch = end_software_switch
def rx_packet(self, packet, in_port, packet_data=None): """ process a dataplane packet packet: an instance of ethernet in_port: the integer port number packet_data: packed version of packet if available """ assert assert_type("packet", packet, ethernet, none_ok=False) assert assert_type("in_port", in_port, int, none_ok=False) port = self.ports.get(in_port) if port is None: self.log.warn("Got packet on missing port %i", in_port) return is_stp = packet.dst == _STP_MAC if (port.config & OFPPC_NO_RECV) and not is_stp: # Drop all except STP return if (port.config & OFPPC_NO_RECV_STP) and is_stp: # Drop STP return self.port_stats[in_port].rx_packets += 1 if packet_data is not None: self.port_stats[in_port].rx_bytes += len(packet_data) else: self.port_stats[in_port].rx_bytes += len( packet.pack()) # Expensive self._lookup_count += 1 entry = self.table.entry_for_packet(packet, in_port) if entry is not None: self._matched_count += 1 entry.touch_packet(len(packet)) self._process_actions_for_packet(entry.actions, packet, in_port) else: # no matching entry if port.config & OFPPC_NO_PACKET_IN: return buffer_id = self._buffer_packet(packet, in_port) if packet_data is None: packet_data = packet.pack() self.send_packet_in(in_port, buffer_id, packet_data, reason=OFPR_NO_MATCH, data_length=self.miss_send_len)
def process_packet(self, packet, in_port): """ process a dataplane packet the way a real OpenFlow switch would. packet: an instance of ethernet in_port: the integer port number """ assert_type("packet", packet, ethernet, none_ok=False) entry = self.table.entry_for_packet(packet, in_port) if(entry != None): entry.touch_packet(len(packet)) self._process_actions_for_packet(entry.actions, packet, in_port) else: # no matching entry buffer_id = self._buffer_packet(packet, in_port) self.send_packet_in(in_port, buffer_id, packet, self.xid_count.next(), reason=OFPR_NO_MATCH)
def _process_actions_for_packet (self, actions, packet, in_port, ofp=None): """ process the output actions for a packet ofp is the message which triggered this processing, if any (used for error generation) """ assert assert_type("packet", packet, (ethernet, bytes), none_ok=False) if not isinstance(packet, ethernet): packet = ethernet.unpack(packet) for action in actions: #if action.type is ofp_action_resubmit: # self.rx_packet(packet, in_port) # return h = self.action_handlers.get(action.type) if h is None: self.log.warn("Unknown action type: %x " % (action.type,)) err = ofp_error(type=OFPET_BAD_ACTION, code=OFPBAC_BAD_TYPE) if ofp: err.xid = ofp.xid err.data = ofp.pack() else: err.xid = 0 self.send(err) return packet = h(action, packet, in_port)
def _output_packet (self, packet, out_port, in_port, max_len=None): """ send a packet out some port This handles virtual ports and does validation. packet: instance of ethernet out_port, in_port: the integer port number max_len: maximum packet payload length to send to controller """ assert assert_type("packet", packet, ethernet, none_ok=False) def real_send (port_no, allow_in_port=False): if type(port_no) == ofp_phy_port: port_no = port_no.port_no if port_no == in_port and not allow_in_port: self.log.warn("Dropping packet sent on port %i: Input port", port_no) return if port_no not in self.ports: self.log.warn("Dropping packet sent on port %i: Invalid port", port_no) return if self.ports[port_no].config & OFPPC_NO_FWD: self.log.warn("Dropping packet sent on port %i: Forwarding disabled", port_no) return if self.ports[port_no].config & OFPPC_PORT_DOWN: self.log.warn("Dropping packet sent on port %i: Port down", port_no) return if self.ports[port_no].state & OFPPS_LINK_DOWN: self.log.debug("Dropping packet sent on port %i: Link down", port_no) return self.port_stats[port_no].tx_packets += 1 self.port_stats[port_no].tx_bytes += len(packet.pack()) #FIXME: Expensive self._output_packet_physical(packet, port_no) if out_port < OFPP_MAX: real_send(out_port) elif out_port == OFPP_IN_PORT: real_send(in_port, allow_in_port=True) elif out_port == OFPP_FLOOD: for no,port in self.ports.iteritems(): if no == in_port: continue if port.config & OFPPC_NO_FLOOD: continue real_send(port) elif out_port == OFPP_ALL: for no,port in self.ports.iteritems(): if no == in_port: continue real_send(port) elif out_port == OFPP_CONTROLLER: buffer_id = self._buffer_packet(packet, in_port) # Should we honor OFPPC_NO_PACKET_IN here? self.send_packet_in(in_port, buffer_id, packet, reason=OFPR_ACTION, data_length=max_len) elif out_port == OFPP_TABLE: # Do we disable send-to-controller when performing this? # (Currently, there's the possibility that a table miss from this # will result in a send-to-controller which may send back to table...) self.rx_packet(packet, in_port) else: self.log.warn("Unsupported virtual output port: %d", out_port)
def send_packet_in(self, in_port, buffer_id=None, packet=b'', reason=None, data_length=None): """ Send PacketIn """ if hasattr(packet, 'pack'): packet = packet.pack() assert assert_type("packet", packet, bytes) self.log.debug("Send PacketIn") if reason is None: reason = OFPR_NO_MATCH if data_length is not None and len(packet) > data_length: if buffer_id is not None: packet = packet[:data_length] msg = ofp_packet_in(xid=0, in_port=in_port, buffer_id=buffer_id, reason=reason, data=packet) self.send(msg)
def __init__(self, node, packet, port): assert assert_type("packet", packet, ethernet, none_ok=False) Event.__init__(self) self.node = node self.packet = packet self.port = port self.switch = node # For backwards compatability
def _output_packet (self, packet, out_port, in_port, max_len=None): """ send a packet out some port This handles virtual ports and does validation. packet: instance of ethernet out_port, in_port: the integer port number max_len: maximum packet payload length to send to controller """ assert assert_type("packet", packet, ethernet, none_ok=False) def real_send (port_no, allow_in_port=False): if type(port_no) == ofp_phy_port: port_no = port_no.port_no if port_no == in_port and not allow_in_port: self.log.warn("Dropping packet sent on port %i: Input port", port_no) return if port_no not in self.ports: self.log.warn("Dropping packet sent on port %i: Invalid port", port_no) return if self.ports[port_no].config & OFPPC_NO_FWD: self.log.warn("Dropping packet sent on port %i: Forwarding disabled", port_no) return if self.ports[port_no].config & OFPPC_PORT_DOWN: self.log.warn("Dropping packet sent on port %i: Port down", port_no) return if self.ports[port_no].state & OFPPS_LINK_DOWN: self.log.debug("Dropping packet sent on port %i: Link down", port_no) return self._output_packet_physical(packet, port_no) if out_port < OFPP_MAX: real_send(out_port) elif out_port == OFPP_IN_PORT: real_send(in_port, allow_in_port=True) elif out_port == OFPP_FLOOD: for no,port in self.ports.iteritems(): if no == in_port: continue if port.config & OFPPC_NO_FLOOD: continue real_send(port) elif out_port == OFPP_ALL: for no,port in self.ports.iteritems(): if no == in_port: continue real_send(port) elif out_port == OFPP_CONTROLLER: buffer_id = self._buffer_packet(packet, in_port) # Should we honor OFPPC_NO_PACKET_IN here? self.send_packet_in(in_port, buffer_id, packet, reason=OFPR_ACTION, data_length=max_len) elif out_port == OFPP_TABLE: # There better be a table entry there, else we get infinite recurision # between switch<->controller # Note that this isn't infinite recursion, since the table entry's # out_port will not be OFPP_TABLE self.rx_packet(packet, in_port) else: raise("Unsupported virtual output port: %d" % (out_port,))
def send_packet_in(self, in_port, buffer_id=None, packet="", xid=None, reason=None): """Send PacketIn Assume no match as reason, buffer_id = 0xFFFFFFFF, and empty packet by default """ assert_type("packet", packet, ethernet) self.log.debug("Send PacketIn %s " % self.name) if (reason == None): reason = ofp_packet_in_reason_rev_map['OFPR_NO_MATCH'] if (buffer_id == None): buffer_id = int("0xFFFFFFFF",16) if xid == None: xid = self.xid_count.next() msg = ofp_packet_in(xid=xid, in_port = in_port, buffer_id = buffer_id, reason = reason, data = packet.pack()) self.send(msg)
def rx_packet(self, packet, in_port, packet_data=None): """ process a dataplane packet packet: an instance of ethernet in_port: the integer port number packet_data: packed version of packet if available """ assert assert_type("packet", packet, ethernet, none_ok=False) assert assert_type("in_port", in_port, int, none_ok=False) port = self.ports.get(in_port) if port is None: self.log.warn("Got packet on missing port %i", in_port) return is_stp = packet.dst == _STP_MAC if (port.config & OFPPC_NO_RECV) and not is_stp: # Drop all except STP return if (port.config & OFPPC_NO_RECV_STP) and is_stp: # Drop STP return self.port_stats[in_port].rx_packets += 1 if packet_data is not None: self.port_stats[in_port].rx_bytes += len(packet_data) else: self.port_stats[in_port].rx_bytes += len(packet.pack()) # Expensive self._lookup_count += 1 entry = self.table.entry_for_packet(packet, in_port) if entry is not None: self._matched_count += 1 entry.touch_packet(len(packet)) self._process_actions_for_packet(entry.actions, packet, in_port) else: # no matching entry if port.config & OFPPC_NO_PACKET_IN: return buffer_id = self._buffer_packet(packet, in_port) if packet_data is None: packet_data = packet.pack() self.send_packet_in(in_port, buffer_id, packet_data, reason=OFPR_NO_MATCH, data_length=self.miss_send_len)
def send_port_status(self, port, reason): """ Send port status port is an ofp_phy_port reason is one of OFPPR_xxx """ assert assert_type("port", port, ofp_phy_port, none_ok=False) assert reason in ofp_port_reason_rev_map.values() msg = ofp_port_status(desc=port, reason=reason) self.send(msg)
def send_port_status (self, port, reason): """ Send port status port is an ofp_phy_port reason is one of OFPPR_xxx """ assert assert_type("port", port, ofp_phy_port, none_ok=False) assert reason in ofp_port_reason_rev_map.values() msg = ofp_port_status(desc=port, reason=reason) self.send(msg)
def send_packet_in(self, in_port, buffer_id=None, packet=b"", reason=None, data_length=None): """ Send PacketIn """ if hasattr(packet, "pack"): packet = packet.pack() assert assert_type("packet", packet, bytes) self.log.debug("Send PacketIn") if reason is None: reason = OFPR_NO_MATCH if data_length is not None and len(packet) > data_length: if buffer_id is not None: packet = packet[:data_length] msg = ofp_packet_in(xid=0, in_port=in_port, buffer_id=buffer_id, reason=reason, data=packet) self.send(msg)
def _process_actions_for_packet(self, actions, packet, in_port): """ process the output actions for a packet """ assert_type("packet", packet, [ethernet, str], none_ok=False) if not isinstance(packet, ethernet): packet = ethernet.unpack(packet) def output_packet(action, packet): self._output_packet(packet, action.port, in_port) return packet def set_vlan_id(action, packet): if not isinstance(packet.next, vlan): packet.next = vlan(prev = packet.next) packet.next.eth_type = packet.type packet.type = ethernet.VLAN_TYPE packet.id = action.vlan_id return packet def set_vlan_pcp(action, packet): if not isinstance(packet.next, vlan): packet.next = vlan(prev = packet) packet.next.eth_type = packet.type packet.type = ethernet.VLAN_TYPE packet.pcp = action.vlan_pcp return packet def strip_vlan(action, packet): if isinstance(packet.next, vlan): packet.type = packet.next.eth_type packet.next = packet.next.next return packet def set_dl_src(action, packet): packet.src = action.dl_addr return packet def set_dl_dst(action, packet): packet.dst = action.dl_addr return packet def set_nw_src(action, packet): if(isinstance(packet.next, ipv4)): packet.next.nw_src = action.nw_addr return packet def set_nw_dst(action, packet): if(isinstance(packet.next, ipv4)): packet.next.nw_dst = action.nw_addr return packet def set_nw_tos(action, packet): if(isinstance(packet.next, ipv4)): packet.next.tos = action.nw_tos return packet def set_tp_src(action, packet): if(isinstance(packet.next, udp) or isinstance(packet.next, tcp)): packet.next.srcport = action.tp_port return packet def set_tp_dst(action, packet): if(isinstance(packet.next, udp) or isinstance(packet.next, tcp)): packet.next.dstport = action.tp_port return packet def enqueue(action, packet): self.log.warn("output_enqueue not supported yet. Performing regular output") return output_packet(action.tp_port, packet) # def push_mpls_tag(action, packet): # bottom_of_stack = isinstance(packet.next, mpls) # packet.next = mpls(prev = packet.pack()) # if bottom_of_stack: # packet.next.s = 1 # packet.type = action.ethertype # return packet # def pop_mpls_tag(action, packet): # if not isinstance(packet.next, mpls): # return packet # if not isinstance(packet.next.next, str): # packet.next.next = packet.next.next.pack() # if action.ethertype in ethernet.type_parsers: # packet.next = ethernet.type_parsers[action.ethertype](packet.next.next) # else: # packet.next = packet.next.next # packet.ethertype = action.ethertype # return packet # def set_mpls_label(action, packet): # if not isinstance(packet.next, mpls): # mock = ofp_action_push_mpls() # packet = push_mpls_tag(mock, packet) # packet.next.label = action.mpls_label # return packet # def set_mpls_tc(action, packet): # if not isinstance(packet.next, mpls): # mock = ofp_action_push_mpls() # packet = push_mpls_tag(mock, packet) # packet.next.tc = action.mpls_tc # return packet # def set_mpls_ttl(action, packet): # if not isinstance(packet.next, mpls): # mock = ofp_action_push_mpls() # packet = push_mpls_tag(mock, packet) # packet.next.ttl = action.mpls_ttl # return packet # def dec_mpls_ttl(action, packet): # if not isinstance(packet.next, mpls): # return packet # packet.next.ttl = packet.next.ttl - 1 # return packet handler_map = { OFPAT_OUTPUT: output_packet, OFPAT_SET_VLAN_VID: set_vlan_id, OFPAT_SET_VLAN_PCP: set_vlan_pcp, OFPAT_STRIP_VLAN: strip_vlan, OFPAT_SET_DL_SRC: set_dl_src, OFPAT_SET_DL_DST: set_dl_dst, OFPAT_SET_NW_SRC: set_nw_src, OFPAT_SET_NW_DST: set_nw_dst, OFPAT_SET_NW_TOS: set_nw_tos, OFPAT_SET_TP_SRC: set_tp_src, OFPAT_SET_TP_DST: set_tp_dst, OFPAT_ENQUEUE: enqueue, # OFPAT_PUSH_MPLS: push_mpls_tag, # OFPAT_POP_MPLS: pop_mpls_tag, # OFPAT_SET_MPLS_LABEL: set_mpls_label, # OFPAT_SET_MPLS_TC: set_mpls_tc, # OFPAT_SET_MPLS_TTL: set_mpls_ttl, # OFPAT_DEC_MPLS_TTL: dec_mpls_ttl, } for action in actions: # if action.type is ofp_action_resubmit: # self.process_packet(packet, in_port) # return if(action.type not in handler_map): raise NotImplementedError("Unknown action type: %x " % type) packet = handler_map[action.type](action, packet)
def send(self, data): """ send data from the client side. fire and forget. """ assert_type("data", data, [bytes], none_ok=False) self.send_buf += data
def __init__ (self, interface, packet): assert_type("interface", interface, HostInterface, none_ok=False) assert_type("packet", packet, ethernet, none_ok=False) self.interface = interface self.packet = packet
def __init__(self, host, interface, switch, switch_port): super(AccessLink, self).__init__(host, interface, switch, switch_port) assert_type("interface", interface, HostInterface, none_ok=False) assert_type("switch_port", switch_port, ofp_phy_port, none_ok=False)
def __init__(self, interface, packet): assert_type("interface", interface, HostInterface, none_ok=False) assert_type("packet", packet, ethernet, none_ok=False) self.interface = interface self.packet = packet
def send(self, data): """ Send data. Fire and forget. """ #print(" Send in IOWOrker") assert assert_type("data", data, [bytes], none_ok=False) self.send_buf += data
def send(self, data): """ Send data. Fire and forget. """ assert assert_type("data", data, [bytes], none_ok=False) self.send_buf += data
def send (self, data): """ Send data. Fire and forget. """ assert assert_type("data", data, [bytes], none_ok=False) self.send_buf += data