bridge: Improve iface_set_ofport() style.
[sliver-openvswitch.git] / vswitchd / bridge.c
index f067c9d..0f4cf2c 100644 (file)
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include "async-append.h"
 #include "bfd.h"
 #include "bitmap.h"
 #include "bond.h"
@@ -67,13 +68,13 @@ struct if_cfg {
     struct hmap_node hmap_node;         /* Node in bridge's if_cfg_todo. */
     const struct ovsrec_interface *cfg; /* Interface record. */
     const struct ovsrec_port *parent;   /* Parent port record. */
-    int64_t ofport;                     /* Requested OpenFlow port number. */
+    ofp_port_t ofport;                  /* Requested OpenFlow port number. */
 };
 
 /* OpenFlow port slated for removal from ofproto. */
 struct ofpp_garbage {
     struct list list_node;      /* Node in bridge's ofpp_garbage. */
-    uint16_t ofp_port;          /* Port to be deleted. */
+    ofp_port_t ofp_port;        /* Port to be deleted. */
 };
 
 struct iface {
@@ -86,7 +87,8 @@ struct iface {
     /* These members are valid only after bridge_reconfigure() causes them to
      * be initialized. */
     struct hmap_node ofp_port_node; /* In struct bridge's "ifaces" hmap. */
-    int ofp_port;               /* OpenFlow port number, -1 if unknown. */
+    ofp_port_t ofp_port;        /* OpenFlow port number, */
+                                /* OFPP_NONE if unknown. */
     struct netdev *netdev;      /* Network device. */
     const char *type;           /* Usually same as cfg->type. */
     const struct ovsrec_interface *cfg;
@@ -195,8 +197,8 @@ static size_t bridge_get_controllers(const struct bridge *br,
 static void bridge_add_del_ports(struct bridge *,
                                  const unsigned long int *splinter_vlans);
 static void bridge_refresh_ofp_port(struct bridge *);
+static void bridge_configure_flow_miss_model(const char *opt);
 static void bridge_configure_datapath_id(struct bridge *);
-static void bridge_configure_flow_eviction_threshold(struct bridge *);
 static void bridge_configure_netflow(struct bridge *);
 static void bridge_configure_forward_bpdu(struct bridge *);
 static void bridge_configure_mac_table(struct bridge *);
@@ -245,7 +247,8 @@ static bool mirror_configure(struct mirror *);
 static void mirror_refresh_stats(struct mirror *);
 
 static void iface_configure_lacp(struct iface *, struct lacp_slave_settings *);
-static bool iface_create(struct bridge *, struct if_cfg *, int ofp_port);
+static bool iface_create(struct bridge *, struct if_cfg *,
+                         ofp_port_t ofp_port);
 static bool iface_is_internal(const struct ovsrec_interface *iface,
                               const struct ovsrec_bridge *br);
 static const char *iface_get_type(const struct ovsrec_interface *,
@@ -255,9 +258,9 @@ static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_find(const char *name);
 static struct if_cfg *if_cfg_lookup(const struct bridge *, const char *name);
 static struct iface *iface_from_ofp_port(const struct bridge *,
-                                         uint16_t ofp_port);
+                                         ofp_port_t ofp_port);
 static void iface_set_mac(struct iface *);
-static void iface_set_ofport(const struct ovsrec_interface *, int64_t ofport);
+static void iface_set_ofport(const struct ovsrec_interface *, ofp_port_t ofport);
 static void iface_clear_db_record(const struct ovsrec_interface *if_cfg);
 static void iface_configure_qos(struct iface *, const struct ovsrec_qos *);
 static void iface_configure_cfm(struct iface *);
@@ -265,7 +268,7 @@ static void iface_refresh_cfm_stats(struct iface *);
 static void iface_refresh_stats(struct iface *);
 static void iface_refresh_status(struct iface *);
 static bool iface_is_synthetic(const struct iface *);
-static int64_t iface_pick_ofport(const struct ovsrec_interface *);
+static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *);
 
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
  *
@@ -365,6 +368,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_state);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_resets);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mac_in_use);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ifindex);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mtu);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ofport);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
@@ -372,6 +376,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_flap_count);
     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);
