summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2009-11-06 17:13:51 -0800
committerJesse Gross <jesse@nicira.com>2009-11-10 13:37:08 -0800
commitf2d7fd66cf51b83acbe509f8ef6d4b34538d0646 (patch)
tree6bd64d88ec02cfad33c57b9171a66f367282f06b
parent93dfc06772a722abf3362606307bab9a9bf33292 (diff)
downloadopenvswitch-f2d7fd66cf51b83acbe509f8ef6d4b34538d0646.tar.gz
mirroring: Allow learning to be disabled on a VLAN.
RSPAN does not work properly unless MAC learning for the VLAN is disabled on all switches between the origin and monitoring point. This allows learning to be disabled on a given VLAN so vSwitch can acts as an intermediate switch. Feature #2136
-rw-r--r--lib/mac-learning.c35
-rw-r--r--lib/mac-learning.h3
-rw-r--r--vswitchd/bridge.c24
-rw-r--r--vswitchd/ovs-vswitchd.conf.5.in7
4 files changed, 65 insertions, 4 deletions
diff --git a/lib/mac-learning.c b/lib/mac-learning.c
index c9b7d3e73..3f1db1461 100644
--- a/lib/mac-learning.c
+++ b/lib/mac-learning.c
@@ -21,6 +21,7 @@
#include <inttypes.h>
#include <stdlib.h>
+#include "bitmap.h"
#include "coverage.h"
#include "hash.h"
#include "list.h"
@@ -129,6 +130,7 @@ mac_learning_create(void)
list_push_front(&ml->free, &s->lru_node);
}
ml->secret = random_uint32();
+ ml->non_learning_vlans = NULL;
return ml;
}
@@ -136,9 +138,36 @@ mac_learning_create(void)
void
mac_learning_destroy(struct mac_learning *ml)
{
+ if (ml) {
+ bitmap_free(ml->non_learning_vlans);
+ }
free(ml);
}
+/* Provides a bitmap of VLANs which have learning disabled. It takes
+ * ownership of the bitmap. Returns true if the set has changed from
+ * the previous value. */
+bool
+mac_learning_set_disabled_vlans(struct mac_learning *ml, unsigned long *bitmap)
+{
+ bool ret = (bitmap == NULL
+ ? ml->non_learning_vlans != NULL
+ : (ml->non_learning_vlans == NULL
+ || !bitmap_equal(bitmap, ml->non_learning_vlans, 4096)));
+
+ bitmap_free(ml->non_learning_vlans);
+ ml->non_learning_vlans = bitmap;
+
+ return ret;
+}
+
+static bool
+is_learning_vlan(const struct mac_learning *ml, uint16_t vlan)
+{
+ return !(ml->non_learning_vlans
+ && bitmap_is_set(ml->non_learning_vlans, vlan));
+}
+
/* Attempts to make 'ml' learn from the fact that a frame from 'src_mac' was
* just observed arriving from 'src_port' on the given 'vlan'.
*
@@ -156,6 +185,10 @@ mac_learning_learn(struct mac_learning *ml,
struct mac_entry *e;
struct list *bucket;
+ if (!is_learning_vlan(ml, vlan)) {
+ return 0;
+ }
+
if (eth_addr_is_multicast(src_mac)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 30);
VLOG_DBG_RL(&rl, "multicast packet source "ETH_ADDR_FMT,
@@ -216,7 +249,7 @@ mac_learning_lookup_tag(const struct mac_learning *ml,
const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan,
tag_type *tag)
{
- if (eth_addr_is_multicast(dst)) {
+ if (eth_addr_is_multicast(dst) || !is_learning_vlan(ml, vlan)) {
return -1;
} else {
struct mac_entry *e = search_bucket(mac_table_bucket(ml, dst, vlan),
diff --git a/lib/mac-learning.h b/lib/mac-learning.h
index e2ee74ba4..ed843cd45 100644
--- a/lib/mac-learning.h
+++ b/lib/mac-learning.h
@@ -52,10 +52,13 @@ struct mac_learning {
struct list table[MAC_HASH_SIZE]; /* Hash table. */
struct mac_entry entries[MAC_MAX]; /* All entries. */
uint32_t secret; /* Secret for */
+ unsigned long *non_learning_vlans; /* Bitmap of learning disabled VLANs. */
};
struct mac_learning *mac_learning_create(void);
void mac_learning_destroy(struct mac_learning *);
+bool mac_learning_set_disabled_vlans(struct mac_learning *,
+ unsigned long *bitmap);
tag_type mac_learning_learn(struct mac_learning *,
const uint8_t src[ETH_ADDR_LEN], uint16_t vlan,
uint16_t src_port);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 84b42d792..1e55ad2f3 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -3265,7 +3265,8 @@ static void
mirror_reconfigure(struct bridge *br)
{
struct svec old_mirrors, new_mirrors;
- size_t i;
+ size_t i, n_rspan_vlans;
+ unsigned long *rspan_vlans;
/* Collect old and new mirrors. */
svec_init(&old_mirrors);
@@ -3314,6 +3315,27 @@ mirror_reconfigure(struct bridge *br)
m->out_port->is_mirror_output_port = true;
}
}
+
+ /* Update learning disabled vlans (for RSPAN). */
+ rspan_vlans = NULL;
+ n_rspan_vlans = cfg_count("vlan.%s.disable-learning", br->name);
+ if (n_rspan_vlans) {
+ rspan_vlans = bitmap_allocate(4096);
+
+ for (i = 0; i < n_rspan_vlans; i++) {
+ int vlan = cfg_get_vlan(i, "vlan.%s.disable-learning", br->name);
+ if (vlan >= 0) {
+ bitmap_set1(rspan_vlans, vlan);
+ } else {
+ VLOG_ERR("bridge %s: invalid value '%s' for learning disabled "
+ "VLAN", br->name,
+ cfg_get_string(i, "vlan.%s.disable-learning", br->name));
+ }
+ }
+ }
+ if (mac_learning_set_disabled_vlans(br->ml, rspan_vlans)) {
+ bridge_flush(br);
+ }
}
static void
diff --git a/vswitchd/ovs-vswitchd.conf.5.in b/vswitchd/ovs-vswitchd.conf.5.in
index 7c3c87f3e..ef9d75979 100644
--- a/vswitchd/ovs-vswitchd.conf.5.in
+++ b/vswitchd/ovs-vswitchd.conf.5.in
@@ -347,12 +347,15 @@ on port 1, disrupting connectivity. If mirroring to a VLAN is desired
in this scenario, then the physical switch must be replaced by one
that learns Ethernet addresses on a per-VLAN basis. In addition,
learning should be disabled on the VLAN containing mirrored traffic.
-If this is not done then the intermediate switch will learn the MAC
+If this is not done then intermediate switches will learn the MAC
address of each end host from the mirrored traffic. If packets being
sent to that end host are also mirrored, then they will be dropped
since the switch will attempt to send them out the input port.
Disabling learning for the VLAN will cause the switch to correctly
-send the packet out all ports configured for that VLAN.
+send the packet out all ports configured for that VLAN. If Open
+vSwitch is being used as an intermediate switch learning can be disabled
+by setting the key \fBvlan.\fIbrname\fB.learning-disable=\fIvid\fR
+to the mirrored VLAN.
.ST "Example"
The following \fBovs\-vswitchd\fR configuration copies all frames received
on \fBeth1\fR or \fBeth2\fR to \fBeth3\fR.