Both the Upstream and Downstream Bandwidth Profiles can be 'named' and Referenced from a Subscriber Record in the SADIS DB on ONOS.

When the vOLT Appplication uses a Subscriber Record for OpenFlow message generation to VOLTHA the vOLT Application Must read the Bandwidth Profile name and be able to retrieve the Profile from a Database of Bandwidth Profiles. The Named Profile is converted to a Meter and Meter Band(s) and configured on the VOLTHA Instance, and the Flows will reference the Meter.

Note the code should be written to follow the SADIS DB model where it is designed to reference an external database but the DB records can be cached locally.

The Upstream Bandwidth Profile will consist of the following optional components:

EIR (Bits/Sec)

EBS (Bytes)

CIR (Bits/Sec)

CBS (Bits/Sec)

AIR (Bits/Sec)

The Downstream Bandwidth Profile will consist of the following optional components:

EIR (Bits/Sec)

EBS (Bytes)

CIR (Bits/Sec)

CBS (Bits/Sec)

 Each bandwidth component will be interpreted as defined in the Technology Profile Whitepaper ([^vOLTHA_Access_Tech_AugmentationV0.6.pdf]

)

Change-Id: Ie4edf4e9f27e9b5b9a84e6c733dc4f283a9996a7
diff --git a/TEST-README.md b/TEST-README.md
new file mode 100644
index 0000000..5dad130
--- /dev/null
+++ b/TEST-README.md
@@ -0,0 +1,160 @@
+How to test technology profile
+------------------------------
+
+- Export ONOS directory:
+
+```
+export ONOS_ROOT=~/voltha-projects/onos
+source $ONOS_ROOT/tools/dev/bash_profile
+```
+
+- Build and run ONOS:
+
+```
+mvn clean install -DskipTests -Dcheckstyle.skip=true OR onos-buck build onos
+ok clean
+```
+
+- Build SADIS and OLT apps:
+
+```
+mvn clean install
+```
+
+- Install and Activate SADIS and OLT apps:
+
+```
+onos-app localhost install ~/voltha-projects/sadis/app/target/sadis-app-3.0.0.oar
+onos-app localhost activate org.opencord.sadis
+
+onos-app localhost install ~/voltha-projects/olt/app/target/olt-app-3.0.0-SNAPSHOT.oar
+onos-app localhost activate org.opencord.olt
+```
+
+- To test with the oldest configuration (as oldest SADIS) - it includes only S and C tags:
+
+```
+onos-netcfg localhost  ~/voltha-projects/olt/app/src/main/resources/cfg.json
+```
+
+- To test AT&T use case:
+    - Note:the tech profile table id is 10 to work with Mininet - if Voltha is used, then it will be 64 or greater value
+
+```
+onos-netcfg localhost  ~/voltha-projects/olt/app/src/main/resources/vlan_cfg.json
+```
+
+- To test DT use case (any vlan):
+    - Note:the tech profile table id is 10 to work with Mininet - if Voltha is used, then it will be 64 or greater value
+
+```
+onos-netcfg localhost  ~/voltha-projects/olt/app/src/main/resources/any_vlan_cfg.json
+```
+
+- To test without VOLTHA, you can use Mininet with UserSwitch and emulate the topology:
+
+```
+sudo mn --custom ~/voltha-projects/olt/app/src/main/resources/custom-topo.py --switch user --controller=remote,ip=127.0.0.1,port=6633
+```
+
+- Run ONOS client:
+
+```
+ cd /tmp/onos-1.13.6/apache-karaf-3.0.8/bin
+ ./client
+```
+
+- Check devices, flows and ports:
+
+```
+devices
+
+the output (note that: the driver is pmc-olt):
+
+id=of:0000000000000001, available=true, local-status=connected 2s ago, role=MASTER, type=SWITCH, mfr=Stanford University, Ericsson Research and CPqD Research, hw=OpenFlow 1.3 Reference Userspace Switch, sw=Sep 10 2018 16:56:31, serial=1, chassis=1, driver=pmc-olt, channelId=127.0.0.1:36022, locType=none, managementAddress=127.0.0.1, name=of:0000000000000001, protocol=OF_13
+
+flows
+
+the output:
+
+deviceId=of:0000000000000001, flowRuleCount=4
+    id=ac00002f18dba3, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=10000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, ETH_TYPE:eapol], treatment=DefaultTrafficTreatment{immediate=[OUTPUT:CONTROLLER], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac00005512664b, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=10000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:LOCAL, ETH_TYPE:eapol], treatment=DefaultTrafficTreatment{immediate=[OUTPUT:CONTROLLER], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac00005d0fea43, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=10000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, ETH_TYPE:lldp], treatment=DefaultTrafficTreatment{immediate=[OUTPUT:CONTROLLER], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000617983d6, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=10000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, ETH_TYPE:ipv4, IP_PROTO:17, UDP_SRC:68, UDP_DST:67], treatment=DefaultTrafficTreatment{immediate=[OUTPUT:CONTROLLER], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+
+ports
+
+the output (assume that port 1 is UNI and 2 is NNI):
+
+id=of:0000000000000001, available=true, local-status=connected 7s ago, role=MASTER, type=SWITCH, mfr=Stanford University, Ericsson Research and CPqD Research, hw=OpenFlow 1.3 Reference Userspace Switch, sw=Sep 10 2018 16:56:31, serial=1, chassis=1, driver=pmc-olt, channelId=127.0.0.1:36022, locType=none, managementAddress=127.0.0.1, name=of:0000000000000001, protocol=OF_13
+  port=LOCAL, state=enabled, type=copper, speed=10 , adminState=enabled, portMac=00:00:00:00:00:01, portName=tap:
+  port=1, state=enabled, type=copper, speed=10485 , adminState=enabled, portMac=ba:5d:49:53:9f:d2, portName=s1-eth1
+  port=2, state=enabled, type=copper, speed=10485 , adminState=enabled, portMac=9e:11:ee:ba:4f:f4, portName=s1-eth
+
+```
+
+- Add subscriber to UNI port:
+
+```
+volt-add-subscriber-access of:0000000000000001 1
+```
+
+- The flows when you use cfg.json:
+
+```
+Upstream Flows:
+
+    id=ac000000f780f6, state=ADDED, bytes=0, packets=0, duration=5, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:0], treatment=DefaultTrafficTreatment{immediate=[VLAN_ID:2], deferred=[], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000c9fd17bf, state=ADDED, bytes=0, packets=0, duration=5, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:2], treatment=DefaultTrafficTreatment{immediate=[VLAN_PUSH:vlan, VLAN_ID:4], deferred=[OUTPUT:2], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+
+Downstream Flows:
+
+    id=ac000022a77664, state=ADDED, bytes=0, packets=0, duration=5, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, METADATA:200000001, VLAN_VID:4], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP], deferred=[], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac00001801d6d1, state=ADDED, bytes=0, packets=0, duration=5, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, VLAN_VID:2], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP, VLAN_ID:0], deferred=[OUTPUT:1], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+```
+
+- The flows when you use vlan_cfg.json:
+
+```
+Upstream Flows:
+
+    id=ac000000f780f6, state=ADDED, bytes=0, packets=0, duration=6, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:0], treatment=DefaultTrafficTreatment{immediate=[VLAN_ID:2], deferred=[], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000c9fd17bf, state=ADDED, bytes=0, packets=0, duration=6, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:2], treatment=DefaultTrafficTreatment{immediate=[VLAN_PUSH:vlan, VLAN_ID:4], deferred=[OUTPUT:2], transition=TABLE:10, meter=[METER:1], cleared=false, StatTrigger=null, metadata=null}
+
+Downstream Flows:
+
+    id=ac000022a77664, state=ADDED, bytes=0, packets=0, duration=6, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, METADATA:200000001, VLAN_VID:4], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP], deferred=[], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac00001801d6d1, state=ADDED, bytes=0, packets=0, duration=6, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, VLAN_VID:2], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP, VLAN_ID:0], deferred=[OUTPUT:1], transition=TABLE:10, meter=[METER:2], cleared=false, StatTrigger=null, metadata=null}
+
+Upstream Meter:
+
+ DefaultMeter{device=of:0000000000000001, cellId=1, appId=org.opencord.olt, unit=KB_PER_SEC, isBurst=true, state=ADDED, bands=[DefaultBand{rate=200000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=10000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=10000000, burst-size=0, type=DROP, drop-precedence=null}]}
+
+Downstream Meter:
+
+ DefaultMeter{device=of:0000000000000001, cellId=2, appId=org.opencord.olt, unit=KB_PER_SEC, isBurst=true, state=ADDED, bands=[DefaultBand{rate=300000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=20000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=30000000, burst-size=0, type=DROP, drop-precedence=null}]}
+```
+
+- The flows when you use any_vlan_cfg.json:
+
+```
+Upstream Flows:
+
+    id=ac000009d37362, state=ADDED, bytes=0, packets=0, duration=3, liveType=UNKNOWN, priority=500, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1], treatment=DefaultTrafficTreatment{immediate=[NOACTION], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000fb6f690a, state=ADDED, bytes=0, packets=0, duration=3, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:Any], treatment=DefaultTrafficTreatment{immediate=[], deferred=[], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000076e2984, state=ADDED, bytes=0, packets=0, duration=3, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:1, VLAN_VID:Any], treatment=DefaultTrafficTreatment{immediate=[VLAN_PUSH:qinq, VLAN_ID:4], deferred=[OUTPUT:2], transition=TABLE:10, meter=[METER:1], cleared=false, StatTrigger=null, metadata=null}
+
+Downstream Flows:
+
+    id=ac000022a77664, state=ADDED, bytes=0, packets=0, duration=3, liveType=UNKNOWN, priority=1000, tableId=0, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, METADATA:200000001, VLAN_VID:4], treatment=DefaultTrafficTreatment{immediate=[], deferred=[VLAN_POP], transition=TABLE:1, meter=[], cleared=false, StatTrigger=null, metadata=null}
+    id=ac0000911ae9cb, state=ADDED, bytes=0, packets=0, duration=3, liveType=UNKNOWN, priority=1000, tableId=1, appId=org.opencord.olt, payLoad=null, selector=[IN_PORT:2, VLAN_VID:Any], treatment=DefaultTrafficTreatment{immediate=[], deferred=[OUTPUT:1], transition=TABLE:10, meter=[METER:2], cleared=false, StatTrigger=null, metadata=null}
+
+Upstream Meter:
+
+ DefaultMeter{device=of:0000000000000001, cellId=1, appId=org.opencord.olt, unit=KB_PER_SEC, isBurst=true, state=ADDED, bands=[DefaultBand{rate=200000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=10000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=10000000, burst-size=0, type=DROP, drop-precedence=null}]}
+
+Downstream Meter:
+
+ DefaultMeter{device=of:0000000000000001, cellId=2, appId=org.opencord.olt, unit=KB_PER_SEC, isBurst=true, state=ADDED, bands=[DefaultBand{rate=300000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=20000000, burst-size=348000, type=DROP, drop-precedence=null}, DefaultBand{rate=30000000, burst-size=0, type=DROP, drop-precedence=null}]}
+```
\ No newline at end of file
diff --git a/api/pom.xml b/api/pom.xml
index b5521bf..2c6d6a9 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>olt</artifactId>
         <groupId>org.opencord</groupId>
