[VOL-4246] Feature parity with the previous implementation

Change-Id: I3741edb3c1b88b1cf8b5e6d4ff0900132e2e5e6a
diff --git a/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java b/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
index 68ceca6..98301db 100644
--- a/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
+++ b/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
@@ -19,34 +19,34 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onlab.osgi.DefaultServiceDirectory;
 import org.onosproject.cli.net.PortNumberCompleter;
-import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
+import org.opencord.olt.impl.OltDeviceServiceInterface;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 
 @Service
 public class OltUniPortCompleter extends PortNumberCompleter {
-    private static final String NNI = "nni-";
 
     public OltUniPortCompleter() {
     }
 
     protected List<String> choices() {
+        DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
         DeviceId deviceId = this.lookForDeviceId();
         if (deviceId == null) {
             return Collections.emptyList();
         } else {
-            DeviceService deviceService = (DeviceService) DefaultServiceDirectory.getService(DeviceService.class);
-            return (List) StreamSupport.stream(deviceService.getPorts(deviceId).spliterator(), false)
-                    .filter((port) -> {
-                        return port.isEnabled() && !port.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI);
-                    })
-                    .map((port) -> {
-                        return port.number().toString();
-                    }).collect(Collectors.toList());
+            Device device = deviceService.getDevice(DeviceId.deviceId(deviceId.toString()));
+            OltDeviceServiceInterface oltDeviceService =
+                    DefaultServiceDirectory.getService(OltDeviceServiceInterface.class);
+            return deviceService.getPorts(deviceId).stream()
+                    .filter((port) -> port.isEnabled() && !oltDeviceService.isNniPort(device, port.number()))
+                    .map((port) -> port.number().toString())
+                    .collect(Collectors.toList());
         }
     }
 }
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java
deleted file mode 100644
index eb1b47d..0000000
--- a/impl/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Foundation
- *
- * 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.opencord.olt.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.meter.MeterKey;
-import org.opencord.olt.internalapi.AccessDeviceMeterService;
-
-import java.util.Collection;
-import java.util.Map;
-
-@Service
-@Command(scope = "onos", name = "volt-bpmeter-mappings",
-        description = "Shows information about bandwidthProfile-meterKey (device / meter) mappings")
-public class ShowBpMeterMappingsCommand extends AbstractShellCommand {
-
-    @Override
-    protected void doExecute() {
-        AccessDeviceMeterService service = AbstractShellCommand.get(AccessDeviceMeterService.class);
-        Map<String, Collection<MeterKey>> bpMeterMappings = service.getBpMeterMappings();
-        bpMeterMappings.forEach(this::display);
-    }
-
-    private void display(String bpInfo, Collection<MeterKey> meterKeyList) {
-        meterKeyList.forEach(meterKey ->
-                print("bpInfo=%s deviceId=%s meterId=%s",
-                        bpInfo, meterKey.deviceId(), meterKey.meterId()));
-
-    }
-}
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowFailedSubscribersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowFailedSubscribersCommand.java
index 5d6bf3d..cb40faa 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowFailedSubscribersCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowFailedSubscribersCommand.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * Copyright 2021-present Open Networking Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,31 +19,20 @@
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.opencord.olt.AccessDeviceService;
-import org.opencord.sadis.UniTagInformation;
-
-import java.util.Map;
-import java.util.Set;
-
 /**
- * Shows subscriber information for those subscriber which have been programmed
- * in the data-plane.
+ * Shows failed subscribers on an OLTs.
  */
 @Service
 @Command(scope = "onos", name = "volt-failed-subscribers",
-        description = "Shows subscribers awaiting for programming in the dataplane")
+        description = "Shows subscribers that failed provisioning")
 public class ShowFailedSubscribersCommand extends AbstractShellCommand {
 
     @Override
     protected void doExecute() {
-        AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-        Map<ConnectPoint, Set<UniTagInformation>> info = service.getFailedSubs();
-        info.forEach(this::display);
+        // NOTE
+        // this command is still available purely for backward compatibility but whilst the old implementation
+        // had a limited number of retries available the new implementation will keep retrying.
+        print("Unimplemented");
     }
 
-    private void display(ConnectPoint cp, Set<UniTagInformation> uniTagInformation) {
-        uniTagInformation.forEach(uniTag ->
-                                          print("location=%s tagInformation=%s", cp, uniTag));
-    }
-}
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java b/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java
new file mode 100644
index 0000000..7e2175d
--- /dev/null
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.opencord.olt.impl.MeterData;
+import org.opencord.olt.impl.OltMeterServiceInterface;
+
+import java.util.Map;
+/**
+ * Shows meters to bandwidth profile mappings.
+ */
+@Service
+@Command(scope = "onos", name = "volt-bpmeter-mappings",
+        description = "Shows information about programmed meters, including the relation with the Bandwidth Profile")
+public class ShowMeterMappings extends AbstractShellCommand {
+
+    @Override
+    protected void doExecute() {
+        OltMeterServiceInterface service = AbstractShellCommand.get(OltMeterServiceInterface.class);
+        Map<DeviceId, Map<String, MeterData>> meters = service.getProgrammedMeters();
+        if (meters.isEmpty()) {
+            print("No meters programmed by the olt app");
+        }
+        meters.forEach(this::display);
+    }
+
+    private void display(DeviceId deviceId, Map<String, MeterData> data) {
+        data.forEach((bp, md) ->
+                print("\tbpInfo=%s deviceId=%s meterId=%s",
+                        deviceId, bp, md.getMeterId()));
+
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowOltCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
index 08aaa48..c379116 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
@@ -40,9 +40,9 @@
     protected void doExecute() {
         AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
         if (outputJson()) {
-            print("%s", json(service.fetchOlts()));
+            print("%s", json(service.getConnectedOlts()));
         } else {
-            service.fetchOlts().forEach(did -> print("OLT %s", did));
+            service.getConnectedOlts().forEach(did -> print("OLT %s", did));
         }
 
     }
@@ -62,4 +62,4 @@
         }
         return node;
     }