@@ -469,10 +474,9 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg,
         SSET_FOR_EACH (target, &targets) {
             struct sockaddr_in *sin = &managers[n_managers];
 
-            if (stream_parse_target_with_default_ports(target,
-                                                       JSONRPC_TCP_PORT,
-                                                       JSONRPC_SSL_PORT,
-                                                       sin)) {
+            if (stream_parse_target_with_default_port(target,
+                                                      OVSDB_OLD_PORT,
+                                                      sin)) {
                 n_managers++;
             }
         }
@@ -494,6 +498,16 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     ovs_assert(!reconfiguring);
     reconfiguring = true;
 
+    ofproto_set_flow_eviction_threshold(
+        smap_get_int(&ovs_cfg->other_config, "flow-eviction-threshold",
+                     OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT));
+
+    ofproto_set_n_handler_threads(
+        smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0));
+
+    bridge_configure_flow_miss_model(smap_get(&ovs_cfg->other_config,
+                                              "force-miss-model"));
+
     /* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according
      * to 'ovs_cfg' while update the "if_cfg_queue", with only very minimal
      * configuration otherwise.
@@ -534,7 +548,6 @@ bridge_reconfigure_ofp(void)
     long long int deadline;
     struct bridge *br;
 
-    time_refresh();
     deadline = time_msec() + OFP_PORT_ACTION_WINDOW;
 
     /* The kernel will reject any attempt to add a given port to a datapath if
@@ -553,7 +566,6 @@ bridge_reconfigure_ofp(void)
             list_remove(&garbage->list_node);
             free(garbage);
 
-            time_refresh();
             if (time_msec() >= deadline) {
                 return false;
             }
@@ -565,8 +577,7 @@ bridge_reconfigure_ofp(void)
         struct if_cfg *if_cfg, *next;
 
         HMAP_FOR_EACH_SAFE (if_cfg, next, hmap_node, &br->if_cfg_todo) {
-            iface_create(br, if_cfg, -1);
-            time_refresh();
+            iface_create(br, if_cfg, OFPP_NONE);
             if (time_msec() >= deadline) {
                 return false;
             }
@@ -612,7 +623,6 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
             }
         }
         bridge_configure_mirrors(br);
-        bridge_configure_flow_eviction_threshold(br);
         bridge_configure_forward_bpdu(br);
         bridge_configure_mac_table(br);
         bridge_configure_remotes(br, managers, n_managers);
@@ -622,6 +632,13 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
         bridge_configure_stp(br);
         bridge_configure_tables(br);
         bridge_configure_dp_desc(br);
+
+        if (smap_get(&br->cfg->other_config, "flow-eviction-threshold")) {
+            /* XXX: Remove this warning message eventually. */
+            VLOG_WARN_ONCE("As of June 2013, flow-eviction-threshold has been"
+                           " moved to the Open_vSwitch table.  Ignoring its"
+                           " setting in the bridge table.");
+        }
     }
     free(managers);
 
@@ -680,7 +697,7 @@ bridge_update_ofprotos(void)
                 error = ofproto_port_del(br2->ofproto, ofproto_port.ofp_port);
                 if (error) {
                     VLOG_ERR("failed to delete port %s: %s", ofproto_port.name,
-                             strerror(error));
+                             ovs_strerror(error));
                 }
                 ofproto_port_destroy(&ofproto_port);
             }
@@ -689,7 +706,7 @@ bridge_update_ofprotos(void)
         error = ofproto_create(br->name, br->type, &br->ofproto);
         if (error) {
             VLOG_ERR("failed to create bridge %s: %s", br->name,
-                     strerror(error));
+                     ovs_strerror(error));
             bridge_destroy(br);
         }
     }
@@ -793,6 +810,22 @@ port_configure(struct port *port)
     free(s.lacp_slaves);
 }
 
+static void
+bridge_configure_flow_miss_model(const char *opt)
+{
+    enum ofproto_flow_miss_model model = OFPROTO_HANDLE_MISS_AUTO;
+
+    if (opt) {
+        if (strcmp(opt, "with-facets")) {
+            model = OFPROTO_HANDLE_MISS_WITH_FACETS;
+        } else if (strcmp(opt, "without-facets")) {
+            model = OFPROTO_HANDLE_MISS_WITHOUT_FACETS;
+        }
+    }
+
+    ofproto_set_flow_miss_model(model);
+}
+
 /* Pick local port hardware address and datapath ID for 'br'. */
 static void
 bridge_configure_datapath_id(struct bridge *br)
