CORD-613 Adding ability to administratively enable or disable a port via CLI.
Currently uses the OpenFlow device provider to change portState.
Also fixes a bug in PortNumberCompleter.
Adds completion options to portstats for deviceId and portNumber.

Change-Id: Idcce775fe8bc5484fdd0e630bcb5026b85125478
diff --git a/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java b/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java
index 113fe31..9e89ff0 100644
--- a/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java
@@ -22,6 +22,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DeviceDescription;
 import org.onosproject.net.device.DeviceProvider;
@@ -100,5 +101,10 @@
         public boolean isReachable(DeviceId deviceId) {
             return false;
         }
+
+        @Override
+        public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                    boolean enable) {
+        }
     }
 }
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortStateCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortStateCommand.java
new file mode 100644
index 0000000..3962266
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortStateCommand.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * 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 org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.device.DeviceService;
+
+/**
+ * Administratively enables or disabled a port on a device.
+ */
+@Command(scope = "onos", name = "portstate",
+         description = "Administratively enables or disabled a port on a device")
+public class DevicePortStateCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "uri", description = "Device ID",
+            required = true, multiValued = false)
+    String uri = null;
+
+    @Argument(index = 1, name = "portNumber", description = "Port Number",
+            required = true, multiValued = false)
+    Integer portNumber = null;
+
+    @Argument(index = 2, name = "portState", description = "Desired State",
+            required = true, multiValued = false)
+    String portState = null;
+
+    @Override
+    protected void execute() {
+        DeviceService deviceService = get(DeviceService.class);
+        DeviceAdminService deviceAdminService = get(DeviceAdminService.class);
+        Device dev = deviceService.getDevice(DeviceId.deviceId(uri));
+        if (dev == null) {
+            print(" %s", "Device does not exist");
+            return;
+        }
+        PortNumber pnum = PortNumber.portNumber(portNumber);
+        Port p = deviceService.getPort(dev.id(), pnum);
+        if (p == null) {
+            print(" %s", "Port does not exist");
+            return;
+        }
+        if (portState.equals("enable")) {
+            deviceAdminService.changePortState(dev.id(), pnum, true);
+        } else if (portState.equals("disable")) {
+            deviceAdminService.changePortState(dev.id(), pnum, false);
+        } else {
+            print(" %s", "State must be enable or disable");
+        }
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
index f9a8237..33ac366 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
@@ -50,6 +50,10 @@
             required = false, multiValued = false)
     String uri = null;
 
+    @Argument(index = 1, name = "portNumber", description = "Port Number",
+            required = false, multiValued = false)
+    Integer portNumber = null;
+
     private static final String FORMAT =
             "   port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s, pktRxDrp=%s, pktTxDrp=%s, Dur=%s";
 
