[ovs-dev,22/23] ovn-northd: Add stages for logical routers.
diff mbox

Message ID 1444450902-12236-3-git-send-email-blp@nicira.com
State Accepted
Headers show

Commit Message

Ben Pfaff Oct. 10, 2015, 4:21 a.m. UTC
Until now, ovn-northd has only set up flows for logical switches.  With the
arrival of logical routers, it needs to set up flows for them too.  The
stages within logical routers are completely different from those for
logical switches, so this prepares for that by adding logic for identifying
those stages.

Signed-off-by: Ben Pfaff <blp@nicira.com>
---
 ovn/northd/ovn-northd.c | 199 +++++++++++++++++++++++++++++-------------------
 1 file changed, 119 insertions(+), 80 deletions(-)

Comments

Justin Pettit Oct. 16, 2015, 1:59 a.m. UTC | #1
> On Oct 9, 2015, at 9:21 PM, Ben Pfaff <blp@nicira.com> wrote:
> 
> Until now, ovn-northd has only set up flows for logical switches.  With the
> arrival of logical routers, it needs to set up flows for them too.  The
> stages within logical routers are completely different from those for
> logical switches, so this prepares for that by adding logic for identifying
> those stages.
> 
> Signed-off-by: Ben Pfaff <blp@nicira.com>

The next patch is the big one!

http://i.imgur.com/7drHiqr.gif

