From e58de0e38647f0ee62a8862e3565e5b788a03a7e Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Fri, 3 Dec 2010 16:41:34 -0800 Subject: [PATCH] vswitchd: Incorporate vlan into bond hash. With this patch vlan tags are incorporated into bond hashes in addition to the source mac address. NIC-294 --- vswitchd/INTERNALS | 13 +++++----- vswitchd/bridge.c | 50 +++++++++++++++++++++++++++----------- vswitchd/ovs-vswitchd.8.in | 5 ++-- vswitchd/vswitch.xml | 9 +++---- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/vswitchd/INTERNALS b/vswitchd/INTERNALS index 30017562..6c1bdc16 100644 --- a/vswitchd/INTERNALS +++ b/vswitchd/INTERNALS @@ -106,12 +106,13 @@ Bond Packet Output ------------------ When a packet is sent out a bond port, the bond slave actually used is -selected based on the packet's source MAC (see choose_output_iface()). -In particular, the source MAC is hashed into one of 256 values, and -that value is looked up in a hash table (the "bond hash") kept in the -"bond_hash" member of struct port. The hash table entry identifies a -bond slave. If no bond slave has yet been chosen for that hash table -entry, vswitchd chooses one arbitrarily. +selected based on the packet's source MAC and VLAN tag (see +choose_output_iface()). In particular, the source MAC and VLAN tag +are hashed into one of 256 values, and that value is looked up in a +hash table (the "bond hash") kept in the "bond_hash" member of struct +port. The hash table entry identifies a bond slave. If no bond slave +has yet been chosen for that hash table entry, vswitchd chooses one +arbitrarily. Every 10 seconds, vswitchd rebalances the bond slaves (see bond_rebalance_port()). To rebalance, vswitchd examines the diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index a6530c63..c0984361 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1945,15 +1945,16 @@ bridge_fetch_dp_ifaces(struct bridge *br) /* Bridge packet processing functions. */ static int -bond_hash(const uint8_t mac[ETH_ADDR_LEN]) +bond_hash(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan) { - return hash_bytes(mac, ETH_ADDR_LEN, 0) & BOND_MASK; + return hash_bytes(mac, ETH_ADDR_LEN, vlan) & BOND_MASK; } static struct bond_entry * -lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN]) +lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN], + uint16_t vlan) { - return &port->bond_hash[bond_hash(mac)]; + return &port->bond_hash[bond_hash(mac, vlan)]; } static int @@ -1988,7 +1989,7 @@ bond_choose_iface(const struct port *port) static bool choose_output_iface(const struct port *port, const uint8_t *dl_src, - uint16_t *dp_ifidx, tag_type *tags) + uint16_t vlan, uint16_t *dp_ifidx, tag_type *tags) { struct iface *iface; @@ -1996,7 +1997,7 @@ choose_output_iface(const struct port *port, const uint8_t *dl_src, if (port->n_ifaces == 1) { iface = port->ifaces[0]; } else { - struct bond_entry *e = lookup_bond_entry(port, dl_src); + struct bond_entry *e = lookup_bond_entry(port, dl_src, vlan); 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 @@ -2233,7 +2234,8 @@ set_dst(struct dst *p, const struct flow *flow, : in_port->vlan >= 0 ? in_port->vlan : flow->vlan_tci == 0 ? OFP_VLAN_NONE : vlan_tci_to_vid(flow->vlan_tci)); - return choose_output_iface(out_port, flow->dl_src, &p->dp_ifidx, tags); + return choose_output_iface(out_port, flow->dl_src, p->vlan, + &p->dp_ifidx, tags); } static void @@ -2745,8 +2747,11 @@ bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags, if (a->type == ODPAT_OUTPUT) { struct port *out_port = port_from_dp_ifidx(br, a->output.port); if (out_port && out_port->n_ifaces >= 2) { + uint16_t vlan = (flow->vlan_tci + ? vlan_tci_to_vid(flow->vlan_tci) + : OFP_VLAN_NONE); struct bond_entry *e = lookup_bond_entry(out_port, - flow->dl_src); + flow->dl_src, vlan); e->tx_bytes += n_bytes; } } @@ -3100,7 +3105,7 @@ bond_send_learning_packets(struct port *port) int retval; if (e->port == port->port_idx - || !choose_output_iface(port, e->mac, &dp_ifidx, &tags)) { + || !choose_output_iface(port, e->mac, e->vlan, &dp_ifidx, &tags)) { continue; } @@ -3246,9 +3251,10 @@ bond_unixctl_show(struct unixctl_conn *conn, LIST_FOR_EACH (me, lru_node, &port->bridge->ml->lrus) { uint16_t dp_ifidx; tag_type tags = 0; - if (bond_hash(me->mac) == hash + if (bond_hash(me->mac, me->vlan) == hash && me->port != port->port_idx - && choose_output_iface(port, me->mac, &dp_ifidx, &tags) + && choose_output_iface(port, me->mac, me->vlan, + &dp_ifidx, &tags) && dp_ifidx == iface->dp_ifidx) { ds_put_format(&ds, "\t\t"ETH_ADDR_FMT"\n", @@ -3410,16 +3416,32 @@ bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args, } static void -bond_unixctl_hash(struct unixctl_conn *conn, const char *args, +bond_unixctl_hash(struct unixctl_conn *conn, const char *args_, void *aux OVS_UNUSED) { + char *args = (char *) args_; uint8_t mac[ETH_ADDR_LEN]; uint8_t hash; char *hash_cstr; + unsigned int vlan; + char *mac_s, *vlan_s; + char *save_ptr = NULL; + + mac_s = strtok_r(args, " ", &save_ptr); + vlan_s = strtok_r(NULL, " ", &save_ptr); + + if (vlan_s) { + if (sscanf(vlan_s, "%u", &vlan) != 1) { + unixctl_command_reply(conn, 501, "invalid vlan"); + return; + } + } else { + vlan = OFP_VLAN_NONE; + } - if (sscanf(args, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) + if (sscanf(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) == ETH_ADDR_SCAN_COUNT) { - hash = bond_hash(mac); + hash = bond_hash(mac, vlan); hash_cstr = xasprintf("%u", hash); unixctl_command_reply(conn, 200, hash_cstr); diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in index a1a63108..189f2138 100644 --- a/vswitchd/ovs-vswitchd.8.in +++ b/vswitchd/ovs-vswitchd.8.in @@ -179,8 +179,9 @@ updelay (or downdelay). .IP This setting is not permanent: it persists only until the carrier status of \fIslave\fR changes. -.IP "\fBbond/hash\fR \fImac\fR" -Returns the hash value which would be used for \fImac\fR. +.IP "\fBbond/hash\fR \fImac\fR [\fIvlan\fR]" +Returns the hash value which would be used for \fImac\fR with \fIvlan\fR +if specified. . .so lib/vlog-unixctl.man .so lib/stress-unixctl.man diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index bec2d58e..7b7a1ac9 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -457,11 +457,10 @@

A port that has more than one interface is a ``bonded port.'' Bonding allows for load balancing and fail-over. Open vSwitch supports ``source load balancing'' (SLB) bonding, which - assigns flows to slaves based on source MAC address, with - periodic rebalancing as traffic patterns change. This form of - bonding does not require 802.3ad or other special support from - the upstream switch to which the slave devices are - connected.

+ assigns flows to slaves based on source MAC address and output VLAN, + with periodic rebalancing as traffic patterns change. This form of + bonding does not require 802.3ad or other special support from the + upstream switch to which the slave devices are connected.

These columns apply only to bonded ports. Their values are otherwise ignored.

-- 2.30.2