cfm: Migrate cfm/show unixctl command to CFM module.
[sliver-openvswitch.git] / vswitchd / bridge.c
index e23ee6f..aba0b94 100644 (file)
 
 #include <config.h>
 #include "bridge.h"
-#include "byte-order.h"
 #include <assert.h>
 #include <errno.h>
-#include <arpa/inet.h>
-#include <ctype.h>
 #include <inttypes.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <openflow/openflow.h>
-#include <signal.h>
 #include <stdlib.h>
-#include <strings.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
 #include "bitmap.h"
 #include "bond.h"
 #include "cfm.h"
-#include "classifier.h"
 #include "coverage.h"
 #include "daemon.h"
 #include "dirs.h"
 #include "dynamic-string.h"
-#include "flow.h"
 #include "hash.h"
 #include "hmap.h"
 #include "jsonrpc.h"
 #include "lacp.h"
 #include "list.h"
-#include "mac-learning.h"
 #include "netdev.h"
-#include "netlink.h"
-#include "odp-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
-#include "ofproto/netflow.h"
 #include "ofproto/ofproto.h"
-#include "ovsdb-data.h"
-#include "packets.h"
 #include "poll-loop.h"
-#include "process.h"
 #include "sha1.h"
 #include "shash.h"
 #include "socket-util.h"
 #include "stream-ssl.h"
 #include "sset.h"
-#include "svec.h"
 #include "system-stats.h"
 #include "timeval.h"
 #include "util.h"
 #include "unixctl.h"
-#include "vconn.h"
 #include "vswitchd/vswitch-idl.h"
 #include "xenserver.h"
 #include "vlog.h"
@@ -187,7 +164,6 @@ static bool bridge_has_bond_fake_iface(const struct bridge *,
                                        const char *name);
 static bool port_is_bond_fake_iface(const struct port *);
 
-static unixctl_cb_func cfm_unixctl_show;
 static unixctl_cb_func qos_unixctl_show;
 
 static struct port *port_create(struct bridge *, const struct ovsrec_port *);
@@ -198,7 +174,8 @@ static struct port *port_lookup(const struct bridge *, const char *name);
 static void port_configure(struct port *);
 static struct lacp_settings *port_configure_lacp(struct port *,
                                                  struct lacp_settings *);
-static void port_configure_bond(struct port *, struct bond_settings *);
+static void port_configure_bond(struct port *, struct bond_settings *,
+                                uint32_t *bond_stable_ids);
 
 static void bridge_configure_mirrors(struct bridge *);
 static struct mirror *mirror_create(struct bridge *,
@@ -290,7 +267,6 @@ bridge_init(const char *remote)
     ovsdb_idl_omit(idl, &ovsrec_ssl_col_external_ids);
 
     /* Register unixctl commands. */
-    unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
     unixctl_command_register("qos/show", qos_unixctl_show, NULL);
     unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
                              NULL);
@@ -298,6 +274,7 @@ bridge_init(const char *remote)
                              NULL);
     lacp_init();
     bond_init();
+    cfm_init();
 }
 
 void
@@ -544,10 +521,16 @@ port_configure(struct port *port)
 
     /* Get bond settings. */
     if (s.n_slaves > 1) {
-        port_configure_bond(port, &bond_settings);
         s.bond = &bond_settings;
+        s.bond_stable_ids = xmalloc(s.n_slaves * sizeof *s.bond_stable_ids);
+        port_configure_bond(port, &bond_settings, s.bond_stable_ids);
     } else {
         s.bond = NULL;
+        s.bond_stable_ids = NULL;
+
+        LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+            netdev_set_miimon_interval(iface->netdev, 0);
+        }
     }
 
     /* Register. */
@@ -556,6 +539,7 @@ port_configure(struct port *port)
     /* Clean up. */
     free(s.trunks);
     free(s.lacp_slaves);
+    free(s.bond_stable_ids);
 }
 
 /* Pick local port hardware address and datapath ID for 'br'. */
@@ -796,7 +780,6 @@ bridge_del_ofproto_ports(struct bridge *br)
                       br->name, name, strerror(error));
         }
         if (iface) {
-            ofproto_port_unregister(br->ofproto, ofproto_port.ofp_port);
             netdev_close(iface->netdev);
             iface->netdev = NULL;
         }
@@ -811,7 +794,7 @@ iface_set_ofp_port(struct iface *iface, int ofp_port)
     assert(iface->ofp_port < 0 && ofp_port >= 0);
     iface->ofp_port = ofp_port;
     hmap_insert(&br->ifaces, &iface->ofp_port_node, hash_int(ofp_port, 0));
-
+    iface_set_ofport(iface->cfg, ofp_port);
 }
 
 static void
@@ -947,7 +930,6 @@ bridge_add_ofproto_ports(struct bridge *br)
                 /* Already exists, nothing to do. */
                 ofproto_port_destroy(&ofproto_port);
             }