Unfortunately, I gotta take a break to get dinner.  (Plus, merge my changes so I don't have to deal with the conflicts. ;-) )

Acked-by: Justin Pettit <jpettit@nicira.com>

--Justin
Ben Pfaff Oct. 16, 2015, 8:57 p.m. UTC | #2
On Thu, Oct 15, 2015 at 06:59:19PM -0700, Justin Pettit wrote:
> 
> > On Oct 9, 2015, at 9:21 PM, Ben Pfaff <blp@nicira.com> wrote:
> > 
> > Until now, ovn-northd has only set up flows for logical switches.  With the
> > arrival of logical routers, it needs to set up flows for them too.  The
> > stages within logical routers are completely different from those for
> > logical switches, so this prepares for that by adding logic for identifying
> > those stages.
> > 
> > Signed-off-by: Ben Pfaff <blp@nicira.com>
> 
> The next patch is the big one!
> 
> http://i.imgur.com/7drHiqr.gif

I'll leave it to someone else to find a "Big One" GIF.

> Acked-by: Justin Pettit <jpettit@nicira.com>

Thanks!

Patch
diff mbox

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 647ed49..ac3b39e 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -53,37 +53,97 @@  static const char *ovnnb_db;
 static const char *ovnsb_db;
 
 static const char *default_db(void);
+
+/* Pipeline stages. */
 
+/* The two pipelines in an OVN logical flow table. */
+enum ovn_pipeline {
+    P_IN,                       /* Ingress pipeline. */
+    P_OUT                       /* Egress pipeline. */
+};
 
-/* Ingress pipeline stages.
- *
- * These must be listed in the order that the stages will be executed. */
-#define INGRESS_STAGES                         \
-    INGRESS_STAGE(PORT_SEC, port_sec)          \
-    INGRESS_STAGE(ACL, acl)                    \
-    INGRESS_STAGE(L2_LKUP, l2_lkup)
-
-enum ingress_stage {
-#define INGRESS_STAGE(NAME, STR) S_IN_##NAME,
-    INGRESS_STAGES
-#undef INGRESS_STAGE
-    INGRESS_N_STAGES
+/* The two purposes for which ovn-northd uses OVN logical datapaths. */
+enum ovn_datapath_type {
+    DP_SWITCH,                  /* OVN logical switch. */
+    DP_ROUTER                   /* OVN logical router. */
 };
 
-/* Egress pipeline stages.
+/* Returns an "enum ovn_stage" built from the arguments.
+ *
+ * (It's better to use ovn_stage_build() for type-safety reasons, but inline
+ * functions can't be used in enums or switch cases.) */
+#define OVN_STAGE_BUILD(DP_TYPE, PIPELINE, TABLE) \
+    (((DP_TYPE) << 9) | ((PIPELINE) << 8) | (TABLE))
+
+/* A stage within an OVN logical switch or router.
  *
- * These must be listed in the order that the stages will be executed. */
-#define EGRESS_STAGES                         \
-    EGRESS_STAGE(ACL, acl)                    \
-    EGRESS_STAGE(PORT_SEC, port_sec)
-
-enum egress_stage {
-#define EGRESS_STAGE(NAME, STR) S_OUT_##NAME,
-    EGRESS_STAGES
-#undef EGRESS_STAGE
-    EGRESS_N_STAGES
+ * An "enum ovn_stage" indicates whether the stage is part of a logical switch
+ * or router, whether the stage is part of the ingress or egress pipeline, and
+ * the table within that pipeline.  The first three components are combined to
+ * form the stage's full name, e.g. S_SWITCH_IN_PORT_SEC,
+ * S_ROUTER_OUT_DELIVERY. */
+enum ovn_stage {
+#define PIPELINE_STAGES                                                 \
+    /* Logical switch ingress stages. */                                \
+    PIPELINE_STAGE(SWITCH, IN,  PORT_SEC,    0, "switch_in_port_sec")   \
+    PIPELINE_STAGE(SWITCH, IN,  ACL,         1, "switch_in_acl")        \
+    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,     2, "switch_in_l2_lkup")    \
+                                                                        \
+    /* Logical switch egress stages. */                                 \
+    PIPELINE_STAGE(SWITCH, OUT, ACL,         0, "switch_out_acl")       \
+    PIPELINE_STAGE(SWITCH, OUT, PORT_SEC,    1, "switch_out_port_sec")  \
+                                                                        \
+    /* Logical router ingress stages. */                                \
+    PIPELINE_STAGE(ROUTER, IN,  ADMISSION,   0, "router_in_admission")  \
+    PIPELINE_STAGE(ROUTER, IN,  IP_INPUT,    1, "router_in_ip_input")   \
+    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,  2, "router_in_ip_routing") \
+    PIPELINE_STAGE(ROUTER, IN,  ARP,         3, "router_in_arp")        \
+                                                                        \
+    /* Logical router egress stages. */                                 \
+    PIPELINE_STAGE(ROUTER, OUT, DELIVERY,    0, "router_out_delivery")
+
+#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME)   \
+    S_##DP_TYPE##_##PIPELINE##_##STAGE                          \
+        = OVN_STAGE_BUILD(DP_##DP_TYPE, P_##PIPELINE, TABLE),
+    PIPELINE_STAGES
+#undef PIPELINE_STAGE
 };
 
+/* Returns an "enum ovn_stage" built from the arguments. */
+static enum ovn_stage
+ovn_stage_build(enum ovn_datapath_type dp_type, enum ovn_pipeline pipeline,
+                uint8_t table)
+{
+    return OVN_STAGE_BUILD(dp_type, pipeline, table);
+}
+
+/* Returns the pipeline to which 'stage' belongs. */
+static enum ovn_pipeline
+ovn_stage_get_pipeline(enum ovn_stage stage)
+{
+    return (stage >> 8) & 1;
+}
+
+/* Returns the table to which 'stage' belongs. */
+static uint8_t
+ovn_stage_get_table(enum ovn_stage stage)
+{
+    return stage & 0xff;
+}
+
+/* Returns a string name for 'stage'. */
+static const char *
+ovn_stage_to_str(enum ovn_stage stage)
+{
+    switch (stage) {
+#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME)       \
+        case S_##DP_TYPE##_##PIPELINE##_##STAGE: return NAME;
+    PIPELINE_STAGES
+#undef PIPELINE_STAGE
+        default: return "<unknown>";
+    }
+}
+
 static void
 usage(void)
 {
@@ -584,8 +644,7 @@  struct ovn_lflow {
     struct hmap_node hmap_node;
 
     struct ovn_datapath *od;
-    enum ovn_pipeline { P_IN, P_OUT } pipeline;
-    uint8_t table_id;
+    enum ovn_stage stage;
     uint16_t priority;
     char *match;
     char *actions;
@@ -595,7 +654,7 @@  static size_t
 ovn_lflow_hash(const struct ovn_lflow *lflow)
 {
     size_t hash = uuid_hash(&lflow->od->key);
-    hash = hash_2words((lflow->table_id << 16) | lflow->priority, hash);
+    hash = hash_2words((lflow->stage << 16) | lflow->priority, hash);
     hash = hash_string(lflow->match, hash);
     return hash_string(lflow->actions, hash);
 }
@@ -604,8 +663,7 @@  static bool
 ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
 {
     return (a->od == b->od
-            && a->pipeline == b->pipeline
-            && a->table_id == b->table_id
+            && a->stage == b->stage
             && a->priority == b->priority
             && !strcmp(a->match, b->match)
             && !strcmp(a->actions, b->actions));
@@ -613,56 +671,35 @@  ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
 
 static void
 ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
-              enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
+              enum ovn_stage stage, uint16_t priority,
               char *match, char *actions)
 {
     lflow->od = od;
-    lflow->pipeline = pipeline;
-    lflow->table_id = table_id;
+    lflow->stage = stage;
     lflow->priority = priority;
     lflow->match = match;
     lflow->actions = actions;
 }
 
-static const char *
-ingress_stage_to_str(int stage) {
-    switch (stage) {
-#define INGRESS_STAGE(NAME, STR) case S_IN_##NAME: return #STR;
-    INGRESS_STAGES
-#undef INGRESS_STAGE
-        default: return "<unknown>";
-    }
-}
-
-static const char *
-egress_stage_to_str(int stage) {
-    switch (stage) {
-#define EGRESS_STAGE(NAME, STR) case S_OUT_##NAME: return #STR;
-    EGRESS_STAGES
-#undef EGRESS_STAGE
-        default: return "<unknown>";
-    }
-}
-
 /* Adds a row with the specified contents to the Logical_Flow table. */
 static void
 ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
-              enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
+              enum ovn_stage stage, uint16_t priority,
               const char *match, const char *actions)
 {
     struct ovn_lflow *lflow = xmalloc(sizeof *lflow);
-    ovn_lflow_init(lflow, od, pipeline, table_id, priority,
+    ovn_lflow_init(lflow, od, stage, priority,
                    xstrdup(match), xstrdup(actions));
     hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow));
 }
 
 static struct ovn_lflow *
 ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od,
-               enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
+               enum ovn_stage stage, uint16_t priority,
                const char *match, const char *actions)
 {
     struct ovn_lflow target;
-    ovn_lflow_init(&target, od, pipeline, table_id, priority,
+    ovn_lflow_init(&target, od, stage, priority,
                    CONST_CAST(char *, match), CONST_CAST(char *, actions));
 
     struct ovn_lflow *lflow;
@@ -738,11 +775,11 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
     struct ovn_datapath *od;
     HMAP_FOR_EACH (od, key_node, datapaths) {
         /* Logical VLANs not supported. */
-        ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "vlan.present",
+        ovn_lflow_add(&lflows, od, S_SWITCH_IN_PORT_SEC, 100, "vlan.present",
                       "drop;");
 
         /* Broadcast/multicast source address is invalid. */
-        ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "eth.src[40]",
+        ovn_lflow_add(&lflows, od, S_SWITCH_IN_PORT_SEC, 100, "eth.src[40]",
                       "drop;");
 
         /* Port security flows have priority 50 (see below) and will continue
@@ -764,7 +801,7 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
         build_port_security("eth.src",
                             op->nb->port_security, op->nb->n_port_security,
                             &match);
-        ovn_lflow_add(&lflows, op->od, P_IN, S_IN_PORT_SEC, 50,
+        ovn_lflow_add(&lflows, op->od, S_SWITCH_IN_PORT_SEC, 50,
                       ds_cstr(&match), "next;");
         ds_destroy(&match);
     }
@@ -782,12 +819,12 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
             action = (!strcmp(acl->action, "allow") ||
                       !strcmp(acl->action, "allow-related"))
                 ? "next;" : "drop;";
-            ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, acl->priority,
+            ovn_lflow_add(&lflows, od, S_SWITCH_IN_ACL, acl->priority,
                           acl->match, action);
         }
     }
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, 0, "1", "next;");
+        ovn_lflow_add(&lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;");
     }
 
     /* Ingress table 2: Destination lookup, broadcast and multicast handling
@@ -798,7 +835,7 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
         }
     }
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 100, "eth.mcast",
+        ovn_lflow_add(&lflows, od, S_SWITCH_IN_L2_LKUP, 100, "eth.mcast",
                       "outport = \""MC_FLOOD"\"; output;");
     }
 
@@ -817,7 +854,7 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
                 ds_put_cstr(&actions, "outport = ");
                 json_string_escape(op->nb->name, &actions);
                 ds_put_cstr(&actions, "; output;");
-                ovn_lflow_add(&lflows, op->od, P_IN, S_IN_L2_LKUP, 50,
+                ovn_lflow_add(&lflows, op->od, S_SWITCH_IN_L2_LKUP, 50,
                               ds_cstr(&match), ds_cstr(&actions));
                 ds_destroy(&actions);
                 ds_destroy(&match);
@@ -839,7 +876,7 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
     /* Ingress table 2: Destination lookup for unknown MACs (priority 0). */
     HMAP_FOR_EACH (od, key_node, datapaths) {
         if (od->has_unknown) {
-            ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 0, "1",
+            ovn_lflow_add(&lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
                           "outport = \""MC_UNKNOWN"\"; output;");
         }
     }
@@ -857,18 +894,18 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
             action = (!strcmp(acl->action, "allow") ||
                       !strcmp(acl->action, "allow-related"))
                 ? "next;" : "drop;";
-            ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, acl->priority,
+            ovn_lflow_add(&lflows, od, S_SWITCH_OUT_ACL, acl->priority,
                           acl->match, action);
         }
     }
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, 0, "1", "next;");
+        ovn_lflow_add(&lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;");
     }
 
     /* Egress table 1: Egress port security multicast/broadcast (priority
      * 100). */
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_OUT, S_OUT_PORT_SEC, 100, "eth.mcast",
+        ovn_lflow_add(&lflows, od, S_SWITCH_OUT_PORT_SEC, 100, "eth.mcast",
                       "output;");
     }
 
