Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Conflicts:
	providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/drivers/impl/OFSwitchImplOVS13.java b/of/ctl/src/main/java/org/onlab/onos/of/drivers/impl/OFSwitchImplOVS13.java
index bb6bb23..3e1b713 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/drivers/impl/OFSwitchImplOVS13.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/drivers/impl/OFSwitchImplOVS13.java
@@ -1,5 +1,7 @@
 package org.onlab.onos.of.drivers.impl;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -11,7 +13,14 @@
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 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;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,6 +38,9 @@
     private OFFactory factory;
     private long barrierXidToWaitFor = -1;
 
+    private static final short MIN_PRIORITY = 0x0;
+    private static final int OFPCML_NO_BUFFER = 0xffff;
+
     public OFSwitchImplOVS13(Dpid dpid, OFDescStatsReply desc) {
         super(dpid);
         driverHandshakeComplete = new AtomicBoolean(false);
@@ -112,6 +124,7 @@
 
 
     private void configureSwitch() {
+        populateTableMissEntry(0, true, false, false, 0);
         sendBarrier(true);
     }
 
@@ -135,7 +148,7 @@
 
     @Override
     public void write(OFMessage msg) {
-        channel.write(msg);
+        channel.write(Collections.singletonList(msg));
 
     }
 
@@ -143,4 +156,78 @@
     public void write(List<OFMessage> msgs) {
         channel.write(msgs);
     }
+
+    /**
+     * 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
+     * @param toControllerNow as an APPLY_ACTION instruction
+     * @param toControllerWrite as a WRITE_ACITION instruction
+     * @param toTable as a GOTO_TABLE instruction
+     * @param tableToSend
+     */
+    @SuppressWarnings("unchecked")
+    private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
+            boolean toControllerWrite,
+            boolean toTable, int tableToSend) {
+        OFOxmList oxmList = OFOxmList.EMPTY;
+        OFMatchV3 match = factory.buildMatchV3()
+                .setOxmList(oxmList)
+                .build();
+        OFAction outc = factory.actions()
+                .buildOutput()
+                .setPort(OFPort.CONTROLLER)
+                .setMaxLen(OFPCML_NO_BUFFER)
+                .build();
+        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+        if (toControllerNow) {
+            // table-miss instruction to send to controller immediately
+            OFInstruction instr = factory.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 = factory.instructions()
+                    .buildWriteActions()
+                    .setActions(Collections.singletonList(outc))
+                    .build();
+            instructions.add(instr);
+        }
+
+        if (toTable) {
+            // table-miss instruction to goto-table x
+            OFInstruction instr = factory.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 = Collections.EMPTY_LIST;
+        }
+
+        OFMessage tableMissEntry = factory.buildFlowAdd()
+                .setTableId(TableId.of(tableToAdd))
+                .setMatch(match) // match everything
+                .setInstructions(instructions)
+                .setPriority(MIN_PRIORITY)
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                .setXid(getNextTransactionId())
+                .build();
+        sendMsg(tableMissEntry);
+    }
+
 }
diff --git a/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index 5dbcd80..61b1c18 100644
--- a/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -14,6 +14,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.onos.net.Device;
+import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.device.DefaultDeviceDescription;
@@ -66,14 +67,22 @@
     public void activate() {
         providerService = providerRegistry.register(this);
         controller.addListener(listener);
+        for (OpenFlowSwitch sw : controller.getSwitches()) {
+            listener.switchAdded(new Dpid(sw.getId()));
+        }
         LOG.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        for (OpenFlowSwitch sw : controller.getSwitches()) {
+            providerService.deviceDisconnected(DeviceId.deviceId("of:"
+                    + Long.toHexString(sw.getId())));
+        }
         providerRegistry.unregister(this);
         controller.removeListener(listener);
         providerService = null;
+
         LOG.info("Stopped");
     }
 
diff --git a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
index 407ded1..da89681 100644
--- a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
+++ b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
@@ -86,6 +86,7 @@
     private final OpenFlowController ctrl;
     private final LinkProviderService linkProvider;
     private final Map<Integer, OFPortDesc> ports;
