rename superclass member to up in netdev-tunnel
[sliver-openvswitch.git] / vswitchd / bridge.c
index 6dc3db2..cf26e87 100644 (file)
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include "bfd.h"
 #include "bitmap.h"
 #include "bond.h"
 #include "cfm.h"
@@ -146,6 +147,23 @@ static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges);
 /* OVSDB IDL used to obtain configuration. */
 static struct ovsdb_idl *idl;
 
+/* We want to complete daemonization, fully detaching from our parent process,
+ * only after we have completed our initial configuration, committed our state
+ * to the database, and received confirmation back from the database server
+ * that it applied the commit.  This allows our parent process to know that,
+ * post-detach, ephemeral fields such as datapath-id and ofport are very likely
+ * to have already been filled in.  (It is only "very likely" rather than
+ * certain because there is always a slim possibility that the transaction will
+ * fail or that some other client has added new bridges, ports, etc. while
+ * ovs-vswitchd was configuring using an old configuration.)
+ *
+ * We only need to do this once for our initial configuration at startup, so
+ * 'initial_config_done' tracks whether we've already done it.  While we are
+ * waiting for a response to our commit, 'daemonize_txn' tracks the transaction
+ * itself and is otherwise NULL. */
+static bool initial_config_done;
+static struct ovsdb_idl_txn *daemonize_txn;
+
 /* Most recently processed IDL sequence number. */
 static unsigned int idl_seqno;
 
@@ -183,6 +201,7 @@ static void bridge_configure_netflow(struct bridge *);
 static void bridge_configure_forward_bpdu(struct bridge *);
 static void bridge_configure_mac_table(struct bridge *);
 static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
+static void bridge_configure_ipfix(struct bridge *);
 static void bridge_configure_stp(struct bridge *);
 static void bridge_configure_tables(struct bridge *);
 static void bridge_configure_dp_desc(struct bridge *);
@@ -355,6 +374,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_health);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_bfd_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
     ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
 
@@ -371,8 +391,9 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_mirror_col_statistics);
 
     ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
-
     ovsdb_idl_omit(idl, &ovsrec_sflow_col_external_ids);
+    ovsdb_idl_omit(idl, &ovsrec_ipfix_col_external_ids);
+    ovsdb_idl_omit(idl, &ovsrec_flow_sample_collector_set_col_external_ids);
 
     ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids);
     ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe);
@@ -586,6 +607,8 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
                 iface_configure_cfm(iface);
                 iface_configure_qos(iface, port->cfg->qos);
                 iface_set_mac(iface);
+                ofproto_port_set_bfd(br->ofproto, iface->ofp_port,
+                                     &iface->cfg->bfd);
             }
         }
         bridge_configure_mirrors(br);
@@ -595,21 +618,13 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
         bridge_configure_remotes(br, managers, n_managers);
         bridge_configure_netflow(br);
         bridge_configure_sflow(br, &sflow_bridge_number);
+        bridge_configure_ipfix(br);
         bridge_configure_stp(br);
         bridge_configure_tables(br);
         bridge_configure_dp_desc(br);
     }
     free(managers);
 
-    if (done) {
-        /* ovs-vswitchd has completed initialization, so allow the process that
-         * forked us to exit successfully. */
-        daemonize_complete();
-        reconfiguring = false;
-
-        VLOG_INFO_ONCE("%s (Open vSwitch) %s", program_name, VERSION);
-    }
-
     return done;
 }
 
@@ -936,6 +951,79 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
     sset_destroy(&oso.targets);
 }
 