-        <version>2.1.0</version>
+        <version>3.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
@@ -33,7 +33,7 @@
 
     <description>OLT application API</description>
     <properties>
-        <sadis.api.version>2.1.0</sadis.api.version>
+        <sadis.api.version>3.0.0</sadis.api.version>
     </properties>
 
     <dependencies>
diff --git a/app/pom.xml b/app/pom.xml
index 9c7af88..e1b9bb0 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>org.opencord</groupId>
         <artifactId>olt</artifactId>
-        <version>2.1.0</version>
+        <version>3.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -45,7 +45,7 @@
         <onos.app.readme>CORD OLT Access management application</onos.app.readme>
         <api.package>org.opencord.olt.rest</api.package>
         <olt.api.version>${project.version}</olt.api.version>
-        <sadis.api.version>2.1.0</sadis.api.version>
+        <sadis.api.version>3.0.0</sadis.api.version>
     </properties>
 
     <dependencies>
diff --git a/app/src/main/java/org/opencord/olt/impl/Olt.java b/app/src/main/java/org/opencord/olt/impl/Olt.java
index e2fdc55..a611723 100644
--- a/app/src/main/java/org/opencord/olt/impl/Olt.java
+++ b/app/src/main/java/org/opencord/olt/impl/Olt.java
@@ -80,15 +80,27 @@
 import org.onosproject.store.service.ConsistentMultimap;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeterRequest;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterService;