@@ -94,6 +98,9 @@
     private void printPortStats(DeviceId deviceId, Iterable<PortStatistics> portStats) {
         print("deviceId=%s", deviceId);
         for (PortStatistics stat : sortByPort(portStats)) {
+            if (portNumber != null && stat.port() != portNumber) {
+                continue;
+            }
             print(FORMAT, stat.port(), stat.packetsReceived(), stat.packetsSent(), stat.bytesReceived(),
                     stat.bytesSent(), stat.packetsRxDropped(), stat.packetsTxDropped(), stat.durationSec());
         }
@@ -109,6 +116,9 @@
                 + " rateRx=%s, rateTx=%s, pktRxDrp=%s, pktTxDrp=%s, interval=%s";
         print("deviceId=%s", deviceId);
         for (PortStatistics stat : sortByPort(portStats)) {
+            if (portNumber != null && stat.port() != portNumber) {
+                continue;
+            }
             float duration = ((float) stat.durationSec()) +
                     (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
             float rateRx = stat.bytesReceived() * 8 / duration;
@@ -142,21 +152,24 @@
         print("|---------------------------------------------------------------------------------------------------|");
 
         for (PortStatistics stat : sortByPort(portStats)) {
-                float duration = ((float) stat.durationSec()) +
-                        (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
-                float rateRx = stat.bytesReceived() * 8 / duration;
-                float rateTx = stat.bytesSent() * 8 / duration;
-                print(formatDeltaTable, stat.port(),
-                        humanReadable(stat.packetsReceived()),
-                        humanReadable(stat.bytesReceived()),
-                        humanReadableBps(rateRx),
-                        humanReadable(stat.packetsRxDropped()),
-                        humanReadable(stat.packetsSent()),
-                        humanReadable(stat.bytesSent()),
-                        humanReadableBps(rateTx),
-                        humanReadable(stat.packetsTxDropped()),
-                        String.format("%.3f", duration));
+            if (portNumber != null && stat.port() != portNumber) {
+                continue;
             }
+            float duration = ((float) stat.durationSec()) +
+                    (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
+            float rateRx = stat.bytesReceived() * 8 / duration;
+            float rateTx = stat.bytesSent() * 8 / duration;
+            print(formatDeltaTable, stat.port(),
+                  humanReadable(stat.packetsReceived()),
+                  humanReadable(stat.bytesReceived()),
+                  humanReadableBps(rateRx),
+                  humanReadable(stat.packetsRxDropped()),
+                  humanReadable(stat.packetsSent()),
+                  humanReadable(stat.bytesSent()),
+                  humanReadableBps(rateTx),
+                  humanReadable(stat.packetsTxDropped()),
+                  String.format("%.3f", duration));
+        }
         print("+---------------------------------------------------------------------------------------------------+");
     }
 
diff --git a/cli/src/main/java/org/onosproject/cli/net/PortNumberCompleter.java b/cli/src/main/java/org/onosproject/cli/net/PortNumberCompleter.java
index 0a05d31..949f4f8 100644
--- a/cli/src/main/java/org/onosproject/cli/net/PortNumberCompleter.java
+++ b/cli/src/main/java/org/onosproject/cli/net/PortNumberCompleter.java
@@ -15,15 +15,16 @@
  */
 package org.onosproject.cli.net;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static org.onlab.osgi.DefaultServiceDirectory.getService;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
 import org.apache.karaf.shell.console.completer.ArgumentCompleter.ArgumentList;
 import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
 
@@ -37,13 +38,22 @@
     @Override
     protected List<String> choices() {
         ArgumentList args = getArgumentList();
-        checkArgument(args.getCursorArgumentIndex() >= 1,
-                     "Expects DeviceId as previous argument");
-
-        String deviceIdStr = args.getArguments()[args.getCursorArgumentIndex() - 1];
-        DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
-
+        //parse argument list for deviceId
         DeviceService deviceService = getService(DeviceService.class);
+        Device dev = null;
+        for (String str : args.getArguments()) {
+            if (str.contains(":")) {
+                dev = deviceService.getDevice(DeviceId.deviceId(str));
+                if (dev != null) {
+                    break;
+                }
+            }
+        }
+        if (dev == null) {
+            return Collections.singletonList("Missing device");
+        }
+        DeviceId deviceId = dev.id();
+
         return StreamSupport.stream(deviceService.getPorts(deviceId).spliterator(), false)
             .map(port -> port.number().toString())
             .collect(Collectors.toList());
diff --git a/cli/src/main/java/org/onosproject/cli/net/PortStateCompleter.java b/cli/src/main/java/org/onosproject/cli/net/PortStateCompleter.java
new file mode 100644
index 0000000..e9accbe
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/PortStateCompleter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * 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 org.onosproject.cli.net;
+
+import java.util.List;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * PortState completer.
+ *
+ * Assumes argument right before the one being completed is PortNumber.
+ */
+public class PortStateCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    protected List<String> choices() {
+        return ImmutableList.of("enable", "disable");
+    }
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index f110960..a6771eb 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -123,6 +123,15 @@
             </completers>
         </command>
         <command>
+            <action class="org.onosproject.cli.net.DevicePortStateCommand"/>
+            <completers>
+                <ref component-id="deviceIdCompleter"/>
+                <ref component-id="portNumberCompleter"/>
+                <ref component-id="portStateCompleter"/>
+                <null/>
+            </completers>
+        </command>
+        <command>
             <action class="org.onosproject.cli.net.DeviceControllersCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
@@ -433,6 +442,11 @@
 
         <command>
             <action class="org.onosproject.cli.net.DevicePortStatsCommand"/>
+            <completers>
+                <ref component-id="deviceIdCompleter"/>
+                <ref component-id="portNumberCompleter"/>
+                <null/>
+            </completers>
         </command>
 
         <command>
@@ -650,6 +664,7 @@
     <bean id="nodeIdCompleter" class="org.onosproject.cli.NodeIdCompleter"/>
     <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
     <bean id="portNumberCompleter" class="org.onosproject.cli.net.PortNumberCompleter"/>
+    <bean id="portStateCompleter" class="org.onosproject.cli.net.PortStateCompleter"/>
     <bean id="clusterIdCompleter" class="org.onosproject.cli.net.ClusterIdCompleter"/>
     <bean id="roleCompleter" class="org.onosproject.cli.net.RoleCompleter"/>
     <bean id="hostIdCompleter" class="org.onosproject.cli.net.HostIdCompleter"/>
diff --git a/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java b/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java
index 500b635..a750e06 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.device;
 
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
 
 /**
  * Service for administering the inventory of infrastructure devices.
@@ -31,4 +32,13 @@
 
     // TODO: add ability to administratively suspend/resume device
 
+
+  /**
+   * Administratively enables or disables a port on a device.
+   *
+   * @param deviceId  device identifier
+   * @param portNumber port identifier
+   * @param enable true if port is to be enabled, false to disable
+   */
+    void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java b/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java
index d8adbb0..1727fc8 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java
@@ -17,6 +17,7 @@
 
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.provider.Provider;
 
 /**
@@ -54,4 +55,14 @@
      * @return true if reachable, false otherwise
      */
     boolean isReachable(DeviceId deviceId);
+
+    /**
+     * Administratively enables or disables a port.
+     *
+     * @param deviceId device identifier
+     * @param portNumber device identifier
+     * @param enable true if port is to be enabled, false to disable
+     */
+    void changePortState(DeviceId deviceId, PortNumber portNumber,
+                         boolean enable);
 }
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index 5ef70fc..f089203 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -248,6 +248,22 @@
     }
 
     @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        checkNotNull(deviceId, DEVICE_ID_NULL);
+        checkNotNull(deviceId, PORT_NUMBER_NULL);
+        DeviceProvider provider = getProvider(deviceId);
+        if (provider != null) {
+            log.warn("Port {} on device {} being administratively brought {}",
+                     portNumber, deviceId,
+                     (enable) ? "UP" : "DOWN");
+            provider.changePortState(deviceId, portNumber, enable);
+        } else {
+            log.warn("Provider not found for {}", deviceId);
+        }
+    }
+
+    @Override
     protected DeviceProviderService createProviderService(
             DeviceProvider provider) {
         return new InternalDeviceProviderService(provider);
@@ -340,6 +356,7 @@
                 log.trace("event: {} {}", event.type(), event);
                 post(event);
             }
+
         }
 
         @Override
@@ -790,4 +807,5 @@
             }
         }
     }
