- struct iface *local_iface;
- struct in_addr ip;
- bool in_band;
-
- in_band = (!c->connection_mode
- || !strcmp(c->connection_mode, "out-of-band"));
- ofproto_set_discovery(br->ofproto, false, NULL, NULL);
- ofproto_set_in_band(br->ofproto, in_band);
-
- local_iface = bridge_get_local_iface(br);
- if (local_iface && c->local_ip && inet_aton(c->local_ip, &ip)) {
- struct netdev *netdev = local_iface->netdev;
- struct in_addr mask, gateway;
-
- if (!c->local_netmask || !inet_aton(c->local_netmask, &mask)) {
- mask.s_addr = 0;
- }
- if (!c->local_gateway
- || !inet_aton(c->local_gateway, &gateway)) {
- gateway.s_addr = 0;
- }
-
- 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(netdev, gateway)) {
- VLOG_INFO("bridge %s: configured gateway "IP_FMT,
- br->name, IP_ARGS(&gateway.s_addr));
- }
- }
- }
- }
-
- ofproto_set_failure(br->ofproto,
- (!c->fail_mode
- || !strcmp(c->fail_mode, "standalone")
- || !strcmp(c->fail_mode, "open")));
-
- probe = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
- ofproto_set_probe_interval(br->ofproto, probe);
-
- max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8;
- ofproto_set_max_backoff(br->ofproto, max_backoff);
-
- rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
- burst_limit = c->controller_burst_limit ? *c->controller_burst_limit : 0;
- ofproto_set_rate_limit(br->ofproto, rate_limit, burst_limit);
- } else {
- union ofp_action action;
- flow_t flow;
-
- /* Set up a flow that matches every packet and directs them to
- * OFPP_NORMAL (which goes to us). */
- memset(&action, 0, sizeof action);
- action.type = htons(OFPAT_OUTPUT);
- action.output.len = htons(sizeof action);
- action.output.port = htons(OFPP_NORMAL);
- memset(&flow, 0, sizeof flow);
- ofproto_add_flow(br->ofproto, &flow, OVSFW_ALL, 0, &action, 1, 0);
-
- ofproto_set_in_band(br->ofproto, false);
- ofproto_set_max_backoff(br->ofproto, 1);
- ofproto_set_probe_interval(br->ofproto, 5);
- ofproto_set_failure(br->ofproto, false);
- }
-
- ofproto_set_controller(br->ofproto, br->controller);
-}
-
-static void
-bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
-{
- size_t i, j;
-
- shash_init(ifaces);
- 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];
- shash_add_once(ifaces, iface->name, iface);
- }
- if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
- shash_add_once(ifaces, port->name, NULL);
- }
- }
-}
-
-/* For robustness, in case the administrator moves around datapath ports behind
- * our back, we re-check all the datapath port numbers here.
- *
- * This function will set the 'dp_ifidx' members of interfaces that have
- * disappeared to -1, so only call this function from a context where those
- * 'struct iface's will be removed from the bridge. Otherwise, the -1
- * 'dp_ifidx'es will cause trouble later when we try to send them to the
- * datapath, which doesn't support UINT16_MAX+1 ports. */
-static void
-bridge_fetch_dp_ifaces(struct bridge *br)
-{
- struct odp_port *dpif_ports;
- size_t n_dpif_ports;
- size_t i, j;
-
- /* Reset all interface numbers. */
- 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];
- iface->dp_ifidx = -1;
- }
- }
- port_array_clear(&br->ifaces);
-
- dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
- for (i = 0; i < n_dpif_ports; i++) {
- struct odp_port *p = &dpif_ports[i];
- struct iface *iface = iface_lookup(br, p->devname);
- if (iface) {
- if (iface->dp_ifidx >= 0) {
- VLOG_WARN("%s reported interface %s twice",
- dpif_name(br->dpif), p->devname);
- } else if (iface_from_dp_ifidx(br, p->port)) {
- VLOG_WARN("%s reported interface %"PRIu16" twice",
- dpif_name(br->dpif), p->port);
- } else {
- port_array_set(&br->ifaces, p->port, iface);
- iface->dp_ifidx = p->port;
- }
-
- if (iface->cfg) {
- int64_t ofport = (iface->dp_ifidx >= 0
- ? odp_port_to_ofp_port(iface->dp_ifidx)
- : -1);
- ovsrec_interface_set_ofport(iface->cfg, &ofport, 1);
- }
- }
- }
- free(dpif_ports);
-}
-\f
-/* Bridge packet processing functions. */
-
-static int
-bond_hash(const uint8_t mac[ETH_ADDR_LEN])
-{
- return hash_bytes(mac, ETH_ADDR_LEN, 0) & BOND_MASK;
-}
-
-static struct bond_entry *
-lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN])
-{
- return &port->bond_hash[bond_hash(mac)];
-}
-
-static int
-bond_choose_iface(const struct port *port)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
- size_t i, best_down_slave = -1;
- long long next_delay_expiration = LLONG_MAX;
-
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
-
- if (iface->enabled) {
- return i;
- } else if (iface->delay_expires < next_delay_expiration) {
- best_down_slave = i;
- next_delay_expiration = iface->delay_expires;
- }
- }
-
- if (best_down_slave != -1) {
- struct iface *iface = port->ifaces[best_down_slave];
-
- VLOG_INFO_RL(&rl, "interface %s: skipping remaining %lli ms updelay "
- "since no other interface is up", iface->name,
- iface->delay_expires - time_msec());
- bond_enable_slave(iface, true);
- }
-
- return best_down_slave;
-}
-
-static bool
-choose_output_iface(const struct port *port, const uint8_t *dl_src,
- uint16_t *dp_ifidx, tag_type *tags)
-{
- struct iface *iface;
-
- assert(port->n_ifaces);
- if (port->n_ifaces == 1) {
- iface = port->ifaces[0];
- } else {
- struct bond_entry *e = lookup_bond_entry(port, dl_src);
- if (e->iface_idx < 0 || e->iface_idx >= port->n_ifaces
- || !port->ifaces[e->iface_idx]->enabled) {
- /* XXX select interface properly. The current interface selection
- * is only good for testing the rebalancing code. */
- e->iface_idx = bond_choose_iface(port);
- if (e->iface_idx < 0) {
- *tags |= port->no_ifaces_tag;
- 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];
- }
- *dp_ifidx = iface->dp_ifidx;
- *tags |= iface->tag; /* Currently only used for bonding. */
- return true;
-}
-
-static void
-bond_link_status_update(struct iface *iface, bool carrier)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
- struct port *port = iface->port;
-
- if ((carrier == iface->enabled) == (iface->delay_expires == LLONG_MAX)) {
- /* Nothing to do. */
- return;
- }
- VLOG_INFO_RL(&rl, "interface %s: carrier %s",
- iface->name, carrier ? "detected" : "dropped");
- if (carrier == iface->enabled) {
- iface->delay_expires = LLONG_MAX;
- VLOG_INFO_RL(&rl, "interface %s: will not be %s",
- iface->name, carrier ? "disabled" : "enabled");
- } else if (carrier && port->active_iface < 0) {
- bond_enable_slave(iface, true);
- if (port->updelay) {
- VLOG_INFO_RL(&rl, "interface %s: skipping %d ms updelay since no "
- "other interface is up", iface->name, port->updelay);
- }
- } else {
- int delay = carrier ? port->updelay : port->downdelay;
- iface->delay_expires = time_msec() + delay;
- if (delay) {
- VLOG_INFO_RL(&rl,
- "interface %s: will be %s if it stays %s for %d ms",
- iface->name,
- carrier ? "enabled" : "disabled",
- carrier ? "up" : "down",
- delay);
- }
- }
-}
-
-static void
-bond_choose_active_iface(struct port *port)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
-
- port->active_iface = bond_choose_iface(port);
- port->active_iface_tag = tag_create_random();
- if (port->active_iface >= 0) {
- VLOG_INFO_RL(&rl, "port %s: active interface is now %s",
- port->name, port->ifaces[port->active_iface]->name);
- } else {
- VLOG_WARN_RL(&rl, "port %s: all ports disabled, no active interface",
- port->name);
- }
-}
-
-static void
-bond_enable_slave(struct iface *iface, bool enable)
-{
- struct port *port = iface->port;
- struct bridge *br = port->bridge;
-
- /* This acts as a recursion check. If the act of disabling a slave
- * causes a different slave to be enabled, the flag will allow us to
- * skip redundant work when we reenter this function. It must be
- * cleared on exit to keep things safe with multiple bonds. */
- static bool moving_active_iface = false;
-
- iface->delay_expires = LLONG_MAX;
- if (enable == iface->enabled) {
- return;
- }
-
- iface->enabled = enable;
- if (!iface->enabled) {
- VLOG_WARN("interface %s: disabled", iface->name);
- ofproto_revalidate(br->ofproto, iface->tag);
- if (iface->port_ifidx == port->active_iface) {
- ofproto_revalidate(br->ofproto,
- port->active_iface_tag);
-
- /* Disabling a slave can lead to another slave being immediately
- * enabled if there will be no active slaves but one is waiting
- * on an updelay. In this case we do not need to run most of the
- * code for the newly enabled slave since there was no period
- * without an active slave and it is redundant with the disabling
- * path. */
- moving_active_iface = true;
- bond_choose_active_iface(port);
- }
- bond_send_learning_packets(port);
- } else {
- VLOG_WARN("interface %s: enabled", iface->name);
- if (port->active_iface < 0 && !moving_active_iface) {
- ofproto_revalidate(br->ofproto, port->no_ifaces_tag);
- bond_choose_active_iface(port);
- bond_send_learning_packets(port);
- }
- iface->tag = tag_create_random();
- }
-
- moving_active_iface = false;
- port->bond_compat_is_stale = true;
-}
-
-static void
-bond_run(struct bridge *br)
-{
- size_t i, j;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
-
- if (port->n_ifaces >= 2) {
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- if (time_msec() >= iface->delay_expires) {
- bond_enable_slave(iface, !iface->enabled);
- }
- }
- }
-
- if (port->bond_compat_is_stale) {
- port->bond_compat_is_stale = false;
- port_update_bond_compat(port);
- }
- }
-}
-
-static void
-bond_wait(struct bridge *br)
-{
- size_t i, j;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- if (port->n_ifaces < 2) {
- continue;
- }
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- if (iface->delay_expires != LLONG_MAX) {
- poll_timer_wait(iface->delay_expires - time_msec());
- }
- }
- }
-}
-
-static bool
-set_dst(struct dst *p, const flow_t *flow,
- const struct port *in_port, const struct port *out_port,
- tag_type *tags)
-{
- p->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
- : in_port->vlan >= 0 ? in_port->vlan
- : ntohs(flow->dl_vlan));
- return choose_output_iface(out_port, flow->dl_src, &p->dp_ifidx, tags);
-}
-
-static void
-swap_dst(struct dst *p, struct dst *q)
-{
- struct dst tmp = *p;
- *p = *q;
- *q = tmp;
-}
-
-/* Moves all the dsts with vlan == 'vlan' to the front of the 'n_dsts' in
- * 'dsts'. (This may help performance by reducing the number of VLAN changes
- * that we push to the datapath. We could in fact fully sort the array by
- * vlan, but in most cases there are at most two different vlan tags so that's
- * possibly overkill.) */
-static void
-partition_dsts(struct dst *dsts, size_t n_dsts, int vlan)
-{
- struct dst *first = dsts;
- struct dst *last = dsts + n_dsts;
-
- while (first != last) {
- /* Invariants:
- * - All dsts < first have vlan == 'vlan'.
- * - All dsts >= last have vlan != 'vlan'.
- * - first < last. */
- while (first->vlan == vlan) {
- if (++first == last) {
- return;
- }
- }