secchan: Tolerate local port change in MAC address.
authorBen Pfaff <blp@nicira.com>
Tue, 17 Mar 2009 20:50:13 +0000 (13:50 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 17 Mar 2009 20:50:13 +0000 (13:50 -0700)
Before, if the local port's MAC address changed, we would not notice, and
continue to set up flows only for the local port's current MAC address,
which completely broke in-band control.

Now, we notice changes and start to set up flows for the new MAC address
instead.

Fixes bug #1081.

secchan/in-band.c

index 4d1635c56fb5ba99c56b36e2c833dadef7216d26..0379e7483ed0155d907fcd957813ebea7df6cab5 100644 (file)
@@ -68,6 +68,10 @@ struct in_band {
     uint8_t mac[ETH_ADDR_LEN];  /* Current MAC, 0 if unknown. */
     uint8_t last_mac[ETH_ADDR_LEN]; /* Last known MAC, 0 if never known */
     time_t next_refresh;        /* Next time to refresh MAC address. */
+
+    /* Keeping track of the local port's MAC address. */
+    uint8_t local_mac[ETH_ADDR_LEN]; /* Current MAC. */
+    time_t next_local_refresh;  /* Next time to refresh MAC address. */
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
@@ -127,6 +131,27 @@ is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN],
     return mac && eth_addr_equals(mac, dl_addr);
 }
 
+static const uint8_t *
+get_local_mac(struct in_band *ib)
+{
+    time_t now = time_now();
+    if (now >= ib->next_local_refresh) {
+        uint8_t ea[ETH_ADDR_LEN];
+        if (!netdev_nodev_get_etheraddr(netdev_get_name(ib->netdev), ea)) {
+            memcpy(ib->local_mac, ea, ETH_ADDR_LEN);
+        }
+        ib->next_local_refresh = now + 1;
+    }
+    return !eth_addr_is_zero(ib->local_mac) ? ib->local_mac : NULL;
+}
+
+static bool
+is_local_mac(const uint8_t dl_addr[ETH_ADDR_LEN], struct in_band *ib)
+{
+    const uint8_t *local_mac = get_local_mac(ib);
+    return local_mac && eth_addr_equals(dl_addr, local_mac);
+}
+
 static void
 in_band_learn_mac(struct in_band *in_band,
                   uint16_t in_port, const uint8_t src_mac[ETH_ADDR_LEN])
@@ -151,8 +176,7 @@ in_band_handle_flow_miss(struct in_band *in_band, struct ofproto *ofproto,
     if (flow->in_port == ODPP_LOCAL) {
         /* Sent by secure channel. */
         out_port = mac_learning_lookup(in_band->mac_learning, flow->dl_dst, 0);
-    } else if (eth_addr_equals(flow->dl_dst,
-                               netdev_get_etheraddr(in_band->netdev))) {
+    } else if (is_local_mac(flow->dl_dst, in_band)) {
         /* Sent to secure channel. */
         out_port = ODPP_LOCAL;
         in_band_learn_mac(in_band, flow->in_port, flow->dl_src);
@@ -214,15 +238,18 @@ in_band_status_cb(struct status_reply *sr, void *in_band_)
 {
     struct in_band *in_band = in_band_;
     struct in_addr local_ip;
+    const uint8_t *local_mac;
     uint32_t controller_ip;
     const uint8_t *controller_mac;
-    const uint8_t *mac;
 
-    mac = netdev_get_etheraddr(in_band->netdev);
     if (netdev_get_in4(in_band->netdev, &local_ip)) {
         status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip.s_addr));
     }
-    status_reply_put(sr, "local-mac="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+    local_mac = get_local_mac(in_band);
+    if (local_mac) {
+        status_reply_put(sr, "local-mac="ETH_ADDR_FMT,
+                         ETH_ADDR_ARGS(local_mac));
+    }
 
     controller_ip = rconn_get_ip(in_band->controller);
     if (controller_ip) {
@@ -277,6 +304,7 @@ in_band_create(struct dpif *dpif, struct switch_status *ss,
     in_band->ss_cat = switch_status_register(ss, "in-band",
                                              in_band_status_cb, in_band);
     in_band->next_refresh = TIME_MIN;
+    in_band->next_local_refresh = TIME_MIN;
 
     *in_bandp = in_band;
     return 0;