@@ -888,10 +925,10 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
             build_port_security("eth.dst",
                                 op->nb->port_security, op->nb->n_port_security,
                                 &match);
-            ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 50,
+            ovn_lflow_add(&lflows, op->od, S_SWITCH_OUT_PORT_SEC, 50,
                           ds_cstr(&match), "output;");
         } else {
-            ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 150,
+            ovn_lflow_add(&lflows, op->od, S_SWITCH_OUT_PORT_SEC, 150,
                           ds_cstr(&match), "drop;");
         }
 
@@ -908,10 +945,12 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
             continue;
         }
 
+        enum ovn_datapath_type dp_type = DP_SWITCH; /* XXX no routers yet. */
+        enum ovn_pipeline pipeline
+            = !strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT;
         struct ovn_lflow *lflow = ovn_lflow_find(
-            &lflows, od, (!strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT),
-            sbflow->table_id, sbflow->priority,
-            sbflow->match, sbflow->actions);
+            &lflows, od, ovn_stage_build(dp_type, pipeline, sbflow->table_id),
+            sbflow->priority, sbflow->match, sbflow->actions);
         if (lflow) {
             ovn_lflow_destroy(&lflows, lflow);
         } else {
@@ -920,20 +959,20 @@  build_lflows(struct northd_context *ctx, struct hmap *datapaths,
     }
     struct ovn_lflow *lflow, *next_lflow;
     HMAP_FOR_EACH_SAFE (lflow, next_lflow, hmap_node, &lflows) {
+        enum ovn_pipeline pipeline = ovn_stage_get_pipeline(lflow->stage);
+        uint8_t table = ovn_stage_get_table(lflow->stage);
+
         sbflow = sbrec_logical_flow_insert(ctx->ovnsb_txn);
         sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
-        sbrec_logical_flow_set_pipeline(
-            sbflow, lflow->pipeline == P_IN ? "ingress" : "egress");
-        sbrec_logical_flow_set_table_id(sbflow, lflow->table_id);
+        sbrec_logical_flow_set_pipeline(sbflow,
+                                        pipeline ? "ingress" : "egress");
+        sbrec_logical_flow_set_table_id(sbflow, table);
         sbrec_logical_flow_set_priority(sbflow, lflow->priority);
         sbrec_logical_flow_set_match(sbflow, lflow->match);
         sbrec_logical_flow_set_actions(sbflow, lflow->actions);
 
-        const struct smap ids = SMAP_CONST1(
-            &ids, "stage-name",
-            (lflow->pipeline == P_IN
-             ? ingress_stage_to_str(lflow->table_id)
-             : egress_stage_to_str(lflow->table_id)));
+        const struct smap ids = SMAP_CONST1(&ids, "stage-name",
+                                            ovn_stage_to_str(lflow->stage));
         sbrec_logical_flow_set_external_ids(sbflow, &ids);
 
         ovn_lflow_destroy(&lflows, lflow);