+import org.onosproject.net.meter.MeterListener;
+import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterEvent;
 import org.opencord.olt.AccessDeviceEvent;
 import org.opencord.olt.AccessDeviceListener;
 import org.opencord.olt.AccessDeviceService;
 import org.opencord.olt.AccessSubscriberId;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SadisService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
-import org.opencord.sadis.SubscriberAndDeviceInformationService;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
+import java.util.HashMap;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
@@ -124,7 +136,10 @@
     protected ComponentConfigService componentConfigService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected SubscriberAndDeviceInformationService subsService;
+    protected SadisService sadisService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MeterService meterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
@@ -149,13 +164,23 @@
             label = "Create IGMP Flow rules when a subscriber is provisioned")
     protected boolean enableIgmpOnProvisioning = false;
 
+    // needed because no implementation for meter statistics in Voltha yet
+    @Property(name = "deleteMeters", boolValue = false,
+            label = "Deleting Meters based on flow count statistics")
+    protected boolean deleteMeters = false;
+
     private final DeviceListener deviceListener = new InternalDeviceListener();
+    private final MeterListener meterListener = new InternalMeterListener();
 
     private ApplicationId appId;
+    protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
+    private BaseInformationService<BandwidthProfileInformation> bpService;
 
-    private ExecutorService oltInstallers = Executors
-            .newFixedThreadPool(4, groupedThreads("onos/olt-service",
-                                                  "olt-installer-%d"));
+    private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
+
+    private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
+            groupedThreads("onos/olt-service",
+                    "olt-installer-%d"));
 
     private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
 
@@ -173,6 +198,9 @@
 
         eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
 
+        subsService = sadisService.getSubscriberInfoService();
+        bpService = sadisService.getBandwidthProfileService();
+
         // look for all provisioned devices in Sadis and create EAPOL flows for the
         // UNI ports
         Iterable<Device> devices = deviceService.getDevices();
@@ -187,6 +215,7 @@
                 .build();
 
         deviceService.addListener(deviceListener);
+        meterService.addListener(meterListener);
 
         log.info("Started with Application ID {}", appId.id());
     }
