lib: Move vlog.h to <openvswitch/vlog.h>
[cascardo/ovs.git] / vswitchd / bridge.c
index 1060719..4d84732 100644 (file)
@@ -37,6 +37,7 @@
 #include "mcast-snooping.h"
 #include "meta-flow.h"
 #include "netdev.h"
+#include "nx-match.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "vlandev.h"
 #include "lib/vswitch-idl.h"
 #include "xenserver.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 #include "sflow_api.h"
 #include "vlan-bitmap.h"
+#include "packets.h"
 
 VLOG_DEFINE_THIS_MODULE(bridge);
 
@@ -72,7 +74,7 @@ struct iface {
      *
      * They are immutable: they never change between iface_create() and
      * iface_destroy(). */
-    struct list port_elem;      /* Element in struct port's "ifaces" list. */
+    struct ovs_list port_elem;  /* Element in struct port's "ifaces" list. */
     struct hmap_node name_node; /* In struct bridge's "iface_by_name" hmap. */
     struct hmap_node ofp_port_node; /* In struct bridge's "ifaces" hmap. */
     struct port *port;          /* Containing port. */
@@ -103,7 +105,7 @@ struct port {
 
     /* An ordinary bridge port has 1 interface.
      * A bridge port for bonding has at least 2 interfaces. */
-    struct list ifaces;         /* List of "struct iface"s. */
+    struct ovs_list ifaces;    /* List of "struct iface"s. */
 };
 
 struct bridge {
@@ -379,6 +381,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_version);
 
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_id);
+    ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_version);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_rstp_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_stp_enable);
@@ -389,6 +392,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_port_col_rstp_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_port_col_rstp_statistics);
     ovsdb_idl_omit_alert(idl, &ovsrec_port_col_statistics);
+    ovsdb_idl_omit_alert(idl, &ovsrec_port_col_bond_active_slave);
     ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
 
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
@@ -537,6 +541,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                                         OFPROTO_FLOW_LIMIT_DEFAULT));
     ofproto_set_max_idle(smap_get_int(&ovs_cfg->other_config, "max-idle",
                                       OFPROTO_MAX_IDLE_DEFAULT));
+    ofproto_set_n_dpdk_rxqs(smap_get_int(&ovs_cfg->other_config,
+                                         "n-dpdk-rxqs", 0));
+    ofproto_set_cpu_mask(smap_get(&ovs_cfg->other_config, "pmd-cpu-mask"));
 
     ofproto_set_threads(
         smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
@@ -589,6 +596,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                          ovs_strerror(error));
                 shash_destroy(&br->wanted_ports);
                 bridge_destroy(br);
+            } else {
+                /* Trigger storing datapath version. */
+                seq_change(connectivity_seq_get());
             }
         }
     }
@@ -1388,6 +1398,16 @@ port_configure_rstp(const struct ofproto *ofproto, struct port *port,
         port_s->priority = RSTP_DEFAULT_PORT_PRIORITY;
     }
 
+    config_str = smap_get(&port->cfg->other_config, "rstp-admin-p2p-mac");
+    if (config_str) {
+        port_s->admin_p2p_mac_state = strtoul(config_str, NULL, 0);
+    } else {
+        port_s->admin_p2p_mac_state = RSTP_ADMIN_P2P_MAC_FORCE_TRUE;
+    }
+
+    port_s->admin_port_state = smap_get_bool(&port->cfg->other_config,
+                                             "rstp-admin-port-state", true);
+
     port_s->admin_edge_port = smap_get_bool(&port->cfg->other_config,
                                             "rstp-port-admin-edge", false);
     port_s->auto_edge = smap_get_bool(&port->cfg->other_config,
@@ -2313,6 +2333,19 @@ iface_refresh_stats(struct iface *iface)
 #undef IFACE_STATS
 }
 