-}
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java b/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java
new file mode 100644
index 0000000..f3b35a0
--- /dev/null
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.cli.net.PortNumberCompleter;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.opencord.olt.impl.OltFlowServiceInterface;
+import org.opencord.olt.impl.OltPortStatus;
+import org.opencord.olt.impl.ServiceKey;
+import org.opencord.sadis.UniTagInformation;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Shows ports' status of an OLT.
+ */
+@Service
+@Command(scope = "onos", name = "volt-port-status",
+        description = "Shows information about the OLT ports (default EAPOL, subscriber flows)")
+public class ShowPortStatus extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "deviceId", description = "Access device ID",
+            required = false, multiValued = false)
+    @Completion(DeviceIdCompleter.class)
+    private String strDeviceId = null;
+
+    @Argument(index = 1, name = "port", description = "Subscriber port number",
+            required = false, multiValued = false)
+    @Completion(PortNumberCompleter.class)
+    private String strPort = null;
+
+    @Override
+    protected void doExecute() {
+
+        OltFlowServiceInterface service = AbstractShellCommand.get(OltFlowServiceInterface.class);
+        Map<ServiceKey, OltPortStatus> connectPointStatus = service.getConnectPointStatus();
+        if (connectPointStatus.isEmpty()) {
+            print("No ports handled by the olt app");
+            return;
+        }
+
+        Map<DeviceId, Map<PortNumber, Map<UniTagInformation, OltPortStatus>>> sortedStatus = new HashMap<>();
+
+        DeviceId deviceId = strDeviceId != null ? DeviceId.deviceId(strDeviceId) : null;
+        PortNumber portNumber = strPort != null ? PortNumber.portNumber(strPort) : null;
+
+        connectPointStatus.forEach((sk, fs) -> {
+            if (deviceId != null && !deviceId.equals(sk.getPort().connectPoint()
+                    .deviceId())) {
+                return;
+            }
+            if (portNumber != null && !portNumber.equals(sk.getPort().connectPoint().port())) {
+                return;
+            }
+            sortedStatus.compute(sk.getPort().connectPoint().deviceId(), (id, portMap) -> {
+                if (portMap == null) {
+                    portMap = new HashMap<>();
+                }
+                portMap.compute(sk.getPort().connectPoint().port(), (id2, ps) -> {
+                    if (ps == null) {
+                        ps = new HashMap<>();
+                    }
+                    ps.put(sk.getService(), fs);
+                    return ps;
+                });
+
+                return portMap;
+            });
+        });
+
+        sortedStatus.forEach(this::display);
+    }
+
+    private void display(DeviceId deviceId, Map<PortNumber, Map<UniTagInformation, OltPortStatus>> ports) {
+        print("deviceId=%s, managedPorts=%d", deviceId, ports.size());
+
+        ports.forEach((port, subscribers) -> {
+            print("\tport=%s", port);
+            subscribers.forEach((uti, status) -> {
+                print("\t\tservice=%s defaultEapolStatus=%s subscriberFlowsStatus=%s dhcpStatus=%s",
+                        uti.getServiceName(), status.defaultEapolStatus,
+                        status.subscriberFlowsStatus, status.dhcpStatus);
+            });
+        });
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java
new file mode 100644
index 0000000..da2307e
--- /dev/null
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.opencord.olt.impl.MeterData;
+import org.opencord.olt.impl.OltMeterServiceInterface;
+
+import java.util.Map;
+/**
+ * Displays the programmed meters through the OLT app.
+ */
+@Service
+@Command(scope = "onos", name = "volt-programmed-meters",
+        description = "Shows information about programmed meters, including the relation with the Bandwidth Profile")
+public class ShowProgrammedMeters extends AbstractShellCommand {
+
+    @Override
+    protected void doExecute() {
+        OltMeterServiceInterface service = AbstractShellCommand.get(OltMeterServiceInterface.class);
+        Map<DeviceId, Map<String, MeterData>> meters = service.getProgrammedMeters();
+        if (meters.isEmpty()) {
+            print("No meters programmed by the olt app");
+            return;
+        }
+        meters.forEach(this::display);
+    }
+
+    private void display(DeviceId deviceId, Map<String, MeterData> data) {
+        print("deviceId=%s, meterCount=%d", deviceId, data.size());
+        data.forEach((bp, md) ->
+                print("\tmeterId=%s bandwidthProfile=%s status=%s",
+                        md.getMeterId(), bp, md.getMeterStatus()));
+
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java
deleted file mode 100644
index a7dbd39..0000000
--- a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Foundation
- *
- * 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.opencord.olt.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.meter.MeterKey;
-import org.opencord.olt.internalapi.AccessDeviceMeterService;
-
-import java.util.Set;
-
-/**
- * Shows information about device-meter mappings that have been programmed in the
- * data-plane.
- */
-@Service
-@Command(scope = "onos", name = "volt-programmed-meters",
-        description = "Shows device-meter mappings programmed in the data-plane")
-public class ShowProgrammedMetersCommand extends AbstractShellCommand {
-
-    @Override
-    protected void doExecute() {
-        AccessDeviceMeterService service = AbstractShellCommand.get(AccessDeviceMeterService.class);
-        Set<MeterKey> programmedMeters = service.getProgMeters();
-        programmedMeters.forEach(this::display);
-    }
-
-    private void display(MeterKey meterKey) {
-        print("device=%s meter=%s", meterKey.deviceId(), meterKey.meterId());
-    }
-}
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
index 413272b..ac8d00d 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * Copyright 2021-present Open Networking Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,34 +16,60 @@
 
 package org.opencord.olt.cli;
 
+import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.opencord.olt.AccessDeviceService;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.opencord.olt.impl.OltFlowServiceInterface;
+import org.opencord.olt.impl.ServiceKey;
 import org.opencord.sadis.UniTagInformation;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
- * Shows subscriber information for those subscriber which have been programmed
- * in the data-plane.
+ * Shows programmed subscribers.
  */
 @Service
 @Command(scope = "onos", name = "volt-programmed-subscribers",
         description = "Shows subscribers programmed in the dataplane")
 public class ShowProgrammedSubscribersCommand extends AbstractShellCommand {
 
+    @Argument(index = 0, name = "deviceId", description = "Access device ID",
+            required = false, multiValued = false)
+    @Completion(DeviceIdCompleter.class)
+    private String strDeviceId = null;
+
+    @Argument(index = 1, name = "port", description = "Subscriber port number",
+            required = false, multiValued = false)
+    @Completion(OltUniPortCompleter.class)
+    private String strPort = null;
+
     @Override
     protected void doExecute() {
-        AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-        Map<ConnectPoint, Set<UniTagInformation>> info = service.getProgSubs();
-        info.forEach(this::display);
+        OltFlowServiceInterface service = AbstractShellCommand.get(OltFlowServiceInterface.class);
+        Map<ServiceKey, UniTagInformation> info = service.getProgrammedSubscribers();
+        Set<Map.Entry<ServiceKey, UniTagInformation>> entries = info.entrySet();
+        if (strDeviceId != null && !strDeviceId.isEmpty()) {
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().deviceId()
+                    .equals(DeviceId.deviceId(strDeviceId))).collect(Collectors.toSet());
+        }
+
+        if (strPort != null && !strPort.isEmpty()) {
+            PortNumber portNumber = PortNumber.portNumber(strPort);
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().port()
+                    .equals(portNumber)).collect(Collectors.toSet());
+        }
+
+        entries.forEach(entry -> display(entry.getKey(), entry.getValue()));
     }
 
-    private void display(ConnectPoint cp, Set<UniTagInformation> uniTagInformation) {
-        uniTagInformation.forEach(uniTag ->
-                                          print("location=%s tagInformation=%s", cp, uniTag));
+    private void display(ServiceKey sk, UniTagInformation uniTag) {
+        print("location=%s tagInformation=%s", sk.getPort().connectPoint(), uniTag);
     }
-}
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java
new file mode 100644
index 0000000..37ef532
--- /dev/null
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.opencord.olt.impl.OltFlowServiceInterface;
+import org.opencord.olt.impl.ServiceKey;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Shows requested subscribers.
+ */
+@Service
+@Command(scope = "onos", name = "volt-requested-subscribers",
+        description = "Shows subscribers programmed by the operator. " +
+                "Their data-plane status depends on the ONU status.")
+public class ShowRequestedSubscribersCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "deviceId", description = "Access device ID",
+            required = false, multiValued = false)
+    @Completion(DeviceIdCompleter.class)
+    private String strDeviceId = null;
+
+    @Argument(index = 1, name = "port", description = "Subscriber port number",
+            required = false, multiValued = false)
+    @Completion(OltUniPortCompleter.class)
+    private String strPort = null;
+
+    @Override
+    protected void doExecute() {
+        OltFlowServiceInterface service = AbstractShellCommand.get(OltFlowServiceInterface.class);
+        Map<ServiceKey, Boolean> info = service.getRequestedSubscribers();
+        Set<Map.Entry<ServiceKey, Boolean>> entries = info.entrySet();
+        if (strDeviceId != null && !strDeviceId.isEmpty()) {
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().deviceId()
+                    .equals(DeviceId.deviceId(strDeviceId))).collect(Collectors.toSet());
+        }
+
+        if (strPort != null && !strPort.isEmpty()) {
+            PortNumber portNumber = PortNumber.portNumber(strPort);
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().port()
+                    .equals(portNumber)).collect(Collectors.toSet());
+        }
+
+        entries.forEach(entry -> display(entry.getKey(), entry.getValue()));
+    }
+
+    private void display(ServiceKey sk, Boolean status) {
+        print("location=%s service=%s provisioned=%s", sk.getPort(), sk.getService().getServiceName(), status);
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/SubscriberAddAllCommand.java b/impl/src/main/java/org/opencord/olt/cli/SubscriberAddAllCommand.java
new file mode 100644
index 0000000..2a1a3c6
--- /dev/null
+++ b/impl/src/main/java/org/opencord/olt/cli/SubscriberAddAllCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.opencord.olt.AccessDeviceService;
+
+/**
+ * Adds a subscriber to an access device.
+ */
+@Service
+@Command(scope = "onos", name = "volt-add-all-subscriber-access",
+        description = "Adds a subscriber to an access device")
+public class SubscriberAddAllCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "deviceId", description = "Access device ID",
+            required = true, multiValued = false)
+    @Completion(DeviceIdCompleter.class)
+    private String strDeviceId = null;
+
+    @Override
+    protected void doExecute() {
+        AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
+        DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
+        DeviceId deviceId = DeviceId.deviceId(strDeviceId);
+
+        deviceService.getPorts(deviceId).forEach(p -> {
+            if (p.isEnabled()) {
+                PortNumber port = p.number();
+                ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
+                service.provisionSubscriber(connectPoint);
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/SubscriberAddCommand.java b/impl/src/main/java/org/opencord/olt/cli/SubscriberAddCommand.java
index de76903..5eeee4e 100644
--- a/impl/src/main/java/org/opencord/olt/cli/SubscriberAddCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/SubscriberAddCommand.java
@@ -28,7 +28,7 @@
 import org.opencord.olt.AccessDeviceService;
 
 /**
- * Adds a subscriber to an access device.
+ * Adds all possible subscribers to an access device.
  */
 @Service
 @Command(scope = "onos", name = "volt-add-subscriber-access",
@@ -48,11 +48,10 @@
     @Override
     protected void doExecute() {
         AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-
         DeviceId deviceId = DeviceId.deviceId(strDeviceId);
         PortNumber port = PortNumber.portNumber(strPort);
         ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
 
         service.provisionSubscriber(connectPoint);
     }
-}
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/SubscriberRemoveCommand.java b/impl/src/main/java/org/opencord/olt/cli/SubscriberRemoveCommand.java
index 79a7369..cf3da93 100644
--- a/impl/src/main/java/org/opencord/olt/cli/SubscriberRemoveCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/SubscriberRemoveCommand.java
@@ -22,18 +22,17 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.cli.net.PortNumberCompleter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.opencord.olt.AccessDeviceService;
 
 /**
- * Adds a subscriber to an access device.
+ * Removes a subscriber to an access device.
  */
 @Service
 @Command(scope = "onos", name = "volt-remove-subscriber-access",
-        description = "Removes a subscriber to an access device")
+        description = "Remove a subscriber from an access device")
 public class SubscriberRemoveCommand extends AbstractShellCommand {
 
     @Argument(index = 0, name = "deviceId", description = "Access device ID",
@@ -43,18 +42,16 @@
 
     @Argument(index = 1, name = "port", description = "Subscriber port number",
             required = true, multiValued = false)
-    @Completion(PortNumberCompleter.class)
+    @Completion(OltUniPortCompleter.class)
     private String strPort = null;
 
     @Override
     protected void doExecute() {
         AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-
         DeviceId deviceId = DeviceId.deviceId(strDeviceId);
         PortNumber port = PortNumber.portNumber(strPort);
         ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
 
         service.removeSubscriber(connectPoint);
-
     }
-}
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java b/impl/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java
index 4eb6495..bd42704 100644
--- a/impl/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java
@@ -22,10 +22,10 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onlab.packet.VlanId;
 import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
 import org.opencord.olt.AccessDeviceService;
-import org.opencord.olt.AccessSubscriberId;
 
-import java.util.Optional;
+import static com.google.common.base.Strings.isNullOrEmpty;
 
 /**
  * Adds a subscriber uni tag.
@@ -37,29 +37,39 @@
 
     @Argument(index = 0, name = "portName", description = "Port name",
             required = true, multiValued = false)
-    private String strPortName = null;
+    private String portName = null;
 
     @Option(name = "--cTag", description = "Inner vlan id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strCtag = null;
 
     @Option(name = "--sTag", description = "Outer vlan id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strStag = null;
 
     @Option(name = "--tpId", description = "Technology profile id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strTpId = null;
 
     @Override
     protected void doExecute() {
 
         AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-        AccessSubscriberId portName = new AccessSubscriberId(strPortName);
+        ConnectPoint cp = service.findSubscriberConnectPoint(portName);
+        if (cp == null) {
+            log.warn("ConnectPoint not found for {}", portName);
+            print("ConnectPoint not found for %s", portName);
+            return;
+        }
+        if (isNullOrEmpty(strCtag) || isNullOrEmpty(strStag) || isNullOrEmpty(strTpId)) {
+            print("Values for c-tag (%s), s-tag (%s) and technology profile Id (%s) " +
+                          "are required", strCtag, strStag, strTpId);
+            return;
+        }
 
-        Optional<VlanId> cTag = strCtag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strCtag));
-        Optional<VlanId> sTag = strStag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strStag));
-        Optional<Integer> tpId = strTpId == null ? Optional.empty() : Optional.of(Integer.parseInt(strTpId));
-        service.provisionSubscriber(portName, sTag, cTag, tpId);
+        VlanId cTag = VlanId.vlanId(strCtag);
+        VlanId sTag = VlanId.vlanId(strStag);
+        Integer tpId = Integer.valueOf(strTpId);
+        service.provisionSubscriber(cp, cTag, sTag, tpId);
     }
 }
diff --git a/impl/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java b/impl/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java
index e256914..d05418a 100644
--- a/impl/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java
@@ -22,10 +22,11 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onlab.packet.VlanId;
 import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
 import org.opencord.olt.AccessDeviceService;
-import org.opencord.olt.AccessSubscriberId;
 
-import java.util.Optional;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
 
 /**
  * Removes a uni tag from a subscriber (portname).
@@ -37,29 +38,39 @@
 
     @Argument(index = 0, name = "portName", description = "Port name",
             required = true, multiValued = false)
-    private String strPortName = null;
+    private String portName = null;
 
     @Option(name = "--cTag", description = "Inner vlan id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strCtag = null;
 
     @Option(name = "--sTag", description = "Outer vlan id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strStag = null;
 
     @Option(name = "--tpId", description = "Technology profile id",
-            required = false, multiValued = false)
+            required = true, multiValued = false)
     private String strTpId = null;
 
     @Override
     protected void doExecute() {
 
         AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
-        AccessSubscriberId portName = new AccessSubscriberId(strPortName);
+        ConnectPoint cp = service.findSubscriberConnectPoint(portName);
+        if (cp == null) {
+            log.warn("ConnectPoint not found for {}", portName);
+            print("ConnectPoint not found for %s", portName);
+            return;
+        }
+        if (isNullOrEmpty(strCtag) || isNullOrEmpty(strStag) || isNullOrEmpty(strTpId)) {
+            print("Values for c-tag (%s), s-tag (%s) and technology profile Id (%s) " +
+                          "are required", strCtag, strStag, strTpId);
+            return;
+        }
 
-        Optional<VlanId> cTag = strCtag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strCtag));
-        Optional<VlanId> sTag = strStag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strStag));
-        Optional<Integer> tpId = strTpId == null ? Optional.empty() : Optional.of(Integer.parseInt(strTpId));
-        service.removeSubscriber(portName, sTag, cTag, tpId);
+        VlanId cTag = VlanId.vlanId(strCtag);
+        VlanId sTag = VlanId.vlanId(strStag);
+        Integer tpId = Integer.valueOf(strTpId);
+        service.removeSubscriber(cp, cTag, sTag, tpId);
     }
 }
diff --git a/impl/src/main/java/org/opencord/olt/cli/package-info.java b/impl/src/main/java/org/opencord/olt/cli/package-info.java
index b100077..c657d73 100644
--- a/impl/src/main/java/org/opencord/olt/cli/package-info.java
+++ b/impl/src/main/java/org/opencord/olt/cli/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * Copyright 2021-present Open Networking Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,6 @@
  */
 
 /**
- * OLT application handling PMC OLT hardware.
+ * CLI package for OLT application.
  */
-package org.opencord.olt.cli;
+package org.opencord.olt.cli;
\ No newline at end of file