@@ -142,7 +142,7 @@ struct ofconn {
static unsigned int bundle_idle_timeout = BUNDLE_IDLE_TIMEOUT_DEFAULT;
-static void ofconn_create(struct ofservice *, struct rconn *, enum ofconn_type,
+static void ofconn_create(struct ofservice *, struct rconn *,
const struct ofproto_controller *settings)
OVS_EXCLUDED(ofproto_mutex);
static void ofconn_destroy(struct ofconn *) OVS_REQUIRES(ofproto_mutex);
@@ -1150,7 +1150,7 @@ bundle_remove_expired(struct ofconn *ofconn, long long int now)
static void
ofconn_create(struct ofservice *ofservice, struct rconn *rconn,
- enum ofconn_type type, const struct ofproto_controller *settings)
+ const struct ofproto_controller *settings)
OVS_EXCLUDED(ofproto_mutex)
{
ovs_mutex_lock(&ofproto_mutex);
@@ -1164,7 +1164,7 @@ ofconn_create(struct ofservice *ofservice, struct rconn *rconn,
ovs_list_push_back(&ofservice->conns, &ofconn->ofservice_node);
ofconn->rconn = rconn;
- ofconn->type = type;
+ ofconn->type = settings->type;
ofconn->band = settings->band;
ofconn->role = OFPCR12_ROLE_EQUAL;
@@ -1708,8 +1708,9 @@ connmgr_get_max_probe_interval(const struct connmgr *mgr)
return max_probe_interval;
}
-/* Returns the number of seconds for which all of 'mgr's primary controllers
- * have been disconnected. Returns 0 if 'mgr' has no primary controllers. */
+/* Returns the number of seconds for which all of 'mgr's active, primary
+ * controllers have been disconnected. Returns 0 if 'mgr' has no active,
+ * primary controllers. */
int
connmgr_failure_duration(const struct connmgr *mgr)
{
@@ -1717,7 +1718,7 @@ connmgr_failure_duration(const struct connmgr *mgr)
struct ofservice *ofservice;
HMAP_FOR_EACH (ofservice, hmap_node, &mgr->services) {
- if (ofservice->rconn) {
+ if (ofservice->s.type == OFCONN_PRIMARY && ofservice->rconn) {
int failure_duration = rconn_failure_duration(ofservice->rconn);
min_failure_duration = MIN(min_failure_duration, failure_duration);
}
@@ -1734,7 +1735,8 @@ connmgr_is_any_controller_connected(const struct connmgr *mgr)
{
struct ofservice *ofservice;
HMAP_FOR_EACH (ofservice, hmap_node, &mgr->services) {
- if (ofservice->rconn && rconn_is_connected(ofservice->rconn)) {
+ if (ofservice->s.type == OFCONN_PRIMARY
+ && !ovs_list_is_empty(&ofservice->conns)) {
return true;
}
}
@@ -1905,7 +1907,7 @@ ofservice_create(struct connmgr *mgr, const char *target,
ofservice->connmgr = mgr;
ofservice->target = xstrdup(target);
ovs_list_init(&ofservice->conns);
- ofservice->type = rconn ? OFCONN_PRIMARY : OFCONN_SERVICE;
+ ofservice->type = c->type;
ofservice->rconn = rconn;
ofservice->pvconn = pvconn;
ofservice->s = *c;
@@ -1962,7 +1964,7 @@ ofservice_run(struct ofservice *ofservice)
rconn_connect_unreliably(rconn, vconn, name);
free(name);
- ofconn_create(ofservice, rconn, OFCONN_SERVICE, &ofservice->s);
+ ofconn_create(ofservice, rconn, &ofservice->s);
} else if (retval != EAGAIN) {
VLOG_WARN_RL(&rl, "accept failed (%s)", ovs_strerror(retval));
}
@@ -1972,8 +1974,7 @@ ofservice_run(struct ofservice *ofservice)
bool connected = rconn_is_connected(ofservice->rconn);
bool has_ofconn = !ovs_list_is_empty(&ofservice->conns);
if (connected && !has_ofconn) {
- ofconn_create(ofservice, ofservice->rconn, OFCONN_PRIMARY,
- &ofservice->s);
+ ofconn_create(ofservice, ofservice->rconn, &ofservice->s);
}
}
}
@@ -2287,12 +2288,6 @@ ofmonitor_wait(struct connmgr *mgr)
ovs_mutex_unlock(&ofproto_mutex);
}
-const char *
-ofconn_type_to_string(enum ofconn_type type)
-{
- return type == OFCONN_PRIMARY ? "primary" : "service";
-}
-
void
ofproto_async_msg_free(struct ofproto_async_msg *am)
{
@@ -37,27 +37,6 @@ struct rule;
struct simap;
struct sset;
-/* ofproto supports two kinds of OpenFlow connections:
- *
- * - "Primary" connections to ordinary OpenFlow controllers. ofproto
- * maintains persistent connections to these controllers and by default
- * sends them asynchronous messages such as packet-ins.
- *
- * - "Service" connections, e.g. from ovs-ofctl. When these connections
- * drop, it is the other side's responsibility to reconnect them if
- * necessary. ofproto does not send them asynchronous messages by default.
- *
- * Currently, active (tcp, ssl, unix) connections are always "primary"
- * connections and passive (ptcp, pssl, punix) connections are always "service"
- * connections. There is no inherent reason for this, but it reflects the
- * common case.
- */
-enum ofconn_type {
- OFCONN_PRIMARY, /* An ordinary OpenFlow controller. */
- OFCONN_SERVICE /* A service connection, e.g. "ovs-ofctl". */
-};
-const char *ofconn_type_to_string(enum ofconn_type);
-
/* An asynchronous message that might need to be queued between threads. */
struct ofproto_async_msg {
struct ovs_list list_node; /* For queuing. */
@@ -1892,6 +1892,12 @@ ofproto_free_ofproto_controller_info(struct shash *info)
connmgr_free_controller_info(info);
}
+const char *
+ofconn_type_to_string(enum ofconn_type type)
+{
+ return type == OFCONN_PRIMARY ? "primary" : "service";
+}
+
/* Makes a deep copy of 'old' into 'port'. */
void
ofproto_port_clone(struct ofproto_port *port, const struct ofproto_port *old)
@@ -207,7 +207,25 @@ enum ofproto_band {
OFPROTO_OUT_OF_BAND /* Out-of-band connection to controller. */
};
+/* ofproto supports two kinds of OpenFlow connections:
+ *
+ * - "Primary" connections to ordinary OpenFlow controllers. ofproto
+ * maintains persistent connections to these controllers and by default
+ * sends them asynchronous messages such as packet-ins.
+ *
+ * - "Service" connections, e.g. from ovs-ofctl. When these connections
+ * drop, it is the other side's responsibility to reconnect them if
+ * necessary. ofproto does not send them asynchronous messages by default.
+ */
+enum ofconn_type {
+ OFCONN_PRIMARY, /* An ordinary OpenFlow controller. */
+ OFCONN_SERVICE /* A service connection, e.g. "ovs-ofctl". */
+};
+const char *ofconn_type_to_string(enum ofconn_type);
+
+/* Configuration for an OpenFlow controller. */
struct ofproto_controller {
+ enum ofconn_type type; /* Primary or service controller. */
int max_backoff; /* Maximum reconnection backoff, in seconds. */
int probe_interval; /* Max idle time before probing, in seconds. */
enum ofproto_band band; /* In-band or out-of-band? */
@@ -46,6 +46,7 @@
#include "openvswitch/meta-flow.h"
#include "openvswitch/ofp-print.h"
#include "openvswitch/ofpbuf.h"
+#include "openvswitch/vconn.h"
#include "openvswitch/vlog.h"
#include "ovs-lldp.h"
#include "ovs-numa.h"
@@ -3536,6 +3537,14 @@ equal_pathnames(const char *a, const char *b, size_t b_stoplen)
}
}
+static enum ofconn_type
+get_controller_ofconn_type(const char *target, const char *type)
+{
+ return (type
+ ? (!strcmp(type, "primary") ? OFCONN_PRIMARY : OFCONN_SERVICE)
+ : (!vconn_verify_name(target) ? OFCONN_PRIMARY : OFCONN_SERVICE));
+}
+
static void
bridge_configure_remotes(struct bridge *br,
const struct sockaddr_in *managers, size_t n_managers)
@@ -3571,6 +3580,7 @@ bridge_configure_remotes(struct bridge *br,
/* Add managment controller. */
struct ofproto_controller *oc = xmalloc(sizeof *oc);
*oc = (struct ofproto_controller) {
+ .type = OFCONN_SERVICE,
.probe_interval = 60,
.band = OFPROTO_OUT_OF_BAND,
.enable_async_msgs = true,
@@ -3639,6 +3649,7 @@ bridge_configure_remotes(struct bridge *br,
oc = xmalloc(sizeof *oc);
*oc = (struct ofproto_controller) {
+ .type = get_controller_ofconn_type(c->target, c->type),
.max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8,
.probe_interval = (c->inactivity_probe
? *c->inactivity_probe / 1000 : 5),
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
- "version": "7.16.1",
- "cksum": "1452282319 23860",
+ "version": "7.17.0",
+ "cksum": "2073324140 24021",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -548,6 +548,10 @@
"indexes": [["id", "bridge"]]},
"Controller": {
"columns": {
+ "type": {
+ "type": {"key": {"type": "string",
+ "enum": ["set", ["primary", "service"]]},
+ "min": 0, "max": 1}},
"target": {
"type": "string"},
"max_backoff": {
@@ -967,9 +967,12 @@
avoid loops on such a bridge, configure <code>secure</code> mode or
enable STP (see <ref column="stp_enable"/>).
</p>
- <p>When more than one controller is configured,
- <ref column="fail_mode"/> is considered only when none of the
- configured controllers can be contacted.</p>
+ <p>
+ The <ref column="fail_mode"/> setting applies only to primary
+ controllers. When more than one primary controller is configured,
+ <ref column="fail_mode"/> is considered only when none of the
+ configured controllers can be contacted.
+ </p>
<p>
Changing <ref column="fail_mode"/> when no primary controllers are
configured clears the OpenFlow flow tables, group table, and meter
@@ -4453,71 +4456,64 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
<table name="Controller" title="OpenFlow controller configuration.">
<p>An OpenFlow controller.</p>
- <p>
- Open vSwitch supports two kinds of OpenFlow controllers:
- </p>
-
- <dl>
- <dt>Primary controllers</dt>
- <dd>
+ <group title="Core Features">
+ <column name="type">
<p>
- This is the kind of controller envisioned by the OpenFlow 1.0
- specification. Usually, a primary controller implements a network
- policy by taking charge of the switch's flow table.
+ Open vSwitch supports two kinds of OpenFlow controllers. A bridge
+ may have any number of each kind:
</p>
- <p>
- Open vSwitch initiates and maintains persistent connections to
- primary controllers, retrying the connection each time it fails or
- drops. The <ref table="Bridge" column="fail_mode"/> column in the
- <ref table="Bridge"/> table applies to primary controllers.
- </p>
+ <dl>
+ <dt>Primary controllers</dt>
+ <dd>
+ <p>
+ This is the kind of controller envisioned by the OpenFlow
+ specifications. Usually, a primary controller implements a
+ network policy by taking charge of the switch's flow table.
+ </p>
- <p>
- Open vSwitch permits a bridge to have any number of primary
- controllers. When multiple controllers are configured, Open
- vSwitch connects to all of them simultaneously. Because
- OpenFlow 1.0 does not specify how multiple controllers
- coordinate in interacting with a single switch, more than
- one primary controller should be specified only if the
- controllers are themselves designed to coordinate with each
- other. (The Nicira-defined <code>NXT_ROLE</code> OpenFlow
- vendor extension may be useful for this.)
- </p>
- </dd>
- <dt>Service controllers</dt>
- <dd>
- <p>
- These kinds of OpenFlow controller connections are intended for
- occasional support and maintenance use, e.g. with
- <code>ovs-ofctl</code>. Usually a service controller connects only
- briefly to inspect or modify some of a switch's state.
- </p>
+ <p>
+ The <ref table="Bridge" column="fail_mode"/> column in the <ref
+ table="Bridge"/> table applies to primary controllers.
+ </p>
- <p>
- Open vSwitch listens for incoming connections from service
- controllers. The service controllers initiate and, if necessary,
- maintain the connections from their end. The <ref table="Bridge"
- column="fail_mode"/> column in the <ref table="Bridge"/> table does
- not apply to service controllers.
- </p>
+ <p>
+ When multiple primary controllers are configured, Open vSwitch
+ connects to all of them simultaneously. OpenFlow provides few
+ facilities to allow multiple controllers to coordinate in
+ interacting with a single switch, so more than one primary
+ controller should be specified only if the controllers are
+ themselves designed to coordinate with each other.
+ </p>
+ </dd>
+ <dt>Service controllers</dt>
+ <dd>
+ <p>
+ These kinds of OpenFlow controller connections are intended for
+ occasional support and maintenance use, e.g. with
+ <code>ovs-ofctl</code>. Usually a service controller connects
+ only briefly to inspect or modify some of a switch's state.
+ </p>
+
+ <p>
+ The <ref table="Bridge" column="fail_mode"/> column in the <ref
+ table="Bridge"/> table does not apply to service controllers.
+ </p>
+ </dd>
+ </dl>
<p>
- Open vSwitch supports configuring any number of service controllers.
+ By default, Open vSwitch treats controllers with active connection
+ methods as primary controllers and those with passive connection
+ methods as service controllers. Set this column to the desired type
+ to override this default.
</p>
- </dd>
- </dl>
-
- <p>
- The <ref column="target"/> determines the type of controller.
- </p>
+ </column>
- <group title="Core Features">
<column name="target">
<p>Connection method for controller.</p>
<p>
- The following connection methods are currently supported for primary
- controllers:
+ The following active connection methods are currently supported:
</p>
<dl>
<dt><code>ssl:<var>host</var></code>[<code>:<var>port</var></code>]</dt>
@@ -4546,8 +4542,7 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
</dd>
</dl>
<p>
- The following connection methods are currently supported for service
- controllers:
+ The following passive connection methods are currently supported:
</p>
<dl>
<dt><code>pssl:</code>[<var>port</var>][<code>:<var>host</var></code>]</dt>
Normally it makes sense for an active connection to be primary and a passive connection to be a service connection, but I've run into a corner case where it is better for a passive connection to be a primary connection. This specific case is for use with OFtest, which expects to be a primary controller. However, it also wants to reconnect frequently, which is slow for active connections because of the backoff; by configuring a passive, primary controller, OFtest can reconnect as frequently and as quickly as it wants, making the overall test much faster. Signed-off-by: Ben Pfaff <blp@ovn.org> --- ofproto/connmgr.c | 29 +++++------- ofproto/connmgr.h | 21 --------- ofproto/ofproto.c | 6 +++ ofproto/ofproto.h | 18 ++++++++ vswitchd/bridge.c | 11 +++++ vswitchd/vswitch.ovsschema | 8 +++- vswitchd/vswitch.xml | 111 ++++++++++++++++++++++----------------------- 7 files changed, 106 insertions(+), 98 deletions(-)