From f3b646aafb26b470b931621cc68eaf56a611ce2e Mon Sep 17 00:00:00 2001
From: Vishnu Emmadi <vishnu.emmadi@bigswitch.com>
Date: Sun, 23 Jun 2013 21:32:51 -0700
Subject: [PATCH] flow reconciliation events

---
 .../debugevent/Event.java                     | 15 ++++--
 .../flowcache/FRQueryBvsAcl.java              | 15 ++++++
 .../flowcache/FRQueryBvsMatchMac.java         | 13 +++++
 .../flowcache/FRQueryBvsMatchSubnet.java      | 11 ++++
 .../flowcache/FRQueryBvsMatchSwitchPort.java  | 15 ++++++
 .../flowcache/FRQueryBvsMatchTag.java         | 11 ++++
 .../flowcache/FRQueryBvsMatchVlan.java        | 11 ++++
 .../flowcache/FRQueryBvsPriority.java         | 13 +++++
 .../FRQueryDevicePropertyChanged.java         | 12 +++++
 .../flowcache/FRQueryVRSArpChange.java        | 11 ++++
 .../flowcache/FRQueryVRSRuleChange.java       | 10 ++++
 .../flowcache/FlowReconcileManager.java       | 10 ++++
 .../flowcache/FlowReconcileQuery.java         | 53 ++++++++++++++++++-
 .../FlowReconcileQueryDeviceMove.java         | 14 +++++
 .../flowcache/FlowReconcileQueryPortDown.java | 15 ++++++
 .../flowcache/OFMatchReconcile.java           |  7 ++-
 .../flowcache/PendingSwitchResp.java          | 45 ----------------
 .../openflow/protocol/OFMatchWithSwDpid.java  |  3 +-
 18 files changed, 231 insertions(+), 53 deletions(-)
 delete mode 100644 src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java

