Configure OVS 1.3 to send packet-ins by default. This is in lieu of a better
switch configuration mechanism.

Change-Id: I1ef80506f7ae33044539a9ba2c1feeb3b0d86d8e
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java
index 668f84d..2248658 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java
@@ -1,6 +1,9 @@
 package net.onrc.onos.core.drivermanager;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
@@ -11,8 +14,14 @@
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
-import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMatchV3;
 import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
 
 /**
  * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
@@ -21,7 +30,6 @@
  */
 public class OFSwitchImplOVS13 extends OFSwitchImplBase {
     private AtomicBoolean driverHandshakeComplete;
-    private OFFactory factory;
     private long barrierXidToWaitFor = -1;
 
     public OFSwitchImplOVS13(OFDescStatsReply desc) {
@@ -44,7 +52,7 @@
             throw new SwitchDriverSubHandshakeAlreadyStarted();
         }
         startDriverHandshakeCalled = true;
-        factory = getFactory();
+        populateTableMissEntry(0, true, false, false, 0);
         configureSwitch();
     }
 
@@ -129,10 +137,86 @@
         if (finalBarrier) {
             barrierXidToWaitFor = xid;
         }
-        OFBarrierRequest br = factory
+        OFBarrierRequest br = getFactory()
                 .buildBarrierRequest()
                 .setXid(xid)
                 .build();
         write(br, null);
     }
+
+    /**
+     * By default if none of the booleans in the call are set, then the
+     * table-miss entry is added with no instructions, which means that pipeline
+     * execution will stop, and the action set associated with the packet will
+     * be executed.
+     *
+     * @param tableToAdd table number to add the table miss entry in
+     * @param toControllerNow as an APPLY_ACTION instruction
+     * @param toControllerWrite as a WRITE_ACITION instruction
+     * @param toTable as a GOTO_TABLE instruction
+     * @param tableToSend table number to a a GOTO_TABLE instruction to
+     * @throws IOException if there's a problem writing to the channel
+     */
+    // TODO: This is copied straight from the CPqD switch. We need to find
+    // an abstraction for this behaviour.
+    @SuppressWarnings("unchecked")
+    private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
+            boolean toControllerWrite,
+            boolean toTable, int tableToSend) throws IOException {
+        OFOxmList oxmList = OFOxmList.EMPTY;
+        OFMatchV3 match = getFactory().buildMatchV3()
+                .setOxmList(oxmList)
+                .build();
+        OFAction outc = getFactory().actions()
+                .buildOutput()
+                .setPort(OFPort.CONTROLLER)
+                .setMaxLen(0xffff)
+                .build();
+        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+        if (toControllerNow) {
+            // table-miss instruction to send to controller immediately
+            OFInstruction instr = getFactory().instructions()
+                    .buildApplyActions()
+                    .setActions(Collections.singletonList(outc))
+                    .build();
+            instructions.add(instr);
+        }
+
+        if (toControllerWrite) {
+            // table-miss instruction to write-action to send to controller
+            // this will be executed whenever the action-set gets executed
+            OFInstruction instr = getFactory().instructions()
+                    .buildWriteActions()
+                    .setActions(Collections.singletonList(outc))
+                    .build();
+            instructions.add(instr);
+        }
+
+        if (toTable) {
+            // table-miss instruction to goto-table x
+            OFInstruction instr = getFactory().instructions()
+                    .gotoTable(TableId.of(tableToSend));
+            instructions.add(instr);
+        }
+
+        if (!toControllerNow && !toControllerWrite && !toTable) {
+            // table-miss has no instruction - at which point action-set will be
+            // executed - if there is an action to output/group in the action
+            // set
+            // the packet will be sent there, otherwise it will be dropped.
+            instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
+        }
+
+        OFMessage tableMissEntry = getFactory().buildFlowAdd()
+                .setTableId(TableId.of(tableToAdd))
+                .setMatch(match) // match everything
+                .setInstructions(instructions)
+                .setPriority(0)
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+        write(tableMissEntry, null);
+    }
 }