vswitch: Use consistent representation of DSCP bits.
[sliver-openvswitch.git] / vswitchd / bridge.c
index bf4f1c6..74cba87 100644 (file)
@@ -50,7 +50,7 @@
 #include "util.h"
 #include "unixctl.h"
 #include "vlandev.h"
-#include "vswitch-idl.h"
+#include "lib/vswitch-idl.h"
 #include "xenserver.h"
 #include "vlog.h"
 #include "sflow_api.h"
@@ -75,6 +75,7 @@ struct iface {
     struct netdev *netdev;      /* Network device. */
     const char *type;           /* Usually same as cfg->type. */
     const struct ovsrec_interface *cfg;
+    bool need_refresh;          /* Refresh iface after create. */
 };
 
 struct mirror {
@@ -86,8 +87,8 @@ struct mirror {
 };
 
 struct port {
-    struct bridge *bridge;
     struct hmap_node hmap_node; /* Element in struct bridge's "ports" hmap. */
+    struct bridge *bridge;
     char *name;
 
     const struct ovsrec_port *cfg;
@@ -128,6 +129,9 @@ static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges);
 /* OVSDB IDL used to obtain configuration. */
 static struct ovsdb_idl *idl;
 
+/* Most recently processed IDL sequence number. */
+static unsigned int idl_seqno;
+
 /* Each time this timer expires, the bridge fetches systems and interface
  * statistics and pushes them into the database. */
 #define STATS_INTERVAL (5 * 1000) /* In milliseconds. */
@@ -139,6 +143,17 @@ static long long int stats_timer = LLONG_MIN;
 #define DB_LIMIT_INTERVAL (1 * 1000) /* In milliseconds. */
 static long long int db_limiter = LLONG_MIN;
 
+/* In some datapaths, creating and destroying OpenFlow ports can be extremely
+ * expensive.  This can cause bridge_reconfigure() to take a long time during
+ * which no other work can be done.  To deal with this problem, we limit port
+ * adds and deletions to a window of OFP_PORT_ACTION_WINDOW milliseconds per
+ * call to bridge_reconfigure().  If there is more work to do after the limit
+ * is reached, 'need_reconfigure', is flagged and it's done on the next loop.
+ * This allows the rest of the code to catch up on important things like
+ * forwarding packets. */
+#define OFP_PORT_ACTION_WINDOW 10
+static bool need_reconfigure = false;
+
 static void add_del_bridges(const struct ovsrec_open_vswitch *);
 static void bridge_del_ofprotos(void);
 static bool bridge_add_ofprotos(struct bridge *);
@@ -151,8 +166,10 @@ static size_t bridge_get_controllers(const struct bridge *br,
                                      struct ovsrec_controller ***controllersp);
 static void bridge_add_del_ports(struct bridge *,
                                  const unsigned long int *splinter_vlans);
-static void bridge_add_ofproto_ports(struct bridge *);
-static void bridge_del_ofproto_ports(struct bridge *);
+static void bridge_add_ofproto_ports(struct bridge *,
+                                     long long int *port_action_timer);
+static void bridge_del_ofproto_ports(struct bridge *,
+                                     long long int *port_action_timer);
 static void bridge_refresh_ofp_port(struct bridge *);
 static void bridge_configure_datapath_id(struct bridge *);
 static void bridge_configure_flow_eviction_threshold(struct bridge *);
@@ -171,11 +188,6 @@ static void bridge_pick_local_hw_addr(struct bridge *,
 static uint64_t bridge_pick_datapath_id(struct bridge *,
                                         const uint8_t bridge_ea[ETH_ADDR_LEN],
                                         struct iface *hw_addr_iface);
-static const char *bridge_get_other_config(const struct ovsrec_bridge *,
-                                            const char *key);
-static const char *get_port_other_config(const struct ovsrec_port *,
-                                         const char *key,
-                                         const char *default_value);
 static uint64_t dpid_from_hash(const void *, size_t nbytes);
 static bool bridge_has_bond_fake_iface(const struct bridge *,
                                        const char *name);
@@ -219,10 +231,6 @@ 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 const char *get_interface_other_config(const struct ovsrec_interface *,
-                                              const char *key,
-                                              const char *default_value);
-
 static void shash_from_ovs_idl_map(char **keys, char **values, size_t n,
                                    struct shash *);
 static void shash_to_ovs_idl_map(struct shash *,
@@ -256,6 +264,7 @@ bridge_init(const char *remote)
 {
     /* Create connection to database. */
     idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true);
+    idl_seqno = ovsdb_idl_get_seqno(idl);
     ovsdb_idl_set_lock(idl, "ovs_vswitchd");
 
     ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
@@ -287,6 +296,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_health);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
     ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
 
@@ -398,6 +408,7 @@ static void
 bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 {
     unsigned long int *splinter_vlans;
+    long long int port_action_timer;
     struct sockaddr_in *managers;
     struct bridge *br, *next;
     int sflow_bridge_number;
@@ -405,6 +416,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
     COVERAGE_INC(bridge_reconfigure);
 
+    port_action_timer = LLONG_MAX;
+    need_reconfigure = false;
+
     /* Create and destroy "struct bridge"s, "struct port"s, and "struct
      * iface"s according to 'ovs_cfg', with only very minimal configuration
      * otherwise.
@@ -427,7 +441,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     bridge_del_ofprotos();
     HMAP_FOR_EACH (br, node, &all_bridges) {
         if (br->ofproto) {
-            bridge_del_ofproto_ports(br);
+            bridge_del_ofproto_ports(br, &port_action_timer);
         }
     }
 
@@ -440,7 +454,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) {
         if (!br->ofproto) {
             if (bridge_add_ofprotos(br)) {
-                bridge_del_ofproto_ports(br);
+                bridge_del_ofproto_ports(br, &port_action_timer);
             } else {
                 bridge_destroy(br);
             }
@@ -448,7 +462,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     }
     HMAP_FOR_EACH (br, node, &all_bridges) {
         bridge_refresh_ofp_port(br);
-        bridge_add_ofproto_ports(br);
+        bridge_add_ofproto_ports(br, &port_action_timer);
     }
 
     /* Complete the configuration. */
@@ -484,9 +498,11 @@ 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();
+    if (!need_reconfigure) {
+        /* ovs-vswitchd has completed initialization, so allow the process that
+         * forked us to exit successfully. */
+        daemonize_complete();
+    }
 }
 
 /* Iterate over all ofprotos and delete any of them that do not have a
@@ -589,7 +605,7 @@ port_configure(struct port *port)
             s.vlan_mode = PORT_VLAN_TRUNK;
         }
     }
-    s.use_priority_tags = !strcmp("true", get_port_other_config(
+    s.use_priority_tags = !strcmp("true", ovsrec_port_get_other_config_value(
                                       cfg, "priority-tags", ""));
 
     /* Get LACP settings. */
@@ -780,7 +796,8 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
     const char *config_str;
     struct iface *iface;
 
-    config_str = get_port_other_config(port->cfg, "stp-enable", NULL);
+    config_str = ovsrec_port_get_other_config_value(port->cfg, "stp-enable",
+                                                    NULL);
     if (config_str && !strcmp(config_str, "false")) {
         port_s->enable = false;
         return;
@@ -813,7 +830,8 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
         return;
     }
 
-    config_str = get_port_other_config(port->cfg, "stp-port-num", NULL);
+    config_str = ovsrec_port_get_other_config_value(port->cfg, "stp-port-num",
+                                                    NULL);
     if (config_str) {
         unsigned long int port_num = strtoul(config_str, NULL, 0);
         int port_idx = port_num - 1;
@@ -842,7 +860,8 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
         port_s->port_num = (*port_num_counter)++;
     }
 
-    config_str = get_port_other_config(port->cfg, "stp-path-cost", NULL);
+    config_str = ovsrec_port_get_other_config_value(port->cfg, "stp-path-cost",
+                                                    NULL);
     if (config_str) {
         port_s->path_cost = strtoul(config_str, NULL, 10);
     } else {
@@ -859,7 +878,9 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
         }
     }
 
-    config_str = get_port_other_config(port->cfg, "stp-port-priority", NULL);
+    config_str = ovsrec_port_get_other_config_value(port->cfg,
+                                                    "stp-port-priority",
+                                                    NULL);
     if (config_str) {
         port_s->priority = strtoul(config_str, NULL, 0);
     } else {
@@ -880,7 +901,9 @@ bridge_configure_stp(struct bridge *br)
         int port_num_counter;
         unsigned long *port_num_bitmap;
 
-        config_str = bridge_get_other_config(br->cfg, "stp-system-id");
+        config_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "stp-system-id",
+                                                          NULL);
         if (config_str) {
             uint8_t ea[ETH_ADDR_LEN];
 
@@ -895,28 +918,36 @@ bridge_configure_stp(struct bridge *br)
             br_s.system_id = eth_addr_to_uint64(br->ea);
         }
 
-        config_str = bridge_get_other_config(br->cfg, "stp-priority");
+        config_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "stp-priority",
+                                                          NULL);
         if (config_str) {
             br_s.priority = strtoul(config_str, NULL, 0);
         } else {
             br_s.priority = STP_DEFAULT_BRIDGE_PRIORITY;
         }
 