@@ -195,6 +224,7 @@
     public void deactivate() {
         componentConfigService.unregisterProperties(getClass(), false);
         deviceService.removeListener(deviceListener);
+        meterService.removeListener(meterListener);
         eventDispatcher.removeSink(AccessDeviceEvent.class);
         log.info("Stopped");
     }
@@ -230,6 +260,11 @@
             log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
                      enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
 
+            Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
+            if (d != null) {
+                deleteMeters = d;
+            }
+
         } catch (Exception e) {
             defaultVlan = DEFAULT_VLAN;
         }
@@ -255,12 +290,11 @@
 
         if (enableDhcpOnProvisioning) {
             processDhcpFilteringObjectives(port.deviceId(), port.port(), true,
-                                           true);
+                    true);
         }
         log.info("Programming vlans for subscriber: {}", sub);
         Optional<VlanId> defaultVlan = Optional.empty();
-        provisionVlans(port.deviceId(), uplinkPort.number(), port.port(),
-                       sub.cTag(), sub.sTag(), defaultVlan);
+        provisionVlans(port, uplinkPort.number(), defaultVlan, sub);
 
         if (enableIgmpOnProvisioning) {
             processIgmpFilteringObjectives(port.deviceId(), port.port(), true);
@@ -289,13 +323,12 @@
 
         if (enableDhcpOnProvisioning) {
             processDhcpFilteringObjectives(port.deviceId(), port.port(), false,
-                                           true);
+                    true);
         }
 
         log.info("Removing programmed vlans for subscriber: {}", subscriber);
         Optional<VlanId> defaultVlan = Optional.empty();
-        unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(),
-                              subscriber.cTag(), subscriber.sTag(), defaultVlan);
+        unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(), subscriber, defaultVlan);
 
         if (enableIgmpOnProvisioning) {
             processIgmpFilteringObjectives(port.deviceId(), port.port(), false);
@@ -438,19 +471,32 @@
         return null;
     }
 
+    private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
+        if (bandwidthProfile == null) {
+            return null;
+        }
+        return bpService.get(bandwidthProfile);
+    }
+
     private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
-                                       PortNumber subscriberPort, VlanId cVlan,
-                                       VlanId sVlan, Optional<VlanId> defaultVlan) {
+                                       PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
+                                       Optional<VlanId> defaultVlan) {
 
         CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
         CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
 
+        VlanId deviceVlan = subscriber.sTag();
+        VlanId subscriberVlan = subscriber.cTag();
+
+        MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
+        MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
+
         ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
-                                                      cVlan, sVlan,
-                                                      defaultVlan);
+                subscriberVlan, deviceVlan,
+                defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
         ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
-                                                          cVlan, sVlan,
-                                                          defaultVlan);
+                subscriberVlan, deviceVlan,
+                defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
 
         flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
             @Override
@@ -479,38 +525,49 @@
         upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
             if (upStatus == null && downStatus == null) {
                 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
-                                           deviceId,
-                                           sVlan,
-                                           cVlan));
+                        deviceId,
+                        deviceVlan,
+                        subscriberVlan));
             } else if (downStatus != null) {
                 log.error("Subscriber with vlan {} on device {} " +
-                                  "on port {} failed downstream uninstallation: {}",
-                          cVlan, deviceId, subscriberPort, downStatus);
+                                "on port {} failed downstream uninstallation: {}",
+                        subscriberVlan, deviceId, subscriberPort, downStatus);
             } else if (upStatus != null) {
                 log.error("Subscriber with vlan {} on device {} " +
-                                  "on port {} failed upstream uninstallation: {}",
-                          cVlan, deviceId, subscriberPort, upStatus);
+                                "on port {} failed upstream uninstallation: {}",
+                        subscriberVlan, deviceId, subscriberPort, upStatus);
             }
         }, oltInstallers);
 
     }
 
-    private void provisionVlans(DeviceId deviceId, PortNumber uplinkPort,
-                                PortNumber subscriberPort,
-                                VlanId subscriberVlan, VlanId deviceVlan,
-                                Optional<VlanId> defaultVlan) {
+    private void provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
+                                SubscriberAndDeviceInformation sub) {
+
+        log.info("Provisioning vlans...");
+
+        DeviceId deviceId = port.deviceId();
+        PortNumber subscriberPort = port.port();
+        VlanId deviceVlan = sub.sTag();
+        VlanId subscriberVlan = sub.cTag();
+        int techProfId = sub.technologyProfileId();
+
+        BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
+        BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
+
+        MeterId usptreamMeterId = createMeter(deviceId, upstreamBpInfo);
+        MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
 
         CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
         CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
 
         ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
-                                                      subscriberVlan, deviceVlan,
-                                                      defaultVlan);
-
+                subscriberVlan, deviceVlan,
+                defaultVlan, usptreamMeterId, techProfId);
 
         ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
-                                                          subscriberVlan, deviceVlan,
-                                                          defaultVlan);
+                subscriberVlan, deviceVlan,
+                defaultVlan, downstreamMeterId, techProfId);
 
         flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
             @Override