+static void
+br_refresh_datapath_info(struct bridge *br)
+{
+    const char *version;
+
+    version = (br->ofproto && br->ofproto->ofproto_class->get_datapath_version
+               ? br->ofproto->ofproto_class->get_datapath_version(br->ofproto)
+               : NULL);
+
+    ovsrec_bridge_set_datapath_version(br->cfg,
+                                       version ? version : "<unknown>");
+}
+
 static void
 br_refresh_stp_status(struct bridge *br)
 {
@@ -2433,7 +2466,7 @@ br_refresh_rstp_status(struct bridge *br)
     }
     smap_add_format(&smap, "rstp_bridge_id", RSTP_ID_FMT,
                     RSTP_ID_ARGS(status.bridge_id));
-    smap_add_format(&smap, "rstp_root_path_cost", "%d",
+    smap_add_format(&smap, "rstp_root_path_cost", "%"PRIu32,
                     status.root_path_cost);
     smap_add_format(&smap, "rstp_root_id", RSTP_ID_FMT,
                     RSTP_ID_ARGS(status.root_id));
@@ -2486,6 +2519,12 @@ port_refresh_rstp_status(struct port *port)
                     rstp_port_role_name(status.role));
     smap_add_format(&smap, "rstp_port_state", "%s",
                     rstp_state_name(status.state));
+    smap_add_format(&smap, "rstp_designated_bridge_id", RSTP_ID_FMT,
+                    RSTP_ID_ARGS(status.designated_bridge_id));
+    smap_add_format(&smap, "rstp_designated_port_id", RSTP_PORT_ID_FMT,
+                    status.designated_port_id);
+    smap_add_format(&smap, "rstp_designated_path_cost", "%"PRIu32,
+                    status.designated_path_cost);
 
     ovsrec_port_set_rstp_status(port->cfg, &smap);
     smap_destroy(&smap);
@@ -2501,6 +2540,26 @@ port_refresh_rstp_status(struct port *port)
             ARRAY_SIZE(int_values));
 }
 