@@ -811,7 +844,7 @@ bridge_configure_datapath_id(struct bridge *br)
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge "
                         "Ethernet address: %s",
-                        br->name, strerror(error));
+                        br->name, ovs_strerror(error));
         }
     }
     memcpy(br->ea, ea, ETH_ADDR_LEN);
@@ -951,28 +984,44 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
     sset_destroy(&oso.targets);
 }
 
+/* Returns whether a IPFIX row is valid. */
+static bool
+ovsrec_ipfix_is_valid(const struct ovsrec_ipfix *ipfix)
+{
+    return ipfix && ipfix->n_targets > 0;
+}
+
+/* Returns whether a Flow_Sample_Collector_Set row is valid. */
+static bool
+ovsrec_fscs_is_valid(const struct ovsrec_flow_sample_collector_set *fscs,
+                     const struct bridge *br)
+{
+    return ovsrec_ipfix_is_valid(fscs->ipfix) && fscs->bridge == br->cfg;
+}
+
 /* Set IPFIX configuration on 'br'. */
 static void
 bridge_configure_ipfix(struct bridge *br)
 {
     const struct ovsrec_ipfix *be_cfg = br->cfg->ipfix;
+    bool valid_be_cfg = ovsrec_ipfix_is_valid(be_cfg);
     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) {
+        if (ovsrec_fscs_is_valid(fe_cfg, br)) {
             n_fe_opts++;
         }
     }
 
-    if (!be_cfg && n_fe_opts == 0) {
+    if (!valid_be_cfg && n_fe_opts == 0) {
         ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
         return;
     }
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         memset(&be_opts, 0, sizeof be_opts);
 
         sset_init(&be_opts.targets);
@@ -989,6 +1038,12 @@ bridge_configure_ipfix(struct bridge *br)
         if (be_cfg->obs_point_id) {
             be_opts.obs_point_id = *be_cfg->obs_point_id;
         }
+        if (be_cfg->cache_active_timeout) {
+            be_opts.cache_active_timeout = *be_cfg->cache_active_timeout;
+        }
+        if (be_cfg->cache_max_flows) {
+            be_opts.cache_max_flows = *be_cfg->cache_max_flows;
+        }
     }
 
     if (n_fe_opts > 0) {
@@ -996,20 +1051,24 @@ bridge_configure_ipfix(struct bridge *br)
         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) {
+            if (ovsrec_fscs_is_valid(fe_cfg, br)) {
                 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->cache_active_timeout = fe_cfg->ipfix->cache_active_timeout
+                    ? *fe_cfg->ipfix->cache_active_timeout : 0;
+                opts->cache_max_flows = fe_cfg->ipfix->cache_max_flows
+                    ? *fe_cfg->ipfix->cache_max_flows : 0;
                 opts++;
             }
         }
     }
 
-    ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts,
+    ofproto_set_ipfix(br->ofproto, valid_be_cfg ? &be_opts : NULL, fe_opts,
                       n_fe_opts);
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         sset_destroy(&be_opts.targets);
     }
 
@@ -1267,13 +1326,14 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg)
 }
 
 static void
-iface_set_ofp_port(struct iface *iface, int ofp_port)
+iface_set_ofp_port(struct iface *iface, ofp_port_t ofp_port)
 {
     struct bridge *br = iface->port->bridge;
 
-    ovs_assert(iface->ofp_port < 0 && ofp_port >= 0);
+    ovs_assert(iface->ofp_port == OFPP_NONE && ofp_port != OFPP_NONE);
     iface->ofp_port = ofp_port;
-    hmap_insert(&br->ifaces, &iface->ofp_port_node, hash_int(ofp_port, 0));
+    hmap_insert(&br->ifaces, &iface->ofp_port_node,
+                hash_ofp_port(ofp_port));
     iface_set_ofport(iface->cfg, ofp_port);
 }
 