-        config_str = bridge_get_other_config(br->cfg, "stp-hello-time");
+        config_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "stp-hello-time",
+                                                          NULL);
         if (config_str) {
             br_s.hello_time = strtoul(config_str, NULL, 10) * 1000;
         } else {
             br_s.hello_time = STP_DEFAULT_HELLO_TIME;
         }
 
-        config_str = bridge_get_other_config(br->cfg, "stp-max-age");
+        config_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "stp-max-age",
+                                                          NULL);
         if (config_str) {
             br_s.max_age = strtoul(config_str, NULL, 10) * 1000;
         } else {
             br_s.max_age = STP_DEFAULT_MAX_AGE;
         }
 
-        config_str = bridge_get_other_config(br->cfg, "stp-forward-delay");
+        config_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "stp-forward-delay",
+                                                          NULL);
         if (config_str) {
             br_s.fwd_delay = strtoul(config_str, NULL, 10) * 1000;
         } else {
@@ -1020,6 +1051,23 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg)
     shash_destroy(&new_br);
 }
 
+static bool
+may_port_action(long long int *port_action_timer)
+{
+    if (need_reconfigure) {
+        return false;
+    }
+
+    time_refresh();
+    if (*port_action_timer == LLONG_MAX) {
+        *port_action_timer = time_msec() + OFP_PORT_ACTION_WINDOW;
+    } else if (time_msec() > *port_action_timer) {
+        need_reconfigure = true;
+        return false;
+    }
+    return true;
+}
+
 /* Delete each ofproto port on 'br' that doesn't have a corresponding "struct
  * iface".
  *
@@ -1027,7 +1075,8 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg)
  * port already belongs to a different datapath, so we must do all port
  * deletions before any port additions. */
 static void
