Remove /proc/net compatibility support.
[sliver-openvswitch.git] / vswitchd / bridge.c
index b4f7a2e..197b6ed 100644 (file)
@@ -35,6 +35,7 @@
 #include "cfm.h"
 #include "classifier.h"
 #include "coverage.h"
+#include "daemon.h"
 #include "dirs.h"
 #include "dpif.h"
 #include "dynamic-string.h"
@@ -54,7 +55,6 @@
 #include "ovsdb-data.h"
 #include "packets.h"
 #include "poll-loop.h"
-#include "proc-net-compat.h"
 #include "process.h"
 #include "sha1.h"
 #include "shash.h"
@@ -75,15 +75,11 @@ VLOG_DEFINE_THIS_MODULE(bridge);
 
 COVERAGE_DEFINE(bridge_flush);
 COVERAGE_DEFINE(bridge_process_flow);
+COVERAGE_DEFINE(bridge_process_cfm);
+COVERAGE_DEFINE(bridge_process_lacp);
 COVERAGE_DEFINE(bridge_reconfigure);
 COVERAGE_DEFINE(bridge_lacp_update);
 
-enum lacp_status {
-    LACP_STATUS_CURRENT,  /* Partner is up to date. */
-    LACP_STATUS_EXPIRED,  /* Partner is out of date. Attempt to re-sync. */
-    LACP_STATUS_DEFAULTED /* Partner information is unknown. */
-};
-
 struct dst {
     uint16_t vlan;
     uint16_t dp_ifidx;
@@ -99,6 +95,13 @@ static void dst_set_init(struct dst_set *);
 static void dst_set_add(struct dst_set *, const struct dst *);
 static void dst_set_free(struct dst_set *);
 
+enum lacp_status {
+    LACP_CURRENT   = 0x01, /* Current State. */
+    LACP_EXPIRED   = 0x02, /* Expired State. */
+    LACP_DEFAULTED = 0x04, /* Partner is defaulted. */
+    LACP_ATTACHED  = 0x08, /* Attached. Interface may be choosen for flows. */
+};
+
 struct iface {
     /* These members are always valid. */
     struct port *port;          /* Containing port. */
@@ -119,14 +122,12 @@ struct iface {
     const struct ovsrec_interface *cfg;
 
     /* LACP information. */
-    enum lacp_status lacp_status;  /* LACP state machine status. */
+    enum lacp_status lacp_status;  /* LACP status. */
     uint16_t lacp_priority;        /* LACP port priority. */
     struct lacp_info lacp_actor;   /* LACP actor information. */
     struct lacp_info lacp_partner; /* LACP partner information. */
     long long int lacp_tx;         /* Next LACP message transmission time. */
     long long int lacp_rx;         /* Next LACP message receive time. */
-    bool lacp_attached;            /* Attached to its aggregator?  LACP allows
-                                      this link to be chosen for flows. */
 };
 
 #define BOND_MASK 0xff
@@ -189,7 +190,6 @@ struct port {
     tag_type active_iface_tag;  /* Tag for bcast flows. */
     tag_type no_ifaces_tag;     /* Tag for flows when all ifaces disabled. */
     int updelay, downdelay;     /* Delay before iface goes up/down, in ms. */
-    bool bond_compat_is_stale;  /* Need to call port_update_bond_compat()? */
     bool bond_fake_iface;       /* Fake a bond interface for legacy compat? */
     bool miimon;                /* Use miimon instead of carrier? */
     long long int bond_miimon_interval; /* Miimon status refresh interval. */
@@ -301,8 +301,6 @@ static struct port *port_lookup(const struct bridge *, const char *name);
 static struct iface *port_lookup_iface(const struct port *, const char *name);
 static struct port *port_from_dp_ifidx(const struct bridge *,
                                        uint16_t dp_ifidx);
-static void port_update_bond_compat(struct port *);
-static void port_update_vlan_compat(struct port *);
 static void port_update_bonding(struct port *);
 static void port_update_lacp(struct port *);
 
@@ -913,7 +911,6 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
             struct port *port = br->ports[i];
             int j;
 
-            port_update_vlan_compat(port);
             port_update_bonding(port);
             port_update_lacp(port);
 
@@ -934,6 +931,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     }
 
     free(managers);
+
+    /* ovs-vswitchd has completed initialization, so allow the process that
+     * forked us to exit successfully. */
+    daemonize_complete();
 }
 
 static const char *
@@ -2158,7 +2159,7 @@ bond_choose_iface(const struct port *port)
         if (iface->enabled) {
             return i;
         } else if (iface->delay_expires < next_delay_expiration
-                   && (iface->lacp_attached
+                   && (iface->lacp_status & LACP_ATTACHED
                        || !(port->lacp & LACP_NEGOTIATED))) {
             best_down_slave = i;
             next_delay_expiration = iface->delay_expires;
@@ -2204,7 +2205,6 @@ choose_output_iface(const struct port *port, const struct flow *flow,
                 return false;
             }
             e->iface_tag = tag_create_random();
-            ((struct port *) port)->bond_compat_is_stale = true;
         }
         *tags |= e->iface_tag;
         iface = port->ifaces[e->iface_idx];
@@ -2236,9 +2236,9 @@ bond_link_status_update(struct iface *iface)
          * They are not required to have synchronized partners because they
          * have no partners at all.  However, they will only be attached if
          * negotiations failed on all interfaces in the bond. */
-        up = iface->lacp_attached
+        up = iface->lacp_status & LACP_ATTACHED
             && (iface->lacp_partner.state & LACP_STATE_SYNC
-                 || iface->lacp_status == LACP_STATUS_DEFAULTED);
+                 || iface->lacp_status & LACP_DEFAULTED);
     }
 
 