+    private Timeout timeout;
 
     /**
      * Instantiates discovery manager for the given physical switch. Creates a
@@ -127,7 +128,7 @@
                 addPort(port);
             }
         }
-        Timer.getTimer().newTimeout(this, this.probeRate,
+        timeout = Timer.getTimer().newTimeout(this, this.probeRate,
                 TimeUnit.MILLISECONDS);
         this.log.debug("Started discovery manager for switch {}",
                 sw.getId());
@@ -186,6 +187,10 @@
                         portnum);
             }
         }
+        ConnectPoint cp = new ConnectPoint(
+                DeviceId.deviceId("of:" + Long.toHexString(sw.getId())),
+                PortNumber.portNumber(port.getPortNo().getPortNumber()));
+        linkProvider.linksVanished(cp);
 
     }
 
@@ -380,14 +385,19 @@
         }
 
         // reschedule timer
-        Timer.getTimer().newTimeout(this, this.probeRate,
+        timeout = Timer.getTimer().newTimeout(this, this.probeRate,
                 TimeUnit.MILLISECONDS);
     }
 
     public void removeAllPorts() {
-        for (OFPortDesc port : sw.getPorts()) {
+        for (OFPortDesc port : ports.values()) {
             removePort(port);
         }
     }
 
+    public void stop() {
+        removeAllPorts();
+        timeout.cancel();
+    }
+
 }
diff --git a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
index a2bf045..218145d 100644
--- a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
+++ b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
@@ -1,18 +1,11 @@
 package org.onlab.onos.provider.of.link.impl;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.link.LinkProvider;
 import org.onlab.onos.net.link.LinkProviderRegistry;
 import org.onlab.onos.net.link.LinkProviderService;
@@ -20,16 +13,21 @@
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.of.controller.Dpid;
 import org.onlab.onos.of.controller.OpenFlowController;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
 import org.onlab.onos.of.controller.OpenFlowSwitchListener;
 import org.onlab.onos.of.controller.PacketContext;
 import org.onlab.onos.of.controller.PacketListener;
-import org.onlab.util.Timer;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortState;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.slf4j.Logger;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Provider which uses an OpenFlow controller to detect network
  * infrastructure links.
@@ -51,6 +49,8 @@
 
     private final InternalLinkProvider listener = new InternalLinkProvider();
 
+    private final Map<Dpid, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
+
     /**
      * Creates an OpenFlow link provider.
      */
@@ -63,23 +63,28 @@
         providerService = providerRegistry.register(this);
         controller.addListener(listener);
         controller.addPacketListener(0, listener);
+        for (OpenFlowSwitch sw : controller.getSwitches()) {
+            listener.switchAdded(new Dpid(sw.getId()));
+        }
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        for (LinkDiscovery ld : discoverers.values()) {
+            ld.stop();
+        }
         providerRegistry.unregister(this);
         controller.removeListener(listener);
         controller.removePacketListener(listener);
         providerService = null;
-        Timer.getTimer().stop();
+
         log.info("Stopped");
     }
 
 
     private class InternalLinkProvider implements PacketListener, OpenFlowSwitchListener {
 
-        private final Map<Dpid, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
 
         @Override
         public void handlePacket(PacketContext pktCtx) {
@@ -96,13 +101,13 @@
         @Override
         public void switchAdded(Dpid dpid) {
             discoverers.put(dpid, new LinkDiscovery(controller.getSwitch(dpid),
-                    controller, providerService, useBDDP));
+                                                    controller, providerService, useBDDP));
 
         }
 
         @Override
         public void switchRemoved(Dpid dpid) {
-            LinkDiscovery ld = this.discoverers.remove(dpid);
+            LinkDiscovery ld = discoverers.remove(dpid);
             if (ld != null) {
                 ld.removeAllPorts();
             }
@@ -122,10 +127,9 @@
             if (enabled) {
                 ld.addPort(port);
             } else {
-                ConnectPoint cp = new ConnectPoint(
-                        DeviceId.deviceId("of:" + Long.toHexString(dpid.value())),
-                        PortNumber.portNumber(port.getPortNo().getPortNumber()));
-                providerService.linksVanished(cp);
+                /*
+                 * remove port calls linkVanished
+                 */
                 ld.removePort(port);
             }
 
diff --git a/utils/misc/src/main/java/org/onlab/packet/ONLabLddp.java b/utils/misc/src/main/java/org/onlab/packet/ONLabLddp.java
index a58387b..ea24422 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ONLabLddp.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ONLabLddp.java
@@ -32,7 +32,7 @@
  */
 public class ONLabLddp extends LLDP {
 
-    private static final Logger log = LoggerFactory.getLogger(ONLabLddp.class);
+    private static final Logger LOG = LoggerFactory.getLogger(ONLabLddp.class);
     // ON.Lab OUI and OVX name for organizationally specific TLVs
     public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05};
     public static final String OVX_NAME = "OpenVirteX";