+
+/* Returns true if 'ofconn' should receive asynchronous messages. */
+static bool
+ofconn_receives_async_msgs(const struct ofconn *ofconn)
+{
+ if (ofconn->type == OFCONN_PRIMARY) {
+ /* Primary controllers always get asynchronous messages unless they
+ * have configured themselves as "slaves". */
+ return ofconn->role != NX_ROLE_SLAVE;
+ } else {
+ /* Service connections don't get asynchronous messages unless they have
+ * explicitly asked for them by setting a nonzero miss send length. */
+ return ofconn->miss_send_len > 0;
+ }
+}
+
+/* Returns a human-readable name for an OpenFlow connection between 'ofproto'
+ * and 'target', suitable for use in log messages for identifying the
+ * connection.
+ *
+ * The name is dynamically allocated. The caller should free it (with free())
+ * when it is no longer needed. */
+static char *
+ofconn_make_name(const struct ofproto *ofproto, const char *target)
+{
+ return xasprintf("%s<->%s", dpif_base_name(ofproto->dpif), target);
+}
+
+static void
+ofconn_set_rate_limit(struct ofconn *ofconn, int rate, int burst)
+{
+ int i;
+
+ for (i = 0; i < N_SCHEDULERS; i++) {
+ struct pinsched **s = &ofconn->schedulers[i];
+
+ if (rate > 0) {
+ if (!*s) {
+ *s = pinsched_create(rate, burst,
+ ofconn->ofproto->switch_status);
+ } else {
+ pinsched_set_limits(*s, rate, burst);
+ }
+ } else {
+ pinsched_destroy(*s);
+ *s = NULL;
+ }
+ }
+}
+\f
+static void
+ofservice_reconfigure(struct ofservice *ofservice,
+ const struct ofproto_controller *c)
+{
+ ofservice->probe_interval = c->probe_interval;
+ ofservice->rate_limit = c->rate_limit;
+ ofservice->burst_limit = c->burst_limit;
+}
+
+/* Creates a new ofservice in 'ofproto'. Returns 0 if successful, otherwise a
+ * positive errno value. */
+static int
+ofservice_create(struct ofproto *ofproto, const struct ofproto_controller *c)
+{
+ struct ofservice *ofservice;
+ struct pvconn *pvconn;
+ int error;
+
+ error = pvconn_open(c->target, &pvconn);
+ if (error) {
+ return error;
+ }
+
+ ofservice = xzalloc(sizeof *ofservice);
+ hmap_insert(&ofproto->services, &ofservice->node,
+ hash_string(c->target, 0));
+ ofservice->pvconn = pvconn;
+
+ ofservice_reconfigure(ofservice, c);
+
+ return 0;
+}
+
+static void
+ofservice_destroy(struct ofproto *ofproto, struct ofservice *ofservice)
+{
+ hmap_remove(&ofproto->services, &ofservice->node);
+ pvconn_close(ofservice->pvconn);
+ free(ofservice);
+}
+
+/* Finds and returns the ofservice within 'ofproto' that has the given
+ * 'target', or a null pointer if none exists. */
+static struct ofservice *
+ofservice_lookup(struct ofproto *ofproto, const char *target)
+{
+ struct ofservice *ofservice;
+
+ HMAP_FOR_EACH_WITH_HASH (ofservice, struct ofservice, node,
+ hash_string(target, 0), &ofproto->services) {
+ if (!strcmp(pvconn_get_name(ofservice->pvconn), target)) {
+ return ofservice;
+ }
+ }
+ return NULL;
+}