aboutsummaryrefslogtreecommitdiff
path: root/lib/mac-learning.c
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2010-06-02 16:26:46 -0700
committerJesse Gross <jesse@nicira.com>2010-06-03 19:46:44 -0700
commit7febb9100b6a63aab46f8850de6de335f8a47345 (patch)
tree5de263fd407f303de6975ba61aad7f0642d31260 /lib/mac-learning.c
parentb33c0ddb28655b5cc0dd851d3e26829a961c0e3d (diff)
bridge: Filter some gratuitous ARPs on bond slaves.
Normally we filter out packets received on a bond if we have learned the source MAC as belonging to another port to avoid packets sent on one slave and reflected back on another. The exception to this is gratuitous ARPs because they indicate that the host has moved to another port. However, this can result in an additional problem on the switch that the host moved to if the gratuitous ARP is reflected back on a bond slave. In this case, we incorrectly relearn the slave as the source of the MAC address. To solve this, we lock the learning entry for 5 seconds after receiving a gratuitous ARP against further updates caused by gratuitous ARPs on bond slaves. Bug #2516 Reported-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'lib/mac-learning.c')
-rw-r--r--lib/mac-learning.c59
1 files changed, 40 insertions, 19 deletions
diff --git a/lib/mac-learning.c b/lib/mac-learning.c
index f9859b6b..5d64f543 100644
--- a/lib/mac-learning.c
+++ b/lib/mac-learning.c
@@ -175,11 +175,14 @@ is_learning_vlan(const struct mac_learning *ml, uint16_t vlan)
* that now need revalidation.
*
* The 'vlan' parameter is used to maintain separate per-VLAN learning tables.
- * Specify 0 if this behavior is undesirable. */
+ * Specify 0 if this behavior is undesirable.
+ *
+ * 'lock_type' specifies whether the entry should be locked or existing locks
+ * are check. */
tag_type
mac_learning_learn(struct mac_learning *ml,
const uint8_t src_mac[ETH_ADDR_LEN], uint16_t vlan,
- uint16_t src_port)
+ uint16_t src_port, enum grat_arp_lock_type lock_type)
{
struct mac_entry *e;
struct list *bucket;
@@ -209,32 +212,42 @@ mac_learning_learn(struct mac_learning *ml,
e->port = -1;
e->vlan = vlan;
e->tag = make_unknown_mac_tag(ml, src_mac, vlan);
+ e->grat_arp_lock = TIME_MIN;
}
- /* Make the entry most-recently-used. */
- list_remove(&e->lru_node);
- list_push_back(&ml->lrus, &e->lru_node);
- e->expires = time_now() + MAC_ENTRY_IDLE_TIME;
-
- /* Did we learn something? */
- if (e->port != src_port) {
- tag_type old_tag = e->tag;
- e->port = src_port;
- e->tag = tag_create_random();
- COVERAGE_INC(mac_learning_learned);
- return old_tag;
+ if (lock_type != GRAT_ARP_LOCK_CHECK || time_now() >= e->grat_arp_lock) {
+ /* Make the entry most-recently-used. */
+ list_remove(&e->lru_node);
+ list_push_back(&ml->lrus, &e->lru_node);
+ e->expires = time_now() + MAC_ENTRY_IDLE_TIME;
+ if (lock_type == GRAT_ARP_LOCK_SET) {
+ e->grat_arp_lock = time_now() + MAC_GRAT_ARP_LOCK_TIME;
+ }
+
+ /* Did we learn something? */
+ if (e->port != src_port) {
+ tag_type old_tag = e->tag;
+ e->port = src_port;
+ e->tag = tag_create_random();
+ COVERAGE_INC(mac_learning_learned);
+ return old_tag;
+ }
}
+
return 0;
}
/* Looks up MAC 'dst' for VLAN 'vlan' in 'ml'. Returns the port on which a
- * frame destined for 'dst' should be sent, -1 if unknown. */
+ * frame destined for 'dst' should be sent, -1 if unknown. 'is_grat_arp_locked'
+ * is an optional parameter that returns whether the entry is currently
+ * locked. */
int
mac_learning_lookup(const struct mac_learning *ml,
- const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan)
+ const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan,
+ bool *is_grat_arp_locked)
{
tag_type tag = 0;
- return mac_learning_lookup_tag(ml, dst, vlan, &tag);
+ return mac_learning_lookup_tag(ml, dst, vlan, &tag, is_grat_arp_locked);
}
/* Looks up MAC 'dst' for VLAN 'vlan' in 'ml'. Returns the port on which a
@@ -242,11 +255,14 @@ mac_learning_lookup(const struct mac_learning *ml,
*
* Adds to '*tag' (which the caller must have initialized) the tag that should
* be attached to any flow created based on the return value, if any, to allow
- * those flows to be revalidated when the MAC learning entry changes. */
+ * those flows to be revalidated when the MAC learning entry changes.
+ *
+ * 'is_grat_arp_locked' is an optional parameter that returns whether the entry
+ * is currently locked.*/
int
mac_learning_lookup_tag(const struct mac_learning *ml,
const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan,
- tag_type *tag)
+ tag_type *tag, bool *is_grat_arp_locked)
{
if (eth_addr_is_multicast(dst) || !is_learning_vlan(ml, vlan)) {
return -1;
@@ -255,6 +271,11 @@ mac_learning_lookup_tag(const struct mac_learning *ml,
dst, vlan);
if (e) {
*tag |= e->tag;
+
+ if (is_grat_arp_locked) {
+ *is_grat_arp_locked = time_now() < e->grat_arp_lock;
+ }
+
return e->port;
} else {
*tag |= make_unknown_mac_tag(ml, dst, vlan);