-bridge_del_ofproto_ports(struct bridge *br)
+bridge_del_ofproto_ports(struct bridge *br,
+                         long long int *port_action_timer)
 {
     struct ofproto_port_dump dump;
     struct ofproto_port ofproto_port;
@@ -1058,10 +1107,16 @@ bridge_del_ofproto_ports(struct bridge *br)
                 || !strcmp(netdev_get_type(iface->netdev), type))) {
             continue;
         }
-        error = ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
-        if (error) {
-            VLOG_WARN("bridge %s: failed to remove %s interface (%s)",
-                      br->name, name, strerror(error));
+
+        if (may_port_action(port_action_timer)) {
+            error = ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
+            if (error) {
+                VLOG_WARN("bridge %s: failed to remove %s interface (%s)",
+                          br->name, name, strerror(error));
+            } else {
+                VLOG_INFO("bridge %s: removed interface %s (%d)", br->name,
+                          name, ofproto_port.ofp_port);
+            }
         }
         if (iface) {
             netdev_close(iface->netdev);
@@ -1119,7 +1174,8 @@ bridge_refresh_ofp_port(struct bridge *br)
  * Delete any "struct iface" for which this fails.
  * Delete any "struct port" that thereby ends up with no ifaces. */
 static void
-bridge_add_ofproto_ports(struct bridge *br)
+bridge_add_ofproto_ports(struct bridge *br,
+                         long long int *port_action_timer)
 {
     struct port *port, *next_port;
 
@@ -1130,6 +1186,12 @@ bridge_add_ofproto_ports(struct bridge *br)
         LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) {
             int error;
 
+            if (iface->ofp_port < 0 && !may_port_action(port_action_timer)) {
+                iface_clear_db_record(iface->cfg);
+                iface_destroy(iface);
+                continue;
+            }
+
             /* Open the netdev. */
             if (!iface->netdev) {
                 error = netdev_open(iface->name, iface->type, &iface->netdev);
@@ -1174,6 +1236,8 @@ bridge_add_ofproto_ports(struct bridge *br)
                 error = ofproto_port_add(br->ofproto, iface->netdev,
                                          &ofp_port);
                 if (!error) {
+                    VLOG_INFO("bridge %s: added interface %s (%d)", br->name,
+                              iface->name, ofp_port);
                     iface_set_ofp_port(iface, ofp_port);
                 } else {
                     netdev_close(iface->netdev);
@@ -1182,9 +1246,10 @@ bridge_add_ofproto_ports(struct bridge *br)
             }
 
             /* Populate stats columns in new Interface rows. */
-            if (iface->netdev && !iface->cfg->mtu) {
+            if (iface->netdev && iface->need_refresh) {
                 iface_refresh_stats(iface);
                 iface_refresh_status(iface);
+                iface->need_refresh = false;
             }
 
             /* Delete the iface if we failed. */
@@ -1199,12 +1264,22 @@ bridge_add_ofproto_ports(struct bridge *br)
                     /* We already reported a related error, don't bother
                      * duplicating it. */
                 }
+                if (!ofproto_port_query_by_name(br->ofproto, port->name,
+                                                &ofproto_port)) {
+                    VLOG_INFO("bridge %s: removed interface %s (%d)",
+                              br->name, port->name, ofproto_port.ofp_port);
+                    ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
+                    ofproto_port_destroy(&ofproto_port);
+                }
                 iface_clear_db_record(iface->cfg);
                 iface_destroy(iface);
             }
         }
+
         if (list_is_empty(&port->ifaces)) {
-            VLOG_WARN("%s port has no interfaces, dropping", port->name);
+            if (!need_reconfigure) {
+                VLOG_WARN("%s port has no interfaces, dropping", port->name);
+            }
             port_destroy(port);
             continue;
         }
@@ -1218,6 +1293,9 @@ bridge_add_ofproto_ports(struct bridge *br)
 
                 error = netdev_open(port->name, "internal", &netdev);
                 if (!error) {
+                    /* There are unlikely to be a great number of fake
+                     * interfaces so we don't bother rate limiting their
+                     * creation. */
                     ofproto_port_add(br->ofproto, netdev, NULL);
                     netdev_close(netdev);
                 } else {
@@ -1232,27 +1310,6 @@ bridge_add_ofproto_ports(struct bridge *br)
     }
 }
 
-static const char *
-get_ovsrec_key_value(char **keys, char **values, size_t n, const char *key)
-{
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        if (!strcmp(keys[i], key)) {
-            return values[i];
-        }
-    }
-    return NULL;
-}
-
-static const char *
-bridge_get_other_config(const struct ovsrec_bridge *br_cfg, const char *key)
-{
-    return get_ovsrec_key_value(br_cfg->key_other_config,
-                                br_cfg->value_other_config,
-                                br_cfg->n_other_config, key);
-}
-
 /* Set Flow eviction threshold */
 static void
 bridge_configure_flow_eviction_threshold(struct bridge *br)
