datapath: Don't call genlmsg_reply() under rcu_read_lock().
[openvswitch] / vswitchd / bridge.c
index 761d02ba36bdaaecfc144786d2a2f5c77c730bb1..58053056ac04dc48b9e24e8a1b6489bcc6871a67 100644 (file)
@@ -164,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 *);
@@ -175,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 *,
@@ -244,10 +244,6 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_status);
     ovsdb_idl_omit(idl, &ovsrec_controller_col_external_ids);
 
-    ovsdb_idl_omit_alert(idl, &ovsrec_maintenance_point_col_fault);
-
-    ovsdb_idl_omit_alert(idl, &ovsrec_monitor_col_fault);
-
     ovsdb_idl_omit(idl, &ovsrec_qos_col_external_ids);
 
     ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
@@ -267,7 +263,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);
@@ -275,6 +270,7 @@ bridge_init(const char *remote)
                              NULL);
     lacp_init();
     bond_init();
+    cfm_init();
 }
 
 void
@@ -405,7 +401,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
             port_configure(port);
 
-            HMAP_FOR_EACH (iface, ofp_port_node, &br->ifaces) {
+            LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
                 iface_configure_cfm(iface);
                 iface_configure_qos(iface, port->cfg->qos);
                 iface_set_mac(iface);
@@ -521,10 +517,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. */
@@ -533,6 +535,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'. */
@@ -787,7 +790,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
@@ -923,7 +926,6 @@ bridge_add_ofproto_ports(struct bridge *br)
                 /* Already exists, nothing to do. */
                 ofproto_port_destroy(&ofproto_port);
             }
-            ofproto_port_destroy(&ofproto_port);
         }
     }
 }
@@ -1213,33 +1215,20 @@ iface_refresh_status(struct iface *iface)
 static bool
 iface_refresh_cfm_stats(struct iface *iface)
 {
-    const struct ovsrec_monitor *mon;
-    const struct cfm *cfm;
+    const struct ovsrec_interface *cfg = iface->cfg;
     bool changed = false;
-    size_t i;
+    int fault;
 
-    mon = iface->cfg->monitor;
-    cfm = ofproto_port_get_cfm(iface->port->bridge->ofproto, iface->ofp_port);
+    fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto,
+                                       iface->ofp_port);
 
