vswitchd: Avoid writing to const struct
[sliver-openvswitch.git] / vswitchd / bridge.c
index 3356a04..f508d58 100644 (file)
@@ -36,6 +36,7 @@
 #include "meta-flow.h"
 #include "netdev.h"
 #include "ofp-print.h"
+#include "ofp-util.h"
 #include "ofpbuf.h"
 #include "ofproto/ofproto.h"
 #include "poll-loop.h"
@@ -181,7 +182,7 @@ 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_idle_time(struct bridge *);
+static void bridge_configure_mac_table(struct bridge *);
 static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
 static void bridge_configure_stp(struct bridge *);
 static void bridge_configure_tables(struct bridge *);
@@ -227,6 +228,8 @@ 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_is_internal(const struct ovsrec_interface *iface,
+                              const struct ovsrec_bridge *br);
 static const char *iface_get_type(const struct ovsrec_interface *,
                                   const struct ovsrec_bridge *);
 static void iface_destroy(struct iface *);
@@ -244,6 +247,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 *);
 
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
  *
@@ -276,25 +280,26 @@ bridge_init_ofproto(const struct ovsrec_open_vswitch *cfg)
 
     shash_init(&iface_hints);
 
-    for (i = 0; i < cfg->n_bridges; i++) {
-        const struct ovsrec_bridge *br_cfg = cfg->bridges[i];
-        int j;
+    if (cfg) {
+        for (i = 0; i < cfg->n_bridges; i++) {
+            const struct ovsrec_bridge *br_cfg = cfg->bridges[i];
+            int j;
 
-        for (j = 0; j < br_cfg->n_ports; j++) {
-            struct ovsrec_port *port_cfg = br_cfg->ports[j];
-            int k;
+            for (j = 0; j < br_cfg->n_ports; j++) {
+                struct ovsrec_port *port_cfg = br_cfg->ports[j];
+                int k;
 
-            for (k = 0; k < port_cfg->n_interfaces; k++) {
-                struct ovsrec_interface *if_cfg = port_cfg->interfaces[k];
-                struct iface_hint *iface_hint;
+                for (k = 0; k < port_cfg->n_interfaces; k++) {
+                    struct ovsrec_interface *if_cfg = port_cfg->interfaces[k];
+                    struct iface_hint *iface_hint;
 
-                iface_hint = xmalloc(sizeof *iface_hint);
-                iface_hint->br_name = br_cfg->name;
-                iface_hint->br_type = br_cfg->datapath_type;
-                iface_hint->ofp_port = if_cfg->n_ofport_request ?
-                                       *if_cfg->ofport_request : OFPP_NONE;
+                    iface_hint = xmalloc(sizeof *iface_hint);
+                    iface_hint->br_name = br_cfg->name;
+                    iface_hint->br_type = br_cfg->datapath_type;
+                    iface_hint->ofp_port = iface_pick_ofport(if_cfg);
 
-                shash_add(&iface_hints, if_cfg->name, iface_hint);
+                    shash_add(&iface_hints, if_cfg->name, iface_hint);
+                }
             }
         }
     }
@@ -586,7 +591,7 @@ 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_idle_time(br);
+        bridge_configure_mac_table(br);
         bridge_configure_remotes(br, managers, n_managers);
         bridge_configure_netflow(br);
         bridge_configure_sflow(br, &sflow_bridge_number);
@@ -810,6 +815,18 @@ bridge_configure_datapath_id(struct bridge *br)
     free(dpid_string);
 }
 
+/* Returns a bitmap of "enum ofputil_protocol"s that are allowed for use with
+ * 'br'. */
+static uint32_t
+bridge_get_allowed_versions(struct bridge *br)
+{
+    if (!br->cfg->n_protocols)
+        return 0;
+
+    return ofputil_versions_from_strings(br->cfg->protocols,
+                                         br->cfg->n_protocols);
+}
+
 /* Set NetFlow configuration on 'br'. */
 static void
 bridge_configure_netflow(struct bridge *br)
@@ -996,16 +1013,11 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
         port_s->path_cost = strtoul(config_str, NULL, 10);
     } else {
         enum netdev_features current;
+        unsigned int mbps;
 
-        if (netdev_get_features(iface->netdev, &current, NULL, NULL, NULL)) {
-            /* Couldn't get speed, so assume 100Mb/s. */
-            port_s->path_cost = 19;
-        } else {
-            unsigned int mbps;
-
-            mbps = netdev_features_to_bps(current) / 1000000;
-            port_s->path_cost = stp_convert_speed_to_cost(mbps);
-        }
+        netdev_get_features(iface->netdev, &current, NULL, NULL, NULL);
+        mbps = netdev_features_to_bps(current, 100 * 1000 * 1000) / 1000000;
+        port_s->path_cost = stp_convert_speed_to_cost(mbps);
     }
 
     config_str = smap_get(&port->cfg->other_config, "stp-port-priority");
@@ -1233,7 +1245,7 @@ bridge_refresh_one_ofp_port(struct bridge *br,
              * configured as the user requested, so we must destroy it. */
             return false;
         } else {
-            /* It's the right type and configured correctly.  keep it. */
+            /* It's the right type and configured correctly.  Keep it. */
             iface_set_ofp_port(iface, ofp_port);
             return true;
         }
@@ -1350,7 +1362,8 @@ iface_do_create(const struct bridge *br,
                  br->name, iface_cfg->name, *ofp_portp);
     }
 
-    if (port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter")) {
+    if ((port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter"))
+        || iface_is_internal(iface_cfg, br->cfg)) {
         netdev_turn_flags_on(netdev, NETDEV_UP, true);
     }
 
@@ -1391,6 +1404,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_clear_db_record(iface_cfg);
         ok = false;
         goto done;
@@ -1479,18 +1493,27 @@ bridge_configure_forward_bpdu(struct bridge *br)
                                            false));
 }
 
