+ struct ofconn *ofconn;
+
+ HMAP_FOR_EACH_WITH_HASH (ofconn, struct ofconn, hmap_node,
+ hash_string(target, 0), &ofproto->controllers) {
+ if (!strcmp(ofconn_get_target(ofconn), target)) {
+ return ofconn;
+ }
+ }
+ return NULL;
+}
+
+void
+ofproto_set_controllers(struct ofproto *p,
+ const struct ofproto_controller *controllers,
+ size_t n_controllers)
+{
+ struct shash new_controllers;
+ struct rconn **in_band_rconns;
+ enum ofproto_fail_mode fail_mode;
+ struct ofconn *ofconn, *next;
+ bool ss_exists;
+ size_t n_in_band;
+ size_t i;
+
+ shash_init(&new_controllers);
+ for (i = 0; i < n_controllers; i++) {
+ const struct ofproto_controller *c = &controllers[i];
+
+ shash_add_once(&new_controllers, c->target, &controllers[i]);
+ if (!find_controller_by_target(p, c->target)) {
+ add_controller(p, c);
+ }
+ }
+
+ in_band_rconns = xmalloc(n_controllers * sizeof *in_band_rconns);
+ n_in_band = 0;
+ fail_mode = OFPROTO_FAIL_STANDALONE;
+ ss_exists = false;
+ HMAP_FOR_EACH_SAFE (ofconn, next, struct ofconn, hmap_node,
+ &p->controllers) {
+ struct ofproto_controller *c;
+
+ c = shash_find_data(&new_controllers, ofconn_get_target(ofconn));
+ if (!c) {
+ ofconn_destroy(ofconn);
+ } else {
+ update_controller(ofconn, c);
+
+ if (ofconn->ss) {
+ ss_exists = true;
+ }
+ if (is_in_band_controller(c)) {
+ in_band_rconns[n_in_band++] = ofconn->rconn;
+ }
+
+ if (c->fail == OFPROTO_FAIL_SECURE) {
+ fail_mode = OFPROTO_FAIL_SECURE;
+ }
+ }
+ }
+ shash_destroy(&new_controllers);
+
+ if (n_in_band) {
+ if (!p->in_band) {
+ in_band_create(p, p->dpif, p->switch_status, &p->in_band);
+ }
+ if (p->in_band) {
+ in_band_set_remotes(p->in_band, in_band_rconns, n_in_band);
+ }
+ } else {
+ in_band_destroy(p->in_band);
+ p->in_band = NULL;
+ }
+ free(in_band_rconns);
+
+ if (!hmap_is_empty(&p->controllers)
+ && fail_mode == OFPROTO_FAIL_STANDALONE) {
+ struct rconn **rconns;
+ size_t n;
+
+ if (!p->fail_open) {
+ p->fail_open = fail_open_create(p, p->switch_status);
+ }
+
+ n = 0;
+ rconns = xmalloc(hmap_count(&p->controllers) * sizeof *rconns);
+ HMAP_FOR_EACH (ofconn, struct ofconn, hmap_node, &p->controllers) {
+ rconns[n++] = ofconn->rconn;
+ }
+
+ fail_open_set_controllers(p->fail_open, rconns, n);
+ /* p->fail_open takes ownership of 'rconns'. */
+ } else {
+ fail_open_destroy(p->fail_open);
+ p->fail_open = NULL;
+ }
+
+ if (!hmap_is_empty(&p->controllers) && !ss_exists) {
+ ofconn = CONTAINER_OF(hmap_first(&p->controllers),
+ struct ofconn, hmap_node);
+ ofconn->ss = switch_status_register(p->switch_status, "remote",
+ rconn_status_cb, ofconn->rconn);
+ }