lib/daemon: support --user option for all OVS daemon
[cascardo/ovs.git] / ovn / northd / ovn-northd.c
index cf8e222..e698907 100644 (file)
@@ -54,6 +54,36 @@ static const char *ovnsb_db;
 
 static const char *default_db(void);
 
+
+/* 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
+};
+
+/* Egress pipeline stages.
+ *
+ * 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
+};
+
 static void
 usage(void)
 {
@@ -280,12 +310,10 @@ build_datapaths(struct northd_context *ctx, struct hmap *datapaths)
 
             od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
 
-            struct smap external_ids = SMAP_INITIALIZER(&external_ids);
             char uuid_s[UUID_LEN + 1];
             sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->nb->header_.uuid));
-            smap_add(&external_ids, "logical-switch", uuid_s);
-            sbrec_datapath_binding_set_external_ids(od->sb, &external_ids);
-            smap_destroy(&external_ids);
+            const struct smap id = SMAP_CONST1(&id, "logical-switch", uuid_s);
+            sbrec_datapath_binding_set_external_ids(od->sb, &id);
 
             sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
         }
@@ -397,6 +425,8 @@ join_logical_ports(struct northd_context *ctx,
 static void
 ovn_port_update_sbrec(const struct ovn_port *op)
 {
+    sbrec_port_binding_set_type(op->sb, op->nb->type);
+    sbrec_port_binding_set_options(op->sb, &op->nb->options);
     sbrec_port_binding_set_datapath(op->sb, op->od->sb);
     sbrec_port_binding_set_parent_port(op->sb, op->nb->parent_name);
     sbrec_port_binding_set_tag(op->sb, op->nb->tag, op->nb->n_tag);
@@ -594,6 +624,26 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
     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,
@@ -650,9 +700,9 @@ build_port_security(const char *eth_addr_field,
 
     size_t n = 0;
     for (size_t i = 0; i < n_port_security; i++) {
-        uint8_t ea[ETH_ADDR_LEN];
+        struct eth_addr ea;
 
-        if (eth_addr_from_string(port_security[i], ea)) {
+        if (eth_addr_from_string(port_security[i], &ea)) {
             ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
             ds_put_char(match, ' ');
             n++;
@@ -678,6 +728,9 @@ static void
 build_lflows(struct northd_context *ctx, struct hmap *datapaths,
              struct hmap *ports)
 {
+    /* This flow table structure is documented in ovn-northd(8), so please
+     * update ovn-northd.8.xml if you change anything. */
+
     struct hmap lflows = HMAP_INITIALIZER(&lflows);
     struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
 
@@ -685,33 +738,59 @@ 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, 0, 100, "vlan.present", "drop;");
+        ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "vlan.present",
+                      "drop;");
 
         /* Broadcast/multicast source address is invalid. */
-        ovn_lflow_add(&lflows, od, P_IN, 0, 100, "eth.src[40]", "drop;");
+        ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "eth.src[40]",
+                      "drop;");
 
         /* Port security flows have priority 50 (see below) and will continue
          * to the next table if packet source is acceptable. */
-
-        /* Otherwise drop the packet. */
-        ovn_lflow_add(&lflows, od, P_IN, 0, 0, "1", "drop;");
     }
 
     /* Ingress table 0: Ingress port security (priority 50). */
     struct ovn_port *op;
     HMAP_FOR_EACH (op, key_node, ports) {
+        if (!lport_is_enabled(op->nb)) {
+            /* Drop packets from disabled logical ports (since logical flow
+             * tables are default-drop). */
+            continue;
+        }
+
         struct ds match = DS_EMPTY_INITIALIZER;
         ds_put_cstr(&match, "inport == ");
         json_string_escape(op->key, &match);
         build_port_security("eth.src",
                             op->nb->port_security, op->nb->n_port_security,
                             &match);
-        ovn_lflow_add(&lflows, op->od, P_IN, 0, 50, ds_cstr(&match),
-                      lport_is_enabled(op->nb) ? "next;" : "drop;");
+        ovn_lflow_add(&lflows, op->od, P_IN, S_IN_PORT_SEC, 50,
+                      ds_cstr(&match), "next;");
         ds_destroy(&match);
     }
 
-    /* Ingress table 1: Destination lookup, broadcast and multicast handling
+    /* Ingress table 1: ACLs (any priority). */
+    HMAP_FOR_EACH (od, key_node, datapaths) {
+        for (size_t i = 0; i < od->nb->n_acls; i++) {
+            const struct nbrec_acl *acl = od->nb->acls[i];
+            const char *action;
+
+            if (strcmp(acl->direction, "from-lport")) {
+                continue;
+            }
+
+            action = (!strcmp(acl->action, "allow") ||
+                      !strcmp(acl->action, "allow-related"))
+                ? "next;" : "drop;";
+            ovn_lflow_add(&lflows, od, P_IN, S_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;");
+    }
+
+    /* Ingress table 2: Destination lookup, broadcast and multicast handling
      * (priority 100). */
     HMAP_FOR_EACH (op, key_node, ports) {
         if (lport_is_enabled(op->nb)) {
@@ -719,16 +798,16 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
         }
     }
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_IN, 1, 100, "eth.dst[40]",
+        ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 100, "eth.dst[40]",
                       "outport = \""MC_FLOOD"\"; output;");
     }
 
