From: Ben Pfaff Date: Tue, 3 Mar 2009 19:44:24 +0000 (-0800) Subject: vswitchd: Choose the bridge local port MAC address intelligently. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f61453fa3cbe8a9286cb763771ce4429d75f624;p=openvswitch vswitchd: Choose the bridge local port MAC address intelligently. Fixes bug #928, "We should have a consistent model for representing the nic/mac address to xenserver." --- diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 29d6b534..64a45c05 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -150,6 +150,7 @@ struct bridge { int flow_idle_time; /* Idle time for flows we set up. */ bool sent_config_request; /* Successfully sent config request? */ bool sent_features_request; /* Successfully sent features request? */ + uint8_t default_ea[ETH_ADDR_LEN]; /* Default MAC. */ /* Support for remote controllers. */ char *controller; /* NULL if there is no remote controller; @@ -211,6 +212,8 @@ static void bridge_get_all_ifaces(const struct bridge *, struct svec *ifaces); static bool bridge_is_backlogged(const struct bridge *); static void bridge_fetch_dp_ifaces(struct bridge *); static void bridge_flush(struct bridge *); +static void bridge_pick_local_hw_addr(struct bridge *, + struct iface *local_iface); static void bridge_process_msg(struct bridge *, struct ofpbuf *); static void revalidate_flow(struct bridge *, struct ft_flow *); @@ -392,6 +395,9 @@ bridge_reconfigure(void) br->dp_idx, iface->name, iface->dp_ifidx); j++; } + if (!strcmp(iface->name, br->name)) { + bridge_pick_local_hw_addr(br, iface); + } } if (!port->n_ifaces) { VLOG_ERR("%s port has no interfaces, dropping", port->name); @@ -406,6 +412,81 @@ bridge_reconfigure(void) } } +static void +bridge_set_local_hw_addr(struct bridge *br, struct iface *local_iface, + const uint8_t ea[ETH_ADDR_LEN]) +{ + int error = netdev_nodev_set_etheraddr(local_iface->name, ea); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge Ethernet " + "address: %s", br->name, strerror(error)); + } +} + +static void +bridge_pick_local_hw_addr(struct bridge *br, struct iface *local_iface) +{ + uint8_t ea[ETH_ADDR_LEN]; + uint64_t requested_ea; + size_t i, j; + int error; + + /* Did the user request a particular MAC? */ + requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name); + if (requested_ea) { + eth_addr_from_uint64(requested_ea, 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 { + bridge_set_local_hw_addr(br, local_iface, ea); + return; + } + } + + /* 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.) */ + memset(ea, 0xff, sizeof ea); + for (i = 0; i < br->n_ports; i++) { + struct port *port = br->ports[i]; + if (port->is_mirror_output_port) { + continue; + } + for (j = 0; j < port->n_ifaces; j++) { + struct iface *iface = port->ifaces[j]; + uint8_t iface_ea[ETH_ADDR_LEN]; + if (iface == local_iface) { + continue; + } + error = netdev_nodev_get_etheraddr(iface->name, iface_ea); + if (!error) { + if (!eth_addr_is_multicast(iface_ea) && + !eth_addr_is_reserved(iface_ea) && + memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0) { + memcpy(ea, iface_ea, ETH_ADDR_LEN); + } + } else { + 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)); + } + } + } + if (eth_addr_is_broadcast(ea)) { + memcpy(ea, br->default_ea, ETH_ADDR_LEN); + 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)); + } + bridge_set_local_hw_addr(br, local_iface, ea); +} + void bridge_run(void) { @@ -476,6 +557,7 @@ bridge_create(const char *name) br->flow_idle_time = 5; br->sent_config_request = false; br->sent_features_request = false; + eth_addr_random(br->default_ea); svec_init(&br->secchan_opts); diff --git a/vswitchd/vswitchd.conf.5 b/vswitchd/vswitchd.conf.5 index d5a8c9ca..2632726b 100644 --- a/vswitchd/vswitchd.conf.5 +++ b/vswitchd/vswitchd.conf.5 @@ -64,6 +64,19 @@ A bridge (switch) with a given \fIname\fR is configured by specifying the names of its network devices as values for key \fBbridge.\fIname\fB.port\fR. .PP +A bridge with a given \fIname\fR always has an associated network +device with the same \fIname\fR. This network device may be included +in the bridge, by specifying it as one of the values for key +\fBbridge.\fIname\fB.port\fR, or it may be omitted. If it is +included, then its MAC address is by default the lowest-numbered MAC +address among the other bridge ports, ignoring bridge ports that are +used as port mirroring destinations (see "Port mirroring", below). To +use a specific MAC address instead, set \fBbridge.\fIname\fB.mac\fR to +a MAC address in the format +\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR, where each +\fIx\fR is a hex digit. If no valid MAC address can be determined +either of these ways, then a MAC address is chosen randomly. +.PP The following syntax defines a bridge named \fBmybr\fR, configured with network devices \fBeth0\fR, \fBeth1\fR, and \fBeth2\fR: .RS