X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=7ec774aca3324e38b98746ef8a1152db837021ae;hb=35c979bff42010f54842d00bec8836f1d3f30545;hp=6a82a031e138747c44d73a69d3c190b770cb9ba4;hpb=092bebdc047b8a4944762a454ff8653baa563ced;p=sliver-openvswitch.git diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 6a82a031e..7ec774aca 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -130,6 +130,7 @@ struct port { tag_type active_iface_tag; /* Tag for bcast flows. */ tag_type no_ifaces_tag; /* Tag for flows when all ifaces disabled. */ int updelay, downdelay; /* Delay before iface goes up/down, in ms. */ + bool bond_compat_is_stale; /* Need to call port_update_bond_compat()? */ /* Port mirroring info. */ mirror_mask_t src_mirrors; /* Mirrors triggered when packet received. */ @@ -192,6 +193,7 @@ enum { DP_MAX = 256 }; static struct bridge *bridge_create(const char *name); static void bridge_destroy(struct bridge *); static struct bridge *bridge_lookup(const char *name); +static void bridge_unixctl_dump_flows(struct unixctl_conn *, const char *); static int bridge_run_one(struct bridge *); static void bridge_reconfigure_one(struct bridge *); static void bridge_reconfigure_controller(struct bridge *); @@ -303,6 +305,8 @@ bridge_init(void) } } + unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows); + bridge_reconfigure(); } @@ -457,9 +461,23 @@ bridge_reconfigure(void) for (i = 0; i < add_ifaces.n; i++) { const char *if_name = add_ifaces.names[i]; for (;;) { - int internal = cfg_get_bool(0, "iface.%s.internal", if_name); - int error = dpif_port_add(&br->dpif, if_name, next_port_no++, - internal ? ODP_PORT_INTERNAL : 0); + bool internal; + int error; + + /* It's an internal interface if it's marked that way, or if + * it's a bonded interface for which we're faking up a network + * device. */ + internal = cfg_get_bool(0, "iface.%s.internal", if_name); + if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) { + struct port *port = port_lookup(br, if_name); + if (port && port->n_ifaces > 1) { + internal = true; + } + } + + /* Add to datapath. */ + error = dpif_port_add(&br->dpif, if_name, next_port_no++, + internal ? ODP_PORT_INTERNAL : 0); if (error != EEXIST) { if (next_port_no >= 256) { VLOG_ERR("ran out of valid port numbers on dp%u", @@ -613,31 +631,75 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN], memset(ea, 0xff, sizeof ea); for (i = 0; i < br->n_ports; i++) { struct port *port = br->ports[i]; + uint8_t iface_ea[ETH_ADDR_LEN]; + uint64_t iface_ea_u64; + struct iface *iface; + + /* Mirror output ports don't participate. */ 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]; + + /* Choose the MAC address to represent the port. */ + iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name); + if (iface_ea_u64) { + /* User specified explicitly. */ + eth_addr_from_uint64(iface_ea_u64, 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_nodev_get_etheraddr(candidate->name, 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). 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 || cfg_get_bool(0, "iface.%s.internal", iface->name)) { continue; } + + /* Grab MAC. */ error = netdev_nodev_get_etheraddr(iface->name, 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; - } - } else { + 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_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 ? iface->name : NULL; + } } if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) { memcpy(ea, br->default_ea, ETH_ADDR_LEN); @@ -926,6 +988,27 @@ bridge_get_datapathid(const char *name) return br ? ofproto_get_datapath_id(br->ofproto) : 0; } +/* Handle requests for a listing of all flows known by the OpenFlow + * stack, including those normally hidden. */ +static void +bridge_unixctl_dump_flows(struct unixctl_conn *conn, const char *args) +{ + struct bridge *br; + struct ds results; + + br = bridge_lookup(args); + if (!br) { + unixctl_command_reply(conn, 501, "Unknown bridge"); + return; + } + + ds_init(&results); + ofproto_get_all_flows(br->ofproto, &results); + + unixctl_command_reply(conn, 200, ds_cstr(&results)); + ds_destroy(&results); +} + static int bridge_run_one(struct bridge *br) { @@ -1172,7 +1255,7 @@ bridge_reconfigure_controller(struct bridge *br) if (probe < 5) { probe = cfg_get_int(0, "mgmt.inactivity-probe"); if (probe < 5) { - probe = 15; + probe = 5; } } ofproto_set_probe_interval(br->ofproto, probe); @@ -1181,7 +1264,7 @@ bridge_reconfigure_controller(struct bridge *br) if (!max_backoff) { max_backoff = cfg_get_int(0, "mgmt.max-backoff"); if (!max_backoff) { - max_backoff = 15; + max_backoff = 8; } } ofproto_set_max_backoff(br->ofproto, max_backoff); @@ -1252,9 +1335,12 @@ bridge_get_all_ifaces(const struct bridge *br, struct svec *ifaces) struct iface *iface = port->ifaces[j]; svec_add(ifaces, iface->name); } + if (port->n_ifaces > 1 + && cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) { + svec_add(ifaces, port->name); + } } - svec_sort(ifaces); - assert(svec_is_unique(ifaces)); + svec_sort_unique(ifaces); } /* For robustness, in case the administrator moves around datapath ports behind @@ -1349,6 +1435,7 @@ choose_output_iface(const struct port *port, const uint8_t *dl_src, return false; } e->iface_tag = tag_create_random(); + ((struct port *) port)->bond_compat_is_stale = true; } *tags |= e->iface_tag; iface = port->ifaces[e->iface_idx]; @@ -1447,6 +1534,12 @@ bond_run(struct bridge *br) for (i = 0; i < br->n_ports; i++) { struct port *port = br->ports[i]; + + if (port->bond_compat_is_stale) { + port->bond_compat_is_stale = false; + port_update_bond_compat(port); + } + if (port->n_ifaces < 2) { continue; } @@ -2229,6 +2322,7 @@ bond_rebalance_port(struct port *port) } else { from++; } + port->bond_compat_is_stale = true; } } @@ -2495,6 +2589,7 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_) ofproto_revalidate(port->bridge->ofproto, entry->iface_tag); entry->iface_idx = iface->port_ifidx; entry->iface_tag = tag_create_random(); + port->bond_compat_is_stale = true; unixctl_command_reply(conn, 200, "migrated"); } @@ -2759,6 +2854,7 @@ port_destroy(struct port *port) size_t i; proc_net_compat_update_vlan(port->name, NULL, 0); + proc_net_compat_update_bond(port->name, NULL); for (i = 0; i < MAX_MIRRORS; i++) { struct mirror *m = br->mirrors[i]; @@ -2825,7 +2921,7 @@ port_update_bonding(struct port *port) if (port->bond_hash) { free(port->bond_hash); port->bond_hash = NULL; - proc_net_compat_update_bond(port->name, NULL); + port->bond_compat_is_stale = true; } } else { if (!port->bond_hash) { @@ -2840,23 +2936,39 @@ port_update_bonding(struct port *port) port->no_ifaces_tag = tag_create_random(); bond_choose_active_iface(port); } - port_update_bond_compat(port); + port->bond_compat_is_stale = true; } } static void port_update_bond_compat(struct port *port) { + struct compat_bond_hash compat_hashes[BOND_MASK + 1]; struct compat_bond bond; size_t i; if (port->n_ifaces < 2) { + proc_net_compat_update_bond(port->name, NULL); return; } bond.up = false; bond.updelay = port->updelay; bond.downdelay = port->downdelay; + + bond.n_hashes = 0; + bond.hashes = compat_hashes; + if (port->bond_hash) { + const struct bond_entry *e; + for (e = port->bond_hash; e <= &port->bond_hash[BOND_MASK]; e++) { + if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) { + struct compat_bond_hash *cbh = &bond.hashes[bond.n_hashes++]; + cbh->hash = e - port->bond_hash; + cbh->netdev_name = port->ifaces[e->iface_idx]->name; + } + } + } + bond.n_slaves = port->n_ifaces; bond.slaves = xmalloc(port->n_ifaces * sizeof *bond.slaves); for (i = 0; i < port->n_ifaces; i++) { @@ -2870,6 +2982,7 @@ port_update_bond_compat(struct port *port) } memcpy(slave->mac, iface->mac, ETH_ADDR_LEN); } + proc_net_compat_update_bond(port->name, &bond); free(bond.slaves); } @@ -2925,8 +3038,17 @@ iface_create(struct port *port, const char *name) iface->tag = tag_create_random(); iface->delay_expires = LLONG_MAX; - netdev_nodev_get_etheraddr(name, iface->mac); - netdev_nodev_get_carrier(name, &iface->enabled); + if (!cfg_get_bool(0, "iface.%s.internal", iface->name)) { + netdev_nodev_get_etheraddr(name, iface->mac); + netdev_nodev_get_carrier(name, &iface->enabled); + } else { + /* Internal interfaces are created later by the call to dpif_port_add() + * in bridge_reconfigure(). Until then, we can't obtain any + * information about them. (There's no real value in doing so, anyway, + * because the 'mac' and 'enabled' values are only used for interfaces + * that are bond slaves, and it doesn't normally make sense to bond an + * internal interface.) */ + } if (port->n_ifaces >= port->allocated_ifaces) { port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,