@@ -642,6 +642,19 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
}
}
+static void
+ofctrl_swap_flow_actions(struct ovn_flow *a, struct ovn_flow *b)
+{
+ struct ofpact *tmp = a->ofpacts;
+ size_t tmp_len = a->ofpacts_len;
+
+ a->ofpacts = b->ofpacts;
+ a->ofpacts_len = b->ofpacts_len;
+
+ b->ofpacts = tmp;
+ b->ofpacts_len = tmp_len;
+}
+
/* Flow table interfaces to the rest of ovn-controller. */
/* Adds a flow to 'desired_flows' with the specified 'match' and 'actions' to
@@ -667,14 +680,21 @@ ofctrl_check_and_add_flow(struct ovn_desired_flow_table *flow_table,
ovn_flow_log(f, "ofctrl_add_flow");
- if (ovn_flow_lookup(&flow_table->match_flow_table, f, true)) {
- if (log_duplicate_flow) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
- if (!VLOG_DROP_DBG(&rl)) {
- char *s = ovn_flow_to_string(f);
- VLOG_DBG("dropping duplicate flow: %s", s);
- free(s);
+ struct ovn_flow *existing_f =
+ ovn_flow_lookup(&flow_table->match_flow_table, f, true);
+ if (existing_f) {
+ if (ofpacts_equal(f->ofpacts, f->ofpacts_len,
+ existing_f->ofpacts, existing_f->ofpacts_len)) {
+ if (log_duplicate_flow) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+ if (!VLOG_DROP_DBG(&rl)) {
+ char *s = ovn_flow_to_string(f);
+ VLOG_DBG("dropping duplicate flow: %s", s);
+ free(s);
+ }
}
+ } else {
+ ofctrl_swap_flow_actions(f, existing_f);
}
ovn_flow_destroy(f);
return;