+/* Set IPFIX configuration on 'br'. */
+static void
+bridge_configure_ipfix(struct bridge *br)
+{
+    const struct ovsrec_ipfix *be_cfg = br->cfg->ipfix;
+    const struct ovsrec_flow_sample_collector_set *fe_cfg;
+    struct ofproto_ipfix_bridge_exporter_options be_opts;
+    struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL;
+    size_t n_fe_opts = 0;
+
+    OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
+        if (fe_cfg->bridge == br->cfg) {
+            n_fe_opts++;
+        }
+    }
+
+    if (!be_cfg && n_fe_opts == 0) {
+        ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
+        return;
+    }
+
+    if (be_cfg) {
+        memset(&be_opts, 0, sizeof be_opts);
+
+        sset_init(&be_opts.targets);
+        sset_add_array(&be_opts.targets, be_cfg->targets, be_cfg->n_targets);
+
+        if (be_cfg->sampling) {
+            be_opts.sampling_rate = *be_cfg->sampling;
+        } else {
+            be_opts.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
+        }
+        if (be_cfg->obs_domain_id) {
+            be_opts.obs_domain_id = *be_cfg->obs_domain_id;
+        }
+        if (be_cfg->obs_point_id) {
+            be_opts.obs_point_id = *be_cfg->obs_point_id;
+        }
+    }
+
+    if (n_fe_opts > 0) {
+        struct ofproto_ipfix_flow_exporter_options *opts;
+        fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts);
+        opts = fe_opts;
+        OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
+            if (fe_cfg->bridge == br->cfg) {
+                opts->collector_set_id = fe_cfg->id;
+                sset_init(&opts->targets);
+                sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
+                               fe_cfg->ipfix->n_targets);
+                opts++;
+            }
+        }
+    }
+
+    ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts,
+                      n_fe_opts);
+
+    if (be_cfg) {
+        sset_destroy(&be_opts.targets);
+    }
+
+    if (n_fe_opts > 0) {
+        struct ofproto_ipfix_flow_exporter_options *opts = fe_opts;
+        size_t i;
+        for (i = 0; i < n_fe_opts; i++) {
+            sset_destroy(&opts->targets);
+            opts++;
+        }
+        free(fe_opts);
+    }
+}
+
 static void
 port_configure_stp(const struct ofproto *ofproto, struct port *port,
                    struct ofproto_port_stp_settings *port_s,
@@ -1361,7 +1449,7 @@ iface_do_create(const struct bridge *br,
 
     if ((port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter"))
         || iface_is_internal(iface_cfg, br->cfg)) {
-        netdev_turn_flags_on(netdev, NETDEV_UP, true);
+        netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
     }
 
     *netdevp = netdev;
@@ -1814,11 +1902,12 @@ iface_refresh_stats(struct iface *iface)
     IFACE_STAT(rx_crc_errors,   "rx_crc_err")   \
     IFACE_STAT(collisions,      "collisions")
 
-#define IFACE_STAT(MEMBER, NAME) NAME,
-    static char *keys[] = { IFACE_STATS };
+#define IFACE_STAT(MEMBER, NAME) + 1
+    enum { N_IFACE_STATS = IFACE_STATS };
 #undef IFACE_STAT
-    int64_t values[ARRAY_SIZE(keys)];
-    int i;
+    int64_t values[N_IFACE_STATS];
+    char *keys[N_IFACE_STATS];
+    int n;
 
     struct netdev_stats stats;
 
@@ -1830,15 +1919,19 @@ iface_refresh_stats(struct iface *iface)
      * all-1s, and we will deal with that correctly below. */
     netdev_get_stats(iface->netdev, &stats);
 
-    /* Copy statistics into values[] array. */
-    i = 0;
-#define IFACE_STAT(MEMBER, NAME) values[i++] = stats.MEMBER;
+    /* Copy statistics into keys[] and values[]. */
+    n = 0;
+#define IFACE_STAT(MEMBER, NAME)                \
+    if (stats.MEMBER != UINT64_MAX) {           \
+        keys[n] = NAME;                         \
+        values[n] = stats.MEMBER;               \
+        n++;                                    \
+    }
     IFACE_STATS;
 #undef IFACE_STAT
-    ovs_assert(i == ARRAY_SIZE(keys));
+    ovs_assert(n <= N_IFACE_STATS);
 
-    ovsrec_interface_set_statistics(iface->cfg, keys, values,
-                                    ARRAY_SIZE(keys));
+    ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
 #undef IFACE_STATS
 }
 
@@ -2086,6 +2179,7 @@ instant_stats_run(void)
 
             HMAP_FOR_EACH (iface, name_node, &br->iface_by_name) {
                 enum netdev_flags flags;
+                struct smap smap;
                 const char *link_state;
                 int64_t link_resets;
                 int current, error;
@@ -2118,6 +2212,13 @@ instant_stats_run(void)
                 ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1);
 
                 iface_refresh_cfm_stats(iface);
+
+                smap_init(&smap);
+                if (!ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port,
+                                                 &smap)) {
+                    ovsrec_interface_set_bfd_status(iface->cfg, &smap);
+                    smap_destroy(&smap);
+                }
             }
         }
     }