+static void
+port_refresh_bond_status(struct port *port, bool force_update)
+{
+    uint8_t mac[ETH_ADDR_LEN];
+
+    /* Return if port is not a bond */
+    if (list_is_singleton(&port->ifaces)) {
+        return;
+    }
+
+    if (bond_get_changed_active_slave(port->name, mac, force_update)) {
+        struct ds mac_s;
+
+        ds_init(&mac_s);
+        ds_put_format(&mac_s, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+        ovsrec_port_set_bond_active_slave(port->cfg, ds_cstr(&mac_s));
+        ds_destroy(&mac_s);
+    }
+}
+
 static bool
 enable_system_stats(const struct ovsrec_open_vswitch *cfg)
 {
@@ -2590,6 +2649,145 @@ refresh_controller_status(void)
     ofproto_free_ofproto_controller_info(&info);
 }
 \f
+/* Update interface and mirror statistics if necessary. */
+static void
+run_stats_update(void)
+{
+    static struct ovsdb_idl_txn *stats_txn;
+    const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(idl);
+    int stats_interval;
+
+    if (!cfg) {
+        return;
+    }
+
+    /* Statistics update interval should always be greater than or equal to
+     * 5000 ms. */
+    stats_interval = MAX(smap_get_int(&cfg->other_config,
+                                      "stats-update-interval",
+                                      5000), 5000);
+    if (stats_timer_interval != stats_interval) {
+        stats_timer_interval = stats_interval;
+        stats_timer = LLONG_MIN;
+    }
+
+    if (time_msec() >= stats_timer) {
+        enum ovsdb_idl_txn_status status;
+
+        /* Rate limit the update.  Do not start a new update if the
+         * previous one is not done. */
+        if (!stats_txn) {
+            struct bridge *br;
+
+            stats_txn = ovsdb_idl_txn_create(idl);
+            HMAP_FOR_EACH (br, node, &all_bridges) {
+                struct port *port;
+                struct mirror *m;
+
+                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+                    struct iface *iface;
+
+                    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+                        iface_refresh_stats(iface);
+                    }
+                    port_refresh_stp_stats(port);
+                }
+                HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
+                    mirror_refresh_stats(m);
+                }
+            }
+            refresh_controller_status();
+        }
+
+        status = ovsdb_idl_txn_commit(stats_txn);
+        if (status != TXN_INCOMPLETE) {
+            stats_timer = time_msec() + stats_timer_interval;
+            ovsdb_idl_txn_destroy(stats_txn);
+            stats_txn = NULL;
+        }
+    }
+}
+
+/* Update bridge/port/interface status if necessary. */
+static void
+run_status_update(void)
+{
+    if (!status_txn) {
+        uint64_t seq;
+
+        /* Rate limit the update.  Do not start a new update if the
+         * previous one is not done. */
+        seq = seq_read(connectivity_seq_get());
+        if (seq != connectivity_seqno || status_txn_try_again) {
+            struct bridge *br;
+
+            connectivity_seqno = seq;
+            status_txn = ovsdb_idl_txn_create(idl);
+            HMAP_FOR_EACH (br, node, &all_bridges) {
+                struct port *port;
+
+                br_refresh_stp_status(br);
+                br_refresh_rstp_status(br);
+                br_refresh_datapath_info(br);
+                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+                    struct iface *iface;
+
+                    port_refresh_stp_status(port);
+                    port_refresh_rstp_status(port);
+                    port_refresh_bond_status(port, status_txn_try_again);
+                    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+                        iface_refresh_netdev_status(iface);
+                        iface_refresh_ofproto_status(iface);
+                    }
+                }
+            }
+        }
+    }
+
+    /* Commit the transaction and get the status. If the transaction finishes,
+     * then destroy the transaction. Otherwise, keep it so that we can check
+     * progress the next time that this function is called. */
+    if (status_txn) {
+        enum ovsdb_idl_txn_status status;
+
+        status = ovsdb_idl_txn_commit(status_txn);
+        if (status != TXN_INCOMPLETE) {
+            ovsdb_idl_txn_destroy(status_txn);
+            status_txn = NULL;
+
+            /* Sets the 'status_txn_try_again' if the transaction fails. */
+            if (status == TXN_SUCCESS || status == TXN_UNCHANGED) {
+                status_txn_try_again = false;
+            } else {
+                status_txn_try_again = true;
+            }
+        }
+    }
+}
+
+static void
+status_update_wait(void)
+{
+    /* This prevents the process from constantly waking up on
+     * connectivity seq, when there is no connection to ovsdb. */
+    if (!ovsdb_idl_has_lock(idl)) {
+        return;
+    }
+
+    /* If the 'status_txn' is non-null (transaction incomplete), waits for the
+     * transaction to complete.  If the status update to database needs to be
+     * run again (transaction fails), registers a timeout in
+     * 'STATUS_CHECK_AGAIN_MSEC'.  Otherwise, waits on the global connectivity
+     * sequence number. */
+    if (status_txn) {
+        ovsdb_idl_txn_wait(status_txn);
+    } else if (status_txn_try_again) {
+        poll_timer_wait_until(time_msec() + STATUS_CHECK_AGAIN_MSEC);
+    } else {
+        seq_wait(connectivity_seq_get(), connectivity_seqno);
+    }
+}
+
 static void
 bridge_run__(void)
 {
@@ -2618,8 +2816,6 @@ bridge_run(void)
     const struct ovsrec_open_vswitch *cfg;
 
     bool vlan_splinters_changed;
-    struct bridge *br;
-    int stats_interval;
 
     ovsrec_open_vswitch_init(&null_cfg);
 
@@ -2678,6 +2874,8 @@ bridge_run(void)
      * usage has changed. */
     vlan_splinters_changed = false;
     if (vlan_splinters_enabled_anywhere) {
+        struct bridge *br;
+
         HMAP_FOR_EACH (br, node, &all_bridges) {
             if (ofproto_has_vlan_usage_changed(br->ofproto)) {
                 vlan_splinters_changed = true;
@@ -2728,99 +2926,8 @@ bridge_run(void)
         }
     }
 
-    /* Statistics update interval should always be greater than or equal to
-     * 5000 ms. */
-    if (cfg) {
-        stats_interval = MAX(smap_get_int(&cfg->other_config,
-                                          "stats-update-interval",
-                                          5000), 5000);
-    } else {
-        stats_interval = 5000;
-    }
-    if (stats_timer_interval != stats_interval) {
-        stats_timer_interval = stats_interval;
-        stats_timer = LLONG_MIN;
-    }
-
-    /* Refresh interface and mirror stats if necessary. */
-    if (time_msec() >= stats_timer) {
-        if (cfg) {
-            struct ovsdb_idl_txn *txn;
-
-            txn = ovsdb_idl_txn_create(idl);
-            HMAP_FOR_EACH (br, node, &all_bridges) {
-                struct port *port;
-                struct mirror *m;
-
-                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
-                    struct iface *iface;
-
-                    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-                        iface_refresh_stats(iface);
-                    }
-
-                    port_refresh_stp_stats(port);
-                }
-
-                HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
-                    mirror_refresh_stats(m);
-                }
-
-            }
-            refresh_controller_status();
-            ovsdb_idl_txn_commit(txn);
-            ovsdb_idl_txn_destroy(txn); /* XXX */
-        }
-
-        stats_timer = time_msec() + stats_timer_interval;
-    }
-
-    if (!status_txn) {
-        uint64_t seq;
-
-        /* Check the need to update status. */
-        seq = seq_read(connectivity_seq_get());
-        if (seq != connectivity_seqno || status_txn_try_again) {
-            connectivity_seqno = seq;
-            status_txn = ovsdb_idl_txn_create(idl);
-            HMAP_FOR_EACH (br, node, &all_bridges) {
-                struct port *port;
-
-                br_refresh_stp_status(br);
-                br_refresh_rstp_status(br);
-                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
-                    struct iface *iface;
-
-                    port_refresh_stp_status(port);
-                    port_refresh_rstp_status(port);
-                    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-                        iface_refresh_netdev_status(iface);
-                        iface_refresh_ofproto_status(iface);
-                    }
-                }
-            }
-        }
-    }
-
-    if (status_txn) {
-        enum ovsdb_idl_txn_status status;
-
-        status = ovsdb_idl_txn_commit(status_txn);
-        /* Do not destroy "status_txn" if the transaction is
-         * "TXN_INCOMPLETE". */
-        if (status != TXN_INCOMPLETE) {
-            ovsdb_idl_txn_destroy(status_txn);
-            status_txn = NULL;
-
-            /* Sets the 'status_txn_try_again' if the transaction fails. */
-            if (status == TXN_SUCCESS || status == TXN_UNCHANGED) {
-                status_txn_try_again = false;
-            } else {
-                status_txn_try_again = true;
-            }
-        }
-    }
-
+    run_stats_update();
+    run_status_update();
     run_system_stats();
 }
 