-    /* Ingress table 1: Destination lookup, unicast handling (priority 50), */
+    /* Ingress table 2: Destination lookup, unicast handling (priority 50), */
     HMAP_FOR_EACH (op, key_node, ports) {
         for (size_t i = 0; i < op->nb->n_macs; i++) {
-            uint8_t mac[ETH_ADDR_LEN];
+            struct eth_addr mac;
 
-            if (eth_addr_from_string(op->nb->macs[i], mac)) {
+            if (eth_addr_from_string(op->nb->macs[i], &mac)) {
                 struct ds match, actions;
 
                 ds_init(&match);
@@ -738,13 +817,15 @@ 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, 1, 50,
+                ovn_lflow_add(&lflows, op->od, P_IN, S_IN_L2_LKUP, 50,
                               ds_cstr(&match), ds_cstr(&actions));
                 ds_destroy(&actions);
                 ds_destroy(&match);
             } else if (!strcmp(op->nb->macs[i], "unknown")) {
-                ovn_multicast_add(&mcgroups, &mc_unknown, op);
-                op->od->has_unknown = true;
+                if (lport_is_enabled(op->nb)) {
+                    ovn_multicast_add(&mcgroups, &mc_unknown, op);
+                    op->od->has_unknown = true;
+                }
             } else {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
@@ -754,10 +835,10 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
         }
     }
 
-    /* Ingress table 1: Destination lookup for unknown MACs (priority 0). */
+    /* 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, 1, 0, "1",
+            ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 0, "1",
                           "outport = \""MC_UNKNOWN"\"; output;");
         }
     }
@@ -768,36 +849,50 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
             const struct nbrec_acl *acl = od->nb->acls[i];
             const char *action;
 
+            if (strcmp(acl->direction, "to-lport")) {
+                continue;
+            }
+
             action = (!strcmp(acl->action, "allow") ||
                       !strcmp(acl->action, "allow-related"))
                 ? "next;" : "drop;";
-            ovn_lflow_add(&lflows, od, P_OUT, 0, acl->priority, acl->match,
-                          action);
+            ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, acl->priority,
+                          acl->match, action);
         }
     }
     HMAP_FOR_EACH (od, key_node, datapaths) {
-        ovn_lflow_add(&lflows, od, P_OUT, 0, 0, "1", "next;");
+        ovn_lflow_add(&lflows, od, P_OUT, S_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, 1, 100, "eth.dst[40]", "output;");
+        ovn_lflow_add(&lflows, od, P_OUT, S_OUT_PORT_SEC, 100, "eth.dst[40]",
+                      "output;");
     }
 
-    /* Egress table 1: Egress port security (priority 50). */
+    /* Egress table 1: Egress port security (priorities 50 and 150).
+     *
+     * Priority 50 rules implement port security for enabled logical port.
+     *
+     * Priority 150 rules drop packets to disabled logical ports, so that they
+     * don't even receive multicast or broadcast packets. */
     HMAP_FOR_EACH (op, key_node, ports) {
         struct ds match;
 
         ds_init(&match);
         ds_put_cstr(&match, "outport == ");
         json_string_escape(op->key, &match);
-        build_port_security("eth.dst",
-                            op->nb->port_security, op->nb->n_port_security,
-                            &match);
-
-        ovn_lflow_add(&lflows, op->od, P_OUT, 1, 50, ds_cstr(&match),
-                      lport_is_enabled(op->nb) ? "output;" : "drop;");
+        if (lport_is_enabled(op->nb)) {
+            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,
+                          ds_cstr(&match), "output;");
+        } else {
+            ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 150,
+                          ds_cstr(&match), "drop;");
+        }
 
         ds_destroy(&match);
     }
@@ -832,6 +927,14 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
         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)));
+        sbrec_logical_flow_set_external_ids(sbflow, &ids);
+
         ovn_lflow_destroy(&lflows, lflow);
     }
     hmap_destroy(&lflows);
@@ -952,14 +1055,16 @@ ovnsb_db_changed(struct northd_context *ctx)
     hmap_destroy(&lports_hmap);
 }
 \f
+
+static char *default_db_;
+
 static const char *
 default_db(void)
 {
-    static char *def;
-    if (!def) {
-        def = xasprintf("unix:%s/db.sock", ovs_rundir());
+    if (!default_db_) {
+        default_db_ = xasprintf("unix:%s/db.sock", ovs_rundir());
     }
-    return def;
+    return default_db_;
 }
 
 static void
@@ -1057,11 +1162,12 @@ main(int argc, char *argv[])
 
     fatal_ignore_sigpipe();
     set_program_name(argv[0]);
+    service_start(&argc, &argv);
     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
     parse_options(argc, argv);
 
-    daemonize_start();
+    daemonize_start(false);
 
     retval = unixctl_server_create(NULL, &unixctl);
     if (retval) {
@@ -1247,11 +1353,17 @@ main(int argc, char *argv[])
             }
             poll_block();
         }
+        if (should_service_stop()) {
+            exiting = true;
+        }
     }
 
     unixctl_server_destroy(unixctl);
     ovsdb_idl_destroy(ovnsb_idl);
     ovsdb_idl_destroy(ovnnb_idl);
+    service_stop();
+
+    free(default_db_);
 
     exit(res);
 }