+
+/* Returns true if 'iface' is the name of an "internal" interface on bridge
+ * 'br', that is, an interface that is entirely simulated within the datapath.
+ * The local port (ODPP_LOCAL) is always an internal interface. Other local
+ * interfaces are created by setting "iface.<iface>.internal = true".
+ *
+ * In addition, we have a kluge-y feature that creates an internal port with
+ * the name of a bonded port if "bonding.<bondname>.fake-iface = true" is set.
+ * This feature needs to go away in the long term. Until then, this is one
+ * reason why this function takes a name instead of a struct iface: the fake
+ * interfaces created this way do not have a struct iface. */
+static bool
+iface_is_internal(const struct bridge *br, const char *iface)
+{
+ if (!strcmp(iface, br->name)
+ || cfg_get_bool(0, "iface.%s.internal", iface)) {
+ return true;
+ }
+
+ if (cfg_get_bool(0, "bonding.%s.fake-iface", iface)) {
+ struct port *port = port_lookup(br, iface);
+ if (port && port->n_ifaces > 1) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Set Ethernet address of 'iface', if one is specified in the configuration
+ * file. */
+static void
+iface_set_mac(struct iface *iface)
+{
+ uint64_t mac = cfg_get_mac(0, "iface.%s.mac", iface->name);
+ if (mac) {
+ static uint8_t ea[ETH_ADDR_LEN];
+
+ eth_addr_from_uint64(mac, ea);
+ if (eth_addr_is_multicast(ea)) {
+ VLOG_ERR("interface %s: cannot set MAC to multicast address",
+ iface->name);
+ } else if (iface->dp_ifidx == ODPP_LOCAL) {
+ VLOG_ERR("ignoring iface.%s.mac; use bridge.%s.mac instead",
+ iface->name, iface->name);
+ } else {
+ int error = netdev_nodev_set_etheraddr(iface->name, ea);
+ if (error) {
+ VLOG_ERR("interface %s: setting MAC failed (%s)",
+ iface->name, strerror(error));
+ }
+ }
+ }
+}