This makes it easier to install the headers, or to use them directly from
another software package with -I$(openflow)/include, without invading
the top-level include file namespace.
Change e10dfcf35, "rconn: Be pickier about what constitutes a successful
connection," caused rconn to consider the connection to have failed even
when we are actually connected until one of several message types was
received. Unfortunately, that meant that "fail open" would intercept and
discard all messages sent by the controller until one of those messages
was received. Thus, the controller would never receive a reply to its
feature_request, assume that the connection was busted, and disconnect.
This happened forever, of course.
Fixes bug #242.
Thanks to Reid for reporting this and Dan for help in diagnosis.
When secchan is configured to "fail open" after failing to connect to
a controller for a period of time, it needs a heuristic for what
constitutes a successful connection. Until now, that heuristic was
simply that when it received an OpenFlow message from the controller
(any OpenFlow message), it considered the connection successful.
However, this is no longer good enough, because NOX performs
admission control on connections after sending a number of OpenFlow
messages, in particular after doing OpenFlow version negotiation and
requesting the switch features (and receiving the reply). Thus, this
commit adjusts the heuristic by only considering certain OpenFlow
messages to demonstrate that admission control checks have passed and
thus that the connection should be considered successful.
As a fallback, any connection that persists for 30 seconds or longer is
also considered successful.
An alternate and complementary approach (that this commit does not
implement) would be to use an OpenFlow error message to indicate why
the connection is closing.
Fixes bug #239.
The timeout() function returns a duration relative to the time at which the
current state was entered, but rconn_run_wait() was treating it as the
waiting time remaining.
Until now, the rconn code would queue up packets not just while connected
but also while connecting. This is not just unnecessary, however, it
actually causes a problem in secchan: if the secchan receives packets
from nl:0 and tries to transmit them, then they will quickly fill up
the rconn's transmit buffer (it uses a 1-packet buffer), which causes
secchan to stop reading packets from nl:0 until the buffer frees up.
That cannot happen until the connection completes. With in-band control,
however, the connection cannot complete until we receive and process
packet_in messages in our in-band hook. Thus, we have a deadlock.
Fixes bug #90, "Sometimes secchan has to go into fail-open mode to connect."
Now it helps clients track the number of in-flight messages, but lets the
clients do the limiting themselves. This will come in handy for packet-in
rate limiting (in an upcoming commit), in which we want to track in-flight
packet-in messages separately from other in-flight messages.
When a vconn reports an error, the rconn would not reliably reconnect.
In particular, if the error was reported after the call to rconn_run()
but before rconn_run_wait() was called, then the state's "run" routine
would not set min_timeout properly, leading to a potentially arbitrarily
long wait (depending on what other events were going on in) until the
state's "run" routine was called again.
The fix is to have a separate per-state "timeout" routine to compute
when the state needs to be re-entered.
This commit was tested using the following change to randomly inject
errors:
@@ -554,11 +554,16 @@
static int
try_send(struct rconn *rc)
{
int retval = 0;
struct buffer *next = rc->txq.head->next;
- retval = vconn_send(rc->vconn, rc->txq.head);
+ if (!random_range(1000)) {
+ fprintf(stderr, "injecting ECONNRESET\n");
+ retval = ECONNRESET;
+ } else {
+ retval = vconn_send(rc->vconn, rc->txq.head);
+ }
if (retval) {
if (retval != EAGAIN) {
disconnect(rc, retval);
}
return retval;
Before, the amount of time disconnected was measured relative to the
last time we connected, that is, the last time connect(2) succeeded.
Thus, if we were connected for a long time, and then disconnected,
we would immediately go into fail-open mode.
This change make the disconnected time relative to the last OpenFlow
message received. Thus, if we are connected for a long time and
receive plenty of packets, and then disconnect, there will still be
an opportunity to reconnect before failing open.
Otherwise, the TCP/IP implementation is responsible for connection
attempt backoff, but we want to have some control over it ourselves.
In particular we want to initially back off faster and to log a
message upon connection attempt retransmission, to make it easier
to see what has happened from the log.
Previously we set a few timers to expire at a time_t of 0, i.e.
immediately. But if the system date is set incorrectly to a date
before 1970, then these timers will essentially never expire.
Set them to expire at TIME_MIN instead.
It can happen that the secure channel thinks that it is connected
to the controller, but in fact the connection has dropped. For
example, a switch intermediate between the secure channel and the
controller could have a flow inserted, due to a malfunction, that
causes packets in one direction or the other to be dropped. When
this happens, the Linux kernel's TCP implementation will continue
retransmitting packets for somewhere between 13 and 30 minutes,
depending on the connection's retransmission timeout (according
to linux/Documentation/networking/ip-sysctl.txt) with the default
Linux settings.
We want to detect the lost connection and re-connect much faster
than that. We use OpenFlow echo request and reply messages: if
no message is received from the controller for N seconds, we
send out an echo request. If no reply (actually, any message at
all) is received for an additional N seconds, then we assume
that the connection has been lost, and reconnect.