-            ofproto_port_destroy(&ofproto_port);
         }
     }
 }
@@ -1416,7 +1398,7 @@ bridge_run(void)
     /* (Re)configure if necessary. */
     database_changed = ovsdb_idl_run(idl);
     cfg = ovsrec_open_vswitch_first(idl);
-#ifdef HAVE_OPENSSL
+
     /* Re-configure SSL.  We do this on every trip through the main loop,
      * instead of just when the database changes, because the contents of the
      * key and certificate files can change without the database changing.
@@ -1429,7 +1411,7 @@ bridge_run(void)
         stream_ssl_set_key_and_cert(ssl->private_key, ssl->certificate);
         stream_ssl_set_ca_cert_file(ssl->ca_cert, ssl->bootstrap_ca_cert);
     }
-#endif
+
     if (database_changed || datapath_destroyed) {
         if (cfg) {
             struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
@@ -1518,33 +1500,6 @@ bridge_wait(void)
     }
 }
 \f
-/* CFM unixctl user interface functions. */
-static void
-cfm_unixctl_show(struct unixctl_conn *conn,
-                 const char *args, void *aux OVS_UNUSED)
-{
-    struct ds ds = DS_EMPTY_INITIALIZER;
-    struct iface *iface;
-    const struct cfm *cfm;
-
-    iface = iface_find(args);
-    if (!iface) {
-        unixctl_command_reply(conn, 501, "no such interface");
-        return;
-    }
-
-    cfm = ofproto_port_get_cfm(iface->port->bridge->ofproto, iface->ofp_port);
-
-    if (!cfm) {
-        unixctl_command_reply(conn, 501, "CFM not enabled");
-        return;
-    }
-
-    cfm_dump_ds(cfm, &ds);
-    unixctl_command_reply(conn, 200, ds_cstr(&ds));
-    ds_destroy(&ds);
-}
-\f
 /* QoS unixctl user interface functions. */
 
 struct qos_unixctl_show_cbdata {
@@ -1650,7 +1605,11 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
     br->name = xstrdup(br_cfg->name);
     br->type = xstrdup(ofproto_normalize_type(br_cfg->datapath_type));
     br->cfg = br_cfg;
-    eth_addr_nicira_random(br->default_ea);
+
+    /* Derive the default Ethernet address from the bridge's UUID.  This should
+     * be unique and it will be stable between ovs-vswitchd runs.  */
+    memcpy(br->default_ea, &br_cfg->header_.uuid, ETH_ADDR_LEN);
+    eth_addr_mark_random(br->default_ea);
 
     hmap_init(&br->ports);
     hmap_init(&br->ifaces);
@@ -2045,7 +2004,10 @@ port_del_ifaces(struct port *port)
     sset_init(&new_ifaces);
     for (i = 0; i < port->cfg->n_interfaces; i++) {
         const char *name = port->cfg->interfaces[i]->name;
-        sset_add(&new_ifaces, name);
+        const char *type = port->cfg->interfaces[i]->name;
+        if (strcmp(type, "null")) {
+            sset_add(&new_ifaces, name);
+        }
     }
 
     /* Get rid of deleted interfaces. */
@@ -2071,7 +2033,8 @@ port_add_ifaces(struct port *port)
     shash_init(&new_ifaces);
     for (i = 0; i < port->cfg->n_interfaces; i++) {
         const struct ovsrec_interface *cfg = port->cfg->interfaces[i];
-        if (!shash_add_once(&new_ifaces, cfg->name, cfg)) {
+        if (strcmp(cfg->type, "null")
+            && !shash_add_once(&new_ifaces, cfg->name, cfg)) {
             VLOG_WARN("port %s: %s specified twice as port interface",
                       port->name, cfg->name);
             iface_set_ofport(cfg, -1);
@@ -2183,9 +2146,10 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
                    ? priority
                    : UINT16_MAX - !list_is_short(&port->ifaces));
 
-    s->strict = !strcmp(get_port_other_config(port->cfg, "lacp-strict",
-                                              "false"),
-                        "true");
+    s->heartbeat = !strcmp(get_port_other_config(port->cfg,
+                                                 "lacp-heartbeat",
+                                                 "false"), "true");
+
 
     lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow");
     custom_time = atoi(lacp_time);
@@ -2206,11 +2170,13 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 static void
 iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
 {
-    int priority, portid;
+    int priority, portid, key;
 
     portid = atoi(get_interface_other_config(iface->cfg, "lacp-port-id", "0"));
     priority = atoi(get_interface_other_config(iface->cfg,
                                                "lacp-port-priority", "0"));
+    key = atoi(get_interface_other_config(iface->cfg, "lacp-aggregation-key",
+                                          "0"));
 
     if (portid <= 0 || portid > UINT16_MAX) {
         portid = iface->ofp_port;
@@ -2220,15 +2186,24 @@ iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
         priority = UINT16_MAX;
     }
 
+    if (key < 0 || key > UINT16_MAX) {
+        key = 0;
+    }
+
     s->name = iface->name;
     s->id = portid;
     s->priority = priority;
+    s->key = key;
 }
 
 static void
-port_configure_bond(struct port *port, struct bond_settings *s)
+port_configure_bond(struct port *port, struct bond_settings *s,
+                    uint32_t *bond_stable_ids)
 {
     const char *detect_s;
+    struct iface *iface;
+    int miimon_interval;
+    size_t i;
 
     s->name = port->name;
     s->balance = BM_SLB;
@@ -2239,22 +2214,24 @@ port_configure_bond(struct port *port, struct bond_settings *s)
                   bond_mode_to_string(s->balance));
     }
 
-    s->detect = BLSM_CARRIER;
-    detect_s = get_port_other_config(port->cfg, "bond-detect-mode", NULL);
-    if (detect_s && !bond_detect_mode_from_string(&s->detect, detect_s)) {
-        VLOG_WARN("port %s: unsupported bond-detect-mode %s, "
-                  "defaulting to %s",
-                  port->name, detect_s, bond_detect_mode_to_string(s->detect));
+    miimon_interval = atoi(get_port_other_config(port->cfg,
+                                                 "bond-miimon-interval", "0"));
+    if (miimon_interval <= 0) {
+        miimon_interval = 200;
     }
 
-    s->miimon_interval = atoi(
-        get_port_other_config(port->cfg, "bond-miimon-interval", "200"));
-    if (s->miimon_interval < 100) {
-        s->miimon_interval = 100;
+    detect_s = get_port_other_config(port->cfg, "bond-detect-mode", "carrier");
+    if (!strcmp(detect_s, "carrier")) {
+        miimon_interval = 0;
+    } else if (strcmp(detect_s, "miimon")) {
+        VLOG_WARN("port %s: unsupported bond-detect-mode %s, "
+                  "defaulting to carrier", port->name, detect_s);
+        miimon_interval = 0;
     }
 
     s->up_delay = MAX(0, port->cfg->bond_updelay);
     s->down_delay = MAX(0, port->cfg->bond_downdelay);
+    s->basis = atoi(get_port_other_config(port->cfg, "bond-hash-basis", "0"));
     s->rebalance_interval = atoi(
         get_port_other_config(port->cfg, "bond-rebalance-interval", "10000"));
     if (s->rebalance_interval < 1000) {
@@ -2262,6 +2239,20 @@ port_configure_bond(struct port *port, struct bond_settings *s)
     }
 
     s->fake_iface = port->cfg->bond_fake_iface;
+
+    i = 0;
+    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+        long long stable_id;
+
+        stable_id = atoll(get_interface_other_config(iface->cfg,
+                                                     "bond-stable-id", "0"));
+        if (stable_id <= 0 || stable_id >= UINT32_MAX) {
+            stable_id = iface->ofp_port;
+        }
+        bond_stable_ids[i++] = stable_id;
+
+        netdev_set_miimon_interval(iface->netdev, miimon_interval);
+    }
 }
 \f
 /* Interface functions. */
@@ -2470,7 +2461,7 @@ iface_delete_queues(unsigned int queue_id,
 static void
 iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
 {
-    if (!qos || qos->type[0] == '\0') {
+    if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
         netdev_set_qos(iface->netdev, NULL, NULL);
     } else {
         struct iface_delete_queues_cbdata cbdata;
@@ -2530,6 +2521,7 @@ iface_configure_cfm(struct iface *iface)
 
     cfm.mpid     = mon->mpid;
     cfm.interval = mon->interval ? *mon->interval : 1000;
+    cfm.name = iface->name;
 
     memcpy(cfm.maid, maid, sizeof cfm.maid);
 
@@ -2672,8 +2664,6 @@ static bool
 mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
 {
     struct ofproto_mirror_settings s;
-    struct port *out_port;
-    struct port *port;
 
     /* Set name. */
     if (strcmp(cfg->name, m->name)) {
@@ -2685,7 +2675,7 @@ mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
     /* Get output port or VLAN. */
     if (cfg->output_port) {
         s.out_bundle = port_lookup(m->bridge, cfg->output_port->name);
-        if (!out_port) {
+        if (!s.out_bundle) {
             VLOG_ERR("bridge %s: mirror %s outputs to port not on bridge",
                      m->bridge->name, m->name);
             return false;
@@ -2711,6 +2701,7 @@ mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
     if (cfg->select_all) {
         size_t n_ports = hmap_count(&m->bridge->ports);
         void **ports = xmalloc(n_ports * sizeof *ports);
+        struct port *port;
         size_t i;
 
         i = 0;