@@ -539,39 +596,97 @@
         upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
             if (upStatus == null && downStatus == null) {
                 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
-                                           deviceId,
-                                           deviceVlan,
-                                           subscriberVlan));
+                        deviceId,
+                        deviceVlan,
+                        subscriberVlan));
 
             } else if (downStatus != null) {
                 log.error("Subscriber with vlan {} on device {} " +
-                                  "on port {} failed downstream installation: {}",
-                          subscriberVlan, deviceId, subscriberPort, downStatus);
+                                "on port {} failed downstream installation: {}",
+                        subscriberVlan, deviceId, subscriberPort, downStatus);
             } else if (upStatus != null) {
                 log.error("Subscriber with vlan {} on device {} " +
-                                  "on port {} failed upstream installation: {}",
-                          subscriberVlan, deviceId, subscriberPort, upStatus);
+                                "on port {} failed upstream installation: {}",
+                        subscriberVlan, deviceId, subscriberPort, upStatus);
             }
         }, oltInstallers);
 
     }
 
+    private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
+
+        if (bpInfo == null) {
+            log.warn("Bandwidth profile information is not found");
+            return null;
+        }
+
+        MeterId meterId = bpInfoToMeter.get(bpInfo.id());
+        if (meterId != null) {
+            log.info("Meter is already added. MeterId {}", meterId);
+            return meterId;
+        }
+
+        List<Band> meterBands = createMeterBands(bpInfo);
+
+        MeterRequest meterRequest = DefaultMeterRequest.builder()
+                .withBands(meterBands)
+                .withUnit(Meter.Unit.KB_PER_SEC)
+                .forDevice(deviceId)
+                .fromApp(appId)
+                .burst()
+                .add();
+
+        Meter meter = meterService.submit(meterRequest);
+        bpInfoToMeter.put(bpInfo.id(), meter.id());
+        log.info("Meter is created. Meter Id {}", meter.id());
+        return meter.id();
+    }
+
+    private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
+        List<Band> meterBands = new ArrayList<>();
+
+        meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
+        meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
+
+        if (bpInfo.assuredInformationRate() != 0) {
+            meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
+        }
+        return meterBands;
+    }
+
+    private Band createMeterBand(long rate, Long burst) {
+        return DefaultBand.builder()
+                .withRate(rate) //already Kbps
+                .burstSize(burst) // already Kbits
+                .ofType(Band.Type.DROP) // no matter
+                .build();
+    }
+
     private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
                                                     PortNumber subscriberPort,
                                                     VlanId subscriberVlan,
                                                     VlanId deviceVlan,
-                                                    Optional<VlanId> defaultVlan) {
+                                                    Optional<VlanId> defaultVlan,
+                                                    MeterId meterId,
+                                                    int techProfId) {
         TrafficSelector downstream = DefaultTrafficSelector.builder()
                 .matchVlanId(deviceVlan)
                 .matchInPort(uplinkPort)
                 .matchInnerVlanId(subscriberVlan)
                 .build();
 
-        TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
+        TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
                 .popVlan()
                 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
-                .setOutput(subscriberPort)
-                .build();
+                .setOutput(subscriberPort);
+
+        if (meterId != null) {
+            downstreamTreatmentBuilder.meter(meterId);
+        }
+
+        if (techProfId != -1) {
+            downstreamTreatmentBuilder.transition(techProfId);
+        }
 
         return DefaultForwardingObjective.builder()
                 .withFlag(ForwardingObjective.Flag.VERSATILE)
@@ -579,27 +694,45 @@
                 .makePermanent()
                 .withSelector(downstream)
                 .fromApp(appId)
-                .withTreatment(downstreamTreatment);
+                .withTreatment(downstreamTreatmentBuilder.build());
     }
 
     private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
                                                   PortNumber subscriberPort,
                                                   VlanId subscriberVlan,
                                                   VlanId deviceVlan,
-                                                  Optional<VlanId> defaultVlan) {
+                                                  Optional<VlanId> defaultVlan,
+                                                  MeterId meterId,
+                                                  int technologyProfileId) {
+
+
+        VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
+
+        if (subscriberVlan.toShort() == 4096) {
+            dVlan = subscriberVlan;
+        }
+
         TrafficSelector upstream = DefaultTrafficSelector.builder()
-                .matchVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
+                .matchVlanId(dVlan)
                 .matchInPort(subscriberPort)
                 .build();
 
 
-        TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
+        TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
                 .pushVlan()
                 .setVlanId(subscriberVlan)
                 .pushVlan()
                 .setVlanId(deviceVlan)
-                .setOutput(uplinkPort)
-                .build();
+                .setOutput(uplinkPort);
+
+        if (meterId != null) {
+            upstreamTreatmentBuilder.meter(meterId);
+        }
+
+        if (technologyProfileId != -1) {
+            upstreamTreatmentBuilder.transition(technologyProfileId);
+
+        }
 
         return DefaultForwardingObjective.builder()
                 .withFlag(ForwardingObjective.Flag.VERSATILE)
@@ -607,9 +740,8 @@
                 .makePermanent()
                 .withSelector(upstream)
                 .fromApp(appId)
-                .withTreatment(upstreamTreatment);
+                .withTreatment(upstreamTreatmentBuilder.build());
     }
