+static void
+clear_rules(struct in_band *ib)
+{
+ memset(ib->installed_local_mac, 0, sizeof ib->installed_local_mac);
+
+ free(ib->remote_ips);
+ ib->remote_ips = NULL;
+ ib->n_remote_ips = 0;
+
+ free(ib->remote_macs);
+ ib->remote_macs = NULL;
+ ib->n_remote_macs = 0;
+}
+
+static void
+drop_rule(struct in_band *ib, const struct in_band_rule *rule)
+{
+ ofproto_delete_flow(ib->ofproto, &rule->flow,
+ rule->wildcards, rule->priority);
+}
+
+static void
+drop_rules(struct in_band *ib)
+{
+ make_rules(ib, drop_rule);
+ clear_rules(ib);
+}
+
+static void
+add_rule(struct in_band *ib, const struct in_band_rule *rule)
+{
+ union ofp_action action;
+
+ action.type = htons(OFPAT_OUTPUT);
+ action.output.len = htons(sizeof action);
+ action.output.port = htons(OFPP_NORMAL);
+ action.output.max_len = htons(0);
+ ofproto_add_flow(ib->ofproto, &rule->flow, rule->wildcards,
+ rule->priority, &action, 1, 0);
+}
+
+static void
+add_rules(struct in_band *ib)
+{
+ make_rules(ib, add_rule);
+}
+
+static int
+compare_ips(const void *a, const void *b)
+{
+ return memcmp(a, b, sizeof(uint32_t));
+}
+
+static int
+compare_macs(const void *a, const void *b)
+{
+ return memcmp(a, b, ETH_ADDR_LEN);
+}
+
+void
+in_band_run(struct in_band *ib)
+{
+ struct in_band_remote *r;
+
+ if (!refresh_local(ib) && !refresh_remotes(ib)) {
+ /* Nothing changed, nothing to do. */
+ return;
+ }
+
+ /* Drop old rules. */
+ drop_rules(ib);
+
+ /* Figure out new rules. */
+ memcpy(ib->installed_local_mac, ib->local_mac, ETH_ADDR_LEN);
+ ib->remote_ips = xmalloc(ib->n_remotes * sizeof *ib->remote_ips);
+ ib->n_remote_ips = 0;
+ ib->remote_macs = xmalloc(ib->n_remotes * ETH_ADDR_LEN);
+ ib->n_remote_macs = 0;
+ for (r = ib->remotes; r < &ib->remotes[ib->n_remotes]; r++) {
+ if (r->remote_ip) {
+ ib->remote_ips[ib->n_remote_ips++] = r->remote_ip;
+ }
+ if (!eth_addr_is_zero(r->remote_mac)) {
+ memcpy(&ib->remote_macs[ib->n_remote_macs * ETH_ADDR_LEN],
+ r->remote_mac, ETH_ADDR_LEN);
+ ib->n_remote_macs++;
+ }
+ }
+
+ /* Sort, to allow make_rules() to easily skip duplicates. */
+ qsort(ib->remote_ips, ib->n_remote_ips, sizeof *ib->remote_ips,
+ compare_ips);
+ qsort(ib->remote_macs, ib->n_remote_macs, ETH_ADDR_LEN, compare_macs);
+
+ /* Add new rules. */
+ add_rules(ib);
+}
+