+
 }
diff --git a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
index 04f266f..7017481 100644
--- a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
@@ -274,6 +274,11 @@
         public boolean isReachable(DeviceId device) {
             return false;
         }
+
+        @Override
+        public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                    boolean enable) {
+        }
     }
 
     private static class TestListener implements DeviceListener {
diff --git a/incubator/rpc-grpc/src/main/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceServer.java b/incubator/rpc-grpc/src/main/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceServer.java
index a13b29c..23ca9a6 100644
--- a/incubator/rpc-grpc/src/main/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceServer.java
+++ b/incubator/rpc-grpc/src/main/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceServer.java
@@ -51,6 +51,7 @@
 import org.onosproject.grpc.LinkProviderServiceRpcGrpc;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
@@ -435,5 +436,12 @@
             return checkNotNull(providerId, "not initialized yet");
         }
 
+        @Override
+        public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                    boolean enable) {
+            // TODO if required
+
+        }
+
     }
 }
diff --git a/incubator/rpc-grpc/src/test/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceTest.java b/incubator/rpc-grpc/src/test/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceTest.java
index e366da3..c04b8c3 100644
--- a/incubator/rpc-grpc/src/test/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceTest.java
+++ b/incubator/rpc-grpc/src/test/java/org/onosproject/incubator/rpc/grpc/GrpcRemoteServiceTest.java
@@ -341,6 +341,10 @@
         DeviceId isReachableDid;
         boolean isReachableReply = false;
 