@@ -1260,8 +1317,10 @@ bridge_configure_flow_eviction_threshold(struct bridge *br)
     const char *threshold_str;
     unsigned threshold;
 
-    threshold_str = bridge_get_other_config(br->cfg,
-                                            "flow-eviction-threshold");
+    threshold_str =
+        ovsrec_bridge_get_other_config_value(br->cfg,
+                                             "flow-eviction-threshold",
+                                             NULL);
     if (threshold_str) {
         threshold = strtoul(threshold_str, NULL, 10);
     } else {
@@ -1277,7 +1336,9 @@ bridge_configure_forward_bpdu(struct bridge *br)
     const char *forward_bpdu_str;
     bool forward_bpdu = false;
 
-    forward_bpdu_str = bridge_get_other_config(br->cfg, "forward-bpdu");
+    forward_bpdu_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                            "forward-bpdu",
+                                                            NULL);
     if (forward_bpdu_str && !strcmp(forward_bpdu_str, "true")) {
         forward_bpdu = true;
     }
@@ -1291,7 +1352,9 @@ bridge_configure_mac_idle_time(struct bridge *br)
     const char *idle_time_str;
     int idle_time;
 
-    idle_time_str = bridge_get_other_config(br->cfg, "mac-aging-time");
+    idle_time_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                         "mac-aging-time",
+                                                         NULL);
     idle_time = (idle_time_str && atoi(idle_time_str)
                  ? atoi(idle_time_str)
                  : MAC_ENTRY_DEFAULT_IDLE_TIME);