@@ -2334,7 +2334,6 @@ bond_enable_slave(struct iface *iface, bool enable)
     }
 
     moving_active_iface = false;
-    port->bond_compat_is_stale = true;
 }
 
 /* Attempts to make the sum of the bond slaves' statistics appear on the fake
@@ -2381,13 +2380,12 @@ bond_link_carrier_update(struct iface *iface, bool carrier)
         return;
     }
 
-    if (iface->lacp_status == LACP_STATUS_CURRENT) {
+    if (iface->lacp_status & LACP_CURRENT) {
         iface_set_lacp_expired(iface);
     }
 
     iface->up = carrier;
     iface->lacp_tx = 0;
-    iface->port->bond_compat_is_stale = true;
 }
 
 static void
@@ -2446,11 +2444,6 @@ bond_run(struct bridge *br)
                 port->bond_next_fake_iface_update = time_msec() + 1000;
             }
         }
-
-        if (port->bond_compat_is_stale) {
-            port->bond_compat_is_stale = false;
-            port_update_bond_compat(port);
-        }
     }
 }
 
@@ -3001,26 +2994,38 @@ bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
                         struct ofpbuf *actions, tag_type *tags,
                         uint16_t *nf_output_iface, void *br_)
 {
-    struct iface *iface;
     struct bridge *br = br_;
 
     COVERAGE_INC(bridge_process_flow);
+    return process_flow(br, flow, packet, actions, tags, nf_output_iface);
+}
+
+static bool
+bridge_special_ofhook_cb(const struct flow *flow,
+                         const struct ofpbuf *packet, void *br_)
+{
+    struct iface *iface;
+    struct bridge *br = br_;
 
     iface = iface_from_dp_ifidx(br, flow->in_port);
 
     if (cfm_should_process_flow(flow)) {
-        if (packet && iface->cfm) {
+
+        if (iface && packet && iface->cfm) {
+            COVERAGE_INC(bridge_process_cfm);
             cfm_process_heartbeat(iface->cfm, packet);
         }
         return false;
     } else if (flow->dl_type == htons(ETH_TYPE_LACP)) {
-        if (packet) {
+
+        if (iface && packet) {
+            COVERAGE_INC(bridge_process_lacp);
             lacp_process_packet(packet, iface);
         }
         return false;
     }
 
-    return process_flow(br, flow, packet, actions, tags, nf_output_iface);
+    return true;
 }
 
 static void
@@ -3055,7 +3060,7 @@ bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags,
         if (nl_attr_type(a) == ODP_ACTION_ATTR_OUTPUT) {
             struct port *out_port = port_from_dp_ifidx(br, nl_attr_get_u32(a));
             if (out_port && out_port->n_ifaces >= 2 &&
-                out_port->bond_mode == BM_SLB) {
+                out_port->bond_mode != BM_AB) {
                 uint16_t vlan = (flow->vlan_tci
                                  ? vlan_tci_to_vid(flow->vlan_tci)
                                  : OFP_VLAN_NONE);
@@ -3080,7 +3085,7 @@ bridge_account_checkpoint_ofhook_cb(void *br_)
     now = time_msec();
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
-        if (port->n_ifaces > 1 && port->bond_mode == BM_SLB
+        if (port->n_ifaces > 1 && port->bond_mode != BM_AB
             && now >= port->bond_next_rebalance) {
             port->bond_next_rebalance = now + port->bond_rebalance_interval;
             bond_rebalance_port(port);
@@ -3090,6 +3095,7 @@ bridge_account_checkpoint_ofhook_cb(void *br_)
 
 static struct ofhooks bridge_ofhooks = {
     bridge_normal_ofhook_cb,
+    bridge_special_ofhook_cb,
     bridge_account_flow_ofhook_cb,
     bridge_account_checkpoint_ofhook_cb,
 };
@@ -3110,7 +3116,8 @@ lacp_process_packet(const struct ofpbuf *packet, struct iface *iface)
         return;
     }
 
-    iface->lacp_status = LACP_STATUS_CURRENT;
+    iface->lacp_status |= LACP_CURRENT;
+    iface->lacp_status &= ~(LACP_EXPIRED | LACP_DEFAULTED);
     iface->lacp_rx = time_msec() + LACP_SLOW_TIME_RX;
 
     iface->lacp_actor.state = iface_get_lacp_state(iface);
@@ -3146,7 +3153,7 @@ lacp_update_ifaces(struct port *port)
         struct iface *iface = port->ifaces[i];
         struct lacp_info pri;
 
-        iface->lacp_attached = true;
+        iface->lacp_status |= LACP_ATTACHED;
         ofproto_revalidate(port->bridge->ofproto, iface->tag);
 
         /* Don't allow loopback interfaces to send traffic or lead. */
