mac-learning: Simplify memory management.
authorEthan Jackson <ethan@nicira.com>
Fri, 22 Jul 2011 19:00:46 +0000 (12:00 -0700)
committerEthan Jackson <ethan@nicira.com>
Sat, 23 Jul 2011 02:04:14 +0000 (19:04 -0700)
The mac-learning implementation used a free list to keep track of
statically allocated table entries.  This made the code slightly
more difficult to understand than the more straightforward heap
based strategy implemented by this patch.

lib/mac-learning.c
lib/mac-learning.h

index 5e05885e7a707401125a21333663ccd84eb453a8..bb84cfcc0b1ecba84db378c96041ea97ce3d84e0 100644 (file)
@@ -103,16 +103,10 @@ struct mac_learning *
 mac_learning_create(void)
 {
     struct mac_learning *ml;
-    int i;
 
     ml = xmalloc(sizeof *ml);
     list_init(&ml->lrus);
-    list_init(&ml->free);
     hmap_init(&ml->table);
-    for (i = 0; i < MAC_MAX; i++) {
-        struct mac_entry *s = &ml->entries[i];
-        list_push_front(&ml->free, &s->lru_node);
-    }
     ml->secret = random_uint32();
     ml->flood_vlans = NULL;
     return ml;
@@ -123,7 +117,14 @@ void
 mac_learning_destroy(struct mac_learning *ml)
 {
     if (ml) {
+        struct mac_entry *e, *next;
+
+        HMAP_FOR_EACH_SAFE (e, next, hmap_node, &ml->table) {
+            hmap_remove(&ml->table, &e->hmap_node);
+            free(e);
+        }
         hmap_destroy(&ml->table);
+
         bitmap_free(ml->flood_vlans);
         free(ml);
     }
@@ -181,22 +182,22 @@ mac_learning_insert(struct mac_learning *ml,
     if (!e) {
         uint32_t hash = mac_table_hash(ml, src_mac, vlan);
 
-        if (!list_is_empty(&ml->free)) {
-            e = mac_entry_from_lru_node(ml->free.next);
-        } else {
-            e = mac_entry_from_lru_node(ml->lrus.next);
-            hmap_remove(&ml->table, &e->hmap_node);
+        if (hmap_count(&ml->table) >= MAC_MAX) {
+            get_lru(ml, &e);
+            mac_learning_expire(ml, e);
         }
 
+        e = xmalloc(sizeof *e);
         hmap_insert(&ml->table, &e->hmap_node, hash);
         memcpy(e->mac, src_mac, ETH_ADDR_LEN);
         e->vlan = vlan;
         e->tag = 0;
         e->grat_arp_lock = TIME_MIN;
+    } else {
+        list_remove(&e->lru_node);
     }
 
     /* Mark 'e' as recently used. */
-    list_remove(&e->lru_node);
     list_push_back(&ml->lrus, &e->lru_node);
     e->expires = time_now() + MAC_ENTRY_IDLE_TIME;
 
@@ -250,14 +251,13 @@ mac_learning_lookup(const struct mac_learning *ml,
     }
 }
 
-/* Expires 'e' from the 'ml' hash table.  'e' must not already be on the free
- * list. */
+/* Expires 'e' from the 'ml' hash table. */
 void
 mac_learning_expire(struct mac_learning *ml, struct mac_entry *e)
 {
     hmap_remove(&ml->table, &e->hmap_node);
     list_remove(&e->lru_node);
-    list_push_front(&ml->free, &e->lru_node);
+    free(e);
 }
 
 /* Expires all the mac-learning entries in 'ml'.  The tags in 'ml' are
@@ -270,6 +270,7 @@ mac_learning_flush(struct mac_learning *ml)
     while (get_lru(ml, &e)){
         mac_learning_expire(ml, e);
     }
+    hmap_shrink(&ml->table);
 }
 
 void
index d2f28744fe59279f37166edbfecee3dc6e7dc3db..0263e4987deba8b7c08fc0f9a6a094bbba4756d2 100644 (file)
@@ -36,7 +36,7 @@
 /* A MAC learning table entry. */
 struct mac_entry {
     struct hmap_node hmap_node; /* Node in a mac_learning hmap. */
-    struct list lru_node;       /* Element in 'lrus' or 'free' list. */
+    struct list lru_node;       /* Element in 'lrus' list. */
     time_t expires;             /* Expiration time. */
     time_t grat_arp_lock;       /* Gratuitous ARP lock expiration time. */
     uint8_t mac[ETH_ADDR_LEN];  /* Known MAC address. */
@@ -76,10 +76,8 @@ static inline bool mac_entry_is_grat_arp_locked(const struct mac_entry *mac)
 /* MAC learning table. */
 struct mac_learning {
     struct hmap table;          /* Learning table. */
-    struct list free;           /* Not-in-use entries. */
     struct list lrus;           /* In-use entries, least recently used at the
                                    front, most recently used at the back. */
-    struct mac_entry entries[MAC_MAX]; /* All entries. */
     uint32_t secret;            /* Secret for randomizing hash table. */
     unsigned long *flood_vlans; /* Bitmap of learning disabled VLANs. */
 };