extern uint64_t mgmt_id;
struct iface {
+ /* These members are always valid. */
struct port *port; /* Containing port. */
size_t port_ifidx; /* Index within containing port. */
-
char *name; /* Host network device name. */
- int dp_ifidx; /* Index within kernel datapath. */
-
- uint8_t mac[ETH_ADDR_LEN]; /* Ethernet address (all zeros if unknowns). */
-
tag_type tag; /* Tag associated with this interface. */
- bool enabled; /* May be chosen for flows? */
long long delay_expires; /* Time after which 'enabled' may change. */
+
+ /* These members are valid only after bridge_reconfigure() causes them to
+ * be initialized.*/
+ int dp_ifidx; /* Index within kernel datapath. */
+ struct netdev *netdev; /* Network device. */
+ bool enabled; /* May be chosen for flows? */
};
#define BOND_MASK 0xff
static void bridge_flush(struct bridge *);
static void bridge_pick_local_hw_addr(struct bridge *,
uint8_t ea[ETH_ADDR_LEN],
- const char **devname);
+ struct iface **hw_addr_iface);
static uint64_t bridge_pick_datapath_id(struct bridge *,
const uint8_t bridge_ea[ETH_ADDR_LEN],
- const char *devname);
+ struct iface *hw_addr_iface);
+static struct iface *bridge_get_local_iface(struct bridge *);
static uint64_t dpid_from_hash(const void *, size_t nbytes);
static void bridge_unixctl_fdb_show(struct unixctl_conn *, const char *args);
uint16_t dp_ifidx);
static void port_update_bond_compat(struct port *);
static void port_update_vlan_compat(struct port *);
+static void port_update_bonding(struct port *);
static void mirror_create(struct bridge *, const char *name);
static void mirror_destroy(struct mirror *);
}
#endif
+/* 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
+ * address and carrier status. */
+static bool
+init_iface_netdev(struct bridge *br UNUSED, struct iface *iface,
+ void *aux UNUSED)
+{
+ if (iface->netdev) {
+ return true;
+ } else if (!netdev_open(iface->name, NETDEV_ETH_TYPE_NONE,
+ &iface->netdev)) {
+ netdev_get_carrier(iface->netdev, &iface->enabled);
+ return true;
+ } else {
+ /* If the network device can't be opened, then we're not going to try
+ * to do anything with this interface. */
+ return false;
+ }
+}
+
+static bool
+check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED)
+{
+ if (iface->dp_ifidx >= 0) {
+ VLOG_DBG("%s has interface %s on port %d",
+ dpif_name(br->dpif),
+ iface->name, iface->dp_ifidx);
+ return true;
+ } else {
+ VLOG_ERR("%s interface not in %s, dropping",
+ iface->name, dpif_name(br->dpif));
+ return false;
+ }
+}
+
+static bool
+set_iface_policing(struct bridge *br UNUSED, struct iface *iface,
+ void *aux UNUSED)
+{
+ int rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
+ int burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
+ netdev_set_policing(iface->netdev, rate, burst);
+ return true;
+}
+
+/* Calls 'cb' for each interfaces in 'br', passing along the 'aux' argument.
+ * Deletes from 'br' all the interfaces for which 'cb' returns false, and then
+ * deletes from 'br' any ports that no longer have any interfaces. */
+static void
+iterate_and_prune_ifaces(struct bridge *br,
+ bool (*cb)(struct bridge *, struct iface *,
+ void *aux),
+ void *aux)
+{
+ size_t i, j;
+
+ for (i = 0; i < br->n_ports; ) {
+ struct port *port = br->ports[i];
+ for (j = 0; j < port->n_ifaces; ) {
+ struct iface *iface = port->ifaces[j];
+ if (cb(br, iface, aux)) {
+ j++;
+ } else {
+ iface_destroy(iface);
+ }
+ }
+
+ if (port->n_ifaces) {
+ i++;
+ } else {
+ VLOG_ERR("%s port has no interfaces, dropping", port->name);
+ port_destroy(port);
+ }
+ }
+}
+
void
bridge_reconfigure(void)
{
struct svec old_br, new_br;
struct bridge *br, *next;
- size_t i, j;
+ size_t i;
COVERAGE_INC(bridge_reconfigure);
LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
uint8_t ea[8];
uint64_t dpid;
- struct iface *local_iface = NULL;
- const char *devname;
+ struct iface *local_iface;
+ struct iface *hw_addr_iface;
uint8_t engine_type, engine_id;
bool add_id_to_iface = false;
struct svec nf_hosts;
bridge_fetch_dp_ifaces(br);
- for (i = 0; i < br->n_ports; ) {
- struct port *port = br->ports[i];
+ iterate_and_prune_ifaces(br, init_iface_netdev, NULL);
- for (j = 0; j < port->n_ifaces; ) {
- struct iface *iface = port->ifaces[j];
- if (iface->dp_ifidx < 0) {
- VLOG_ERR("%s interface not in %s, dropping",
- iface->name, dpif_name(br->dpif));
- iface_destroy(iface);
- } else {
- if (iface->dp_ifidx == ODPP_LOCAL) {
- local_iface = iface;
- }
- VLOG_DBG("%s has interface %s on port %d",
- dpif_name(br->dpif),
- iface->name, iface->dp_ifidx);
- j++;
- }
- }
- if (!port->n_ifaces) {
- VLOG_ERR("%s port has no interfaces, dropping", port->name);
- port_destroy(port);
- continue;
- }
- i++;
- }
+ iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL);
/* Pick local port hardware address, datapath ID. */
- bridge_pick_local_hw_addr(br, ea, &devname);
+ bridge_pick_local_hw_addr(br, ea, &hw_addr_iface);
+ local_iface = bridge_get_local_iface(br);
if (local_iface) {
- int error = netdev_nodev_set_etheraddr(local_iface->name, ea);
+ int error = netdev_set_etheraddr(local_iface->netdev, 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 "
}
}
- dpid = bridge_pick_datapath_id(br, ea, devname);
+ dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
ofproto_set_datapath_id(br->ofproto, dpid);
/* Set NetFlow configuration on this bridge. */
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
port_update_vlan_compat(port);
+ port_update_bonding(port);
}
}
LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
brstp_reconfigure(br);
+ iterate_and_prune_ifaces(br, set_iface_policing, NULL);
}
}
static void
bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
- const char **devname)
+ struct iface **hw_addr_iface)
{
uint64_t requested_ea;
size_t i, j;
int error;
- *devname = NULL;
+ *hw_addr_iface = NULL;
/* Did the user request a particular MAC? */
requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name);
|| cfg_get_bool(0, "iface.%s.internal", iface->name)) {
continue;
}
- error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
+ error = netdev_get_etheraddr(iface->netdev, iface_ea);
if (!error) {
if (!eth_addr_is_multicast(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);
- *devname = iface->name;
+ *hw_addr_iface = iface;
}
} else {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
}
if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
memcpy(ea, br->default_ea, ETH_ADDR_LEN);
- *devname = NULL;
+ *hw_addr_iface = NULL;
VLOG_WARN("bridge %s: using default bridge Ethernet "
"address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
} else {
/* 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
- * a network device, then that network device's name must be passed in as
- * 'devname'; if 'bridge_ea' was derived some other way, then 'devname' must be
- * passed in as a null pointer. */
+ * 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],
- const char *devname)
+ struct iface *hw_addr_iface)
{
/*
* The procedure for choosing a bridge MAC address will, in the most
return dpid;
}
- if (devname) {
+ if (hw_addr_iface) {
int vlan;
- if (!netdev_get_vlan_vid(devname, &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
mac_learning_flush(br->ml);
}
}
+
+/* Returns the 'br' interface for the ODPP_LOCAL port, or null if 'br' has no
+ * such interface. */
+static struct iface *
+bridge_get_local_iface(struct bridge *br)
+{
+ size_t i, j;
+
+ for (i = 0; i < br->n_ports; i++) {
+ struct port *port = br->ports[i];
+ for (j = 0; j < port->n_ifaces; j++) {
+ struct iface *iface = port->ifaces[j];
+ if (iface->dp_ifidx == ODPP_LOCAL) {
+ return iface;
+ }
+ }
+ }
+
+ return NULL;
+}
\f
/* Bridge unixctl user interface functions. */
static void
if (br->ml) {
const struct mac_entry *e;
LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
+ if (e->port < 0 || e->port >= br->n_ports) {
+ continue;
+ }
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
- e->port, e->vlan, ETH_ADDR_ARGS(e->mac),
- mac_entry_age(e));
+ br->ports[e->port]->ifaces[0]->dp_ifidx,
+ e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
}
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
return controller && controller[0] ? controller : NULL;
}
+static bool
+check_duplicate_ifaces(struct bridge *br, struct iface *iface, void *ifaces_)
+{
+ struct svec *ifaces = ifaces_;
+ if (!svec_contains(ifaces, iface->name)) {
+ svec_add(ifaces, iface->name);
+ svec_sort(ifaces);
+ return true;
+ } else {
+ VLOG_ERR("bridge %s: %s interface is on multiple ports, "
+ "removing from %s",
+ br->name, iface->name, iface->port->name);
+ return false;
+ }
+}
+
static void
bridge_reconfigure_one(struct bridge *br)
{
struct svec old_ports, new_ports, ifaces;
struct svec listeners, old_listeners;
struct svec snoops, old_snoops;
- size_t i, j;
+ size_t i;
/* Collect old ports. */
svec_init(&old_ports);
/* Check and delete duplicate interfaces. */
svec_init(&ifaces);
- for (i = 0; i < br->n_ports; ) {
- struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; ) {
- struct iface *iface = port->ifaces[j];
- if (svec_contains(&ifaces, iface->name)) {
- VLOG_ERR("bridge %s: %s interface is on multiple ports, "
- "removing from %s",
- br->name, iface->name, port->name);
- iface_destroy(iface);
- } else {
- svec_add(&ifaces, iface->name);
- svec_sort(&ifaces);
- j++;
- }
- }
- if (!port->n_ifaces) {
- VLOG_ERR("%s port has no interfaces, dropping", port->name);
- port_destroy(port);
- } else {
- i++;
- }
- }
+ iterate_and_prune_ifaces(br, check_duplicate_ifaces, &ifaces);
svec_destroy(&ifaces);
/* Delete all flows if we're switching from connected to standalone or vice
cfg_get_string(0, "%s.accept-regex", pfx),
update_resolv_conf);
} else {
- char local_name[IF_NAMESIZE];
- struct netdev *netdev;
+ struct iface *local_iface;
bool in_band;
- int error;
in_band = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED,
"%s.in-band", pfx)
ofproto_set_discovery(br->ofproto, false, NULL, NULL);
ofproto_set_in_band(br->ofproto, in_band);
- error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
- local_name, sizeof local_name);
- if (!error) {
- error = netdev_open(local_name, NETDEV_ETH_TYPE_NONE, &netdev);
- }
- if (!error) {
- if (cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
- struct in_addr ip, mask, gateway;
- ip.s_addr = cfg_get_ip(0, "%s.ip", pfx);
- mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx);
- gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx);
-
- netdev_turn_flags_on(netdev, NETDEV_UP, true);
- if (!mask.s_addr) {
- mask.s_addr = guess_netmask(ip.s_addr);
- }
- if (!netdev_set_in4(netdev, ip, mask)) {
- VLOG_INFO("bridge %s: configured IP address "IP_FMT", "
- "netmask "IP_FMT,
- br->name, IP_ARGS(&ip.s_addr),
- IP_ARGS(&mask.s_addr));
- }
+ local_iface = bridge_get_local_iface(br);
+ if (local_iface
+ && cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
+ struct netdev *netdev = local_iface->netdev;
+ struct in_addr ip, mask, gateway;
+ ip.s_addr = cfg_get_ip(0, "%s.ip", pfx);
+ mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx);
+ gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx);
+
+ netdev_turn_flags_on(netdev, NETDEV_UP, true);
+ if (!mask.s_addr) {
+ mask.s_addr = guess_netmask(ip.s_addr);
+ }
+ if (!netdev_set_in4(netdev, ip, mask)) {
+ VLOG_INFO("bridge %s: configured IP address "IP_FMT", "
+ "netmask "IP_FMT,
+ br->name, IP_ARGS(&ip.s_addr),
+ IP_ARGS(&mask.s_addr));
+ }
- if (gateway.s_addr) {
- if (!netdev_add_router(gateway)) {
- VLOG_INFO("bridge %s: configured gateway "IP_FMT,
- br->name, IP_ARGS(&gateway.s_addr));
- }
+ if (gateway.s_addr) {
+ if (!netdev_add_router(netdev, gateway)) {
+ VLOG_INFO("bridge %s: configured gateway "IP_FMT,
+ br->name, IP_ARGS(&gateway.s_addr));
}
}
- netdev_close(netdev);
}
}
bridge_flush(br);
} else {
- memcpy(iface->mac, opp->hw_addr, ETH_ADDR_LEN);
if (port->n_ifaces > 1) {
bool up = !(opp->state & OFPPS_LINK_DOWN);
bond_link_status_update(iface, up);
if (slave->up) {
bond.up = true;
}
- memcpy(slave->mac, iface->mac, ETH_ADDR_LEN);
+ netdev_get_etheraddr(iface->netdev, slave->mac);
}
proc_net_compat_update_bond(port->name, &bond);
free(bond.slaves);
&& p->n_ifaces
&& (!vlandev_name || strcmp(p->name, vlandev_name) <= 0))
{
- const uint8_t *ea = p->ifaces[0]->mac;
+ uint8_t ea[ETH_ADDR_LEN];
+ netdev_get_etheraddr(p->ifaces[0]->netdev, ea);
if (!eth_addr_is_multicast(ea) &&
!eth_addr_is_reserved(ea) &&
!eth_addr_is_zero(ea)) {
iface->dp_ifidx = -1;
iface->tag = tag_create_random();
iface->delay_expires = LLONG_MAX;
-
- netdev_nodev_get_etheraddr(name, iface->mac);
- netdev_nodev_get_carrier(name, &iface->enabled);
+ iface->netdev = NULL;
if (port->n_ifaces >= port->allocated_ifaces) {
port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
- port_update_bonding(port);
bridge_flush(port->bridge);
}
del = port->ifaces[iface->port_ifidx] = port->ifaces[--port->n_ifaces];
del->port_ifidx = iface->port_ifidx;
+ netdev_close(iface->netdev);
free(iface->name);
free(iface);
bond_send_learning_packets(port);
}
- port_update_bonding(port);
bridge_flush(port->bridge);
}
}
if (!iface) {
VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d",
br->name, port_no);
- } else if (eth_addr_is_zero(iface->mac)) {
- VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d with unknown MAC",
- br->name, port_no);
} else {
- union ofp_action action;
struct eth_header *eth = pkt->l2;
- flow_t flow;
- memcpy(eth->eth_src, iface->mac, ETH_ADDR_LEN);
+ netdev_get_etheraddr(iface->netdev, eth->eth_src);
+ if (eth_addr_is_zero(eth->eth_src)) {
+ VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
+ "with unknown MAC", br->name, port_no);
+ } else {
+ union ofp_action action;
+ flow_t flow;
- memset(&action, 0, sizeof action);
- action.type = htons(OFPAT_OUTPUT);
- action.output.len = htons(sizeof action);
- action.output.port = htons(port_no);
+ memset(&action, 0, sizeof action);
+ action.type = htons(OFPAT_OUTPUT);
+ action.output.len = htons(sizeof action);
+ action.output.port = htons(port_no);
- flow_extract(pkt, ODPP_NONE, &flow);
- ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
+ flow_extract(pkt, ODPP_NONE, &flow);
+ ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
+ }
}
ofpbuf_delete(pkt);
}