@@ -1312,7 +1375,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     *hw_addr_iface = NULL;
 
     /* Did the user request a particular MAC? */
-    hwaddr = bridge_get_other_config(br->cfg, "hwaddr");
+    hwaddr = ovsrec_bridge_get_other_config_value(br->cfg, "hwaddr", NULL);
     if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
         if (eth_addr_is_multicast(ea)) {
             VLOG_ERR("bridge %s: cannot set MAC address to multicast "
@@ -1402,10 +1465,11 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
         VLOG_DBG("bridge %s: using bridge Ethernet address "ETH_ADDR_FMT,
                  br->name, ETH_ADDR_ARGS(ea));
     } else {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
         memcpy(ea, br->default_ea, ETH_ADDR_LEN);
         *hw_addr_iface = NULL;
-        VLOG_WARN("bridge %s: using default bridge Ethernet "
-                  "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
+        VLOG_WARN_RL(&rl, "bridge %s: using default bridge Ethernet "
+                     "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
     }
 
     hmapx_destroy(&mirror_output_ports);
@@ -1436,7 +1500,8 @@ bridge_pick_datapath_id(struct bridge *br,
     const char *datapath_id;
     uint64_t dpid;
 
-    datapath_id = bridge_get_other_config(br->cfg, "datapath-id");
+    datapath_id = ovsrec_bridge_get_other_config_value(br->cfg, "datapath-id",
+                                                       NULL);
     if (datapath_id && dpid_from_string(datapath_id, &dpid)) {
         return dpid;
     }
@@ -1553,6 +1618,7 @@ iface_refresh_cfm_stats(struct iface *iface)
     int fault, error;
     const uint64_t *rmps;
     size_t n_rmps;
+    int health;
 
     if (iface_is_synthetic(iface)) {
         return;
@@ -1588,6 +1654,15 @@ iface_refresh_cfm_stats(struct iface *iface)
     } else {
         ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
     }
+
+    health = ofproto_port_get_cfm_health(iface->port->bridge->ofproto,
+                                        iface->ofp_port);
+    if (health >= 0) {
+        int64_t cfm_health = health;
+        ovsrec_interface_set_cfm_health(cfg, &cfm_health, 1);
+    } else {
+        ovsrec_interface_set_cfm_health(cfg, NULL, 0);
+    }
 }
 
 static void
@@ -1734,10 +1809,9 @@ enable_system_stats(const struct ovsrec_open_vswitch *cfg)
     const char *enable;
 
     /* Use other-config:enable-system-stats by preference. */
-    enable = get_ovsrec_key_value(cfg->key_other_config,
-                                  cfg->value_other_config,
-                                  cfg->n_other_config,
-                                  "enable-statistics");
+    enable = ovsrec_open_vswitch_get_other_config_value(cfg,
+                                                        "enable-statistics",
+                                                        NULL);
     if (enable) {
         return !strcmp(enable, "true");
     }
@@ -1859,11 +1933,10 @@ bridge_run(void)
     const struct ovsrec_open_vswitch *cfg;
 
     bool vlan_splinters_changed;
-    bool database_changed;
     struct bridge *br;
 
     /* (Re)configure if necessary. */
-    database_changed = ovsdb_idl_run(idl);
+    ovsdb_idl_run(idl);
     if (ovsdb_idl_is_lock_contended(idl)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
         struct bridge *br, *next_br;
@@ -1910,7 +1983,9 @@ bridge_run(void)
         }
     }
 
-    if (database_changed || vlan_splinters_changed) {
+    if (need_reconfigure || ovsdb_idl_get_seqno(idl) != idl_seqno
+        || vlan_splinters_changed) {
+        idl_seqno = ovsdb_idl_get_seqno(idl);
         if (cfg) {
             struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
 
@@ -2014,6 +2089,11 @@ void
 bridge_wait(void)
 {
     ovsdb_idl_wait(idl);
+
+    if (need_reconfigure) {
+        poll_immediate_wake();
+    }
+
     if (!hmap_is_empty(&all_bridges)) {
         struct bridge *br;
 
@@ -2343,6 +2423,8 @@ static void
 bridge_ofproto_controller_from_ovsrec(const struct ovsrec_controller *c,
                                       struct ofproto_controller *oc)
 {
+    const char *config_str;
+
     oc->target = c->target;
     oc->max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8;
     oc->probe_interval = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
@@ -2353,6 +2435,16 @@ bridge_ofproto_controller_from_ovsrec(const struct ovsrec_controller *c,
                        ? *c->controller_burst_limit : 0);
     oc->enable_async_msgs = (!c->enable_async_messages
                              || *c->enable_async_messages);
+    config_str = ovsrec_controller_get_other_config_value(c, "dscp", NULL);
+
+    oc->dscp = DSCP_DEFAULT;
+    if (config_str) {
+        int dscp = atoi(config_str);
+
+        if (dscp >= 0 && dscp <= 63) {
+            oc->dscp = dscp;
+        }
+    }
 }
 
 /* Configures the IP stack for 'br''s local interface properly according to the
@@ -2437,13 +2529,17 @@ bridge_configure_remotes(struct bridge *br,
     size_t i;
 
     /* Check if we should disable in-band control on this bridge. */
-    disable_ib_str = bridge_get_other_config(br->cfg, "disable-in-band");
+    disable_ib_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                          "disable-in-band",
+                                                          NULL);
     if (disable_ib_str && !strcmp(disable_ib_str, "true")) {
         disable_in_band = true;
     }
 
     /* Set OpenFlow queue ID for in-band control. */
-    queue_id_str = bridge_get_other_config(br->cfg, "in-band-queue");
+    queue_id_str = ovsrec_bridge_get_other_config_value(br->cfg,
+                                                        "in-band-queue",
+                                                        NULL);
     queue_id = queue_id_str ? strtol(queue_id_str, NULL, 10) : -1;
     ofproto_set_in_band_queue(br->ofproto, queue_id);
 
@@ -2592,36 +2688,9 @@ port_create(struct bridge *br, const struct ovsrec_port *cfg)
     list_init(&port->ifaces);
 
     hmap_insert(&br->ports, &port->hmap_node, hash_string(port->name, 0));
-
-    VLOG_INFO("created port %s on bridge %s", port->name, br->name);
-
     return port;
 }
 
-static const char *
-get_port_other_config(const struct ovsrec_port *port, const char *key,
-                      const char *default_value)
-{
-    const char *value;
-
-    value = get_ovsrec_key_value(port->key_other_config,
-                                 port->value_other_config,
-                                 port->n_other_config, key);
-    return value ? value : default_value;
-}
-
-static const char *
-get_interface_other_config(const struct ovsrec_interface *iface,
-                           const char *key, const char *default_value)
-{
-    const char *value;
-
-    value = get_ovsrec_key_value(iface->key_other_config,
-                                 iface->value_other_config,
-                                 iface->n_other_config, key);
-    return value ? value : default_value;
-}
-
 /* Deletes interfaces from 'port' that are no longer configured for it. */
 static void
 port_del_ifaces(struct port *port)
@@ -2711,9 +2780,6 @@ port_destroy(struct port *port)
         }
 
         hmap_remove(&br->ports, &port->hmap_node);
-
-        VLOG_INFO("destroyed port %s on bridge %s", port->name, br->name);
-
         free(port->name);
         free(port);
     }
@@ -2768,7 +2834,8 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 
     s->name = port->name;
 
-    system_id = get_port_other_config(port->cfg, "lacp-system-id", NULL);
+    system_id = ovsrec_port_get_other_config_value(port->cfg, "lacp-system-id",
+                                                   NULL);
     if (system_id) {
         if (sscanf(system_id, ETH_ADDR_SCAN_FMT,
                    ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) {
@@ -2786,17 +2853,20 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
     }
 
     /* Prefer bondable links if unspecified. */
-    priority = atoi(get_port_other_config(port->cfg, "lacp-system-priority",
-                                          "0"));
+    priority = atoi(ovsrec_port_get_other_config_value(port->cfg,
+                                                       "lacp-system-priority",
+                                                       "0"));
     s->priority = (priority > 0 && priority <= UINT16_MAX
                    ? priority
                    : UINT16_MAX - !list_is_short(&port->ifaces));
 
-    s->heartbeat = !strcmp(get_port_other_config(port->cfg,
-                                                 "lacp-heartbeat",
-                                                 "false"), "true");
+    s->heartbeat = !strcmp(ovsrec_port_get_other_config_value(port->cfg,
+                                                              "lacp-heartbeat",
+                                                              "false"),
+                           "true");
 
-    lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow");
+    lacp_time = ovsrec_port_get_other_config_value(port->cfg, "lacp-time",
+                                                   "slow");
     custom_time = atoi(lacp_time);
     if (!strcmp(lacp_time, "fast")) {
         s->lacp_time = LACP_TIME_FAST;
@@ -2817,11 +2887,16 @@ iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
 {
     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"));
+    portid = atoi(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                          "lacp-port-id",
+                                                          "0"));
+    priority =
+        atoi(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                     "lacp-port-priority",
+                                                     "0"));
+    key = atoi(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                       "lacp-aggregation-key",
+                                                       "0"));
 
     if (portid <= 0 || portid > UINT16_MAX) {
         portid = iface->ofp_port;
@@ -2874,13 +2949,16 @@ port_configure_bond(struct port *port, struct bond_settings *s,
                   port->name);
     }
 
-    miimon_interval = atoi(get_port_other_config(port->cfg,
-                                                 "bond-miimon-interval", "0"));
+    miimon_interval =
+        atoi(ovsrec_port_get_other_config_value(port->cfg,
+                                                "bond-miimon-interval", "0"));
     if (miimon_interval <= 0) {
         miimon_interval = 200;
     }
 
-    detect_s = get_port_other_config(port->cfg, "bond-detect-mode", "carrier");
+    detect_s = ovsrec_port_get_other_config_value(port->cfg,
+                                                  "bond-detect-mode",
+                                                  "carrier");
     if (!strcmp(detect_s, "carrier")) {
         miimon_interval = 0;
     } else if (strcmp(detect_s, "miimon")) {
@@ -2891,9 +2969,13 @@ port_configure_bond(struct port *port, struct bond_settings *s,
 
     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->basis = atoi(ovsrec_port_get_other_config_value(port->cfg,
+                                                       "bond-hash-basis",
+                                                       "0"));
     s->rebalance_interval = atoi(
-        get_port_other_config(port->cfg, "bond-rebalance-interval", "10000"));
+        ovsrec_port_get_other_config_value(port->cfg,
+                                           "bond-rebalance-interval",
+                                           "10000"));
     if (s->rebalance_interval && s->rebalance_interval < 1000) {
         s->rebalance_interval = 1000;
     }
@@ -2904,8 +2986,10 @@ port_configure_bond(struct port *port, struct bond_settings *s,
     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"));
+        stable_id =
+            atoll(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                          "bond-stable-id",
+                                                          "0"));
         if (stable_id <= 0 || stable_id >= UINT32_MAX) {
             stable_id = iface->ofp_port;
         }
@@ -2939,6 +3023,7 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
     iface->tag = tag_create_random();
     iface->netdev = NULL;
     iface->cfg = if_cfg;
+    iface->need_refresh = true;
 
     hmap_insert(&br->iface_by_name, &iface->name_node, hash_string(name, 0));
 
@@ -3238,11 +3323,15 @@ iface_configure_cfm(struct iface *iface)
     }
 
     s.mpid = *cfg->cfm_mpid;
-    s.interval = atoi(get_interface_other_config(iface->cfg, "cfm_interval",
-                                                 "0"));
-    cfm_ccm_vlan = get_interface_other_config(iface->cfg, "cfm_ccm_vlan", "0");
-    s.ccm_pcp = atoi(get_interface_other_config(iface->cfg, "cfm_ccm_pcp",
-                                                "0"));
+    s.interval = atoi(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                              "cfm_interval",
+                                                              "0"));
+    cfm_ccm_vlan = ovsrec_interface_get_other_config_value(iface->cfg,
+                                                           "cfm_ccm_vlan",
+                                                           "0");
+    s.ccm_pcp = atoi(ovsrec_interface_get_other_config_value(iface->cfg,
+                                                             "cfm_ccm_pcp",
+                                                             "0"));
     if (s.interval <= 0) {
         s.interval = 1000;
     }
@@ -3256,11 +3345,14 @@ iface_configure_cfm(struct iface *iface)
         }
     }
 
-    extended_str = get_interface_other_config(iface->cfg, "cfm_extended",
-                                              "false");
+    extended_str = ovsrec_interface_get_other_config_value(iface->cfg,
+                                                           "cfm_extended",
+                                                           "false");
     s.extended = !strcasecmp("true", extended_str);
 
-    opstate_str = get_interface_other_config(iface->cfg, "cfm_opstate", "up");
+    opstate_str = ovsrec_interface_get_other_config_value(iface->cfg,
+                                                          "cfm_opstate",
+                                                          "up");
     s.opup = !strcasecmp("up", opstate_str);
 
     ofproto_port_set_cfm(iface->port->bridge->ofproto, iface->ofp_port, &s);
@@ -3273,6 +3365,7 @@ iface_is_synthetic(const struct iface *iface)
 {
     return ovsdb_idl_row_is_synthetic(&iface->cfg->header_);
 }
+
 \f
 /* Port mirroring. */
 
@@ -3501,7 +3594,9 @@ vlan_splinters_is_enabled(const struct ovsrec_interface *iface_cfg)
 {
     const char *value;
 
-    value = get_interface_other_config(iface_cfg, "enable-vlan-splinters", "");
+    value = ovsrec_interface_get_other_config_value(iface_cfg,
+                                                    "enable-vlan-splinters",
+                                                    "");
     return !strcmp(value, "true");
 }
 
@@ -3646,7 +3741,8 @@ configure_splinter_port(struct port *port)
     vlandev = CONTAINER_OF(list_front(&port->ifaces), struct iface,
                            port_elem);
 
-    realdev_name = get_port_other_config(port->cfg, "realdev", NULL);
+    realdev_name = ovsrec_port_get_other_config_value(port->cfg,
+                                                      "realdev", NULL);
     realdev = iface_lookup(port->bridge, realdev_name);
     realdev_ofp_port = realdev ? realdev->ofp_port : 0;