diff --git a/src/main/java/net/floodlightcontroller/debugevent/Event.java b/src/main/java/net/floodlightcontroller/debugevent/Event.java
index 9da23f170..84f450c8f 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/Event.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/Event.java
@@ -20,7 +20,6 @@ public class Event {
     Object eventData;
     private String returnString;
     private Map<String, String> returnMap;
-
     public Event(long timestamp, long threadId, Object eventData) {
         super();
         this.timestamp = timestamp;
@@ -210,12 +209,18 @@ public class Event {
                     case SREF_OBJECT:
                         @SuppressWarnings("unchecked")
                         SoftReference<Object> srefObj = (SoftReference<Object>)obj;
-                        Object o = srefObj.get();
-                        if (o != null) {
-                            retMap.put(ec.name(), o.toString());
+                        if (srefObj == null) {
+                            retMap.put(ec.name(), "--");
                         } else {
-                            retMap.put(ec.name(), "-- reference not available --");
+                            Object o = srefObj.get();
+                            if (o != null) {
+                                retMap.put(ec.name(), o.toString());
+                            } else {
+                                retMap.put(ec.name(),
+                                           "-- reference not available --");
+                            }
                         }
+                        break;
                     case STRING:
                     case OBJECT:
                     case PRIMITIVE:
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java
index af084f747..47db538a3 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java
@@ -67,4 +67,19 @@ public class FRQueryBvsAcl extends FlowReconcileQuery {
         if (! direction.equals(other.direction)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("BVS Name: ");
+        builder.append(bvsName);
+        builder.append(", BVS Interface Name: ");
+        builder.append(bvsInterfaceName);
+        builder.append(", ACL Direction: ");
+        builder.append(direction);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
index 2fd116e04..261a98004 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
@@ -16,6 +16,8 @@
 
 package net.floodlightcontroller.flowcache;
 
+import net.floodlightcontroller.util.MACAddress;
+
 /**
  * The Class for FlowReconcileQuery for link down event.
  */
@@ -55,4 +57,15 @@ public class FRQueryBvsMatchMac extends FlowReconcileQuery {
         if (! mac.equals(other.mac)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("MAC: ");
+        builder.append(MACAddress.valueOf(mac).toString());
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java
index 53a204223..6e2a100fc 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java
@@ -55,4 +55,15 @@ public class FRQueryBvsMatchSubnet extends FlowReconcileQuery {
         if (! ipSubnet.equals(other.ipSubnet)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("IP Subnet: ");
+        builder.append(ipSubnet);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
index 80e4e4075..dad5ae464 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
@@ -17,6 +17,8 @@
 package net.floodlightcontroller.flowcache;
 
 import java.util.List;
+
+import org.openflow.util.HexString;
 /**
  * The Class for FlowReconcileQuery for BVS config interface match switch port.
  */
@@ -60,4 +62,17 @@ public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
         if (! matchPortList.equals(other.matchPortList)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Switch: ");
+        builder.append(HexString.toHexString(swId));
+        builder.append(", Match Port List:");
+        builder.append(matchPortList);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java
index 330754f52..3d7f4ca20 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java
@@ -56,4 +56,15 @@ public class FRQueryBvsMatchTag extends FlowReconcileQuery {
         if (! tag.equals(other.tag)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Tags: ");
+        builder.append(tag);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java
index 039337b7c..fd1fc6c34 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java
@@ -57,4 +57,15 @@ public class FRQueryBvsMatchVlan extends FlowReconcileQuery {
         if (! vlans.equals(other.vlans)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Vlans: ");
+        builder.append(vlans);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java
index 6843c5dba..8752edcd7 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java
@@ -59,4 +59,17 @@ public class FRQueryBvsPriority extends FlowReconcileQuery {
         if (highP != other.highP) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Lower Priority: ");
+        builder.append(lowP);
+        builder.append("Higher Priority: ");
+        builder.append(highP);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
index 4b8bbb5ec..cc10326c5 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
@@ -17,6 +17,7 @@
 package net.floodlightcontroller.flowcache;
 
 import net.floodlightcontroller.devicemanager.IDevice;
+import net.floodlightcontroller.util.MACAddress;
 
 /**
  * The Class for FlowReconcileQuery for device property changed event.
@@ -55,4 +56,15 @@ public class FRQueryDevicePropertyChanged extends FlowReconcileQuery {
         if (! device.equals(other.device)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Device: ");
+        builder.append(MACAddress.valueOf(device.getMACAddress()));
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java
index 7a7a8eb19..2397b7bdc 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java
@@ -53,4 +53,15 @@ public class FRQueryVRSArpChange extends FlowReconcileQuery {
         if (! tenant.equals(other.tenant)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Tenant: ");
+        builder.append(tenant);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java
index 39d163b4c..21d87f7c9 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java
@@ -56,4 +56,14 @@ public class FRQueryVRSRuleChange extends FlowReconcileQuery {
         if (! bvsNames.equals(other.bvsNames)) return false;
         return true;
     }
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("BVS Names: ");
+        builder.append(bvsNames);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
index 0d7848c38..4ae2caed6 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
@@ -41,6 +41,7 @@ import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.NullDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
 import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.flowcache.FlowReconcileQuery.FlowReconcileQueryDebugEvent;
 import net.floodlightcontroller.flowcache.IFlowReconcileListener;
 import net.floodlightcontroller.flowcache.OFMatchReconcile;
 import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
@@ -328,6 +329,15 @@ public class FlowReconcileManager
                     break;
                 }
             }
+            for (OFMatchReconcile ofmRc : ofmRcList) {
+                if (ofmRc.origReconcileQueryEvent != null) {
+                    ofmRc.origReconcileQueryEvent.evType.getDebugEvent()
+                        .updateEventWithFlush(new FlowReconcileQueryDebugEvent(
+                            ofmRc.origReconcileQueryEvent,
+                            "Flow Reconciliation Complete",
+                            ofmRc));
+                }
+            }
             // Flush the flowCache counters.
             updateFlush();
             flowReconcileThreadRunCount.incrementAndGet();
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
index 62884731e..07af1a4e9 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
@@ -16,6 +16,14 @@
 
 package net.floodlightcontroller.flowcache;
 
+import java.lang.ref.SoftReference;
+
+import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
+import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+import net.floodlightcontroller.debugevent.IDebugEventService;
+import net.floodlightcontroller.debugevent.IEventUpdater;
 import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
 
 /**
@@ -24,6 +32,29 @@ import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
 public class FlowReconcileQuery {
     public ReconcileQueryEvType evType;
     public EventPriority evPriority;
+    public static class FlowReconcileQueryDebugEvent {
+        @EventColumn(name = "Event Info",
+                     description = EventFieldType.SREF_OBJECT)
+        private final SoftReference<FlowReconcileQuery> eventInfo;
+        @EventColumn(name = "Stage",
+                     description = EventFieldType.STRING)
+        private final String stage;
+        @EventColumn(name = "Stage Info",
+                     description = EventFieldType.SREF_OBJECT)
+        private final SoftReference<Object> stageInfo;
+        public FlowReconcileQueryDebugEvent(FlowReconcileQuery eventInfo,
+                                            String stage,
+                                            Object stageInfo) {
+            super();
+            this.eventInfo = new SoftReference<FlowReconcileQuery>(eventInfo);
+            this.stage = stage;
+            if (stageInfo != null) {
+                this.stageInfo = new SoftReference<Object>(stageInfo);
+            } else {
+                this.stageInfo = null;
+            }
+        }
+    }
     public static enum ReconcileQueryEvType {
         /* Interface rule of a bvs was modified */
         BVS_INTERFACE_RULE_CHANGED(EventPriority.LOW),
@@ -48,12 +79,32 @@ public class FlowReconcileQuery {
         LINK_DOWN(EventPriority.MEDIUM);
 
         private EventPriority priority;
+        private IEventUpdater<FlowReconcileQueryDebugEvent>
+                evReconcileQueryDebugEvent;
+
         private ReconcileQueryEvType(EventPriority priority) {
             this.priority = priority;
         }
         public EventPriority getPriority() {
              return this.priority;
-       }
+        }
+        public void registerDebugEvent(String packageName,
+                                       IDebugEventService debugEvents)
+                                       throws MaxEventsRegistered {
+            try {
+                evReconcileQueryDebugEvent =
+                        debugEvents.registerEvent(packageName, this.toString(),
+                                                  this.toString(),
+                                                  EventType.ALWAYS_LOG,
+                                                  FlowReconcileQueryDebugEvent.class,
+                                                  100);
+            } catch (MaxEventsRegistered e) {
+                throw e;
+            }
+        }
+        public IEventUpdater<FlowReconcileQueryDebugEvent> getDebugEvent() {
+            return evReconcileQueryDebugEvent;
+        }
     }
     public FlowReconcileQuery(ReconcileQueryEvType evType) {
         this.evType = evType;
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
index 6e5460877..62d34ae61 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
@@ -20,6 +20,7 @@ import java.util.Arrays;
 
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.floodlightcontroller.util.MACAddress;
 
 /**
  * The Class for FlowReconcileQuery for device move event.
@@ -67,4 +68,17 @@ public class FlowReconcileQueryDeviceMove extends FlowReconcileQuery {
         } else if (!deviceMoved.equals(other.deviceMoved)) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Device: ");
+        builder.append(MACAddress.valueOf(deviceMoved.getMACAddress()).toString());
+        builder.append(", Old Attachment Points:");
+        builder.append(Arrays.toString(oldAp));
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
index 4210a6eb2..7973a1197 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
@@ -16,6 +16,8 @@
 
 package net.floodlightcontroller.flowcache;
 
+import org.openflow.util.HexString;
+
 /**
  * The Class for FlowReconcileQuery for link down event.
  */
@@ -60,4 +62,17 @@ public class FlowReconcileQueryPortDown extends FlowReconcileQuery {
         if (port != other.port) return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(evType.toString());
+        builder.append("[");
+        builder.append("Switch: ");
+        builder.append(HexString.toHexString(swId));
+        builder.append(", Port: ");
+        builder.append(port);
+        builder.append("]");
+        return builder.toString();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
index c4777294c..70b4d42a3 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
@@ -70,7 +70,11 @@ public class OFMatchReconcile  {
 
     // The context for the reconcile action
     public FloodlightContext cntx;
-    
+
+    // The original flow reconcile query event that triggered this flow
+    // to be reconciled
+    public FlowReconcileQuery origReconcileQueryEvent;
+
     /**
      * Instantiates a new oF match reconcile object.
      */
@@ -92,6 +96,7 @@ public class OFMatchReconcile  {
         rcAction = copy.rcAction;
         outPort = copy.outPort;
         cntx = new FloodlightContext();
+        origReconcileQueryEvent = copy.origReconcileQueryEvent;
     }
     
     @Override
diff --git a/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java b/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java
deleted file mode 100644
index 8a59ddd37..000000000
--- a/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- *    Copyright 2013, Big Switch Networks, Inc.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
-
-package net.floodlightcontroller.flowcache;
-
-import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
-
-/**
- * The Class PendingSwitchResp. This object is used to track the pending
- * responses to switch flow table queries.
- */
-public class PendingSwitchResp {
-    protected boolean requeryType;
-    protected EventPriority priority;
-
-    public PendingSwitchResp(
-            boolean requeryType, EventPriority priority) {
-        this.requeryType = requeryType;
-        this.priority = priority;
-    }
-    
-    public boolean getRequeryType() {
-        return requeryType;
-    }
-
-    public void setRequeryType(boolean requeryType) {
-        this.requeryType = requeryType;
-    }
-    public EventPriority getEventPriority() {
-        return priority;
-    }
-}
diff --git a/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java b/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
index 3fe094717..04ecf5e5e 100644
--- a/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
+++ b/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
@@ -50,7 +50,8 @@ public class OFMatchWithSwDpid {
 
     @Override
     public String toString() {
-        return "OFMatchWithSwDpid [" + HexString.toHexString(switchDataPathId) + ofMatch + "]";
+        return "OFMatchWithSwDpid [" + HexString.toHexString(switchDataPathId)
+                + " " + ofMatch + "]";
     }
 
     @Override
-- 
GitLab