-
     private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
                                            PortNumber subscriberPort,
                                            VlanId innerVlan,
@@ -656,11 +788,11 @@
         upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
             if (downStatus != null) {
                 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
-                        "on port {} failed downstream installation: {}",
+                                "on port {} failed downstream installation: {}",
                         innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
             } else if (upStatus != null) {
                 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
-                        "on port {} failed upstream installation: {}",
+                                "on port {} failed upstream installation: {}",
                         innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
             }
         }, oltInstallers);
@@ -757,11 +889,11 @@
         upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
             if (downStatus != null) {
                 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
-                        "on port {} failed downstream uninstallation: {}",
+                                "on port {} failed downstream uninstallation: {}",
                         innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
             } else if (upStatus != null) {
                 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
-                        "on port {} failed upstream uninstallation: {}",
+                                "on port {} failed upstream uninstallation: {}",
                         innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
             }
         }, oltInstallers);
@@ -778,21 +910,21 @@
                 .withKey(Criteria.matchInPort(port))
                 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
                 .withMeta(DefaultTrafficTreatment.builder()
-                                  .setOutput(PortNumber.CONTROLLER).build())
+                        .setOutput(PortNumber.CONTROLLER).build())
                 .fromApp(appId)
                 .withPriority(10000)
                 .add(new ObjectiveContext() {
                     @Override
                     public void onSuccess(Objective objective) {
                         log.info("Eapol filter for {} on {} {}.",
-                                 devId, port, (install) ? "installed" : "removed");
+                                devId, port, (install) ? "installed" : "removed");
                     }
 
                     @Override
                     public void onError(Objective objective, ObjectiveError error) {
                         log.info("Eapol filter for {} on {} failed {} because {}",
-                                 devId, port, (install) ? "installation" : "removal",
-                                 error);
+                                devId, port, (install) ? "installation" : "removal",
+                                error);
                     }
                 });
 
@@ -901,7 +1033,7 @@
                 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
                 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
                 .withMeta(DefaultTrafficTreatment.builder()
-                                  .setOutput(PortNumber.CONTROLLER).build())
+                        .setOutput(PortNumber.CONTROLLER).build())
                 .fromApp(appId)
                 .withPriority(10000)
                 .add(new ObjectiveContext() {
@@ -929,7 +1061,7 @@
             return;
         }
 
-       DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+        DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
 
         builder = install ? builder.permit() : builder.deny();
 
@@ -938,21 +1070,21 @@
                 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
                 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
                 .withMeta(DefaultTrafficTreatment.builder()
-                                  .setOutput(PortNumber.CONTROLLER).build())
+                        .setOutput(PortNumber.CONTROLLER).build())
                 .fromApp(appId)
                 .withPriority(10000)
                 .add(new ObjectiveContext() {
                     @Override
                     public void onSuccess(Objective objective) {
                         log.info("Igmp filter for {} on {} {}.",
-                                 devId, port, (install) ? "installed" : "removed");
+                                devId, port, (install) ? "installed" : "removed");
                     }
 
                     @Override
                     public void onError(Objective objective, ObjectiveError error) {
                         log.info("Igmp filter for {} on {} failed {} because {}.",
-                                 devId, port, (install) ? "installation" : "removal",
-                                 error);
+                                devId, port, (install) ? "installation" : "removal",
+                                error);
                     }
                 });
 