@@ -2190,11 +2291,16 @@ bridge_run(void)
             struct bridge *br, *next_br;
 
             VLOG_ERR_RL(&rl, "another ovs-vswitchd process is running, "
-                        "disabling this process until it goes away");
+                        "disabling this process (pid %ld) until it goes away",
+                        (long int) getpid());
 
             HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
                 bridge_destroy(br);
             }
+            /* Since we will not be running system_stats_run() in this process
+             * with the current situation of multiple ovs-vswitchd daemons,
+             * disable system stats collection. */
+            system_stats_enable(false);
             return;
         } else if (!ovsdb_idl_has_lock(idl)) {
             return;
@@ -2261,15 +2367,25 @@ bridge_run(void)
     }
 
     if (reconfiguring) {
-        if (cfg) {
-            if (!reconf_txn) {
-                reconf_txn = ovsdb_idl_txn_create(idl);
-            }
-            if (bridge_reconfigure_continue(cfg)) {
+        if (!reconf_txn) {
+            reconf_txn = ovsdb_idl_txn_create(idl);
+        }
+
+        if (bridge_reconfigure_continue(cfg ? cfg : &null_cfg)) {
+            reconfiguring = false;
+
+            if (cfg) {
                 ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
             }
-        } else {
-            bridge_reconfigure_continue(&null_cfg);
+
+            /* If we are completing our initial configuration for this run
+             * of ovs-vswitchd, then keep the transaction around to monitor
+             * it for completion. */
+            if (!initial_config_done) {
+                initial_config_done = true;
+                daemonize_txn = reconf_txn;
+                reconf_txn = NULL;
+            }
         }
     }
 
@@ -2279,6 +2395,20 @@ bridge_run(void)
         reconf_txn = NULL;
     }
 
+    if (daemonize_txn) {
+        enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(daemonize_txn);
+        if (status != TXN_INCOMPLETE) {
+            ovsdb_idl_txn_destroy(daemonize_txn);
+            daemonize_txn = NULL;
+
+            /* ovs-vswitchd has completed initialization, so allow the
+             * process that forked us to exit successfully. */
+            daemonize_complete();
+
+            VLOG_INFO_ONCE("%s (Open vSwitch) %s", program_name, VERSION);
+        }
+    }
+
     /* Refresh interface and mirror stats if necessary. */
     if (time_msec() >= iface_stats_timer) {
         if (cfg) {
@@ -2322,6 +2452,9 @@ bridge_wait(void)
     const char *type;
 
     ovsdb_idl_wait(idl);
+    if (daemonize_txn) {
+        ovsdb_idl_txn_wait(daemonize_txn);
+    }
 
     if (reconfiguring) {
         poll_immediate_wake();
@@ -2759,7 +2892,7 @@ bridge_configure_local_iface_netdev(struct bridge *br,
 
     /* Bring up the local interface. */
     netdev = local_iface->netdev;
-    netdev_turn_flags_on(netdev, NETDEV_UP, true);
+    netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
 
     /* Configure the IP address and netmask. */
     if (!c->local_netmask