+static int
+handle_role_request(struct ofproto *ofproto,
+ struct ofconn *ofconn, struct nicira_header *msg)
+{
+ struct nx_role_request *nrr;
+ struct nx_role_request *reply;
+ struct ofpbuf *buf;
+ uint32_t role;
+
+ if (ntohs(msg->header.length) != sizeof *nrr) {
+ VLOG_WARN_RL(&rl, "received role request of length %zu (expected %zu)",
+ ntohs(msg->header.length), sizeof *nrr);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+ nrr = (struct nx_role_request *) msg;
+
+ if (ofconn->type != OFCONN_CONTROLLER) {
+ VLOG_WARN_RL(&rl, "ignoring role request on non-controller "
+ "connection");
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
+ }
+
+ role = ntohl(nrr->role);
+ if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
+ && role != NX_ROLE_SLAVE) {
+ VLOG_WARN_RL(&rl, "received request for unknown role %"PRIu32, role);
+
+ /* There's no good error code for this. */
+ return ofp_mkerr(OFPET_BAD_REQUEST, -1);
+ }
+
+ if (role == NX_ROLE_MASTER) {
+ struct ofconn *other;
+
+ HMAP_FOR_EACH (other, struct ofconn, hmap_node,
+ &ofproto->controllers) {
+ if (other->role == NX_ROLE_MASTER) {
+ other->role = NX_ROLE_SLAVE;
+ }
+ }
+ }
+ ofconn->role = role;
+
+ reply = make_openflow_xid(sizeof *reply, OFPT_VENDOR, msg->header.xid,
+ &buf);
+ reply->nxh.vendor = htonl(NX_VENDOR_ID);
+ reply->nxh.subtype = htonl(NXT_ROLE_REPLY);
+ reply->role = htonl(role);
+ queue_tx(buf, ofconn, ofconn->reply_counter);
+
+ return 0;
+}
+