+ 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 (iface) {
+ netdev_close(iface->netdev);
+ iface->netdev = NULL;
+ }
+ }
+}
+
+static void
+iface_set_ofp_port(struct iface *iface, int ofp_port)
+{
+ struct bridge *br = iface->port->bridge;
+
+ assert(iface->ofp_port < 0 && ofp_port >= 0);
+ iface->ofp_port = ofp_port;
+ hmap_insert(&br->ifaces, &iface->ofp_port_node, hash_int(ofp_port, 0));
+ iface_set_ofport(iface->cfg, ofp_port);
+}
+
+static void
+bridge_refresh_ofp_port(struct bridge *br)
+{
+ struct ofproto_port_dump dump;
+ struct ofproto_port ofproto_port;
+ struct port *port;
+
+ /* Clear all the "ofp_port"es. */
+ hmap_clear(&br->ifaces);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ iface->ofp_port = -1;
+ }
+ }
+
+ /* Obtain the correct "ofp_port"s from ofproto. */
+ OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
+ struct iface *iface = iface_lookup(br, ofproto_port.name);
+ if (iface) {
+ if (iface->ofp_port >= 0) {
+ VLOG_WARN("bridge %s: interface %s reported twice",
+ br->name, ofproto_port.name);
+ } else if (iface_from_ofp_port(br, ofproto_port.ofp_port)) {
+ VLOG_WARN("bridge %s: interface %"PRIu16" reported twice",
+ br->name, ofproto_port.ofp_port);
+ } else {
+ iface_set_ofp_port(iface, ofproto_port.ofp_port);
+ }
+ }
+ }
+}
+
+/* Add an ofproto port for any "struct iface" that doesn't have one.
+ * 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)
+{
+ struct port *port, *next_port;
+
+ HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
+ struct iface *iface, *next_iface;
+ struct ofproto_port ofproto_port;
+
+ LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) {
+ struct shash args;
+ int error;
+
+ /* Open the netdev or reconfigure it. */
+ shash_init(&args);
+ shash_from_ovs_idl_map(iface->cfg->key_options,
+ iface->cfg->value_options,
+ iface->cfg->n_options, &args);
+ if (!iface->netdev) {
+ struct netdev_options options;
+ options.name = iface->name;
+ options.type = iface->type;
+ options.args = &args;
+ options.ethertype = NETDEV_ETH_TYPE_NONE;
+ error = netdev_open(&options, &iface->netdev);
+ } else {
+ error = netdev_set_config(iface->netdev, &args);
+ }
+ shash_destroy(&args);
+ if (error) {
+ VLOG_WARN("could not %s network device %s (%s)",
+ iface->netdev ? "reconfigure" : "open",
+ iface->name, strerror(error));
+ }
+
+ /* Add the port, if necessary. */
+ if (iface->netdev && iface->ofp_port < 0) {
+ uint16_t ofp_port;
+ int error;
+
+ error = ofproto_port_add(br->ofproto, iface->netdev,
+ &ofp_port);
+ if (!error) {
+ iface_set_ofp_port(iface, ofp_port);
+ } else {
+ netdev_close(iface->netdev);
+ iface->netdev = NULL;
+ }
+ }
+
+ /* Delete the iface if */
+ if (iface->netdev && iface->ofp_port >= 0) {
+ VLOG_DBG("bridge %s: interface %s is on port %d",
+ br->name, iface->name, iface->ofp_port);
+ } else {
+ if (iface->netdev) {
+ VLOG_ERR("bridge %s: missing %s interface, dropping",
+ br->name, iface->name);
+ } else {
+ /* We already reported a related error, don't bother
+ * duplicating it. */
+ }
+ iface_set_ofport(iface->cfg, -1);
+ iface_destroy(iface);
+ }
+ }
+ if (list_is_empty(&port->ifaces)) {
+ VLOG_WARN("%s port has no interfaces, dropping", port->name);
+ port_destroy(port);
+ continue;
+ }
+
+ /* Add bond fake iface if necessary. */
+ if (port_is_bond_fake_iface(port)) {
+ if (ofproto_port_query_by_name(br->ofproto, port->name,
+ &ofproto_port)) {
+ struct netdev_options options;
+ struct netdev *netdev;
+ int error;
+
+ options.name = port->name;
+ options.type = "internal";
+ options.args = NULL;
+ options.ethertype = NETDEV_ETH_TYPE_NONE;
+ error = netdev_open(&options, &netdev);
+ if (!error) {
+ ofproto_port_add(br->ofproto, netdev, NULL);
+ netdev_close(netdev);
+ } else {
+ VLOG_WARN("could not open network device %s (%s)",
+ port->name, strerror(error));
+ }
+ } else {
+ /* Already exists, nothing to do. */
+ ofproto_port_destroy(&ofproto_port);
+ }
+ }
+ }
+}
+
+static const char *
+get_ovsrec_key_value(const struct ovsdb_idl_row *row,
+ const struct ovsdb_idl_column *column,
+ const char *key)
+{
+ const struct ovsdb_datum *datum;
+ union ovsdb_atom atom;
+ unsigned int idx;
+
+ datum = ovsdb_idl_get(row, column, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
+ atom.string = (char *) key;
+ idx = ovsdb_datum_find_key(datum, &atom, OVSDB_TYPE_STRING);
+ return idx == UINT_MAX ? NULL : datum->values[idx].string;
+}
+
+static const char *
+bridge_get_other_config(const struct ovsrec_bridge *br_cfg, const char *key)
+{
+ return get_ovsrec_key_value(&br_cfg->header_,
+ &ovsrec_bridge_col_other_config, key);
+}
+
+static void
+bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
+ struct iface **hw_addr_iface)
+{
+ const char *hwaddr;
+ struct port *port;
+ int error;
+
+ *hw_addr_iface = NULL;
+
+ /* Did the user request a particular MAC? */
+ hwaddr = bridge_get_other_config(br->cfg, "hwaddr");
+ if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
+ if (eth_addr_is_multicast(ea)) {
+ VLOG_ERR("bridge %s: cannot set MAC address to multicast "
+ "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
+ } else if (eth_addr_is_zero(ea)) {
+ VLOG_ERR("bridge %s: cannot set MAC address to zero", br->name);
+ } else {
+ return;
+ }
+ }
+
+ /* Otherwise choose the minimum non-local MAC address among all of the
+ * interfaces. */
+ memset(ea, 0xff, ETH_ADDR_LEN);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ uint8_t iface_ea[ETH_ADDR_LEN];
+ struct iface *candidate;
+ struct iface *iface;
+
+ /* Mirror output ports don't participate. */
+ if (ofproto_is_mirror_output_bundle(br->ofproto, port)) {
+ continue;
+ }
+
+ /* Choose the MAC address to represent the port. */
+ iface = NULL;
+ if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
+ /* Find the interface with this Ethernet address (if any) so that