@@ -1288,7 +1348,7 @@ iface_set_netdev_config(const struct ovsrec_interface *iface_cfg,
     error = netdev_set_config(netdev, &iface_cfg->options);
     if (error) {
         VLOG_WARN("could not configure network device %s (%s)",
-                  iface_cfg->name, strerror(error));
+                  iface_cfg->name, ovs_strerror(error));
     }
     return error;
 }
@@ -1308,12 +1368,12 @@ bridge_refresh_one_ofp_port(struct bridge *br,
 {
     const char *name = ofproto_port->name;
     const char *type = ofproto_port->type;
-    uint16_t ofp_port = ofproto_port->ofp_port;
+    ofp_port_t ofp_port = ofproto_port->ofp_port;
 
     struct iface *iface = iface_lookup(br, name);
     if (iface) {
         /* Check that the name-to-number mapping is one-to-one. */
-        if (iface->ofp_port >= 0) {
+        if (iface->ofp_port != OFPP_NONE) {
             VLOG_WARN("bridge %s: interface %s reported twice",
                       br->name, name);
             return false;
@@ -1367,7 +1427,7 @@ bridge_refresh_ofp_port(struct bridge *br)
         struct iface *iface;
 
         LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-            iface->ofp_port = -1;
+            iface->ofp_port = OFPP_NONE;
         }
     }
 
@@ -1389,7 +1449,7 @@ bridge_refresh_ofp_port(struct bridge *br)
         struct iface *iface, *iface_next;
 
         LIST_FOR_EACH_SAFE (iface, iface_next, port_elem, &port->ifaces) {
-            if (iface->ofp_port < 0) {
+            if (iface->ofp_port == OFPP_NONE) {
                 bridge_queue_if_cfg(br, iface->cfg, port->cfg);
                 iface_destroy(iface);
             }
@@ -1402,7 +1462,7 @@ bridge_refresh_ofp_port(struct bridge *br)
 }
 
 /* Opens a network device for 'if_cfg' and configures it.  If '*ofp_portp'
- * is negative, adds the network device to br->ofproto and stores the OpenFlow
+ * is OFPP_NONE, adds the network device to br->ofproto and stores the OpenFlow
  * port number in '*ofp_portp'; otherwise leaves br->ofproto and '*ofp_portp'
  * untouched.
  *
@@ -1411,7 +1471,7 @@ bridge_refresh_ofp_port(struct bridge *br)
 static int
 iface_do_create(const struct bridge *br,
                 const struct if_cfg *if_cfg,
-                int *ofp_portp, struct netdev **netdevp)
+                ofp_port_t *ofp_portp, struct netdev **netdevp)
 {
     const struct ovsrec_interface *iface_cfg = if_cfg->cfg;
     const struct ovsrec_port *port_cfg = if_cfg->parent;
@@ -1429,7 +1489,7 @@ iface_do_create(const struct bridge *br,
                         iface_get_type(iface_cfg, br->cfg), &netdev);
     if (error) {
         VLOG_WARN("could not open network device %s (%s)",
-                  iface_cfg->name, strerror(error));
+                  iface_cfg->name, ovs_strerror(error));
         goto error;
     }
 
@@ -1438,8 +1498,8 @@ iface_do_create(const struct bridge *br,
         goto error;
     }
 
-    if (*ofp_portp < 0) {
-        uint16_t ofp_port = if_cfg->ofport;
+    if (*ofp_portp == OFPP_NONE) {
+        ofp_port_t ofp_port = if_cfg->ofport;
 
         error = ofproto_port_add(br->ofproto, netdev, &ofp_port);
         if (error) {
@@ -1469,13 +1529,13 @@ error:
 }
 
 /* Creates a new iface on 'br' based on 'if_cfg'.  The new iface has OpenFlow
- * port number 'ofp_port'.  If ofp_port is negative, an OpenFlow port is
+ * port number 'ofp_port'.  If ofp_port is OFPP_NONE, an OpenFlow port is
  * automatically allocated for the iface.  Takes ownership of and
  * deallocates 'if_cfg'.
  *
  * Return true if an iface is successfully created, false otherwise. */
 static bool
-iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
+iface_create(struct bridge *br, struct if_cfg *if_cfg, ofp_port_t ofp_port)
 {
     const struct ovsrec_interface *iface_cfg = if_cfg->cfg;
     const struct ovsrec_port *port_cfg = if_cfg->parent;
@@ -1496,7 +1556,7 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
     error = iface_do_create(br, if_cfg, &ofp_port, &netdev);
     bridge_run_fast();
     if (error) {
-        iface_set_ofport(iface_cfg, -1);
+        iface_set_ofport(iface_cfg, OFPP_NONE);
         iface_clear_db_record(iface_cfg);
         ok = false;
         goto done;
@@ -1515,7 +1575,7 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
                 hash_string(iface_cfg->name, 0));
     iface->port = port;
     iface->name = xstrdup(iface_cfg->name);
-    iface->ofp_port = -1;
+    iface->ofp_port = OFPP_NONE;
     iface->netdev = netdev;
     iface->type = iface_get_type(iface_cfg, br->cfg);
     iface->cfg = iface_cfg;
@@ -1537,13 +1597,13 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
 
             error = netdev_open(port->name, "internal", &netdev);
             if (!error) {
-                uint16_t fake_ofp_port = if_cfg->ofport;
+                ofp_port_t fake_ofp_port = if_cfg->ofport;
 
                 ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
                 netdev_close(netdev);
             } else {
                 VLOG_WARN("could not open network device %s (%s)",
-                          port->name, strerror(error));
+                          port->name, ovs_strerror(error));
             }
         } else {
             /* Already exists, nothing to do. */
@@ -1558,23 +1618,6 @@ done:
     return ok;
 }
 
-/* Set Flow eviction threshold */
-static void
-bridge_configure_flow_eviction_threshold(struct bridge *br)
-{
-    const char *threshold_str;
-    unsigned threshold;
-
-    threshold_str = smap_get(&br->cfg->other_config,
-                             "flow-eviction-threshold");
-    if (threshold_str) {
-        threshold = strtoul(threshold_str, NULL, 10);
-    } else {
-        threshold = OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT;
-    }
-    ofproto_set_flow_eviction_threshold(br->ofproto, threshold);
-}
-
 /* Set forward BPDU option. */
 static void
 bridge_configure_forward_bpdu(struct bridge *br)
@@ -1795,6 +1838,7 @@ iface_refresh_status(struct iface *iface)
     int mtu;
     int64_t mtu_64;
     uint8_t mac[ETH_ADDR_LEN];
+    int64_t ifindex64;
     int error;
 
     if (iface_is_synthetic(iface)) {
@@ -1840,6 +1884,14 @@ iface_refresh_status(struct iface *iface)
     } else {
         ovsrec_interface_set_mac_in_use(iface->cfg, NULL);
     }
+
+    /* The netdev may return a negative number (such as -EOPNOTSUPP)
+     * if there is no valid ifindex number. */
+    ifindex64 = netdev_get_ifindex(iface->netdev);
+    if (ifindex64 < 0) {
+        ifindex64 = 0;
+    }
+    ovsrec_interface_set_ifindex(iface->cfg, &ifindex64, 1);
 }
 
 /* Writes 'iface''s CFM statistics to the database. 'iface' must not be
@@ -1855,11 +1907,13 @@ iface_refresh_cfm_stats(struct iface *iface)
         ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
         ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
         ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
+        ovsrec_interface_set_cfm_flap_count(cfg, NULL, 0);
         ovsrec_interface_set_cfm_health(cfg, NULL, 0);
         ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
     } else {
         const char *reasons[CFM_FAULT_N_REASONS];
         int64_t cfm_health = status.health;
+        int64_t cfm_flap_count = status.flap_count;
         bool faulted = status.faults != 0;
         size_t i, j;
 
@@ -1874,6 +1928,8 @@ iface_refresh_cfm_stats(struct iface *iface)
         }
         ovsrec_interface_set_cfm_fault_status(cfg, (char **) reasons, j);
 
+        ovsrec_interface_set_cfm_flap_count(cfg, &cfm_flap_count, 1);
+
         if (status.remote_opstate >= 0) {
             const char *remote_opstate = status.remote_opstate ? "up" : "down";
             ovsrec_interface_set_cfm_remote_opstate(cfg, remote_opstate);
@@ -1889,6 +1945,8 @@ iface_refresh_cfm_stats(struct iface *iface)
         } else {
             ovsrec_interface_set_cfm_health(cfg, NULL, 0);
         }
+
+        free(status.rmps);
     }
 }
 
@@ -2221,11 +2279,10 @@ instant_stats_run(void)
                 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);
-                }
+                ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port,
+                                            &smap);
+                ovsrec_interface_set_bfd_status(iface->cfg, &smap);
+                smap_destroy(&smap);
             }
         }
     }
@@ -2321,6 +2378,13 @@ bridge_run(void)
      * returns immediately. */
     bridge_init_ofproto(cfg);
 
+    /* Once the value of flow-restore-wait is false, we no longer should
+     * check its value from the database. */
+    if (cfg && ofproto_get_flow_restore_wait()) {
+        ofproto_set_flow_restore_wait(smap_get_bool(&cfg->other_config,
+                                        "flow-restore-wait", false));
+    }
+
     /* Let each datapath type do the work that it needs to do. */
     sset_init(&types);
     ofproto_enumerate_types(&types);
@@ -2412,6 +2476,8 @@ bridge_run(void)
              * process that forked us to exit successfully. */
             daemonize_complete();
 
+            vlog_enable_async();
+
             VLOG_INFO_ONCE("%s (Open vSwitch) %s", program_name, VERSION);
         }
     }