@@ -2852,19 +2959,7 @@ bridge_wait(void)
         poll_timer_wait_until(stats_timer);
     }
 
-    /* If the 'status_txn' is non-null (transaction incomplete), waits for the
-     * transaction to complete.  If the status update to database needs to be
-     * run again (transaction fails), registers a timeout in
-     * 'STATUS_CHECK_AGAIN_MSEC'.  Otherwise, waits on the global connectivity
-     * sequence number. */
-    if (status_txn) {
-        ovsdb_idl_txn_wait(status_txn);
-    } else if (status_txn_try_again) {
-        poll_timer_wait_until(time_msec() + STATUS_CHECK_AGAIN_MSEC);
-    } else {
-        seq_wait(connectivity_seq_get(), connectivity_seqno);
-    }
-
+    status_update_wait();
     system_stats_wait();
 }
 
@@ -3732,6 +3827,7 @@ port_configure_bond(struct port *port, struct bond_settings *s)
 {
     const char *detect_s;
     struct iface *iface;
+    const char *mac_s;
     int miimon_interval;
 
     s->name = port->name;
@@ -3788,6 +3884,13 @@ port_configure_bond(struct port *port, struct bond_settings *s)
     LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
         netdev_set_miimon_interval(iface->netdev, miimon_interval);
     }
+
+    mac_s = port->cfg->bond_active_slave;
+    if (!mac_s || !ovs_scan(mac_s, ETH_ADDR_SCAN_FMT,
+                            ETH_ADDR_SCAN_ARGS(s->active_slave_mac))) {
+        /* OVSDB did not store the last active interface */
+        memset(s->active_slave_mac, 0, sizeof(s->active_slave_mac));
+    }
 }
 
 /* Returns true if 'port' is synthetic, that is, if we constructed it locally