(I understand that nox-classic is no longer maintained. However, if pox
is using some of the same methodology, maybe this issue still exists.)
I believe install_datapath_flow as implemented in nox has a design flaw...
When a PACKET_IN message occurs from the switch to the controller, it
may have a buffer_id and some (or all) of the data of the packet in the
buffer. It is my experience that if the full packet is in the buffer,
the buffer_id is -1 (in Python, UINT32MAX). The important thing is
that sometimes you get a pointer and no full packet; or you get a full
packet and no pointer. Install_datapath_flow may behave differently
when you pass that information back to the switch.
Suppose you have some action to apply to the packet, more than just
outputting it to a port. For the purposes of this discussion, we'll
assume the action is to rewrite just the source ethernet address.
There are four ways that install_datapath_flow might be passed buffer
information:
Buffer is valid, and buffer_id = UINT32MAX (ie, -1) The buffer
parameter contains the packet info to be sent out
Buffer is None, and buffer_id is a valid buffer_id. The buffer_id
parameter is passed back to the switch; the switch uses that
information as the packet.
Buffer is None and buffer_id = UINT32MAX. No packet is sent when this
flow rule is installed
Buffer is valid, and buffer_id is valid. I didn't check to see what it
does. IMHO, this should be an error.
If there is a valid buffer_id, that id is passed to the switch in the
flow mod command. The switch will then apply the actions to the packet
stored at that buffer_id, as per the OpenFlow 1.0 spec:
5.3.3 Modify State Messages
struct ofp_flow_mod {
....
uint32_t buffer_id; /* Buffered packet to apply to (or -1).
Likewise, if a buffer_id or a buffer is passed with the to OpenFlow's
OFP_Packet_Out message, the actions are applied to the packet.
I would have expected that install_datapath_flow behaved in the same
way: it doesn't matter whether you pass the packet as a buffer_id or as
a buffer, the actions are applied to the packet.
But that is not so. install_datapath_flow intentionally avoids passing
the full set of actions to send_openflow_packet, and raises an error if
any actions are not simply an output.
if buffer_id == UINT32_MAX and packet != None:
for action in actions:
if action[0] == openflow.OFPAT_OUTPUT:
if type(action[1]) == int or type(action[1]) == long:
self.send_openflow_packet(dp_id, packet,
action[1], inport)
else:
self.send_openflow_packet(dp_id, packet,
action[1][1], inport)
else:
raise NotImplementedError
So, the user of install_datapath_flow that doesn't have a buffer_id has
to either apply the actions to the packet himself, or call
send_openflow_packet with the full set of actions and call
install_datapath_flow with buffer = None.
-----------
A hypothesis I have (but have not confirmed): On the HP ProCurve, for
Packet In messages, if you indicate enough bytes are to be sent to the
controller so that the entire packet is passed, the switch passes the
buffer, and not the buffer-id (ie, it is -1); the buffer on the switch
can be flushed. If you have fewer bytes sent than is sufficient to
include the whole packet, the packet is buffered and you get the buffer-id.
There is a work-around: If you get a valid buffer_id, use
install_datapath_flow. If you get a buffer, use install_datapath_flow
with no buffer, and call send_openflow_packet on your own.