+        final CountDownLatch portStateChanged = new CountDownLatch(1);
+        DeviceId portStateChangedDid;
+        PortNumber portStateChangedPort;
+
         @Override
         public ProviderId id() {
             return PID;
@@ -369,6 +373,17 @@
             return isReachableReply;
         }
 
+        @Override
+        public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                    boolean enable) {
+            log.info("portState change to {} on ({},{}) on Client called", enable,
+                     deviceId, portNumber);
+            portStateChangedDid = deviceId;
+            portStateChangedPort = portNumber;
+            portStateChanged.countDown();
+
+        }
+
     }
 
     class NoOpRemoteServiceProviderRegistry
diff --git a/providers/bgp/topology/src/main/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProvider.java b/providers/bgp/topology/src/main/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProvider.java
index 3480366..064745d 100755
--- a/providers/bgp/topology/src/main/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProvider.java
+++ b/providers/bgp/topology/src/main/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProvider.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DeviceDescription;
 import org.onosproject.net.device.DeviceProvider;
@@ -122,4 +123,9 @@
         // TODO Auto-generated method stub
         return true;
     }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+    }
 }
diff --git a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
index 6025e07..1ad4025 100644
--- a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
+++ b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
@@ -34,6 +34,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.behaviour.PortDiscovery;
 import org.onosproject.net.config.ConfigFactory;
@@ -250,6 +251,12 @@
         }
     }
 
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        // TODO if required
+    }
+
     private class InnerNetconfDeviceListener implements NetconfDeviceListener {
 
 
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
index fb1823d..6ecac8e 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
@@ -32,6 +32,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceAdminService;
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
@@ -431,6 +432,12 @@
         @Override
         public void triggerProbe(DeviceId deviceId) {
         }
+
+        @Override
+        public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                    boolean enable) {
+            // TODO maybe required
+        }
     }
 
     // Host provider facade.
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index 6a2f9d7..3c6feb8 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -71,6 +72,8 @@
 import org.projectfloodlight.openflow.protocol.OFCalientPortDescProp;
 import org.projectfloodlight.openflow.protocol.OFCalientPortDescPropOptical;
 import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
 import org.projectfloodlight.openflow.protocol.OFExpPort;
 import org.projectfloodlight.openflow.protocol.OFExpPortDescPropOpticalTransport;
 import org.projectfloodlight.openflow.protocol.OFExpPortOpticalTransportLayerEntry;
@@ -81,6 +84,7 @@
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
 import org.projectfloodlight.openflow.protocol.OFPortFeatures;
+import org.projectfloodlight.openflow.protocol.OFPortMod;
 import org.projectfloodlight.openflow.protocol.OFPortOptical;
 import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportLayerClass;
 import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportSignalType;
@@ -93,6 +97,7 @@
 import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
 import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.PortSpeed;
 import org.slf4j.Logger;
 
