ovn: Suppport ct_mark/ct_label in lflow matches.
[cascardo/ovs.git] / ovn / controller / lflow.c
index 38c72c1..33dca9b 100644 (file)
@@ -24,6 +24,7 @@
 #include "ovn/lib/actions.h"
 #include "ovn/lib/expr.h"
 #include "ovn/lib/ovn-sb-idl.h"
+#include "packets.h"
 #include "simap.h"
 
 VLOG_DEFINE_THIS_MODULE(lflow);
@@ -59,13 +60,22 @@ symtab_init(void)
 #undef MFF_LOG_REG
 
     /* Connection tracking state. */
+    expr_symtab_add_field(&symtab, "ct_mark", MFF_CT_MARK, NULL, false);
+    expr_symtab_add_field(&symtab, "ct_label", MFF_CT_LABEL, NULL, false);
     expr_symtab_add_field(&symtab, "ct_state", MFF_CT_STATE, NULL, false);
-    expr_symtab_add_predicate(&symtab, "ct.trk", "ct_state[7]");
-    expr_symtab_add_subfield(&symtab, "ct.new", "ct.trk", "ct_state[0]");
-    expr_symtab_add_subfield(&symtab, "ct.est", "ct.trk", "ct_state[1]");
-    expr_symtab_add_subfield(&symtab, "ct.rel", "ct.trk", "ct_state[2]");
-    expr_symtab_add_subfield(&symtab, "ct.inv", "ct.trk", "ct_state[5]");
-    expr_symtab_add_subfield(&symtab, "ct.rpl", "ct.trk", "ct_state[6]");
+    char ct_state_str[16];
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_TRACKED_BIT);
+    expr_symtab_add_predicate(&symtab, "ct.trk", ct_state_str);
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_NEW_BIT);
+    expr_symtab_add_subfield(&symtab, "ct.new", "ct.trk", ct_state_str);
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_ESTABLISHED_BIT);
+    expr_symtab_add_subfield(&symtab, "ct.est", "ct.trk", ct_state_str);
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_RELATED_BIT);
+    expr_symtab_add_subfield(&symtab, "ct.rel", "ct.trk", ct_state_str);
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_REPLY_DIR_BIT);
+    expr_symtab_add_subfield(&symtab, "ct.rpl", "ct.trk", ct_state_str);
+    snprintf(ct_state_str, sizeof ct_state_str, "ct_state[%d]", CS_INVALID_BIT);
+    expr_symtab_add_subfield(&symtab, "ct.inv", "ct.trk", ct_state_str);
 
     /* Data fields. */
     expr_symtab_add_field(&symtab, "eth.src", MFF_ETH_SRC, NULL, false);
@@ -149,6 +159,11 @@ symtab_init(void)
 \f
 /* Logical datapaths and logical port numbers. */
 
+enum ldp_type {
+    LDP_TYPE_ROUTER,
+    LDP_TYPE_SWITCH,
+};
+
 /* A logical datapath.
  *
  * 'ports' maps 'logical_port' names to 'tunnel_key' values in the OVN_SB
@@ -158,6 +173,7 @@ struct logical_datapath {
     struct uuid uuid;           /* UUID from Datapath_Binding row. */
     uint32_t tunnel_key;        /* 'tunnel_key' from Datapath_Binding row. */
     struct simap ports;         /* Logical port name to port number. */
+    enum ldp_type type;         /* Type of logical datapath */
 };
 
 /* Contains "struct logical_datapath"s. */
@@ -189,6 +205,8 @@ ldp_create(const struct sbrec_datapath_binding *binding)
                 uuid_hash(&binding->header_.uuid));
     ldp->uuid = binding->header_.uuid;
     ldp->tunnel_key = binding->tunnel_key;
+    const char *ls = smap_get(&binding->external_ids, "logical-switch");
+    ldp->type = ls ? LDP_TYPE_SWITCH : LDP_TYPE_ROUTER;
     simap_init(&ldp->ports);
     return ldp;
 }
@@ -259,7 +277,8 @@ lflow_init(void)
  * into OpenFlow flows.  See ovn-architecture(7) for more information. */
 void
 lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
-          const struct simap *ct_zones)
+          const struct simap *ct_zones,
+          struct hmap *local_datapaths)
 {
     struct hmap flows = HMAP_INITIALIZER(&flows);
     uint32_t conj_id_ofs = 1;
@@ -268,7 +287,7 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
 
     const struct sbrec_logical_flow *lflow;
     SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
-        /* Find the "struct logical_datapath" asssociated with this
+        /* Find the "struct logical_datapath" associated with this
          * Logical_Flow row.  If there's no such struct, that must be because
          * no logical ports are bound to that logical datapath, so there's no
          * point in maintaining any flows for it anyway, so skip it. */
@@ -278,8 +297,38 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
             continue;
         }
 
-        /* Determine translation of logical table IDs to physical table IDs. */
         bool ingress = !strcmp(lflow->pipeline, "ingress");
+
+        if (ldp->type == LDP_TYPE_SWITCH && !ingress) {
+            /* For a logical switch datapath, local_datapaths tells us if there
+             * are any local ports for this datapath.  If not, processing
+             * logical flows for the egress pipeline of this datapath is
+             * unnecessary.
+             *
+             * We still need the ingress pipeline because even if there are no
+             * local ports, we still may need to execute the ingress pipeline
+             * after a packet leaves a logical router.  Further optimization
+             * is possible, but not based on what we know with local_datapaths
+             * right now.
+             *
+             * A better approach would be a kind of "flood fill" algorithm:
+             *
+             *   1. Initialize set S to the logical datapaths that have a port
+             *      located on the hypervisor.
+             *
+             *   2. For each patch port P in a logical datapath in S, add the
+             *      logical datapath of the remote end of P to S.  Iterate
+             *      until S reaches a fixed point.
+             */
+
+            struct hmap_node *ld;
+            ld = hmap_first_with_hash(local_datapaths, ldp->tunnel_key);
+            if (!ld) {
+                continue;
+            }
+        }
+
+        /* Determine translation of logical table IDs to physical table IDs. */
         uint8_t first_ptable = (ingress
                                 ? OFTABLE_LOG_INGRESS_PIPELINE
                                 : OFTABLE_LOG_EGRESS_PIPELINE);
@@ -297,10 +346,17 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
         char *error;
 
         ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
-        error = actions_parse_string(lflow->actions, &symtab, &ldp->ports,
-                                     ct_zones, first_ptable, LOG_PIPELINE_LEN,
-                                     lflow->table_id, output_ptable,
-                                     &ofpacts, &prereqs);
+        struct action_params ap = {
+            .symtab = &symtab,
+            .ports = &ldp->ports,
+            .ct_zones = ct_zones,
+
+            .n_tables = LOG_PIPELINE_LEN,
+            .first_ptable = first_ptable,
+            .cur_ltable = lflow->table_id,
+            .output_ptable = output_ptable,
+        };
+        error = actions_parse_string(lflow->actions, &ap, &ofpacts, &prereqs);
         if (error) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
             VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",