@@ -51,7 +51,27 @@
VLOG_DEFINE_THIS_MODULE(ofctrl);
-/* An OpenFlow flow.
+/* An OpenFlow flow. */
+struct ovn_flow {
+ /* Key. */
+ uint8_t table_id;
+ uint16_t priority;
+ struct minimatch match;
+
+ /* Hash. */
+ uint32_t hash;
+
+ /* Data. */
+ struct ofpact *ofpacts;
+ size_t ofpacts_len;
+ uint64_t cookie;
+};
+
+/* A desired flow, in struct ovn_desired_flow_table, calculated by the
+ * incremental processing engine.
+ * - They are added/removed incrementally when I-P engine is able to process
+ * the changes incrementally, or
+ * - Completely cleared and recomputed by I-P engine when recompute happens.
*
* Links are maintained between desired flows and SB data. The relationship
* is M to N. The struct sb_flow_ref is used to link a pair of desired flow
@@ -82,52 +102,92 @@ VLOG_DEFINE_THIS_MODULE(ofctrl);
* The links are updated whenever there is a change in desired flows, which is
* usually triggered by a SB data change in I-P engine.
*/
-struct ovn_flow {
+struct desired_flow {
+ struct ovn_flow flow;
struct hmap_node match_hmap_node; /* For match based hashing. */
struct ovs_list list_node; /* For handling lists of flows. */
- struct ovs_list references; /* A list of struct sb_flow_ref nodes, which
- references this flow. (There are cases
- that multiple SB entities share the same
- desired OpenFlow flow, e.g. when
- conjunction is used.) */
- /* Key. */
- uint8_t table_id;
- uint16_t priority;
- struct minimatch match;
+ /* A list of struct sb_flow_ref nodes, which references this flow. (There
+ * are cases that multiple SB entities share the same desired OpenFlow
+ * flow, e.g. when conjunction is used.) */
+ struct ovs_list references;
- /* Data. */
- struct ofpact *ofpacts;
- size_t ofpacts_len;
- uint64_t cookie;
+ /* The corresponding flow in installed table. */
+ struct installed_flow *installed_flow;
+
+ /* Node in installed_flow.desired_refs list. */
+ struct ovs_list installed_ref_list_node;
};
struct sb_to_flow {
struct hmap_node hmap_node; /* Node in
ovn_desired_flow_table.uuid_flow_table. */
struct uuid sb_uuid;
- struct ovs_list flows; /* A list of struct sb_flow_ref nodes that are
- referenced by the sb_uuid. */
+ struct ovs_list flows; /* A list of struct sb_flow_ref nodes that
+ are referenced by the sb_uuid. */
};
struct sb_flow_ref {
- struct ovs_list sb_list; /* List node in ovn_flow.references. */
- struct ovs_list flow_list; /* List node in sb_to_flow.ovn_flows. */
- struct ovn_flow *flow;
+ struct ovs_list sb_list; /* List node in desired_flow.references. */
+ struct ovs_list flow_list; /* List node in sb_to_flow.desired_flows. */
+ struct desired_flow *flow;
struct uuid sb_uuid;
};
-static struct ovn_flow *ovn_flow_alloc(uint8_t table_id, uint16_t priority,
- uint64_t cookie,
- const struct match *match,
- const struct ofpbuf *actions);
+/* A installed flow, in static variable installed_flows.
+ *
+ * Installed flows are updated in ofctrl_put for maintaining the flow
+ * installation to OVS. They are updated according to desired flows: either by
+ * processing the tracked desired flow changes, or by comparing desired flows
+ * with currently installed flows when tracked desired flows changes are not
+ * available.
+ *
+ * In addition, when ofctrl state machine enters S_CLEAR, the installed flows
+ * will be cleared. (This happens in initialization phase and also when
+ * ovs-vswitchd is disconnected/reconnected).
+ *
+ * Links are maintained between installed flows and desired flows. The
+ * relationship is 1 to N. A link is added when a flow addition is processed.
+ * A link is removed when a flow deletion is processed, the desired flow
+ * table is cleared, or the installed flow table is cleared.
+ */
+struct installed_flow {
+ struct ovn_flow flow;
+ struct hmap_node match_hmap_node; /* For match based hashing. */
+
+ /* A list of desired ovn_flow nodes (linked by
+ * desired_flow.installed_ref_list_node), which reference this installed
+ * flow. (There are cases that multiple desired flows reference the same
+ * installed flow, e.g. when there are conflict/duplicated ACLs that
+ * generates same match conditions). */
+ struct ovs_list desired_refs;
+
+ /* The corresponding flow in desired table. It must be one of the flows in
+ * desired_refs list. If there are more than one flows in references list,
+ * this is the one that is actually installed. */
+ struct desired_flow *desired_flow;
+};
+
+static struct desired_flow *desired_flow_alloc(
+ uint8_t table_id,
+ uint16_t priority,
+ uint64_t cookie,
+ const struct match *match,
+ const struct ofpbuf *actions);
+static struct desired_flow *desired_flow_lookup(
+ struct ovn_desired_flow_table *,
+ const struct ovn_flow *target,
+ const struct uuid *sb_uuid);
+static void desired_flow_destroy(struct desired_flow *);
+
+static struct installed_flow *installed_flow_lookup(
+ const struct ovn_flow *target);
+static void installed_flow_destroy(struct installed_flow *);
+static struct installed_flow *installed_flow_dup(struct desired_flow *);
+
static uint32_t ovn_flow_match_hash(const struct ovn_flow *);
-static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
- const struct ovn_flow *target,
- const struct uuid *sb_uuid);
static char *ovn_flow_to_string(const struct ovn_flow *);
static void ovn_flow_log(const struct ovn_flow *, const char *action);
-static void ovn_flow_destroy(struct ovn_flow *);
/* OpenFlow connection to the switch. */
static struct rconn *swconn;
@@ -216,7 +276,6 @@ static struct ofpbuf *encode_meter_mod(const struct ofputil_meter_mod *);
static void ovn_installed_flow_table_clear(void);
static void ovn_installed_flow_table_destroy(void);
-static struct ovn_flow *ovn_flow_dup(struct ovn_flow *source);
static void ofctrl_recv(const struct ofp_header *, enum ofptype);
@@ -691,6 +750,45 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
}
}
+static void
+link_installed_to_desired(struct installed_flow *i, struct desired_flow *d)
+{
+ if (i->desired_flow == d) {
+ return;
+ }
+
+ if (ovs_list_is_empty(&i->desired_refs)) {
+ ovs_assert(!i->desired_flow);
+ i->desired_flow = d;
+ }
+ ovs_list_insert(&i->desired_refs, &d->installed_ref_list_node);
+ d->installed_flow = i;
+}
+
+static void
+unlink_installed_to_desired(struct installed_flow *i, struct desired_flow *d)
+{
+ ovs_assert(i && i->desired_flow && !ovs_list_is_empty(&i->desired_refs));
+ ovs_assert(d && d->installed_flow == i);
+ ovs_list_remove(&d->installed_ref_list_node);
+ d->installed_flow = NULL;
+ if (i->desired_flow == d) {
+ i->desired_flow = ovs_list_is_empty(&i->desired_refs) ? NULL :
+ CONTAINER_OF(ovs_list_front(&i->desired_refs),
+ struct desired_flow,
+ installed_ref_list_node);
+ }
+}
+
+static void
+unlink_all_refs_for_installed_flow(struct installed_flow *i)
+{
+ struct desired_flow *d, *next;
+ LIST_FOR_EACH_SAFE (d, next, installed_ref_list_node, &i->desired_refs) {
+ unlink_installed_to_desired(i, d);
+ }
+}
+
static struct sb_to_flow *