- /* Choose the MAC address to represent the port. */
- if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
- /* Find the interface with this Ethernet address (if any) so that
- * we can provide the correct devname to the caller. */
- iface = NULL;
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
- uint8_t candidate_ea[ETH_ADDR_LEN];
- if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
- && eth_addr_equals(iface_ea, candidate_ea)) {
- iface = candidate;
- }
- }
- } else {
- /* Choose the interface whose MAC address will represent the port.
- * The Linux kernel bonding code always chooses the MAC address of
- * the first slave added to a bond, and the Fedora networking
- * scripts always add slaves to a bond in alphabetical order, so
- * for compatibility we choose the interface with the name that is
- * first in alphabetical order. */
- iface = port->ifaces[0];
- for (j = 1; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
- if (strcmp(candidate->name, iface->name) < 0) {
- iface = candidate;
- }
- }
-
- /* The local port doesn't count (since we're trying to choose its
- * MAC address anyway). */
- if (iface->dp_ifidx == ODPP_LOCAL) {
- continue;
- }
-
- /* Grab MAC. */
- error = netdev_get_etheraddr(iface->netdev, iface_ea);
- if (error) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
- iface->name, strerror(error));
- continue;
- }
- }
-
- /* 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)
- {
- memcpy(ea, iface_ea, ETH_ADDR_LEN);
- *hw_addr_iface = iface;
- }
- }
- 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 "
- "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
- } else {
- VLOG_DBG("bridge %s: using bridge Ethernet address "ETH_ADDR_FMT,
- br->name, ETH_ADDR_ARGS(ea));
- }
-}
-
-/* Choose and returns the datapath ID for bridge 'br' given that the bridge
- * Ethernet address is 'bridge_ea'. If 'bridge_ea' is the Ethernet address of
- * an interface on 'br', then that interface must be passed in as
- * 'hw_addr_iface'; if 'bridge_ea' was derived some other way, then
- * 'hw_addr_iface' must be passed in as a null pointer. */
-static uint64_t
-bridge_pick_datapath_id(struct bridge *br,
- const uint8_t bridge_ea[ETH_ADDR_LEN],
- struct iface *hw_addr_iface)
-{
- /*
- * The procedure for choosing a bridge MAC address will, in the most
- * ordinary case, also choose a unique MAC that we can use as a datapath
- * ID. In some special cases, though, multiple bridges will end up with
- * the same MAC address. This is OK for the bridges, but it will confuse
- * the OpenFlow controller, because each datapath needs a unique datapath
- * ID.
- *
- * Datapath IDs must be unique. It is also very desirable that they be
- * stable from one run to the next, so that policy set on a datapath
- * "sticks".
- */
- const char *datapath_id;
- uint64_t dpid;
-
- datapath_id = bridge_get_other_config(br->cfg, "datapath-id");
- if (datapath_id && dpid_from_string(datapath_id, &dpid)) {
- return dpid;
- }
-
- if (hw_addr_iface) {
- int vlan;
- if (!netdev_get_vlan_vid(hw_addr_iface->netdev, &vlan)) {
- /*
- * A bridge whose MAC address is taken from a VLAN network device
- * (that is, a network device created with vconfig(8) or similar
- * tool) will have the same MAC address as a bridge on the VLAN
- * device's physical network device.
- *
- * Handle this case by hashing the physical network device MAC
- * along with the VLAN identifier.
- */
- uint8_t buf[ETH_ADDR_LEN + 2];
- memcpy(buf, bridge_ea, ETH_ADDR_LEN);
- buf[ETH_ADDR_LEN] = vlan >> 8;
- buf[ETH_ADDR_LEN + 1] = vlan;
- return dpid_from_hash(buf, sizeof buf);
- } else {
- /*
- * Assume that this bridge's MAC address is unique, since it
- * doesn't fit any of the cases we handle specially.
- */
- }
- } else {
- /*
- * A purely internal bridge, that is, one that has no non-virtual
- * network devices on it at all, is more difficult because it has no
- * natural unique identifier at all.
- *
- * When the host is a XenServer, we handle this case by hashing the
- * host's UUID with the name of the bridge. Names of bridges are
- * persistent across XenServer reboots, although they can be reused if
- * an internal network is destroyed and then a new one is later
- * created, so this is fairly effective.
- *
- * When the host is not a XenServer, we punt by using a random MAC
- * address on each run.
- */
- const char *host_uuid = xenserver_get_host_uuid();
- if (host_uuid) {
- char *combined = xasprintf("%s,%s", host_uuid, br->name);
- dpid = dpid_from_hash(combined, strlen(combined));
- free(combined);
- return dpid;
- }
- }
-
- return eth_addr_to_uint64(bridge_ea);
-}
-
-static uint64_t
-dpid_from_hash(const void *data, size_t n)
-{
- uint8_t hash[SHA1_DIGEST_SIZE];
-
- BUILD_ASSERT_DECL(sizeof hash >= ETH_ADDR_LEN);
- sha1_bytes(data, n, hash);
- eth_addr_mark_random(hash);
- return eth_addr_to_uint64(hash);
-}
-
-static void
-iface_refresh_status(struct iface *iface)
-{
- struct shash sh;
-
- enum netdev_flags flags;
- uint32_t current;
- int64_t bps;
- int mtu;
- int64_t mtu_64;
- int error;
-
- shash_init(&sh);
-
- if (!netdev_get_status(iface->netdev, &sh)) {
- size_t n;
- char **keys, **values;