diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | lib/mac-learning.c | 24 | ||||
-rw-r--r-- | lib/mac-learning.h | 5 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 6 | ||||
-rw-r--r-- | ofproto/ofproto-provider.h | 11 | ||||
-rw-r--r-- | ofproto/ofproto.c | 11 | ||||
-rw-r--r-- | ofproto/ofproto.h | 3 | ||||
-rw-r--r-- | tests/ofproto-dpif.at | 62 | ||||
-rw-r--r-- | vswitchd/bridge.c | 19 | ||||
-rw-r--r-- | vswitchd/vswitch.xml | 9 |
10 files changed, 131 insertions, 20 deletions
@@ -1,5 +1,6 @@ post-v1.9.0 -------------------- + - The maximum size of the MAC learning table is now configurable. - New support for the VXLAN tunnel protocol (see the IETF draft here: http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02). - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit" commands diff --git a/lib/mac-learning.c b/lib/mac-learning.c index 3c541af2b..f609d48e2 100644 --- a/lib/mac-learning.c +++ b/lib/mac-learning.c @@ -110,7 +110,8 @@ normalize_idle_time(unsigned int idle_time) } /* Creates and returns a new MAC learning table with an initial MAC aging - * timeout of 'idle_time' seconds. */ + * timeout of 'idle_time' seconds and an initial maximum of MAC_DEFAULT_MAX + * entries. */ struct mac_learning * mac_learning_create(unsigned int idle_time) { @@ -122,6 +123,7 @@ mac_learning_create(unsigned int idle_time) ml->secret = random_uint32(); ml->flood_vlans = NULL; ml->idle_time = normalize_idle_time(idle_time); + ml->max_entries = MAC_DEFAULT_MAX; return ml; } @@ -176,6 +178,16 @@ mac_learning_set_idle_time(struct mac_learning *ml, unsigned int idle_time) } } +/* Sets the maximum number of entries in 'ml' to 'max_entries', adjusting it + * to be within a reasonable range. */ +void +mac_learning_set_max_entries(struct mac_learning *ml, size_t max_entries) +{ + ml->max_entries = (max_entries < 10 ? 10 + : max_entries > 1000 * 1000 ? 1000 * 1000 + : max_entries); +} + static bool is_learning_vlan(const struct mac_learning *ml, uint16_t vlan) { @@ -212,7 +224,7 @@ mac_learning_insert(struct mac_learning *ml, if (!e) { uint32_t hash = mac_table_hash(ml, src_mac, vlan); - if (hmap_count(&ml->table) >= MAC_MAX) { + if (hmap_count(&ml->table) >= ml->max_entries) { get_lru(ml, &e); mac_learning_expire(ml, e); } @@ -311,7 +323,9 @@ void mac_learning_run(struct mac_learning *ml, struct tag_set *set) { struct mac_entry *e; - while (get_lru(ml, &e) && time_now() >= e->expires) { + while (get_lru(ml, &e) + && (hmap_count(&ml->table) > ml->max_entries + || time_now() >= e->expires)) { COVERAGE_INC(mac_learning_expired); if (set) { tag_set_add(set, e->tag); @@ -323,7 +337,9 @@ mac_learning_run(struct mac_learning *ml, struct tag_set *set) void mac_learning_wait(struct mac_learning *ml) { - if (!list_is_empty(&ml->lrus)) { + if (hmap_count(&ml->table) > ml->max_entries) { + poll_immediate_wake(); + } else if (!list_is_empty(&ml->lrus)) { struct mac_entry *e = mac_entry_from_lru_node(ml->lrus.next); poll_timer_wait_until(e->expires * 1000LL); } diff --git a/lib/mac-learning.h b/lib/mac-learning.h index 8f8fd4587..284e7f636 100644 --- a/lib/mac-learning.h +++ b/lib/mac-learning.h @@ -26,7 +26,8 @@ struct mac_learning; -#define MAC_MAX 2048 +/* Default maximum size of a MAC learning table, in entries. */ +#define MAC_DEFAULT_MAX 2048 /* Time, in seconds, before expiring a mac_entry due to inactivity. */ #define MAC_ENTRY_DEFAULT_IDLE_TIME 300 @@ -83,6 +84,7 @@ struct mac_learning { 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. */ + size_t max_entries; /* Max number of learned MACs. */ }; /* Basics. */ @@ -96,6 +98,7 @@ void mac_learning_wait(struct mac_learning *); 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); +void mac_learning_set_max_entries(struct mac_learning *, size_t max_entries); /* Learning. */ bool mac_learning_may_learn(const struct mac_learning *, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d32f6d163..ca0a06511 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -2762,10 +2762,12 @@ forward_bpdu_changed(struct ofproto *ofproto_) } static void -set_mac_idle_time(struct ofproto *ofproto_, unsigned int idle_time) +set_mac_table_config(struct ofproto *ofproto_, unsigned int idle_time, + size_t max_entries) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); mac_learning_set_idle_time(ofproto->ml, idle_time); + mac_learning_set_max_entries(ofproto->ml, max_entries); } /* Ports. */ @@ -7940,6 +7942,6 @@ const struct ofproto_class ofproto_dpif_class = { set_flood_vlans, is_mirror_output_bundle, forward_bpdu_changed, - set_mac_idle_time, + set_mac_table_config, set_realdev, }; diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 8f6f6b1a8..bc0105fc1 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1279,9 +1279,14 @@ 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); + /* Sets the MAC aging timeout for the OFPP_NORMAL action to 'idle_time', in + * seconds, and the maximum number of MAC table entries to + * 'max_entries'. + * + * An implementation that doesn't support configuring these features may + * set this function to NULL or implement it as a no-op. */ + void (*set_mac_table_config)(struct ofproto *ofproto, + unsigned int idle_time, size_t max_entries); /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) * diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 1130eb748..504b422b2 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -585,12 +585,15 @@ 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. */ + * 'idle_time', in seconds, and the maximum number of MAC table entries to + * 'max_entries'. */ void -ofproto_set_mac_idle_time(struct ofproto *ofproto, unsigned idle_time) +ofproto_set_mac_table_config(struct ofproto *ofproto, unsigned idle_time, + size_t max_entries) { - if (ofproto->ofproto_class->set_mac_idle_time) { - ofproto->ofproto_class->set_mac_idle_time(ofproto, idle_time); + if (ofproto->ofproto_class->set_mac_table_config) { + ofproto->ofproto_class->set_mac_table_config(ofproto, idle_time, + max_entries); } } diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index e4abe523d..dc5d9ce96 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -229,7 +229,8 @@ 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_mac_table_config(struct ofproto *, unsigned idle_time, + size_t max_entries); 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/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 6693f1baf..6a4dc2331 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -930,6 +930,68 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br1 | sed 's/[[0-9]]\{1,\}$/?/'], [0], [d OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - MAC table overflow]) +OVS_VSWITCHD_START( + [set bridge br0 fail-mode=standalone other-config:mac-table-size=10 -- \ + add-port br0 p1 -- set Interface p1 type=dummy -- \ + add-port br0 p2 -- set Interface p2 type=dummy -- \ + add-port br0 p3 -- set Interface p3 type=dummy]) + +arp='eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' + +AT_CHECK([ovs-appctl time/stop]) + +# Trace 10 ARP packets arriving on p3, to create MAC learning entries. +for i in 0 1 2 3 4 5 6 7 8 9; do + OFPROTO_TRACE( + [br0], + [in_port(3),eth(src=50:54:00:00:00:0$i,dst=ff:ff:ff:ff:ff:ff),$arp], + [-generate], + [1,2,100]) + ovs-appctl time/warp 1000 +done + +# Check for the MAC learning entries. +AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/ *[[0-9]]\{1,\}$//' | sort], + [0], [dnl + 3 0 50:54:00:00:00:00 + 3 0 50:54:00:00:00:01 + 3 0 50:54:00:00:00:02 + 3 0 50:54:00:00:00:03 + 3 0 50:54:00:00:00:04 + 3 0 50:54:00:00:00:05 + 3 0 50:54:00:00:00:06 + 3 0 50:54:00:00:00:07 + 3 0 50:54:00:00:00:08 + 3 0 50:54:00:00:00:09 + port VLAN MAC Age +]) + +# Trace another ARP packet on another MAC. +OFPROTO_TRACE( + [br0], + [in_port(3),eth(src=50:54:00:00:00:10,dst=ff:ff:ff:ff:ff:ff),$arp], + [-generate], + [1,2,100]) + +# Check that the new one chased the oldest one out of the table. +AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/[[0-9]]\{1,\}$/?/' | sort], + [0], [dnl + 3 0 50:54:00:00:00:01 ? + 3 0 50:54:00:00:00:02 ? + 3 0 50:54:00:00:00:03 ? + 3 0 50:54:00:00:00:04 ? + 3 0 50:54:00:00:00:05 ? + 3 0 50:54:00:00:00:06 ? + 3 0 50:54:00:00:00:07 ? + 3 0 50:54:00:00:00:08 ? + 3 0 50:54:00:00:00:09 ? + 3 0 50:54:00:00:00:10 ? + port VLAN MAC Age +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + dnl Test that basic NetFlow reports flow statistics correctly: dnl - The initial packet of a flow are correctly accounted. dnl - Later packets within a flow are correctly accounted. diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index b1d2feb05..53dd2f659 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -182,7 +182,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_mac_table(struct bridge *); static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number); static void bridge_configure_stp(struct bridge *); static void bridge_configure_tables(struct bridge *); @@ -591,7 +591,7 @@ bridge_reconfigure_continue(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_mac_table(br); bridge_configure_remotes(br, managers, n_managers); bridge_configure_netflow(br); bridge_configure_sflow(br, &sflow_bridge_number); @@ -1493,18 +1493,27 @@ bridge_configure_forward_bpdu(struct bridge *br) false)); } -/* Set MAC aging time for 'br'. */ +/* Set MAC learning table configuration for 'br'. */ static void -bridge_configure_mac_idle_time(struct bridge *br) +bridge_configure_mac_table(struct bridge *br) { const char *idle_time_str; int idle_time; + const char *mac_table_size_str; + int mac_table_size; + idle_time_str = smap_get(&br->cfg->other_config, "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); + + mac_table_size_str = smap_get(&br->cfg->other_config, "mac-table-size"); + mac_table_size = (mac_table_size_str && atoi(mac_table_size_str) + ? atoi(mac_table_size_str) + : MAC_DEFAULT_MAX); + + ofproto_set_mac_table_config(br->ofproto, idle_time, mac_table_size); } static void diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 31c15b41e..c78899f7e 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -623,6 +623,15 @@ transmit packets. </p> </column> + + <column name="other_config" key="mac-table-size" + type='{"type": "integer", "minInteger": 1}'> + <p> + The maximum number of MAC addresses to learn. The default is + currently 2048. The value, if specified, is forced into a reasonable + range, currently 10 to 1,000,000. + </p> + </column> </group> <group title="Bridge Status"> |