[SDFAB-355] Revisit MeterService and north abstractions

Change-Id: I685cb90d53f8aa61017ecda9fa7ff842e58e2940
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManager.java
index 9ec530b..9d4f7e4 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMeterManager.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.meter.DefaultMeter;
 import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterCellId;
 import org.onosproject.net.meter.MeterEvent;
 import org.onosproject.net.meter.MeterFailReason;
 import org.onosproject.net.meter.MeterFeatures;
@@ -139,11 +140,16 @@
 
     @Override
     public void withdraw(MeterRequest request, MeterId meterId) {
+        withdraw(request, (MeterCellId) meterId);
+    }
+
+    @Override
+    public void withdraw(MeterRequest request, MeterCellId meterCellId) {
         Meter.Builder mBuilder = DefaultMeter.builder()
                 .forDevice(request.deviceId())
                 .fromApp(request.appId())
                 .withBands(request.bands())
-                .withId(meterId)
+                .withCellId(meterCellId)
                 .withUnit(request.unit());
 
         if (request.isBurst()) {
@@ -158,6 +164,11 @@
 
     @Override
     public Meter getMeter(DeviceId deviceId, MeterId id) {
+        return getMeter(deviceId, (MeterCellId) id);
+    }
+
+    @Override
+    public Meter getMeter(DeviceId deviceId, MeterCellId id) {
         MeterKey key = MeterKey.key(deviceId, id);
         return store.getMeter(networkId(), key);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
index 681846f..f3e29fe 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
@@ -23,6 +23,7 @@
 import org.onosproject.net.DeviceId;
 
 import java.util.Collection;
+import java.util.Optional;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkArgument;
@@ -36,7 +37,7 @@
 
 
     private final MeterCellId cellId;
-    private final ApplicationId appId;
+    private final Optional<ApplicationId> appId;
     private final Unit unit;
     private final boolean burst;
     private final Collection<Band> bands;
@@ -48,8 +49,9 @@
     private long packets;
     private long bytes;
 
-    private DefaultMeter(DeviceId deviceId, MeterCellId cellId, ApplicationId appId,
-                         Unit unit, boolean burst, Collection<Band> bands,
+    private DefaultMeter(DeviceId deviceId, MeterCellId cellId,
+                         Optional<ApplicationId> appId, Unit unit,
+                         boolean burst, Collection<Band> bands,
                          Annotations... annotations) {
         super(annotations);
         this.deviceId = deviceId;
@@ -81,7 +83,8 @@
 
     @Override
     public ApplicationId appId() {
-        return appId;
+        return appId.orElse(null);
+        // TODO: Deprecate this API because AppId becomes optional in Meter
     }
 
     @Override
@@ -158,7 +161,7 @@
         return toStringHelper(this)
                 .add("device", deviceId)
                 .add("cellId", cellId)
-                .add("appId", appId.name())
+                .add("appId", appId.orElse(null))
                 .add("unit", unit)
                 .add("isBurst", burst)
                 .add("state", state)
@@ -190,7 +193,7 @@
     public static final class Builder implements Meter.Builder {
 
         private MeterCellId cellId;
-        private ApplicationId appId;
+        private Optional<ApplicationId> appId = Optional.empty();
         private Unit unit = Unit.KB_PER_SEC;
         private boolean burst = false;
         private Collection<Band> bands;
@@ -217,7 +220,7 @@
 
         @Override
         public Meter.Builder fromApp(ApplicationId appId) {
-            this.appId = appId;
+            this.appId = Optional.ofNullable(appId);
             return this;
         }
 
@@ -250,7 +253,6 @@
             checkNotNull(deviceId, "Must specify a device");
             checkNotNull(bands, "Must have bands.");
             checkArgument(!bands.isEmpty(), "Must have at least one band.");
-            checkNotNull(appId, "Must have an application id");
             checkArgument(cellId != null, "Must specify a cell id.");
             return new DefaultMeter(deviceId, cellId, appId, unit, burst, bands,
                                     annotations);
diff --git a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
index e6e2d1b..0dbd4f7 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
@@ -42,11 +42,14 @@
     private final DeviceId deviceId;
     private final Optional<MeterContext> context;
     private final Type op;
+    private final MeterScope scope;
+    private final Optional<Long> index;
 
     private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId,
                                 Meter.Unit unit, boolean burst,
                                 Collection<Band> bands, MeterContext context,
-                                Type op, Annotations... annotations) {
+                                Type op, MeterScope scope, Optional<Long> index,
+                                Annotations... annotations) {
         super(annotations);
         this.deviceId = deviceId;
         this.appId = appId;
@@ -55,6 +58,8 @@
         this.bands = bands;
         this.context = Optional.ofNullable(context);
         this.op = op;
+        this.scope = scope;
+        this.index = index;
     }
 
     @Override
@@ -88,7 +93,15 @@
         return context;
     }
 
+    @Override
+    public MeterScope scope() {
+        return scope;
+    }
 
+    @Override
+    public Optional<Long> index() {
+        return index;
+    }
 
     public static Builder builder() {
         return new Builder();
@@ -102,6 +115,8 @@
                 .add("unit", unit)
                 .add("isBurst", burst)
                 .add("bands", bands)
+                .add("scope", scope)
+                .add("desired index", index.orElse(null))
                 .add("annotations", annotations())
                 .toString();
     }
@@ -114,9 +129,9 @@
         private Collection<Band> bands;
         private DeviceId deviceId;
         private MeterContext context;
-        private Optional<MeterId> desiredId = Optional.empty();
         private Annotations annotations;
-
+        private MeterScope scope = MeterScope.globalScope();
+        private Optional<Long> desiredIndex = Optional.empty();
 
         @Override
         public MeterRequest.Builder forDevice(DeviceId deviceId) {
@@ -131,19 +146,19 @@
         }
 
         @Override
-        public MeterRequest.Builder  withUnit(Meter.Unit unit) {
+        public MeterRequest.Builder withUnit(Meter.Unit unit) {
             this.unit = unit;
             return this;
         }
 
         @Override
-        public MeterRequest.Builder  burst() {
+        public MeterRequest.Builder burst() {
             this.burst = true;
             return this;
         }
 
         @Override
-        public MeterRequest.Builder  withBands(Collection<Band> bands) {
+        public MeterRequest.Builder withBands(Collection<Band> bands) {
             this.bands = ImmutableSet.copyOf(bands);
             return this;
         }
@@ -161,17 +176,29 @@
         }
 
         @Override
+        public MeterRequest.Builder withScope(MeterScope scope) {
+            this.scope = scope;
+            return this;
+        }
+
+        @Override
+        public MeterRequest.Builder withIndex(Long index) {
+            this.desiredIndex = Optional.ofNullable(index);
+            return this;
+        }
+
+        @Override
         public MeterRequest add() {
             validate();
-            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands,
-                                           context, Type.ADD, annotations);
+            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, context,
+                                           Type.ADD, scope, desiredIndex, annotations);
         }
 
         @Override
         public MeterRequest remove() {
             validate();
-            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands,
-                                           context, Type.REMOVE, annotations);
+            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, context,
+                                           Type.REMOVE, scope, desiredIndex, annotations);
         }
 
         private void validate() {
@@ -179,6 +206,9 @@
             checkNotNull(bands, "Must have bands.");
             checkArgument(!bands.isEmpty(), "Must have at least one band.");
             checkNotNull(appId, "Must have an application id");
+            if (desiredIndex.isPresent()) {
+                checkArgument(desiredIndex.get() >= 0, "Desired index cannot be negative");
+            }
         }
 
 
diff --git a/core/api/src/main/java/org/onosproject/net/meter/Meter.java b/core/api/src/main/java/org/onosproject/net/meter/Meter.java
index 63b6db3..64379d3 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/Meter.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/Meter.java
@@ -37,7 +37,12 @@
         /**
          * Kilo bits per second.
          */
-        KB_PER_SEC
+        KB_PER_SEC,
+
+        /**
+         * Bytes per second.
+         */
+        BYTES_PER_SEC
     }
 
     /**
@@ -65,10 +70,13 @@
 
     /**
      * The id of the application which created this meter.
+     * Could be null if the meter is read from the controller southbound.
      *
      * @return an application id
      */
     ApplicationId appId();
+    // TODO: Deprecate this and create a new method returns an Optional ApplicationId
+    // TODO: Or introduce MeterEntry on south and keep this method
 
     /**
      * The unit used within this meter.
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java b/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
index a2be1ce..e156fd4 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
@@ -77,6 +77,20 @@
     Optional<MeterContext> context();
 
     /**
+     * Returns the scope of this meter request.
+     *
+     * @return a meter scope
+     */
+    MeterScope scope();
+
+    /**
+     * Returns the desired meter index of this meter request.
+     *
+     * @return an optional long index
+     */
+    Optional<Long> index();
+
+    /**
      * A meter builder.
      */
     interface Builder {
@@ -139,6 +153,22 @@
         Builder withAnnotations(Annotations annotations);
 
         /**
+         * Sets the scope.
+         *
+         * @param scope a meter scope
+         * @return this
+         */
+        Builder withScope(MeterScope scope);
+
+        /**
+         * Sets the index.
+         *
+         * @param index an optional index
+         * @return this
+         */
+        Builder withIndex(Long index);
+
+        /**
          * Requests the addition of a meter.
          *
          * @return a meter request
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterService.java b/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
index 6339101..5b3ca3b 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
@@ -42,19 +42,40 @@
      *
      * @param meter a meter to remove
      * @param meterId the meter id of the meter to remove.
+     * @deprecated in onos-2.5, replace MeterId with MeterCellId
      */
+    @Deprecated
     void withdraw(MeterRequest meter, MeterId meterId);
 
     /**
+     * Remove a meter from the system and the dataplane.
+     *
+     * @param meter a meter to remove
+     * @param meterCellId the meter cell id of the meter to remove.
+     */
+    void withdraw(MeterRequest meter, MeterCellId meterCellId);
+
+    /**
      * Fetch the meter by the meter id.
      *
      * @param deviceId a device id
      * @param id a meter id
      * @return a meter
+     * @deprecated in onos-2.5, Replace MeterId with MeterCellId
      */
+    @Deprecated
     Meter getMeter(DeviceId deviceId, MeterId id);
 
     /**
+     * Fetch the meter by the meter id.
+     *
+     * @param deviceId a device id
+     * @param id a meter cell id
+     * @return a meter
+     */
+    Meter getMeter(DeviceId deviceId, MeterCellId id);
+
+    /**
      * Fetches all the meters.
      *
      * @return a collection of meters
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterState.java b/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
index 78fdd90..c098d91 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
@@ -35,9 +35,4 @@
      */
     PENDING_REMOVE,
 
-    /**
-     * The meter has been removed.
-     */
-    REMOVED,
-
 }
diff --git a/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
index 7148c06..2a298b4 100644
--- a/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
@@ -36,11 +36,21 @@
     }
 
     @Override
