daemon: Allow daemon child process to report success or failure to parent.
[openvswitch] / vswitchd / bridge.c
index d7f4d32893fbed64a630e42b62b243e5bf3e4fd0..040c7f382de42564ed97b0c170f9333be8e26a66 100644 (file)
@@ -247,7 +247,8 @@ static bool vlan_is_mirrored(const struct mirror *m UNUSED, int vlan UNUSED)
 }
 #endif
 
-static struct iface *iface_create(struct port *, const char *name);
+static struct iface *iface_create(struct port *port, 
+                                  const struct ovsrec_interface *if_cfg);
 static void iface_destroy(struct iface *);
 static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_from_dp_ifidx(const struct bridge *,
@@ -421,24 +422,12 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, bool create)
     return error;
 }
 
-static int
-create_iface(const struct ovsrec_interface *iface_cfg)
-{
-    return set_up_iface(iface_cfg, true);
-}
-
 static int
 reconfigure_iface(const struct ovsrec_interface *iface_cfg)
 {
     return set_up_iface(iface_cfg, false);
 }
 
-static void
-destroy_iface(const char *iface_name)
-{
-    netdev_destroy(iface_name);
-}
-
 
 /* iterate_and_prune_ifaces() callback function that opens the network device
  * for 'iface', if it is not already open, and retrieves the interface's MAC
@@ -528,6 +517,7 @@ iterate_and_prune_ifaces(struct bridge *br,
 void
 bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 {
+    struct ovsdb_idl_txn *txn;
     struct shash old_br, new_br;
     struct shash_node *node;
     struct bridge *br, *next;
@@ -535,6 +525,8 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
     COVERAGE_INC(bridge_reconfigure);
 
+    txn = ovsdb_idl_txn_create(ovs_cfg->header_.table->idl);
+
     /* Collect old and new bridges. */
     shash_init(&old_br);
     shash_init(&new_br);
@@ -602,7 +594,6 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                              p->devname, dpif_name(br->dpif),
                              strerror(retval));
                 }
-                destroy_iface(p->devname);
             }
         }
         shash_destroy(&want_ifaces);
@@ -642,17 +633,8 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                 bool internal;
                 int error;
 
-                /* Attempt to create the network interface in case it
-                 * doesn't exist yet. */
-                error = iface ? create_iface(iface->cfg) : 0;
-                if (error) {
-                    VLOG_WARN("could not create iface %s: %s\n", if_name,
-                              strerror(error));
-                    continue;
-                }
-
                 /* Add to datapath. */
-                internal = !iface || iface_is_internal(br, if_name);
+                internal = iface_is_internal(br, if_name);
                 error = dpif_port_add(br->dpif, if_name,
                                       internal ? ODP_PORT_INTERNAL : 0, NULL);
                 if (error == EFBIG) {
@@ -673,6 +655,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         uint64_t dpid;
         struct iface *local_iface;
         struct iface *hw_addr_iface;
+        char *dpid_string;
 
         bridge_fetch_dp_ifaces(br);
         iterate_and_prune_ifaces(br, init_iface_netdev, NULL);
@@ -695,6 +678,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
         ofproto_set_datapath_id(br->ofproto, dpid);
 
+        dpid_string = xasprintf("%012"PRIx64, dpid);
+        ovsrec_bridge_set_datapath_id(br->cfg, dpid_string);
+        free(dpid_string);
+
         /* Set NetFlow configuration on this bridge. */
         if (br->cfg->netflow) {
             struct ovsrec_netflow *nf_cfg = br->cfg->netflow;
@@ -766,19 +753,39 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         iterate_and_prune_ifaces(br, set_iface_properties, NULL);
     }
+
+    ovsrec_open_vswitch_set_cur_cfg(ovs_cfg, ovs_cfg->next_cfg);
+
+    ovsdb_idl_txn_commit(txn);
+    ovsdb_idl_txn_destroy(txn); /* XXX */
+}
+
+static const char *
+bridge_get_other_config(const struct ovsrec_bridge *br_cfg, const char *key)
+{
+    size_t i;
+
+    for (i = 0; i < br_cfg->n_other_config; i++) {
+        if (!strcmp(br_cfg->key_other_config[i], key)) {
+            return br_cfg->value_other_config[i];
+        }
+    }
+    return NULL;
 }
 
 static void
 bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
                           struct iface **hw_addr_iface)
 {
+    const char *hwaddr;
     size_t i, j;
     int error;
 
     *hw_addr_iface = NULL;
 
     /* Did the user request a particular MAC? */
-    if (br->cfg->hwaddr && eth_addr_from_string(br->cfg->hwaddr, ea)) {
+    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));
@@ -789,9 +796,8 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
         }
     }
 
