+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, node, hash_string(target, 0),
+ &ofproto->services) {
+ if (!strcmp(pvconn_get_name(ofservice->pvconn), target)) {
+ return ofservice;
+ }
+ }
+ return NULL;
+}
+\f
+/* Returns true if 'rule' should be hidden from the controller.
+ *
+ * Rules with priority higher than UINT16_MAX are set up by ofproto itself
+ * (e.g. by in-band control) and are intentionally hidden from the
+ * controller. */
+static bool
+rule_is_hidden(const struct rule *rule)
+{
+ return rule->cr.priority > UINT16_MAX;
+}
+
+/* Creates and returns a new rule initialized as specified.
+ *
+ * The caller is responsible for inserting the rule into the classifier (with
+ * rule_insert()). */
+static struct rule *
+rule_create(const struct cls_rule *cls_rule,
+ const union ofp_action *actions, size_t n_actions,
+ uint16_t idle_timeout, uint16_t hard_timeout,
+ ovs_be64 flow_cookie, bool send_flow_removed)
+{
+ struct rule *rule = xzalloc(sizeof *rule);
+ rule->cr = *cls_rule;
+ rule->idle_timeout = idle_timeout;
+ rule->hard_timeout = hard_timeout;
+ rule->flow_cookie = flow_cookie;
+ rule->used = rule->created = time_msec();
+ rule->send_flow_removed = send_flow_removed;
+ list_init(&rule->facets);
+ if (n_actions > 0) {
+ rule->n_actions = n_actions;
+ rule->actions = xmemdup(actions, n_actions * sizeof *actions);
+ }
+
+ return rule;
+}