int burst_limit; /* Limit on accumulating packet credits. */
bool enable_async_msgs; /* Initially enable async messages? */
uint8_t dscp; /* DSCP Value for controller connection */
+ uint32_t allowed_versions; /* OpenFlow protocol versions that may
+ * be negotiated for a session. */
};
static void ofservice_reconfigure(struct ofservice *,
const struct ofproto_controller *c = &controllers[i];
if (!vconn_verify_name(c->target)) {
- if (!find_controller_by_target(mgr, c->target)) {
+ bool add = false;
+ ofconn = find_controller_by_target(mgr, c->target);
+ if (!ofconn) {
VLOG_INFO("%s: added primary controller \"%s\"",
mgr->name, c->target);
+ add = true;
+ } else if (rconn_get_allowed_versions(ofconn->rconn) !=
+ allowed_versions) {
+ VLOG_INFO("%s: re-added primary controller \"%s\"",
+ mgr->name, c->target);
+ add = true;
+ ofconn_destroy(ofconn);
+ }
+ if (add) {
add_controller(mgr, c->target, c->dscp, allowed_versions);
}
} else if (!pvconn_verify_name(c->target)) {
- if (!ofservice_lookup(mgr, c->target)) {
+ bool add = false;
+ ofservice = ofservice_lookup(mgr, c->target);
+ if (!ofservice) {
VLOG_INFO("%s: added service controller \"%s\"",
mgr->name, c->target);
+ add = true;
+ } else if (ofservice->allowed_versions != allowed_versions) {
+ VLOG_INFO("%s: re-added service controller \"%s\"",
+ mgr->name, c->target);
+ ofservice_destroy(mgr, ofservice);
+ add = true;
+ }
+ if (add) {
ofservice_create(mgr, c->target, allowed_versions, c->dscp);
}
} else {
/* Returns the currently configured protocol for 'ofconn', one of OFPUTIL_P_*.
*
- * The default, if no other format has been set, is OFPUTIL_P_OPENFLOW10. */
+ * Returns OFPUTIL_P_NONE, which is not a valid protocol, if 'ofconn' hasn't
+ * completed version negotiation. This can't happen if at least one OpenFlow
+ * message, other than OFPT_HELLO, has been received on the connection (such as
+ * in ofproto.c's message handling code), since version negotiation is a
+ * prerequisite for starting to receive messages. This means that
+ * OFPUTIL_P_NONE is a special case that most callers need not worry about. */
enum ofputil_protocol
-ofconn_get_protocol(struct ofconn *ofconn)
-{
+ofconn_get_protocol(const struct ofconn *ofconn)
+{
+ if (ofconn->protocol == OFPUTIL_P_NONE &&
+ rconn_is_connected(ofconn->rconn)) {
+ int version = rconn_get_version(ofconn->rconn);
+ if (version > 0) {
+ ofconn_set_protocol(CONST_CAST(struct ofconn *, ofconn),
+ ofputil_protocol_from_ofp_version(version));
+ }
+ }
+
return ofconn->protocol;
}
ofconn_send_error(const struct ofconn *ofconn,
const struct ofp_header *request, enum ofperr error)
{
+ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(10, 10);
struct ofpbuf *reply;
reply = ofperr_encode_reply(error, request);
- if (reply) {
- static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(10, 10);
-
- if (!VLOG_DROP_INFO(&err_rl)) {
- const char *type_name;
- size_t request_len;
- enum ofpraw raw;
-
- request_len = ntohs(request->length);
- type_name = (!ofpraw_decode_partial(&raw, request,
- MIN(64, request_len))
- ? ofpraw_get_name(raw)
- : "invalid");
-
- VLOG_INFO("%s: sending %s error reply to %s message",
- rconn_get_name(ofconn->rconn), ofperr_to_string(error),
- type_name);
- }
- ofconn_send_reply(ofconn, reply);
+ if (!VLOG_DROP_INFO(&err_rl)) {
+ const char *type_name;
+ size_t request_len;
+ enum ofpraw raw;
+
+ request_len = ntohs(request->length);
+ type_name = (!ofpraw_decode_partial(&raw, request,
+ MIN(64, request_len))
+ ? ofpraw_get_name(raw)
+ : "invalid");
+
+ VLOG_INFO("%s: sending %s error reply to %s message",
+ rconn_get_name(ofconn->rconn), ofperr_to_string(error),
+ type_name);
}
+ ofconn_send_reply(ofconn, reply);
}
/* Same as pktbuf_retrieve(), using the pktbuf owned by 'ofconn'. */
int i;
ofconn->role = NX_ROLE_OTHER;
- ofconn->protocol = OFPUTIL_P_OF10;
+ ofconn_set_protocol(ofconn, OFPUTIL_P_NONE);
ofconn->packet_in_format = NXPIF_OPENFLOW10;
/* Disassociate 'ofconn' from all of the ofopgroups that it initiated that
assert(reason < 32);
assert((unsigned int) type < OAM_N_TYPES);
- if (!rconn_is_connected(ofconn->rconn)) {
+ if (ofconn_get_protocol(ofconn) == OFPUTIL_P_NONE
+ || !rconn_is_connected(ofconn->rconn)) {
return false;
}
if (ofconn_receives_async_msg(ofconn, OAM_PORT_STATUS, reason)) {
struct ofpbuf *msg;
- msg = ofputil_encode_port_status(&ps, ofconn->protocol);
+ msg = ofputil_encode_port_status(&ps, ofconn_get_protocol(ofconn));
ofconn_send(ofconn, msg, NULL);
}
}
* also prevents new flows from being added (and expiring). (It
* also prevents processing OpenFlow requests that would not add
* new flows, so it is imperfect.) */
- msg = ofputil_encode_flow_removed(fr, ofconn->protocol);
+ msg = ofputil_encode_flow_removed(fr, ofconn_get_protocol(ofconn));
ofconn_send_reply(ofconn, msg);
}
}
* while (until a later call to pinsched_run()). */
pinsched_send(ofconn->schedulers[pin.reason == OFPR_NO_MATCH ? 0 : 1],
pin.fmd.in_port,
- ofputil_encode_packet_in(&pin, ofconn->protocol,
+ ofputil_encode_packet_in(&pin, ofconn_get_protocol(ofconn),
ofconn->packet_in_format),
do_send_packet_in, ofconn);
}
ofservice = xzalloc(sizeof *ofservice);
hmap_insert(&mgr->services, &ofservice->node, hash_string(target, 0));
ofservice->pvconn = pvconn;
+ ofservice->allowed_versions = allowed_versions;
return 0;
}