-    /* Otherwise choose the minimum MAC address among all of the interfaces.
-     * (Xen uses FE:FF:FF:FF:FF:FF for virtual interfaces so this will get the
-     * MAC of the physical interface in such an environment.) */
+    /* Otherwise choose the minimum non-local MAC address among all of the
+     * interfaces. */
     memset(ea, 0xff, sizeof ea);
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
@@ -832,11 +838,8 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             }
 
             /* The local port doesn't count (since we're trying to choose its
-             * MAC address anyway).  Other internal ports don't count because
-             * we really want a physical MAC if we can get it, and internal
-             * ports typically have randomly generated MACs. */
-            if (iface->dp_ifidx == ODPP_LOCAL
-                || !strcmp(iface->cfg->type, "internal")) {
+             * MAC address anyway). */
+            if (iface->dp_ifidx == ODPP_LOCAL) {
                 continue;
             }
 
@@ -852,6 +855,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
 
         /* Compare against our current choice. */
         if (!eth_addr_is_multicast(iface_ea) &&
+            !eth_addr_is_local(iface_ea) &&
             !eth_addr_is_reserved(iface_ea) &&
             !eth_addr_is_zero(iface_ea) &&
             memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
@@ -860,7 +864,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             *hw_addr_iface = iface;
         }
     }
-    if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
+    if (eth_addr_is_multicast(ea)) {
         memcpy(ea, br->default_ea, ETH_ADDR_LEN);
         *hw_addr_iface = NULL;
         VLOG_WARN("bridge %s: using default bridge Ethernet "
@@ -893,10 +897,11 @@ bridge_pick_datapath_id(struct bridge *br,
      * stable from one run to the next, so that policy set on a datapath
      * "sticks".
      */
+    const char *datapath_id;
     uint64_t dpid;
 
-    if (br->cfg->datapath_id
-        && dpid_from_string(br->cfg->datapath_id, &dpid)) {
+    datapath_id = bridge_get_other_config(br->cfg, "datapath-id");
+    if (datapath_id && dpid_from_string(datapath_id, &dpid)) {
         return dpid;
     }
 
@@ -1253,14 +1258,21 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
                       br->name, name);
         }
     }
+
+    /* If we have a controller, then we need a local port.  Complain if the
+     * user didn't specify one.
+     *
+     * XXX perhaps we should synthesize a port ourselves in this case. */
     if (bridge_get_controller(ovs_cfg, br)) {
         char local_name[IF_NAMESIZE];
         int error;
 
         error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
                                    local_name, sizeof local_name);
-        if (!error) {
-            shash_add_once(&new_ports, local_name, NULL);
+        if (!error && !shash_find(&new_ports, local_name)) {
+            VLOG_WARN("bridge %s: controller specified but no local port "
+                      "(port named %s) defined",
+                      br->name, local_name);
         }
     }
 
@@ -1528,6 +1540,13 @@ bridge_fetch_dp_ifaces(struct bridge *br)
                 port_array_set(&br->ifaces, p->port, iface);
                 iface->dp_ifidx = p->port;
             }
+
+            if (iface->cfg) {
+                int64_t ofport = (iface->dp_ifidx >= 0
+                                  ? odp_port_to_ofp_port(iface->dp_ifidx)
+                                  : -1);
+                ovsrec_interface_set_ofport(iface->cfg, &ofport, 1);
+            }
         }
     }
     free(dpif_ports);
@@ -3002,12 +3021,11 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
     }
     SHASH_FOR_EACH (node, &new_ifaces) {
         const struct ovsrec_interface *if_cfg = node->data;
-        const char *if_name = node->name;
         struct iface *iface;
 
-        iface = shash_find_data(&old_ifaces, if_name);
+        iface = shash_find_data(&old_ifaces, if_cfg->name);
         if (!iface) {
-            iface = iface_create(port, if_name);
+            iface = iface_create(port, if_cfg);
         }
         iface->cfg = if_cfg;
     }
@@ -3290,9 +3308,11 @@ port_update_vlan_compat(struct port *port)
 /* Interface functions. */
 
 static struct iface *
-iface_create(struct port *port, const char *name)
+iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
 {
     struct iface *iface;
+    char *name = if_cfg->name;
+    int error;
 
     iface = xzalloc(sizeof *iface);
     iface->port = port;
@@ -3312,6 +3332,14 @@ iface_create(struct port *port, const char *name)
         port->bridge->has_bonded_ports = true;
     }
 
+    /* Attempt to create the network interface in case it
+     * doesn't exist yet. */
+    error = set_up_iface(if_cfg, true);
+    if (error) {
+        VLOG_WARN("could not create iface %s: %s\n", iface->name,
+                strerror(error));
+    }
+
     VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
 
     bridge_flush(port->bridge);
@@ -3336,8 +3364,6 @@ iface_destroy(struct iface *iface)
         del->port_ifidx = iface->port_ifidx;
 
         netdev_close(iface->netdev);
-        free(iface->name);
-        free(iface);
 
         if (del_active) {
             ofproto_revalidate(port->bridge->ofproto, port->active_iface_tag);
@@ -3345,6 +3371,10 @@ iface_destroy(struct iface *iface)
             bond_send_learning_packets(port);
         }
 
+        netdev_destroy(iface->name);
+        free(iface->name);
+        free(iface);
+
         bridge_flush(port->bridge);
     }
 }