+    public void withdraw(MeterRequest meter, MeterCellId meterCellId) {
+
+    }
+
+    @Override
     public Meter getMeter(DeviceId deviceId, MeterId id) {
         return null;
     }
 
     @Override
+    public Meter getMeter(DeviceId deviceId, MeterCellId meterCellId) {
+        return null;
+    }
+
+    @Override
     public Collection<Meter> getAllMeters() {
         return null;
     }
diff --git a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
index 805009d..9b786e5 100644
--- a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
+++ b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
@@ -34,7 +34,7 @@
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.meter.DefaultMeter;
 import org.onosproject.net.meter.Meter;
-import org.onosproject.net.meter.MeterCellId.MeterCellType;
+import org.onosproject.net.meter.MeterCellId;
 import org.onosproject.net.meter.MeterEvent;
 import org.onosproject.net.meter.MeterFailReason;
 import org.onosproject.net.meter.MeterFeatures;
@@ -46,6 +46,7 @@
 import org.onosproject.net.meter.MeterProviderRegistry;
 import org.onosproject.net.meter.MeterProviderService;
 import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterScope;
 import org.onosproject.net.meter.MeterService;
 import org.onosproject.net.meter.MeterState;
 import org.onosproject.net.meter.MeterStore;
@@ -53,6 +54,8 @@
 import org.onosproject.net.meter.MeterStoreResult;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.runtime.PiMeterCellId;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -252,13 +255,24 @@
     @Override
     public Meter submit(MeterRequest request) {
         checkNotNull(request, "request cannot be null.");
-        // Allocate an id and then submit the request
-        MeterId id = allocateMeterId(request.deviceId());
+        MeterCellId cellId;
+        if (request.index().isPresent()) {
+            // User provides index
+            if (request.scope().isGlobal()) {
+                cellId = MeterId.meterId(request.index().get());
+            } else {
+                cellId = PiMeterCellId.ofIndirect(
+                    PiMeterId.of(request.scope().id()), request.index().get());
+            }
+        } else {
+            // Allocate an id
+            cellId = allocateMeterId(request.deviceId(), request.scope());
+        }
         Meter.Builder mBuilder = DefaultMeter.builder()
                 .forDevice(request.deviceId())
                 .fromApp(request.appId())
                 .withBands(request.bands())
-                .withCellId(id)
+                .withCellId(cellId)
                 .withUnit(request.unit());
         if (request.isBurst()) {
             mBuilder.burst();
@@ -277,12 +291,17 @@
 
     @Override
     public void withdraw(MeterRequest request, MeterId meterId) {
+        withdraw(request, (MeterCellId) meterId);
+    }
+
+    @Override
+    public void withdraw(MeterRequest request, MeterCellId meterCellId) {
         checkNotNull(request, "request cannot be null.");
         Meter.Builder mBuilder = DefaultMeter.builder()
                 .forDevice(request.deviceId())
                 .fromApp(request.appId())
                 .withBands(request.bands())
-                .withCellId(meterId)
+                .withCellId(meterCellId)
                 .withUnit(request.unit());
 
         if (request.isBurst()) {
@@ -299,6 +318,11 @@
 
     @Override
     public Meter getMeter(DeviceId deviceId, MeterId id) {
+        return getMeter(deviceId, (MeterCellId) id);
+    }
+
+    @Override
+    public Meter getMeter(DeviceId deviceId, MeterCellId id) {
         MeterKey key = MeterKey.key(deviceId, id);
         return store.getMeter(key);
     }
@@ -320,6 +344,10 @@
         return store.allocateMeterId(deviceId);
     }
 
+    private MeterCellId allocateMeterId(DeviceId deviceId, MeterScope scope) {
+        return store.allocateMeterId(deviceId, scope);
+    }
+
     @Override
     public void freeMeterId(DeviceId deviceId, MeterId meterId) {
         // We delegate directly to the store
@@ -361,14 +389,14 @@
             // Each update on the store is reflected on this collection
             Collection<Meter> allMeters = store.getAllMeters(deviceId);
 
-            Map<MeterId, Meter> meterEntriesMap = meterEntries.stream()
-                    .collect(Collectors.toMap(Meter::id, Meter -> Meter));
+            Map<MeterCellId, Meter> meterEntriesMap = meterEntries.stream()
+                    .collect(Collectors.toMap(Meter::meterCellId, Meter -> Meter));
 
             // Look for meters defined in onos and missing in the device (restore)
             allMeters.stream().forEach(m -> {
                 if ((m.state().equals(MeterState.PENDING_ADD) ||
                         m.state().equals(MeterState.ADDED)) &&
-                        !meterEntriesMap.containsKey(m.id())) {
+                        !meterEntriesMap.containsKey(m.meterCellId())) {
                     // The meter is missing in the device. Reinstall!
                     log.debug("Adding meter missing in device {} {}", deviceId, m);
                     // offload the task to avoid the overloading of the sb threads
@@ -378,27 +406,21 @@
 
             // Look for meters defined in the device and not in onos (remove)
             meterEntriesMap.entrySet().stream()
-                    .filter(md -> !allMeters.stream().anyMatch(m -> m.id().equals(md.getKey())))
+                    .filter(md -> !allMeters.stream().anyMatch(m -> m.meterCellId().equals(md.getKey())))
                     .forEach(mio -> {
                         Meter meter = mio.getValue();
-                        // FIXME: Removing a meter is meaningful for OpenFlow, but not for P4Runtime.
-                        // In P4Runtime meter cells cannot be removed. For the
-                        // moment, we make the distinction between OpenFlow and
-                        // P4Runtime by looking at the MeterCellType (always
-                        // INDEX for OpenFlow).
-                        if (meter.meterCellId().type() == MeterCellType.INDEX) {
-                            // The meter is missing in onos. Uninstall!
-                            log.debug("Remove meter in device not in onos {} {}", deviceId, mio.getKey());
-                            // offload the task to avoid the overloading of the sb threads
-                            meterInstallers.execute(new MeterInstaller(deviceId, meter, MeterOperation.Type.REMOVE));
-                        }
+                        // The meter is missing in onos. Uninstall!
+                        log.debug("Remove meter in device not in onos {} {}", deviceId, mio.getKey());
+                        // offload the task to avoid the overloading of the sb threads
+                        meterInstallers.execute(new MeterInstaller(deviceId, meter, MeterOperation.Type.REMOVE));
                     });
 
             // Update the meter stats in the store (first time move the state from pending to added)
             Collection<Meter> addedMeters = Sets.newHashSet();
             meterEntries.stream()
                     .filter(m -> allMeters.stream()
-                            .anyMatch(sm -> sm.deviceId().equals(deviceId) && sm.id().equals(m.id())))
+                            .anyMatch(sm -> sm.deviceId().equals(deviceId) &&
+                             sm.meterCellId().equals(m.meterCellId())))
                     .forEach(m -> {
                         Meter updatedMeter = store.updateMeterState(m);
                         if (updatedMeter != null && updatedMeter.state() == MeterState.ADDED) {
@@ -409,20 +431,13 @@
             newAllMeters.removeAll(addedMeters);
 
             newAllMeters.forEach(m -> {
-                // FIXME: Installing a meter is meaningful for OpenFlow, but not for P4Runtime.
-                // It looks like this flow is used only for p4runtime to emulate the installation
-                // since meters are already instantiated - we need just modify the params.
-                if (m.state() == MeterState.PENDING_ADD && m.meterCellId().type() != MeterCellType.INDEX) {
-                    // offload the task to avoid the overloading of the sb threads
-                    log.debug("Modify meter {} in device {}", m.id(), deviceId);
-                    meterInstallers.execute(new MeterInstaller(m.deviceId(), m, MeterOperation.Type.MODIFY));
                 // Remove workflow. Regarding OpenFlow, meters have been removed from
                 // the device but they are still in the store, we will purge them definitely.
                 // Instead, P4Runtime devices will not remove the meter. The first workaround
                 // for P4Runtime will avoid to send a remove op. Then, we reach this point
                 // and we purge the meter from the store
-                } else if (m.state() == MeterState.PENDING_REMOVE) {
-                    log.debug("Delete meter {} now in store", m.id());
+                if (m.state() == MeterState.PENDING_REMOVE) {
+                    log.debug("Delete meter {} now in store", m.meterCellId());
                     store.purgeMeter(m);
                 }
             });
@@ -498,7 +513,7 @@
             NodeId master = mastershipService.getMasterFor(meter.deviceId());
             if (!Objects.equals(local, master)) {
                 log.trace("Not the master of device {}, skipping installation of the meter {}",
-                        meter.deviceId(), meter.id());
+                        meter.deviceId(), meter.meterCellId());
                 return;
             }
             MeterProvider p = getProvider(this.deviceId);
@@ -511,7 +526,7 @@
 
         @Override
         public int hint() {
-            return meter.id().hashCode();
+            return meter.meterCellId().hashCode();
         }
     }
 
diff --git a/core/protobuf/models/proto/net/meter/MeterEnumsProto.proto b/core/protobuf/models/proto/net/meter/MeterEnumsProto.proto
index 1b0bbf5..63a35b6 100644
--- a/core/protobuf/models/proto/net/meter/MeterEnumsProto.proto
+++ b/core/protobuf/models/proto/net/meter/MeterEnumsProto.proto
@@ -28,6 +28,11 @@
     * Kilo bits per second.
     */
     KB_PER_SEC = 1;
+
+    /**
+    * Bytes per second.
+    */
+    BYTES_PER_SEC = 2;
 }
 
 enum MeterStateProto {
@@ -45,11 +50,6 @@
     * The meter is in the process of being removed.
     */
     PENDING_REMOVE = 2;
-
-    /**
-    * The meter has been removed.
-    */
-    REMOVED = 3;
 }
 
 enum MeterRequestTypeProto {
diff --git a/core/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/meter/MeterEnumsProtoTranslator.java b/core/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/meter/MeterEnumsProtoTranslator.java
index b73117c..bb416de 100644
--- a/core/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/meter/MeterEnumsProtoTranslator.java
+++ b/core/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/meter/MeterEnumsProtoTranslator.java
@@ -42,6 +42,8 @@
                 return Optional.of(Meter.Unit.PKTS_PER_SEC);
             case KB_PER_SEC:
                 return Optional.of(Meter.Unit.KB_PER_SEC);
+            case BYTES_PER_SEC:
+                return Optional.of(Meter.Unit.BYTES_PER_SEC);
             default:
                 log.warn("Unrecognized MeterUnit gRPC message: {}", unit);
                 return Optional.empty();
@@ -60,6 +62,8 @@
                 return MeterEnumsProto.MeterUnitProto.PKTS_PER_SEC;
             case KB_PER_SEC:
                 return MeterEnumsProto.MeterUnitProto.KB_PER_SEC;
+            case BYTES_PER_SEC:
+                return MeterEnumsProto.MeterUnitProto.BYTES_PER_SEC;
             default:
                 log.warn("Unrecognized MeterUnit ONOS message: {}", unit);
                 return MeterEnumsProto.MeterUnitProto.UNRECOGNIZED;
@@ -80,8 +84,6 @@
                 return MeterEnumsProto.MeterStateProto.ADDED;
             case PENDING_REMOVE:
                 return MeterEnumsProto.MeterStateProto.PENDING_REMOVE;
-            case REMOVED:
-                return MeterEnumsProto.MeterStateProto.REMOVED;
             default:
                 log.warn("Unrecognized MeterState ONOS message: {}", meterState);
                 return MeterEnumsProto.MeterStateProto.UNRECOGNIZED;
diff --git a/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java b/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
index b2034dc..7f7873c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
@@ -614,7 +614,7 @@
         // Get a new value
         // If the value is smaller than the start index, get another one
         do {
-            id = meterIdGenerators.incrementAndGet(meterTableKey);
+            id = meterIdGenerators.getAndIncrement(meterTableKey);
         } while (id < startIndex);
         // Check with the end index, and if the value is bigger, cannot proceed
         if (id > endIndex) {
@@ -649,7 +649,7 @@
             return;
         }
         // Avoid to free meter not allocated
-        if (meterIdGenerators.get(meterTableKey) < index) {
+        if (meterIdGenerators.get(meterTableKey) <= index) {
             return;
         }
         // Update the availability