@@ -3154,11 +3161,11 @@ lacp_update_ifaces(struct port *port)
                             iface->lacp_actor.sysid)) {
             VLOG_WARN_RL(&rl, "iface %s: Loopback detected. Interface is "
                          "connected to its own bridge", iface->name);
-            iface->lacp_attached = false;
+            iface->lacp_status &= ~LACP_ATTACHED;
             continue;
         }
 
-        if (iface->lacp_status == LACP_STATUS_DEFAULTED) {
+        if (iface->lacp_status & LACP_DEFAULTED) {
             continue;
         }
 
@@ -3180,11 +3187,11 @@ lacp_update_ifaces(struct port *port)
     for (i = 0; i < port->n_ifaces; i++) {
         struct iface *iface = port->ifaces[i];
 
-        if (iface->lacp_status == LACP_STATUS_DEFAULTED
+        if (iface->lacp_status & LACP_DEFAULTED
             || lead->lacp_partner.key != iface->lacp_partner.key
             || !eth_addr_equals(lead->lacp_partner.sysid,
                                 iface->lacp_partner.sysid)) {
-            iface->lacp_attached = false;
+            iface->lacp_status &= ~LACP_ATTACHED;
         }
     }
 }
@@ -3193,7 +3200,7 @@ static bool
 lacp_iface_may_tx(const struct iface *iface)
 {
     return iface->port->lacp & LACP_ACTIVE
-        || iface->lacp_status != LACP_STATUS_DEFAULTED;
+        || iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED);
 }
 
 static void
@@ -3215,9 +3222,9 @@ lacp_run(struct bridge *br)
             struct iface *iface = port->ifaces[j];
 
             if (time_msec() > iface->lacp_rx) {
-                if (iface->lacp_status == LACP_STATUS_CURRENT) {
+                if (iface->lacp_status & LACP_CURRENT) {
                     iface_set_lacp_expired(iface);
-                } else if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+                } else if (iface->lacp_status & LACP_EXPIRED) {
                     iface_set_lacp_defaulted(iface);
                 }
             }
@@ -3276,7 +3283,7 @@ lacp_wait(struct bridge *br)
                 poll_timer_wait_until(iface->lacp_tx);
             }
 
-            if (iface->lacp_status != LACP_STATUS_DEFAULTED) {
+            if (iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED)) {
                 poll_timer_wait_until(iface->lacp_rx);
             }
         }