@@ -968,11 +1100,10 @@
     private void checkAndCreateDeviceFlows(Device dev) {
         // we create only for the ones we are master of
         if (!mastershipService.isLocalMaster(dev.id())) {
-                return;
+            return;
         }
         // check if this device is provisioned in Sadis
-        String devSerialNo = dev.serialNumber();
-        SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
+        SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
         log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
 
         if (deviceInfo != null) {
@@ -999,8 +1130,7 @@
      */
     private Port getUplinkPort(Device dev) {
         // check if this device is provisioned in Sadis
-        String devSerialNo = dev.serialNumber();
-        SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
+        SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
         log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
         if (deviceInfo == null) {
             log.warn("Device {} is not configured in SADIS .. cannot fetch device"
@@ -1042,8 +1172,7 @@
 
     private SubscriberAndDeviceInformation getOltInfo(Device dev) {
         String devSerialNo = dev.serialNumber();
-        SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
-        return deviceInfo;
+        return subsService.get(devSerialNo);
     }
 
     private class InternalDeviceListener implements DeviceListener {
@@ -1147,4 +1276,45 @@
             });
         }
     }
-}
+
+    private class InternalMeterListener implements MeterListener {
+
+        @Override
+        public void event(MeterEvent meterEvent) {
+            if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
+                log.debug("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
+                Meter meter = meterEvent.subject();
+                if (meter != null && appId.equals(meter.appId())) {
+                    deleteMeter(meter.deviceId(), meter.id());
+                }
+            } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
+                log.debug("Meter removed event is received. Meter is {}", meterEvent.subject());
+                removeMeterFromBpMap(meterEvent.subject());
+            }
+        }
+
+        private void deleteMeter(DeviceId deviceId, MeterId meterId) {
+            Meter meter = meterService.getMeter(deviceId, meterId);
+            MeterRequest meterRequest = DefaultMeterRequest.builder()
+                    .withBands(meter.bands())
+                    .withUnit(meter.unit())
+                    .forDevice(deviceId)
+                    .fromApp(appId)
+                    .burst()
+                    .remove();
+
+            meterService.withdraw(meterRequest, meterId);
+
+        }
+
+        private void removeMeterFromBpMap(Meter meter) {
+            for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
+                if (entry.getValue().equals(meter.id())) {
+                    bpInfoToMeter.remove(entry.getKey());
+                    log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
+                    break;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/resources/any_vlan_cfg.json b/app/src/main/resources/any_vlan_cfg.json
new file mode 100644
index 0000000..0c42301
--- /dev/null
+++ b/app/src/main/resources/any_vlan_cfg.json
@@ -0,0 +1,62 @@
+{
+"apps" : {
+  "org.opencord.sadis" : {
+      "sadis" : {
+        "integration" : {
+          "cache" : {
+            "enabled" : true,
+            "maxsize" : 40,
+            "ttl" : "PT1m"
+          }
+        },
+        "entries" : [ {
+          "id" : "s1-eth1",
+          "cTag" : 4096,
+          "sTag" : 4,
+          "nasPortId" : "s1-eth1",
+          "technologyProfileId" : 10,
+          "upstreamBandwidthProfile" : "High-Speed-Internet",
+          "downstreamBandwidthProfile" : "User1-Specific"
+        }, {
+          "id" : "1",
+          "hardwareIdentifier" : "00:00:00:00:00:01",
+          "ipAddress" : "127.0.0.1",
+          "uplinkPort": "2"
+        } ]
+      },
+         "bandwidthprofile":{
+            "integration":{
+               "cache":{
+                  "enabled":true,
+                  "maxsize":40,
+                  "ttl":"PT1m"
+               }
+            },
+            "entries":[
+               {
+                  "id":"High-Speed-Internet",
+                  "cir":200000000,
+                  "cbs":348000,
+                  "eir":10000000,
+                  "ebs":348000,
+                  "air":10000000
+               },
+               {
+                  "id":"User1-Specific",
+                  "cir":300000000,
+                  "cbs":348000,
+                  "eir":20000000,
+                  "ebs":348000
+               }
+            ]
+         }
+    }
+  },
+   "devices":{
+      "of:0000000000000001":{
+         "basic":{
+            "driver":"pmc-olt"
+         }
+      }
+   }
+}
diff --git a/app/src/main/resources/cfg.json b/app/src/main/resources/cfg.json
new file mode 100644
index 0000000..0b61e65
--- /dev/null
+++ b/app/src/main/resources/cfg.json
@@ -0,0 +1,33 @@
+{  
+"apps" : {
+  "org.opencord.sadis" : {
+      "sadis" : {
+        "integration" : {
+          "cache" : {
+            "enabled" : true,
+            "maxsize" : 50,
+            "ttl" : "PT1m"
+          }
+        },
+        "entries" : [ {
+          "id" : "s1-eth1",
+          "cTag" : 2,
+          "sTag" : 4,
+          "nasPortId" : "s1-eth1"
+        }, {
+          "id" : "1",
+          "hardwareIdentifier" : "00:00:00:00:00:01",
+          "ipAddress" : "127.0.0.1",
+          "uplinkPort": "2"
+        } ]
+      }
+    }
+  },
+   "devices":{  
+      "of:0000000000000001":{
+         "basic":{
+            "driver":"pmc-olt"
+         }
+      }
+   }
+}
diff --git a/app/src/main/resources/custom-topo.py b/app/src/main/resources/custom-topo.py
new file mode 100644
index 0000000..dfb414d
--- /dev/null
+++ b/app/src/main/resources/custom-topo.py
@@ -0,0 +1,69 @@
+'''
+ 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.
+
+'''
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.net import Mininet
+from mininet.topo import Topo
+from mininet.node import RemoteController, UserSwitch
+
+class MinimalTopo( Topo ):
+    "Minimal topology with a single switch and two hosts"
+
+    def build( self ):
+        # Create two hosts.
+        h1 = self.addHost( 'h1' )
+        h2 = self.addHost( 'h2' )
+
+        # Create a switch
+        s1 = self.addSwitch( 's1', cls=UserSwitch)
+
+        # Add links between the switch and each host
+        self.addLink( s1, h1 )
+        self.addLink( s1, h2 )
+
+def runMinimalTopo():
+    "Bootstrap a Mininet network using the Minimal Topology"
+
+    # Create an instance of our topology
+    topo = MinimalTopo()
+
+    # Create a network based on the topology using OVS and controlled by
+    # a remote controller.
+    net = Mininet(
+        topo=topo,
+        controller=lambda name: RemoteController( name, ip='127.0.0.1' ),
+        switch=UserSwitch,
+        autoSetMacs=True )
+
+    # Actually start the network
+    net.start()
+
+    # Drop the user in to a CLI so user can run commands.
+    CLI( net )
+
+    # After the user exits the CLI, shutdown the network.
+    net.stop()
+
+if __name__ == '__main__':
+    # This runs if this file is executed directly
+    setLogLevel( 'info' )
+    runMinimalTopo()
+
+# Allows the file to be imported using `mn --custom <filename> --topo minimal`
+topos = {
+    'minimal': MinimalTopo
+}
diff --git a/app/src/main/resources/vlan_cfg.json b/app/src/main/resources/vlan_cfg.json
new file mode 100644
index 0000000..133aed7
--- /dev/null
+++ b/app/src/main/resources/vlan_cfg.json
@@ -0,0 +1,62 @@
+{
+"apps" : {
+  "org.opencord.sadis" : {
+      "sadis" : {
+        "integration" : {
+          "cache" : {
+            "enabled" : true,
+            "maxsize" : 60,
+            "ttl" : "PT1m"
+          }
+        },
+        "entries" : [ {
+          "id" : "s1-eth1",
+          "cTag" : 2,
+          "sTag" : 4,
+          "nasPortId" : "s1-eth1",
+          "technologyProfileId" : 10,
+          "upstreamBandwidthProfile" : "High-Speed-Internet",
+          "downstreamBandwidthProfile" : "User1-Specific"
+        }, {
+          "id" : "1",
+          "hardwareIdentifier" : "00:00:00:00:00:01",
+          "ipAddress" : "127.0.0.1",
+          "uplinkPort": "2"
+        } ]
+      },
+         "bandwidthprofile":{
+            "integration":{
+               "cache":{
+                  "enabled":true,
+                  "maxsize":40,
+                  "ttl":"PT1m"
+               }
+            },
+            "entries":[
+               {
+                  "id":"High-Speed-Internet",
+                  "cir":200000000,
+                  "cbs":348000,
+                  "eir":10000000,
+                  "ebs":348000,
+                  "air":10000000
+               },
+               {
+                  "id":"User1-Specific",
+                  "cir":300000000,
+                  "cbs":348000,
+                  "eir":20000000,
+                  "ebs":348000
+               }
+            ]
+         }
+    }
+  },
+   "devices":{
+      "of:0000000000000001":{
+         "basic":{
+            "driver":"pmc-olt"
+         }
+      }
+   }
+}
diff --git a/app/src/test/java/org/opencord/olt/impl/OltTest.java b/app/src/test/java/org/opencord/olt/impl/OltTest.java
index 1878c74..a925aa3 100644
--- a/app/src/test/java/org/opencord/olt/impl/OltTest.java
+++ b/app/src/test/java/org/opencord/olt/impl/OltTest.java
@@ -38,8 +38,10 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.provider.ProviderId;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
-import org.opencord.sadis.SubscriberAndDeviceInformationService;
+import org.opencord.sadis.SadisService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,7 +64,9 @@
     public void setUp() {
         olt = new Olt();
         olt.deviceService = new MockDeviceService();
-        olt.subsService = new MockSubService();
+        olt.sadisService = new MockSadisService();
+        olt.subsService = olt.sadisService.getSubscriberInfoService();
+
     }
 
     /**
@@ -166,7 +170,21 @@
         }
     }
 
-    private class MockSubService implements SubscriberAndDeviceInformationService {
+    private class MockSadisService implements SadisService {
+
+
+        @Override
+        public BaseInformationService<SubscriberAndDeviceInformation> getSubscriberInfoService() {
+            return new MockSubService();
+        }
+
+        @Override
+        public BaseInformationService<BandwidthProfileInformation> getBandwidthProfileService() {
+            return null;
+        }
+    }
+
+    private class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
         MockSubscriberAndDeviceInformation sub =
                 new MockSubscriberAndDeviceInformation(CLIENT_NAS_PORT_ID, CLIENT_C_TAG,
                                                        CLIENT_S_TAG, CLIENT_NAS_PORT_ID, CLIENT_CIRCUIT_ID, null, null);
diff --git a/pom.xml b/pom.xml
index 6b72058..b9d22a8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,18 +22,18 @@
     <parent>
         <groupId>org.onosproject</groupId>
         <artifactId>onos-dependencies</artifactId>
-        <version>1.13.1</version>
+        <version>1.13.6</version>
         <relativePath></relativePath>
     </parent>
 
     <groupId>org.opencord</groupId>
     <artifactId>olt</artifactId>
-    <version>2.1.0</version>
+    <version>3.0.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <onos.version>1.13.1</onos.version>
+        <onos.version>1.13.6</onos.version>
     </properties>
 
     <modules>