-/* Set MAC aging time for 'br'. */
+/* Set MAC learning table configuration for 'br'. */
 static void
-bridge_configure_mac_idle_time(struct bridge *br)
+bridge_configure_mac_table(struct bridge *br)
 {
     const char *idle_time_str;
     int idle_time;
 
+    const char *mac_table_size_str;
+    int mac_table_size;
+
     idle_time_str = smap_get(&br->cfg->other_config, "mac-aging-time");
     idle_time = (idle_time_str && atoi(idle_time_str)
                  ? atoi(idle_time_str)
                  : MAC_ENTRY_DEFAULT_IDLE_TIME);
-    ofproto_set_mac_idle_time(br->ofproto, idle_time);
+
+    mac_table_size_str = smap_get(&br->cfg->other_config, "mac-table-size");
+    mac_table_size = (mac_table_size_str && atoi(mac_table_size_str)
+                      ? atoi(mac_table_size_str)
+                      : MAC_DEFAULT_MAX);
+
+    ofproto_set_mac_table_config(br->ofproto, idle_time, mac_table_size);
 }
 
 static void
@@ -1593,15 +1616,10 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             found_addr = true;
         }
     }
-    if (found_addr) {
-        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);
+
+    if (!found_addr) {
         memcpy(ea, br->default_ea, ETH_ADDR_LEN);
         *hw_addr_iface = NULL;
-        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);
@@ -1701,12 +1719,11 @@ iface_refresh_status(struct iface *iface)
     smap_destroy(&smap);
 
     error = netdev_get_features(iface->netdev, &current, NULL, NULL, NULL);
-    if (!error) {
+    bps = !error ? netdev_features_to_bps(current, 0) : 0;
+    if (bps) {
         ovsrec_interface_set_duplex(iface->cfg,
                                     netdev_features_is_full_duplex(current)
                                     ? "full" : "half");
-        /* warning: uint64_t -> int64_t conversion */
-        bps = netdev_features_to_bps(current);
         ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
     }
     else {
@@ -2097,7 +2114,7 @@ bridge_run_fast(void)
 void
 bridge_run(void)
 {
-    static const struct ovsrec_open_vswitch null_cfg;
+    static struct ovsrec_open_vswitch null_cfg;
     const struct ovsrec_open_vswitch *cfg;
     struct ovsdb_idl_txn *reconf_txn = NULL;
     struct sset types;
@@ -2106,7 +2123,7 @@ bridge_run(void)
     bool vlan_splinters_changed;
     struct bridge *br;
 
-    ovsrec_open_vswitch_init((struct ovsrec_open_vswitch *) &null_cfg);
+    ovsrec_open_vswitch_init(&null_cfg);
 
     /* (Re)configure if necessary. */
     if (!reconfiguring) {
@@ -2533,7 +2550,7 @@ bridge_queue_if_cfg(struct bridge *br,
 
     if_cfg->cfg = cfg;
     if_cfg->parent = parent;
-    if_cfg->ofport = cfg->n_ofport_request ? *cfg->ofport_request : OFPP_NONE;
+    if_cfg->ofport = iface_pick_ofport(cfg);
     hmap_insert(&br->if_cfg_todo, &if_cfg->hmap_node,
                 hash_string(if_cfg->cfg->name, 0));
 }
@@ -2801,7 +2818,8 @@ bridge_configure_remotes(struct bridge *br,
         n_ocs++;
     }
 
-    ofproto_set_controllers(br->ofproto, ocs, n_ocs);
+    ofproto_set_controllers(br->ofproto, ocs, n_ocs,
+                            bridge_get_allowed_versions(br));
     free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
     free(ocs);
 
@@ -3139,17 +3157,32 @@ port_is_synthetic(const struct port *port)
 \f
 /* Interface functions. */
 
+static bool
+iface_is_internal(const struct ovsrec_interface *iface,
+                  const struct ovsrec_bridge *br)
+{
+    /* The local port and "internal" ports are always "internal". */
+    return !strcmp(iface->type, "internal") || !strcmp(iface->name, br->name);
+}
+
 /* Returns the correct network device type for interface 'iface' in bridge
  * 'br'. */
 static const char *
 iface_get_type(const struct ovsrec_interface *iface,
                const struct ovsrec_bridge *br)
 {
-    /* The local port always has type "internal".  Other ports take their type
-     * from the database and default to "system" if none is specified. */
-    return (!strcmp(iface->name, br->name) ? "internal"
-            : iface->type[0] ? iface->type
-            : "system");
+    const char *type;
+
+    /* The local port always has type "internal".  Other ports take
+     * their type from the database and default to "system" if none is
+     * specified. */
+    if (iface_is_internal(iface, br)) {
+        type = "internal";
+    } else {
+        type = iface->type[0] ? iface->type : "system";
+    }
+
+    return ofproto_port_open_type(br->datapath_type, type);
 }
 
 static void
@@ -3280,7 +3313,6 @@ static void
 iface_clear_db_record(const struct ovsrec_interface *if_cfg)
 {
     if (!ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
-        iface_set_ofport(if_cfg, -1);
         ovsrec_interface_set_status(if_cfg, NULL);
         ovsrec_interface_set_admin_state(if_cfg, NULL);
         ovsrec_interface_set_duplex(if_cfg, NULL);
@@ -3450,6 +3482,13 @@ iface_is_synthetic(const struct iface *iface)
     return ovsdb_idl_row_is_synthetic(&iface->cfg->header_);
 }
 
+static int64_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;
+}
+
 \f
 /* Port mirroring. */