aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2012-02-01 15:04:51 -0800
committerBen Pfaff <blp@nicira.com>2012-02-01 15:08:03 -0800
commite3cdd9fdd18c131037c3726fca69cdc355931097 (patch)
tree73f73ae479934f3979b4fe55bc21a4379e6e4342
parent5cca1685a25a0b517a30e056b6e0c920d4c94c37 (diff)
vswitchd: Make the MAC entry aging time configurable.
NICS-11. Signed-off-by: Ben Pfaff <blp@nicira.com>
-rw-r--r--NEWS2
-rw-r--r--lib/learning-switch.c6
-rw-r--r--lib/mac-learning.c41
-rw-r--r--lib/mac-learning.h10
-rw-r--r--ofproto/ofproto-dpif.c13
-rw-r--r--ofproto/ofproto-provider.h4
-rw-r--r--ofproto/ofproto.c10
-rw-r--r--ofproto/ofproto.h3
-rw-r--r--vswitchd/bridge.c17
-rw-r--r--vswitchd/vswitch.xml20
10 files changed, 111 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index c9616af0..735c863e 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ v1.5.0 - xx xxx xxxx
{=}, {!=}, {<}, {>}, {<=}, and {>=}.
- ovsdb-tool now uses the typical database and schema installation
directories as defaults.
+ - The default MAC learning timeout has been increased from 60 seconds
+ to 300 seconds. The MAC learning timeout is now configurable.
v1.4.0 - 30 Jan 2012
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 2fc6392f..05eb578c 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -96,7 +96,9 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
sw->max_idle = cfg->max_idle;
sw->datapath_id = 0;
sw->last_features_request = time_now() - 1;
- sw->ml = cfg->mode == LSW_LEARN ? mac_learning_create() : NULL;
+ sw->ml = (cfg->mode == LSW_LEARN
+ ? mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME)
+ : NULL);
sw->action_normal = cfg->mode == LSW_NORMAL;
flow_wildcards_init_exact(&sw->wc);
diff --git a/lib/mac-learning.c b/lib/mac-learning.c
index efd1dd4b..836bcd48 100644
--- a/lib/mac-learning.c
+++ b/lib/mac-learning.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,12 +37,12 @@ VLOG_DEFINE_THIS_MODULE(mac_learning);
COVERAGE_DEFINE(mac_learning_learned);
COVERAGE_DEFINE(mac_learning_expired);
-/* Returns the number of seconds since 'e' was last learned. */
+/* Returns the number of seconds since 'e' (within 'ml') was last learned. */
int
-mac_entry_age(const struct mac_entry *e)
+mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e)
{
time_t remaining = e->expires - time_now();
- return MAC_ENTRY_IDLE_TIME - remaining;
+ return ml->idle_time - remaining;
}
static uint32_t
@@ -98,9 +98,18 @@ get_lru(struct mac_learning *ml, struct mac_entry **e)
}
}
-/* Creates and returns a new MAC learning table. */
+static unsigned int
+normalize_idle_time(unsigned int idle_time)
+{
+ return (idle_time < 15 ? 15
+ : idle_time > 3600 ? 3600
+ : idle_time);
+}
+
+/* Creates and returns a new MAC learning table with an initial MAC aging
+ * timeout of 'idle_time' seconds. */
struct mac_learning *
-mac_learning_create(void)
+mac_learning_create(unsigned int idle_time)
{
struct mac_learning *ml;
@@ -109,6 +118,7 @@ mac_learning_create(void)
hmap_init(&ml->table);
ml->secret = random_uint32();
ml->flood_vlans = NULL;
+ ml->idle_time = normalize_idle_time(idle_time);
return ml;
}
@@ -146,6 +156,23 @@ mac_learning_set_flood_vlans(struct mac_learning *ml,
}
}
+/* Changes the MAC aging timeout of 'ml' to 'idle_time' seconds. */
+void
+mac_learning_set_idle_time(struct mac_learning *ml, unsigned int idle_time)
+{
+ idle_time = normalize_idle_time(idle_time);
+ if (idle_time != ml->idle_time) {
+ struct mac_entry *e;
+ int delta;
+
+ delta = (int) idle_time - (int) ml->idle_time;
+ LIST_FOR_EACH (e, lru_node, &ml->lrus) {
+ e->expires += delta;
+ }
+ ml->idle_time = idle_time;
+ }
+}
+
static bool
is_learning_vlan(const struct mac_learning *ml, uint16_t vlan)
{
@@ -199,7 +226,7 @@ mac_learning_insert(struct mac_learning *ml,
/* Mark 'e' as recently used. */
list_push_back(&ml->lrus, &e->lru_node);
- e->expires = time_now() + MAC_ENTRY_IDLE_TIME;
+ e->expires = time_now() + ml->idle_time;
return e;
}
diff --git a/lib/mac-learning.h b/lib/mac-learning.h
index 4bcf221d..8d0ac622 100644
--- a/lib/mac-learning.h
+++ b/lib/mac-learning.h
@@ -24,10 +24,12 @@
#include "tag.h"
#include "timeval.h"
+struct mac_learning;
+
#define MAC_MAX 2048
/* Time, in seconds, before expiring a mac_entry due to inactivity. */
-#define MAC_ENTRY_IDLE_TIME 300
+#define MAC_ENTRY_DEFAULT_IDLE_TIME 300
/* Time, in seconds, to lock an entry updated by a gratuitous ARP to avoid
* relearning based on a reflection from a bond slave. */
@@ -50,7 +52,7 @@ struct mac_entry {
} port;
};
-int mac_entry_age(const struct mac_entry *);
+int mac_entry_age(const struct mac_learning *, const struct mac_entry *);
/* Returns true if mac_learning_insert() just created 'mac' and the caller has
* not yet properly initialized it. */
@@ -80,10 +82,11 @@ struct mac_learning {
front, most recently used at the back. */
uint32_t secret; /* Secret for randomizing hash table. */
unsigned long *flood_vlans; /* Bitmap of learning disabled VLANs. */
+ unsigned int idle_time; /* Max age before deleting an entry. */
};
/* Basics. */
-struct mac_learning *mac_learning_create(void);
+struct mac_learning *mac_learning_create(unsigned int idle_time);
void mac_learning_destroy(struct mac_learning *);
void mac_learning_run(struct mac_learning *, struct tag_set *);
@@ -92,6 +95,7 @@ void mac_learning_wait(struct mac_learning *);
/* Configuration. */
bool mac_learning_set_flood_vlans(struct mac_learning *,
const unsigned long *bitmap);
+void mac_learning_set_idle_time(struct mac_learning *, unsigned int idle_time);
/* Learning. */
bool mac_learning_may_learn(const struct mac_learning *,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index b6e42f83..cd27528c 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -651,7 +651,7 @@ construct(struct ofproto *ofproto_, int *n_tablesp)
ofproto->sflow = NULL;
ofproto->stp = NULL;
hmap_init(&ofproto->bundles);
- ofproto->ml = mac_learning_create();
+ ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
for (i = 0; i < MAX_MIRRORS; i++) {
ofproto->mirrors[i] = NULL;
}
@@ -2136,6 +2136,13 @@ forward_bpdu_changed(struct ofproto *ofproto_)
/* Revalidate cached flows whenever forward_bpdu option changes. */
ofproto->need_revalidate = true;
}
+
+static void
+set_mac_idle_time(struct ofproto *ofproto_, unsigned int idle_time)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ mac_learning_set_idle_time(ofproto->ml, idle_time);
+}
/* Ports. */
@@ -5684,7 +5691,8 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
struct ofbundle *bundle = e->port.p;
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
ofbundle_get_a_port(bundle)->odp_port,
- e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
+ e->vlan, ETH_ADDR_ARGS(e->mac),
+ mac_entry_age(ofproto->ml, e));
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
ds_destroy(&ds);
@@ -6120,5 +6128,6 @@ const struct ofproto_class ofproto_dpif_class = {
set_flood_vlans,
is_mirror_output_bundle,
forward_bpdu_changed,
+ set_mac_idle_time,
set_realdev,
};
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 6c8583ea..6dd206b9 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1064,6 +1064,10 @@ struct ofproto_class {
* will be invoked. */
void (*forward_bpdu_changed)(struct ofproto *ofproto);
+ /* Sets the MAC aging timeout for the OFPP_NORMAL action to 'idle_time',
+ * in seconds. */
+ void (*set_mac_idle_time)(struct ofproto *ofproto, unsigned int idle_time);
+
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
*
* This is deprecated. It is only for compatibility with broken device drivers
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 07d4934b..aad63331 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -446,6 +446,16 @@ ofproto_set_forward_bpdu(struct ofproto *ofproto, bool forward_bpdu)
}
}
+/* Sets the MAC aging timeout for the OFPP_NORMAL action on 'ofproto' to
+ * 'idle_time', in seconds. */
+void
+ofproto_set_mac_idle_time(struct ofproto *ofproto, unsigned idle_time)
+{
+ if (ofproto->ofproto_class->set_mac_idle_time) {
+ ofproto->ofproto_class->set_mac_idle_time(ofproto, idle_time);
+ }
+}
+
void
ofproto_set_desc(struct ofproto *p,
const char *mfr_desc, const char *hw_desc,
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 2d478784..24efa155 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -205,6 +205,7 @@ void ofproto_set_extra_in_band_remotes(struct ofproto *,
void ofproto_set_in_band_queue(struct ofproto *, int queue_id);
void ofproto_set_flow_eviction_threshold(struct ofproto *, unsigned threshold);
void ofproto_set_forward_bpdu(struct ofproto *, bool forward_bpdu);
+void ofproto_set_mac_idle_time(struct ofproto *, unsigned idle_time);
void ofproto_set_desc(struct ofproto *,
const char *mfr_desc, const char *hw_desc,
const char *sw_desc, const char *serial_desc,
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index b45b9727..261a3622 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -32,6 +32,7 @@
#include "jsonrpc.h"
#include "lacp.h"
#include "list.h"
+#include "mac-learning.h"
#include "netdev.h"
#include "ofp-print.h"
#include "ofpbuf.h"
@@ -156,6 +157,7 @@ static void bridge_configure_datapath_id(struct bridge *);
static void bridge_configure_flow_eviction_threshold(struct bridge *);
static void bridge_configure_netflow(struct bridge *);
static void bridge_configure_forward_bpdu(struct bridge *);
+static void bridge_configure_mac_idle_time(struct bridge *);
static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
static void bridge_configure_stp(struct bridge *);
static void bridge_configure_remotes(struct bridge *,
@@ -465,6 +467,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
bridge_configure_mirrors(br);
bridge_configure_flow_eviction_threshold(br);
bridge_configure_forward_bpdu(br);
+ bridge_configure_mac_idle_time(br);
bridge_configure_remotes(br, managers, n_managers);
bridge_configure_netflow(br);
bridge_configure_sflow(br, &sflow_bridge_number);
@@ -1271,6 +1274,20 @@ bridge_configure_forward_bpdu(struct bridge *br)
ofproto_set_forward_bpdu(br->ofproto, forward_bpdu);
}
+/* Set MAC aging time for 'br'. */
+static void
+bridge_configure_mac_idle_time(struct bridge *br)
+{
+ const char *idle_time_str;
+ int idle_time;
+
+ idle_time_str = bridge_get_other_config(br->cfg, "mac-aging-time");
+ idle_time = (idle_time_str && atoi(idle_time_str)
+ ? atoi(idle_time_str)
+ : MAC_ENTRY_DEFAULT_IDLE_TIME);
+ ofproto_set_mac_idle_time(br->ofproto, idle_time);
+}
+
static void
bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
struct iface **hw_addr_iface)
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index e28b053b..f3545e5a 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -553,6 +553,26 @@
should be enabled. Default is disabled, set to
<code>true</code> to enable.
</column>
+
+ <column name="other_config" key="mac-aging-time"
+ type='{"type": "integer", "minInteger": 1}'>
+ <p>
+ The maximum number of seconds to retain a MAC learning entry for
+ which no packets have been seen. The default is currently 300
+ seconds (5 minutes). The value, if specified, is forced into a
+ reasonable range, currently 15 to 3600 seconds.
+ </p>
+
+ <p>
+ A short MAC aging time allows a network to more quickly detect that a
+ host is no longer connected to a switch port. However, it also makes
+ it more likely that packets will be flooded unnecessarily, when they
+ are addressed to a connected host that rarely transmits packets. To
+ reduce the incidence of unnecessary flooding, use a MAC aging time
+ longer than the maximum interval at which a host will ordinarily
+ transmit packets.
+ </p>
+ </column>
</group>
<group title="Bridge Status">