def parseICMP(packet): if eth_packet.type == ethernet.IP_type: ip_packet = eth_packet.next if ip_packet.protocol = ipv4.ICMP_PROTOCOL icmp_packet = ip_packet.next ...
This is probably not the best way to navigate a packet, but it illustrates the structure of packet headers in POX. At each level of encapsulation the packet header values can be obtained. For example, the source mac ip address of an ethernet frame the ip packet above and icmp sequence number can be retrieved obtained as followsshown:
... src_macip = ethip_packet.hw_srcsrcip icmp_sequence = icmp_packet.seq
And similarly for other packet headers. Refer to the specific packet code for other headers.
Generating arbitrary messages
This section briefly describes how to generate arbitrary packet which are defined within POX in pox/lib/packet.
Handling ARP packet as they arrive as packet ins can be a little confusing. Moreover you'll probably want the controller proxy the arp replies rather than flood them all over the network depending on whether you know the mac address of the machine the arp request is looking for. To handle arp packet in you should have an event listener set up to receive packet ins as shown:
def _handle_PacketIn (self, event): packet = event.parsed if packet.type == packet.ARP_TYPE: if packet.next.opcode == arp.REQUEST: arp_reply = arp() arp_reply.hwsrc = <requested mac address> arp_reply.hwdst = packet.src arp_reply.hwtype = packet.next.hwtype arp_reply.prototype = packet.next.prototype arp_reply.opcode = arp.REPLY #No shit! arp_reply.protosrc = <IP of requested mac-associated machine> arp_reply.protodst = packet.next.protosrc ether = ethernet() ether.type = ethernet.ARP_TYPE ether.dst = packet.src ether.src = <requested mac address> ether.set_payload(arp_reply) #send this packet to the switch #see section below on this topic elif packet.next.opcode == arp.REPLY: print "It's a reply do something cool" else: print "Some other ARP opcode, probably do something smart here"
Sending a message to a datapath
There are several methods to send messages to the datapath. We will cover FlowMods and PacketOuts in this document.
When a datapath connects to the controller an event will be generated provided you are listening to connection up events. Below is the basic code to handle switch connections:
def _handle_ConnectionUp (self, event): connection = event.connection
The connection parameter is essentially the connection to the datapath and can be used to send messages down to the datapath. This variable should be stored.
Sending a FlowMod
To send a flow mod you must define a match structure (discussed above) and set some flow mod specific parameters as shown here:
msg = ofp_flow_mod() msg.match = match msg.idle_timeout = idle_timeout msg.hard_timeout = hard_timeout msg.actions.append(of.ofp_action_output(port = port)) msg.buffer_id = <some buffer id, if any> connection.send(msg)
Using the connection variable obtained when the datapath joined, we can send the flowmod to the switch.
Sending a PacketOut
In a similar manner to a flow mod, one must first define a packet out as shown here:
msg = of.ofp_packet_out(in_port=of.OFPP_NONE) msg.actions.append(of.ofp_action_output(port = outport)) msg.buffer_id = <some buffer id, if any> connection.send(msg)
The inport is set to OFPP_NONE because the packet was generated at the controller and did not originate as a packet in at the datapath.