vswitchd: Incorporate vlan into bond hash.
authorEthan Jackson <ethan@nicira.com>
Sat, 4 Dec 2010 00:41:34 +0000 (16:41 -0800)
committerEthan Jackson <ethan@nicira.com>
Mon, 6 Dec 2010 21:59:43 +0000 (13:59 -0800)
With this patch vlan tags are incorporated into bond hashes in
addition to the source mac address.

NIC-294

vswitchd/INTERNALS
vswitchd/bridge.c
vswitchd/ovs-vswitchd.8.in
vswitchd/vswitch.xml

index 300175627a18a3db9e6ceeeef3579a623a385fdc..6c1bdc16bf65f0201c5a58e1d692d2dcff3c3ddf 100644 (file)
@@ -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
index a6530c638d381ffd7870b089b184d85cb18e59cb..c0984361ba117f64afdcf522745bc17f2cd6a1ab 100644 (file)
@@ -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);
index a1a631087df408726897e88562b593934e82f845..189f213824bbc2dedafe6f1676c2bf56987a325d 100644 (file)
@@ -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
index bec2d58e894735b76cbdb9f8fec476bc5d6f3752..7b7a1ac928666a8399fa1e1d8bb84c872af204af 100644 (file)
       <p>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.</p>
+        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.</p>
 
       <p>These columns apply only to bonded ports.  Their values are
         otherwise ignored.</p>