@@ -2507,13 +2573,11 @@ struct qos_unixctl_show_cbdata {
 };
 
 static void
-qos_unixctl_show_cb(unsigned int queue_id,
-                    const struct smap *details,
-                    void *aux)
+qos_unixctl_show_queue(unsigned int queue_id,
+                       const struct smap *details,
+                       struct iface *iface,
+                       struct ds *ds)
 {
-    struct qos_unixctl_show_cbdata *data = aux;
-    struct ds *ds = data->ds;
-    struct iface *iface = data->iface;
     struct netdev_queue_stats stats;
     struct smap_node *node;
     int error;
@@ -2544,7 +2608,7 @@ qos_unixctl_show_cb(unsigned int queue_id,
         }
     } else {
         ds_put_format(ds, "\tFailed to get statistics for queue %u: %s",
-                      queue_id, strerror(error));
+                      queue_id, ovs_strerror(error));
     }
 }
 
@@ -2557,8 +2621,6 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     struct iface *iface;
     const char *type;
     struct smap_node *node;
-    struct qos_unixctl_show_cbdata data;
-    int error;
 
     iface = iface_find(argv[1]);
     if (!iface) {
@@ -2569,19 +2631,22 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     netdev_get_qos(iface->netdev, &type, &smap);
 
     if (*type != '\0') {
+        struct netdev_queue_dump dump;
+        struct smap details;
+        unsigned int queue_id;
+
         ds_put_format(&ds, "QoS: %s %s\n", iface->name, type);
 
         SMAP_FOR_EACH (node, &smap) {
             ds_put_format(&ds, "%s: %s\n", node->key, node->value);
         }
 
-        data.ds = &ds;
-        data.iface = iface;
-        error = netdev_dump_queues(iface->netdev, qos_unixctl_show_cb, &data);
-
-        if (error) {
-            ds_put_format(&ds, "failed to dump queues: %s", strerror(error));
+        smap_init(&details);
+        NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &dump, iface->netdev) {
+            qos_unixctl_show_queue(queue_id, &details, iface, &ds);
         }
+        smap_destroy(&details);
+
         unixctl_command_reply(conn, ds_cstr(&ds));
     } else {
         ds_put_format(&ds, "QoS not configured on %s\n", iface->name);
@@ -3253,8 +3318,8 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 
     system_id = smap_get(&port->cfg->other_config, "lacp-system-id");
     if (system_id) {
-        if (sscanf(system_id, ETH_ADDR_SCAN_FMT,
-                   ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) {
+        if (!ovs_scan(system_id, ETH_ADDR_SCAN_FMT,
+                      ETH_ADDR_SCAN_ARGS(s->id))) {
             VLOG_WARN("port %s: LACP system ID (%s) must be an Ethernet"
                       " address.", port->name, system_id);
             return NULL;
@@ -3277,6 +3342,10 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 
     lacp_time = smap_get(&port->cfg->other_config, "lacp-time");
     s->fast = lacp_time && !strcasecmp(lacp_time, "fast");
+
+    s->fallback_ab_cfg = smap_get_bool(&port->cfg->other_config,
+                                       "lacp-fallback-ab", false);
+
     return s;
 }
 
@@ -3291,7 +3360,7 @@ iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
     key = smap_get_int(&iface->cfg->other_config, "lacp-aggregation-key", 0);
 
     if (portid <= 0 || portid > UINT16_MAX) {
-        portid = iface->ofp_port;
+        portid = ofp_to_u16(iface->ofp_port);
     }
 
     if (priority <= 0 || priority > UINT16_MAX) {
@@ -3365,6 +3434,9 @@ port_configure_bond(struct port *port, struct bond_settings *s)
 
     s->fake_iface = port->cfg->bond_fake_iface;
 
+    s->lacp_fallback_ab_cfg = smap_get_bool(&port->cfg->other_config,
+                                       "lacp-fallback-ab", false);
+
     LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
         netdev_set_miimon_interval(iface->netdev, miimon_interval);
     }
@@ -3415,11 +3487,11 @@ iface_destroy(struct iface *iface)
         struct port *port = iface->port;
         struct bridge *br = port->bridge;
 
-        if (br->ofproto && iface->ofp_port >= 0) {
+        if (br->ofproto && iface->ofp_port != OFPP_NONE) {
             ofproto_port_unregister(br->ofproto, iface->ofp_port);
         }
 
-        if (iface->ofp_port >= 0) {
+        if (iface->ofp_port != OFPP_NONE) {
             hmap_remove(&br->ifaces, &iface->ofp_port_node);
         }
 
@@ -3479,12 +3551,12 @@ if_cfg_lookup(const struct bridge *br, const char *name)
 }
 
 static struct iface *
-iface_from_ofp_port(const struct bridge *br, uint16_t ofp_port)
+iface_from_ofp_port(const struct bridge *br, ofp_port_t ofp_port)
 {
     struct iface *iface;
 
-    HMAP_FOR_EACH_IN_BUCKET (iface, ofp_port_node,
-                             hash_int(ofp_port, 0), &br->ifaces) {
+    HMAP_FOR_EACH_IN_BUCKET (iface, ofp_port_node, hash_ofp_port(ofp_port),
+                             &br->ifaces) {
         if (iface->ofp_port == ofp_port) {
             return iface;
         }
@@ -3512,7 +3584,7 @@ iface_set_mac(struct iface *iface)
             int error = netdev_set_etheraddr(iface->netdev, ea);
             if (error) {
                 VLOG_ERR("interface %s: setting MAC failed (%s)",
-                         iface->name, strerror(error));
+                         iface->name, ovs_strerror(error));
             }
         }
     }
@@ -3520,10 +3592,11 @@ iface_set_mac(struct iface *iface)
 
 /* Sets the ofport column of 'if_cfg' to 'ofport'. */
 static void
-iface_set_ofport(const struct ovsrec_interface *if_cfg, int64_t ofport)
+iface_set_ofport(const struct ovsrec_interface *if_cfg, ofp_port_t ofport)
 {
     if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
-        ovsrec_interface_set_ofport(if_cfg, &ofport, 1);
+        int64_t port = ofport == OFPP_NONE ? -1 : ofp_to_u16(ofport);
+        ovsrec_interface_set_ofport(if_cfg, &port, 1);
     }
 }
 
@@ -3548,14 +3621,10 @@ iface_clear_db_record(const struct ovsrec_interface *if_cfg)
         ovsrec_interface_set_cfm_remote_mpids(if_cfg, NULL, 0);
         ovsrec_interface_set_lacp_current(if_cfg, NULL, 0);
         ovsrec_interface_set_statistics(if_cfg, NULL, NULL, 0);
+        ovsrec_interface_set_ifindex(if_cfg, NULL, 0);
     }
 }
 
-struct iface_delete_queues_cbdata {
-    struct netdev *netdev;
-    const struct ovsdb_datum *queues;
-};
-
 static bool
 queue_ids_include(const struct ovsdb_datum *queues, int64_t target)
 {
@@ -3565,17 +3634,6 @@ queue_ids_include(const struct ovsdb_datum *queues, int64_t target)
     return ovsdb_datum_find_key(queues, &atom, OVSDB_TYPE_INTEGER) != UINT_MAX;
 }
 
-static void
-iface_delete_queues(unsigned int queue_id,
-                    const struct smap *details OVS_UNUSED, void *cbdata_)
-{
-    struct iface_delete_queues_cbdata *cbdata = cbdata_;
-
-    if (!queue_ids_include(cbdata->queues, queue_id)) {
-        netdev_delete_queue(cbdata->netdev, queue_id);
-    }
-}
-
 static void
 iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
 {
@@ -3586,7 +3644,10 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
     if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
         netdev_set_qos(iface->netdev, NULL, NULL);
     } else {
-        struct iface_delete_queues_cbdata cbdata;
+        const struct ovsdb_datum *queues;
+        struct netdev_queue_dump dump;
+        unsigned int queue_id;
+        struct smap details;
         bool queue_zero;
         size_t i;
 
@@ -3594,10 +3655,15 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
         netdev_set_qos(iface->netdev, qos->type, &qos->other_config);
 
         /* Deconfigure queues that were deleted. */
-        cbdata.netdev = iface->netdev;
-        cbdata.queues = ovsrec_qos_get_queues(qos, OVSDB_TYPE_INTEGER,
-                                              OVSDB_TYPE_UUID);
-        netdev_dump_queues(iface->netdev, iface_delete_queues, &cbdata);
+        queues = ovsrec_qos_get_queues(qos, OVSDB_TYPE_INTEGER,
+                                       OVSDB_TYPE_UUID);
+        smap_init(&details);
+        NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &dump, iface->netdev) {
+            if (!queue_ids_include(queues, queue_id)) {
+                netdev_delete_queue(iface->netdev, queue_id);
+            }
+        }
+        smap_destroy(&details);
 
         /* Configure queues for 'iface'. */
         queue_zero = false;
@@ -3629,7 +3695,7 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
         }
     }
 
-    if (iface->ofp_port >= 0) {
+    if (iface->ofp_port != OFPP_NONE) {
         const struct ofproto_port_queue *port_queues = queues_buf.data;
         size_t n_queues = queues_buf.size / sizeof *port_queues;
 
@@ -3707,11 +3773,13 @@ iface_is_synthetic(const struct iface *iface)
     return ovsdb_idl_row_is_synthetic(&iface->cfg->header_);
 }
 
-static int64_t
+static ofp_port_t
 iface_pick_ofport(const struct ovsrec_interface *cfg)
 {
-    int64_t ofport = cfg->n_ofport ? *cfg->ofport : OFPP_NONE;
-    return cfg->n_ofport_request ? *cfg->ofport_request : ofport;
+    ofp_port_t ofport = cfg->n_ofport ? u16_to_ofp(*cfg->ofport)
+                                      : OFPP_NONE;
+    return cfg->n_ofport_request ? u16_to_ofp(*cfg->ofport_request)
+                                 : ofport;
 }
 
 \f
@@ -4049,10 +4117,10 @@ collect_splinter_vlans(const struct ovsrec_open_vswitch *ovs_cfg)
                 if (!netdev_open(vlan_dev->name, "system", &netdev)) {
                     if (!netdev_get_in4(netdev, NULL, NULL) ||
                         !netdev_get_in6(netdev, NULL)) {
-                        vlandev_del(vlan_dev->name);
-                    } else {
                         /* It has an IP address configured, so we don't own
                          * it.  Don't delete it. */
+                    } else {
+                        vlandev_del(vlan_dev->name);
                     }
                     netdev_close(netdev);
                 }
@@ -4089,7 +4157,7 @@ static void
 configure_splinter_port(struct port *port)
 {
     struct ofproto *ofproto = port->bridge->ofproto;
-    uint16_t realdev_ofp_port;
+    ofp_port_t realdev_ofp_port;
     const char *realdev_name;
     struct iface *vlandev, *realdev;