@@ -268,6 +273,34 @@
         LOG.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
     }
 
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        final Dpid dpid = dpid(deviceId.uri());
+        OpenFlowSwitch sw = controller.getSwitch(dpid);
+        if (sw == null || !sw.isConnected()) {
+            LOG.error("Failed to change portState on device {}", deviceId);
+            return;
+        }
+        OFPortMod.Builder pmb = sw.factory().buildPortMod();
+        OFPort port = OFPort.of((int) portNumber.toLong());
+        pmb.setPortNo(port);
+        if (enable) {
+            pmb.setConfig(0x0); // port_down bit 0
+        } else {
+            pmb.setConfig(0x1); // port_down bit 1
+        }
+        pmb.setMask(0x1);
+        pmb.setAdvertise(0x0);
+        for (OFPortDesc pd : sw.getPorts()) {
+            if (pd.getPortNo().equals(port)) {
+                pmb.setHwAddr(pd.getHwAddr());
+                break;
+            }
+        }
+        sw.sendMsg(Collections.singletonList(pmb.build()));
+    }
+
     private void pushPortMetrics(Dpid dpid, List<OFPortStatsEntry> portStatsEntries) {
         DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
         Collection<PortStatistics> stats = buildPortStatistics(deviceId, portStatsEntries);
@@ -756,9 +789,15 @@
                         }
                     }
                     break;
+                case ERROR:
+                    if (((OFErrorMsg) msg).getErrType() == OFErrorType.PORT_MOD_FAILED) {
+                        LOG.error("port mod failed");
+                    }
                 default:
                     break;
             }
         }
     }
+
+
 }
diff --git a/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java b/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
index d573458..ecf4b0f 100644
--- a/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
+++ b/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
@@ -32,6 +32,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DeviceDescription;
@@ -148,4 +149,10 @@
         }
         return new OvsdbNodeId(IpAddress.valueOf(strings[1]), 0);
     }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        // TODO if required
+    }
 }
diff --git a/providers/pcep/topology/src/main/java/org/onosproject/provider/pcep/topology/impl/PcepTopologyProvider.java b/providers/pcep/topology/src/main/java/org/onosproject/provider/pcep/topology/impl/PcepTopologyProvider.java
index c52ca63..25d4a26 100644
--- a/providers/pcep/topology/src/main/java/org/onosproject/provider/pcep/topology/impl/PcepTopologyProvider.java
+++ b/providers/pcep/topology/src/main/java/org/onosproject/provider/pcep/topology/impl/PcepTopologyProvider.java
@@ -34,6 +34,7 @@
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OmsPort;
 import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DefaultPortDescription;
 import org.onosproject.net.device.DeviceDescription;
@@ -318,4 +319,10 @@
         // TODO Auto-generated method stub
         return true;
     }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        // TODO Auto-generated method stub
+    }
 }
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
index 2f25bb3..8cbfe49 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
@@ -31,6 +31,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.behaviour.PortDiscovery;
 import org.onosproject.net.config.ConfigFactory;
@@ -256,4 +257,10 @@
                             event.type() == CONFIG_UPDATED);
         }
     }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        // TODO if required
+    }
 }
diff --git a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
index 56e3b6a..c32296c 100644
--- a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
+++ b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
@@ -37,6 +37,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.behaviour.PortDiscovery;
 import org.onosproject.net.device.DefaultDeviceDescription;
@@ -427,4 +428,10 @@
     protected ISnmpSessionFactory getSessionFactory(ISnmpConfigurationFactory configurationFactory) {
         return new SnmpSessionFactory(configurationFactory);
     }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+        // TODO if required
+    }
 }
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java b/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
index 005341e..0050a19 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
@@ -568,6 +568,11 @@
     }
 
     @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber,
+                                boolean enable) {
+    }
+
+    @Override
     public ProviderId id() {
         return PID;
     }
@@ -610,4 +615,6 @@
         }
     }
 
+
+
 }