+static void
+add_pr_rule(struct bond *bond, const struct match *match,
+ ofp_port_t out_ofport, struct rule **rule)
+{
+ uint32_t hash = match_hash(match, 0);
+ struct bond_pr_rule_op *pr_op;
+
+ HMAP_FOR_EACH_WITH_HASH(pr_op, hmap_node, hash, &bond->pr_rule_ops) {
+ if (match_equal(&pr_op->match, match)) {
+ pr_op->op = ADD;
+ pr_op->out_ofport = out_ofport;
+ pr_op->pr_rule = rule;
+ return;
+ }
+ }
+
+ pr_op = xmalloc(sizeof *pr_op);
+ pr_op->match = *match;
+ pr_op->op = ADD;
+ pr_op->out_ofport = out_ofport;
+ pr_op->pr_rule = rule;
+ hmap_insert(&bond->pr_rule_ops, &pr_op->hmap_node, hash);
+}
+
+static void
+update_recirc_rules(struct bond *bond)
+{
+ struct match match;
+ struct bond_pr_rule_op *pr_op, *next_op;
+ uint64_t ofpacts_stub[128 / 8];
+ struct ofpbuf ofpacts;
+ int i;
+
+ ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+
+ HMAP_FOR_EACH(pr_op, hmap_node, &bond->pr_rule_ops) {
+ pr_op->op = DEL;
+ }
+
+ if (bond->hash && bond->recirc_id) {
+ for (i = 0; i < BOND_BUCKETS; i++) {
+ struct bond_slave *slave = bond->hash[i].slave;
+
+ if (slave) {
+ match_init_catchall(&match);
+ match_set_recirc_id(&match, bond->recirc_id);
+ match_set_dp_hash_masked(&match, i, BOND_MASK);
+
+ add_pr_rule(bond, &match, slave->ofp_port,
+ &bond->hash[i].pr_rule);
+ }
+ }
+ }
+
+ HMAP_FOR_EACH_SAFE(pr_op, next_op, hmap_node, &bond->pr_rule_ops) {
+ int error;
+ switch (pr_op->op) {
+ case ADD:
+ ofpbuf_clear(&ofpacts);
+ ofpact_put_OUTPUT(&ofpacts)->port = pr_op->out_ofport;
+ error = ofproto_dpif_add_internal_flow(bond->ofproto,
+ &pr_op->match,
+ RECIRC_RULE_PRIORITY,
+ &ofpacts, pr_op->pr_rule);
+ if (error) {
+ char *err_s = match_to_string(&pr_op->match,
+ RECIRC_RULE_PRIORITY);
+
+ VLOG_ERR("failed to add post recirculation flow %s", err_s);
+ free(err_s);
+ }
+ break;
+
+ case DEL:
+ error = ofproto_dpif_delete_internal_flow(bond->ofproto,
+ &pr_op->match,
+ RECIRC_RULE_PRIORITY);
+ if (error) {
+ char *err_s = match_to_string(&pr_op->match,
+ RECIRC_RULE_PRIORITY);
+
+ VLOG_ERR("failed to remove post recirculation flow %s", err_s);
+ free(err_s);
+ }
+
+ hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
+ *pr_op->pr_rule = NULL;
+ free(pr_op);
+ break;
+ }
+ }
+
+ ofpbuf_uninit(&ofpacts);
+}
+
+