-    if (!cfm || !mon) {
+    if (fault < 0) {
         return false;
     }
 
-    for (i = 0; i < mon->n_remote_mps; i++) {
-        const struct ovsrec_maintenance_point *mp;
-        const struct remote_mp *rmp;
-
-        mp = mon->remote_mps[i];
-        rmp = cfm_get_remote_mp(cfm, mp->mpid);
-
-        if (mp->n_fault != 1 || mp->fault[0] != rmp->fault) {
-            ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
-            changed = true;
-        }
-    }
-
-    if (mon->n_fault != 1 || mon->fault[0] != cfm->fault) {
-        ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+    if (cfg->n_cfm_fault != 1 || cfg->cfm_fault[0] != fault) {
+        bool fault_bool = fault;
+        ovsrec_interface_set_cfm_fault(cfg, &fault_bool, 1);
         changed = true;
     }
 
@@ -1263,30 +1252,25 @@ iface_refresh_lacp_stats(struct iface *iface)
 static void
 iface_refresh_stats(struct iface *iface)
 {
-    struct iface_stat {
-        char *name;
-        int offset;
-    };
-    static const struct iface_stat iface_stats[] = {
-        { "rx_packets", offsetof(struct netdev_stats, rx_packets) },
-        { "tx_packets", offsetof(struct netdev_stats, tx_packets) },
-        { "rx_bytes", offsetof(struct netdev_stats, rx_bytes) },
-        { "tx_bytes", offsetof(struct netdev_stats, tx_bytes) },
-        { "rx_dropped", offsetof(struct netdev_stats, rx_dropped) },
-        { "tx_dropped", offsetof(struct netdev_stats, tx_dropped) },
-        { "rx_errors", offsetof(struct netdev_stats, rx_errors) },
-        { "tx_errors", offsetof(struct netdev_stats, tx_errors) },
-        { "rx_frame_err", offsetof(struct netdev_stats, rx_frame_errors) },
-        { "rx_over_err", offsetof(struct netdev_stats, rx_over_errors) },
-        { "rx_crc_err", offsetof(struct netdev_stats, rx_crc_errors) },
-        { "collisions", offsetof(struct netdev_stats, collisions) },
-    };
-    enum { N_STATS = ARRAY_SIZE(iface_stats) };
-    const struct iface_stat *s;
-
-    char *keys[N_STATS];
-    int64_t values[N_STATS];
-    int n;
+#define IFACE_STATS                             \
+    IFACE_STAT(rx_packets,      "rx_packets")   \
+    IFACE_STAT(tx_packets,      "tx_packets")   \
+    IFACE_STAT(rx_bytes,        "rx_bytes")     \
+    IFACE_STAT(tx_bytes,        "tx_bytes")     \
+    IFACE_STAT(rx_dropped,      "rx_dropped")   \
+    IFACE_STAT(tx_dropped,      "tx_dropped")   \
+    IFACE_STAT(rx_errors,       "rx_errors")    \
+    IFACE_STAT(tx_errors,       "tx_errors")    \
+    IFACE_STAT(rx_frame_errors, "rx_frame_err") \
+    IFACE_STAT(rx_over_errors,  "rx_over_err")  \
+    IFACE_STAT(rx_crc_errors,   "rx_crc_err")   \
+    IFACE_STAT(collisions,      "collisions")
+
+#define IFACE_STAT(MEMBER, NAME) NAME,
+    static char *keys[] = { IFACE_STATS };
+#undef IFACE_STAT
+    int64_t values[ARRAY_SIZE(keys)];
+    int i;
 
     struct netdev_stats stats;
 
@@ -1298,17 +1282,15 @@ iface_refresh_stats(struct iface *iface)
      * all-1s, and we will deal with that correctly below. */
     netdev_get_stats(iface->netdev, &stats);
 
-    n = 0;
-    for (s = iface_stats; s < &iface_stats[N_STATS]; s++) {
-        uint64_t value = *(uint64_t *) (((char *) &stats) + s->offset);
-        if (value != UINT64_MAX) {
-            keys[n] = s->name;
-            values[n] = value;
-            n++;
-        }
-    }
+    /* Copy statistics into values[] array. */
+    i = 0;
+#define IFACE_STAT(MEMBER, NAME) values[i++] = stats.MEMBER;
+    IFACE_STATS;
+#undef IFACE_STAT
+    assert(i == ARRAY_SIZE(keys));
 
-    ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
+    ovsrec_interface_set_statistics(iface->cfg, keys, values, ARRAY_SIZE(keys));
+#undef IFACE_STATS
 }
 
 static void
@@ -1392,7 +1374,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.
@@ -1405,7 +1387,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);
@@ -1494,33 +1476,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 {
@@ -1626,7 +1581,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);
@@ -2021,7 +1980,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. */
@@ -2047,7 +2009,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);
@@ -2159,9 +2122,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);
@@ -2182,11 +2146,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;
@@ -2196,15 +2162,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;
@@ -2215,22 +2190,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) {
@@ -2238,6 +2215,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. */
@@ -2446,7 +2437,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;
@@ -2486,37 +2477,27 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
 static void
 iface_configure_cfm(struct iface *iface)
 {
-    size_t i;
-    struct cfm cfm;
-    uint16_t *remote_mps;
-    struct ovsrec_monitor *mon;
-    uint8_t maid[CCM_MAID_LEN];
+    const struct ovsrec_interface *cfg = iface->cfg;
+    struct cfm_settings s;
+    uint16_t remote_mpid;
 
-    mon = iface->cfg->monitor;
-
-    if (!mon) {
+    if (!cfg->n_cfm_mpid || !cfg->n_cfm_remote_mpid) {
         ofproto_port_clear_cfm(iface->port->bridge->ofproto, iface->ofp_port);
         return;
     }
 
-    if (!cfm_generate_maid(mon->md_name, mon->ma_name, maid)) {
-        VLOG_WARN("interface %s: Failed to generate MAID.", iface->name);
-        return;
-    }
-
-    cfm.mpid     = mon->mpid;
-    cfm.interval = mon->interval ? *mon->interval : 1000;
-
-    memcpy(cfm.maid, maid, sizeof cfm.maid);
+    s.mpid = *cfg->cfm_mpid;
+    remote_mpid = *cfg->cfm_remote_mpid;
+    s.remote_mpids = &remote_mpid;
+    s.n_remote_mpids = 1;
 
-    remote_mps = xzalloc(mon->n_remote_mps * sizeof *remote_mps);
-    for(i = 0; i < mon->n_remote_mps; i++) {
-        remote_mps[i] = mon->remote_mps[i]->mpid;
+    s.interval = atoi(get_interface_other_config(iface->cfg, "cfm_interval",
+                                                 "0"));
+    if (s.interval <= 0) {
+        s.interval = 1000;
     }
 
-    ofproto_port_set_cfm(iface->port->bridge->ofproto, iface->ofp_port,
-                         &cfm, remote_mps, mon->n_remote_mps);
-    free(remote_mps);
+    ofproto_port_set_cfm(iface->port->bridge->ofproto, iface->ofp_port, &s);
 }
 
 /* Read carrier or miimon status directly from 'iface''s netdev, according to