For SNAT, don't store the pre-fragment L2 header before actions are applied.
[sliver-openvswitch.git] / lib / mac-learning.c
index 5311ccf..b924e49 100644 (file)
@@ -31,6 +31,7 @@
  * derivatives without specific, written prior permission.
  */
 
+#include <config.h>
 #include "mac-learning.h"
 
 #include <assert.h>
@@ -39,7 +40,8 @@
 
 #include "hash.h"
 #include "list.h"
-#include "openflow.h"
+#include "openflow/openflow.h"
+#include "timeval.h"
 #include "util.h"
 
 #define THIS_MODULE VLM_mac_learning
@@ -55,8 +57,9 @@
 struct mac_entry {
     struct list hash_node;      /* Element in a mac_learning 'table' list. */
     struct list lru_node;       /* Element in mac_learning 'lrus' list. */
+    time_t used;                /* Last used time. */
     uint8_t mac[ETH_ADDR_LEN];  /* Known MAC address. */
-    uint16_t port;              /* Port on which MAC was most recently seen. */
+    int port;                   /* Port on which MAC was most recently seen. */
 };
 
 /* MAC learning table. */
@@ -125,38 +128,36 @@ mac_learning_learn(struct mac_learning *ml,
     struct mac_entry *e;
     struct list *bucket;
 
-    assert(src_port != OFPP_FLOOD);
     if (eth_addr_is_multicast(src_mac)) {
-        VLOG_DBG("multicast packet source "ETH_ADDR_FMT,
-                 ETH_ADDR_ARGS(src_mac));
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 30);
+        VLOG_DBG_RL(&rl, "multicast packet source "ETH_ADDR_FMT,
+                    ETH_ADDR_ARGS(src_mac));
         return false;
     }
 
     bucket = mac_table_bucket(ml, src_mac);
     e = search_bucket(bucket, src_mac);
-    if (e) {
-        /* Make 'e' most-recently-used.  */
-        list_remove(&e->lru_node);
-        list_push_back(&ml->lrus, &e->lru_node);
-        if (e->port == src_port) {
-            return false;
-        }
-    } else {
-        /* Learn a new address.
-         * First drop the least recently used mac source. */
+    if (!e) {
         e = CONTAINER_OF(ml->lrus.next, struct mac_entry, lru_node);
+        memcpy(e->mac, src_mac, ETH_ADDR_LEN);
         if (e->hash_node.next) {
             list_remove(&e->hash_node);
         }
-        list_remove(&e->lru_node);
-
-        /* Create new mac source. */
-        memcpy(e->mac, src_mac, ETH_ADDR_LEN);
         list_push_front(bucket, &e->hash_node);
-        list_push_back(&ml->lrus, &e->lru_node);
+        e->port = -1;
+    }
+
+    /* Make the entry most-recently-used. */
+    list_remove(&e->lru_node);
+    list_push_back(&ml->lrus, &e->lru_node);
+    e->used = time_now();
+
+    /* Did we learn something? */
+    if (e->port != src_port) {
+        e->port = src_port;
+        return true;
     }
-    e->port = src_port;
-    return true;
+    return false;
 }
 
 /* Looks up address 'dst' in 'ml'.  Returns the port on which a frame destined
@@ -167,7 +168,7 @@ mac_learning_lookup(const struct mac_learning *ml,
 {
     if (!eth_addr_is_multicast(dst)) {
         struct mac_entry *e = search_bucket(mac_table_bucket(ml, dst), dst);
-        if (e) {
+        if (e && time_now() - e->used < 60) {
             return e->port;
         }
     }