@@ -3421,7 +3428,7 @@ bond_shift_load(struct slave_balance *from, struct slave_balance *to,
     struct port *port = from->iface->port;
     uint64_t delta = hash->tx_bytes;
 
-    assert(port->bond_mode == BM_SLB);
+    assert(port->bond_mode != BM_AB);
 
     VLOG_INFO("bond %s: shift %"PRIu64"kB of load (with hash %td) "
               "from %s to %s (now carrying %"PRIu64"kB and "
@@ -3575,7 +3582,6 @@ bond_rebalance_port(struct port *port)
             }
             if (i < from->n_hashes) {
                 bond_shift_load(from, to, i);
-                port->bond_compat_is_stale = true;
 
                 /* If the result of the migration changed the relative order of
                  * 'from' and 'to' swap them back to maintain invariants. */
@@ -3830,15 +3836,19 @@ bond_unixctl_show(struct unixctl_conn *conn,
         if (port->lacp) {
             ds_put_cstr(&ds, "\tstatus: ");
 
-            if (iface->lacp_status == LACP_STATUS_CURRENT) {
+            if (iface->lacp_status & LACP_CURRENT) {
                 ds_put_cstr(&ds, "current ");
-            } else if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+            }
+
+            if (iface->lacp_status & LACP_EXPIRED) {
                 ds_put_cstr(&ds, "expired ");
-            } else {
+            }
+
+            if (iface->lacp_status & LACP_DEFAULTED) {
                 ds_put_cstr(&ds, "defaulted ");
             }
 
-            if (iface->lacp_attached) {
+            if (iface->lacp_status & LACP_ATTACHED) {
                 ds_put_cstr(&ds, "attached ");
             }
 
@@ -3984,7 +3994,6 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_,
     ofproto_revalidate(port->bridge->ofproto, entry->iface_tag);
     entry->iface_idx = iface->port_ifidx;
     entry->iface_tag = tag_create_random();
-    port->bond_compat_is_stale = true;
     unixctl_command_reply(conn, 200, "migrated");
 }
 
@@ -4416,9 +4425,6 @@ port_destroy(struct port *port)
         struct port *del;
         int i;
 
-        proc_net_compat_update_vlan(port->name, NULL, 0);
-        proc_net_compat_update_bond(port->name, NULL);
-
         for (i = 0; i < MAX_MIRRORS; i++) {
             struct mirror *m = br->mirrors[i];
             if (m && m->out_port == port) {
@@ -4521,12 +4527,8 @@ port_update_bonding(struct port *port)
     }
     if (port->n_ifaces < 2) {
         /* Not a bonded port. */
-        if (port->bond_hash) {
-            free(port->bond_hash);
-            port->bond_hash = NULL;
-            port->bond_compat_is_stale = true;
-        }
-
+        free(port->bond_hash);
+        port->bond_hash = NULL;
         port->bond_fake_iface = false;
     } else {
         size_t i;
@@ -4550,7 +4552,6 @@ port_update_bonding(struct port *port)
             free(port->bond_hash);
             port->bond_hash = NULL;
         }
-        port->bond_compat_is_stale = true;
         port->bond_fake_iface = port->cfg->bond_fake_iface;
 
         if (!port->miimon) {
@@ -4561,116 +4562,6 @@ port_update_bonding(struct port *port)
         }
     }
 }
-
-static void
-port_update_bond_compat(struct port *port)
-{
-    struct compat_bond_hash compat_hashes[BOND_MASK + 1];
-    struct compat_bond bond;
-    size_t i;
-
-    if (port->n_ifaces < 2 || port->bond_mode != BM_SLB) {
-        proc_net_compat_update_bond(port->name, NULL);
-        return;
-    }
-
-    bond.up = false;
-    bond.updelay = port->updelay;
-    bond.downdelay = port->downdelay;
-
-    bond.n_hashes = 0;
-    bond.hashes = compat_hashes;
-    if (port->bond_hash) {
-        const struct bond_entry *e;
-        for (e = port->bond_hash; e <= &port->bond_hash[BOND_MASK]; e++) {
-            if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) {
-                struct compat_bond_hash *cbh = &bond.hashes[bond.n_hashes++];
-                cbh->hash = e - port->bond_hash;
-                cbh->netdev_name = port->ifaces[e->iface_idx]->name;
-            }
-        }
-    }
-
-    bond.n_slaves = port->n_ifaces;
-    bond.slaves = xmalloc(port->n_ifaces * sizeof *bond.slaves);
-    for (i = 0; i < port->n_ifaces; i++) {
-        struct iface *iface = port->ifaces[i];
-        struct compat_bond_slave *slave = &bond.slaves[i];
-        slave->name = iface->name;
-
-        /* We need to make the same determination as the Linux bonding
-         * code to determine whether a slave should be consider "up".
-         * The Linux function bond_miimon_inspect() supports four
-         * BOND_LINK_* states:
-         *
-         *    - BOND_LINK_UP: carrier detected, updelay has passed.
-         *    - BOND_LINK_FAIL: carrier lost, downdelay in progress.
-         *    - BOND_LINK_DOWN: carrier lost, downdelay has passed.
-         *    - BOND_LINK_BACK: carrier detected, updelay in progress.
-         *
-         * The function bond_info_show_slave() only considers BOND_LINK_UP
-         * to be "up" and anything else to be "down".
-         */
-        slave->up = iface->enabled && iface->delay_expires == LLONG_MAX;
-        if (slave->up) {
-            bond.up = true;
-        }
-        netdev_get_etheraddr(iface->netdev, slave->mac);
-    }
-
-    if (port->bond_fake_iface) {
-        struct netdev *bond_netdev;
-
-        if (!netdev_open_default(port->name, &bond_netdev)) {
-            if (bond.up) {
-                netdev_turn_flags_on(bond_netdev, NETDEV_UP, true);
-            } else {
-                netdev_turn_flags_off(bond_netdev, NETDEV_UP, true);
-            }
-            netdev_close(bond_netdev);
-        }
-    }
-
-    proc_net_compat_update_bond(port->name, &bond);
-    free(bond.slaves);
-}
-
-static void
-port_update_vlan_compat(struct port *port)
-{
-    struct bridge *br = port->bridge;
-    char *vlandev_name = NULL;
-
-    if (port->vlan > 0) {
-        /* Figure out the name that the VLAN device should actually have, if it
-         * existed.  This takes some work because the VLAN device would not
-         * have port->name in its name; rather, it would have the trunk port's
-         * name, and 'port' would be attached to a bridge that also had the
-         * VLAN device one of its ports.  So we need to find a trunk port that
-         * includes port->vlan.
-         *
-         * There might be more than one candidate.  This doesn't happen on
-         * XenServer, so if it happens we just pick the first choice in
-         * alphabetical order instead of creating multiple VLAN devices. */
-        size_t i;
-        for (i = 0; i < br->n_ports; i++) {
-            struct port *p = br->ports[i];
-            if (port_trunks_vlan(p, port->vlan)
-                && p->n_ifaces
-                && (!vlandev_name || strcmp(p->name, vlandev_name) <= 0))
-            {
-                uint8_t ea[ETH_ADDR_LEN];
-                netdev_get_etheraddr(p->ifaces[0]->netdev, ea);
-                if (!eth_addr_is_multicast(ea) &&
-                    !eth_addr_is_reserved(ea) &&
-                    !eth_addr_is_zero(ea)) {
-                    vlandev_name = p->name;
-                }
-            }
-        }
-    }
-    proc_net_compat_update_vlan(port->name, vlandev_name, port->vlan);
-}
 \f
 /* Interface functions. */
 
@@ -4679,7 +4570,8 @@ iface_set_lacp_defaulted(struct iface *iface)
 {
     memset(&iface->lacp_partner, 0, sizeof iface->lacp_partner);
 
-    iface->lacp_status = LACP_STATUS_DEFAULTED;
+    iface->lacp_status |= LACP_DEFAULTED;
+    iface->lacp_status &= ~(LACP_CURRENT | LACP_EXPIRED);
     iface->lacp_tx = 0;
     iface->port->lacp_need_update = true;
 }
@@ -4687,7 +4579,8 @@ iface_set_lacp_defaulted(struct iface *iface)
 static void
 iface_set_lacp_expired(struct iface *iface)
 {
-    iface->lacp_status = LACP_STATUS_EXPIRED;
+    iface->lacp_status &= ~LACP_CURRENT;
+    iface->lacp_status |= LACP_EXPIRED;
     iface->lacp_partner.state |= LACP_STATE_TIME;
     iface->lacp_partner.state &= ~LACP_STATE_SYNC;
 
@@ -4704,13 +4597,15 @@ iface_get_lacp_state(const struct iface *iface)
         state |= LACP_STATE_ACT;
     }
 
-    if (iface->lacp_status == LACP_STATUS_DEFAULTED) {
-        state |= LACP_STATE_DEF;
-    } else if (iface->lacp_attached) {
+    if (iface->lacp_status & LACP_ATTACHED) {
         state |= LACP_STATE_SYNC;
     }
 
-    if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+    if (iface->lacp_status & LACP_DEFAULTED) {
+        state |= LACP_STATE_DEF;
+    }
+
+    if (iface->lacp_status & LACP_EXPIRED) {
         state |= LACP_STATE_EXP;
     }