+static bool
+is_discovery_controller(const struct ofproto_controller *c)
+{
+ return !strcmp(c->target, "discover");
+}
+
+static bool
+is_in_band_controller(const struct ofproto_controller *c)
+{
+ return is_discovery_controller(c) || c->band == OFPROTO_IN_BAND;
+}
+
+/* Creates a new controller in 'ofproto'. Some of the settings are initially
+ * drawn from 'c', but update_controller() needs to be called later to finish
+ * the new ofconn's configuration. */
+static void
+add_controller(struct ofproto *ofproto, const struct ofproto_controller *c)
+{
+ struct discovery *discovery;
+ struct ofconn *ofconn;
+
+ if (is_discovery_controller(c)) {
+ int error = discovery_create(c->accept_re, c->update_resolv_conf,
+ ofproto->dpif, ofproto->switch_status,
+ &discovery);
+ if (error) {
+ return;
+ }
+ } else {
+ discovery = NULL;
+ }
+
+ ofconn = ofconn_create(ofproto, rconn_create(5, 8), OFCONN_CONTROLLER);
+ ofconn->pktbuf = pktbuf_create();
+ ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
+ if (discovery) {
+ ofconn->discovery = discovery;
+ } else {
+ rconn_connect(ofconn->rconn, c->target);
+ }
+ hmap_insert(&ofproto->controllers, &ofconn->hmap_node,
+ hash_string(c->target, 0));
+}
+
+/* Reconfigures 'ofconn' to match 'c'. This function cannot update an ofconn's
+ * target or turn discovery on or off (these are done by creating new ofconns
+ * and deleting old ones), but it can update the rest of an ofconn's
+ * settings. */
+static void
+update_controller(struct ofconn *ofconn, const struct ofproto_controller *c)