controller: serialize calls to socket.sendall
The sendall method is not atomic. Concurrent calls may end up with their data
interleaved on the socket. This is especially likely when the socket buffer
fills up, causing sendall to call select(2) between writes.
I noticed this bug when installing many flows. The echo reply sent by the
controller thread ended up in the middle of a flow mod.
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index b23eefa..1d911bc 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -103,6 +103,7 @@
self.switch_addr = None
self.connect_cv = Condition()
self.message_cv = Condition()
+ self.tx_lock = Lock()
# Used to wake up the event loop from another thread
self.waker = ofutils.EventDescriptor()
@@ -693,8 +694,10 @@
msg_len,
msg_version,
msg_xid)
- if self.switch_socket.sendall(outpkt) is not None:
- raise AssertionError("failed to send message to switch")
+
+ with self.tx_lock:
+ if self.switch_socket.sendall(outpkt) is not None:
+ raise AssertionError("failed to send message to switch")
return 0 # for backwards compatibility