[SDFAB-500][SDFAB-527] Meters cleanup and leftovers
- Improve ONOS cli enabling CRUD of p4rt trtcm
- Improve ONOS rest enabling CRUD of p4rt trtcm
- Improve MeterService with scope defined reads and integrate in cli/rest
- Add support along the stack for BYTE_PER_SEC unit
- Add support along the stack for COMMITTED and PEAK bands
- Fix several bugs in ONOS cli/rest interfaces
- Improve REST codecs
- Fix NPE in MeterDriverProvider
- Improve PiMeterTransalation by enforcing trtcm config
- Implement explicit translation of the bands
- Fix ONOS reconciliation by removing from the mirror the wrong configs
- Remove unnecessary checks in MeterEntryCodec
- Update unit tests
It will follow a 2nd patch to complete SDFAB-527
Change-Id: I855235b17f60cb1d39f5b9a042c1015105a8a269
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 9d4f7e4..e98734d 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
@@ -40,6 +40,7 @@
import org.onosproject.net.meter.MeterListener;
import org.onosproject.net.meter.MeterOperation;
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.MeterStoreDelegate;
@@ -50,6 +51,7 @@
import org.slf4j.Logger;
import java.util.Collection;
+import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
@@ -180,6 +182,11 @@
}
@Override
+ public Collection<Meter> getMeters(DeviceId deviceId, MeterScope scope) {
+ return Collections.emptyList();
+ }
+
+ @Override
public Collection<Meter> getAllMeters() {
return store.getAllMeters(networkId());
}
diff --git a/cli/src/main/java/org/onosproject/cli/net/MeterAddCommand.java b/cli/src/main/java/org/onosproject/cli/net/MeterAddCommand.java
index 3e71ad9..4ddf91d 100644
--- a/cli/src/main/java/org/onosproject/cli/net/MeterAddCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/MeterAddCommand.java
@@ -28,6 +28,7 @@
import org.onosproject.net.meter.DefaultMeterRequest;
import org.onosproject.net.meter.Meter;
import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterScope;
import org.onosproject.net.meter.MeterService;
import static com.google.common.base.Strings.isNullOrEmpty;
@@ -45,9 +46,8 @@
private Meter.Unit unit;
private Set<Band> bands = new HashSet<>();
- private Long rate;
- private Long burstSize;
-
+ private MeterScope scope;
+ private Long index;
@Option(name = "-bd", aliases = "--bandDrop",
description = "Assign band DROP to this meter",
@@ -59,6 +59,16 @@
required = false, multiValued = false)
private boolean hasBandRemark = false;
+ @Option(name = "-by", aliases = "--bandYel",
+ description = "Assign band MARK_YELLOW to this meter",
+ required = false, multiValued = false)
+ private boolean hasBandYel = false;
+
+ @Option(name = "-bre", aliases = "--bandRed",
+ description = "Assign band MARK_RED to this meter",
+ required = false, multiValued = false)
+ private boolean hasBandRed = false;
+
@Option(name = "-up", aliases = "--unitPkts",
description = "Assign unit Packets per Second to this meter",
required = false, multiValued = false)
@@ -69,18 +79,31 @@
required = false, multiValued = false)
private boolean hasKbps = false;
+ @Option(name = "-ub", aliases = "--unitBytes",
+ description = "Assign unit Bytes per Second to this meter",
+ required = false, multiValued = false)
+ private boolean hasBytes = false;
+
@Option(name = "-ib", aliases = "--isBurst",
description = "Set meter applicable only to burst",
required = false, multiValued = false)
private boolean isBurst = false;
@Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth",
- required = false, multiValued = false)
- private String bandwidthString = null;
+ required = false, multiValued = true)
+ private String[] bandwidthString = null;
@Option(name = "-bs", aliases = "--burstSize", description = "Burst size",
+ required = false, multiValued = true)
+ private String[] burstSizeString = null;
+
+ @Option(name = "-sc", aliases = "--scope", description = "Scope",
required = false, multiValued = false)
- private String burstSizeString = null;
+ private String scopeString = null;
+
+ @Option(name = "-id", aliases = "--index", description = "Index",
+ required = false, multiValued = false)
+ private String indexString = null;
@Argument(index = 0, name = "uri", description = "Device ID",
required = true, multiValued = false)
@@ -93,53 +116,110 @@
// check units
if (hasPkts) {
unit = Meter.Unit.PKTS_PER_SEC;
- } else {
+ } else if (hasKbps) {
unit = Meter.Unit.KB_PER_SEC;
+ } else if (hasBytes) {
+ unit = Meter.Unit.BYTES_PER_SEC;
}
+ int numBands = 0;
+ if (hasBandDrop) {
+ numBands++;
+ }
+ if (hasBandRemark) {
+ numBands++;
+ }
+ if (hasBandYel) {
+ numBands++;
+ }
+ if (hasBandRed) {
+ numBands++;
+ }
+
+ long[] rates = new long[numBands];
+ long[] bursts = new long[numBands];
// check rate (does not take into account if it is kbps or pkts)
- if (!isNullOrEmpty(bandwidthString)) {
- rate = Long.parseLong(bandwidthString);
- } else {
- rate = 500L;
- }
-
- // burst size
- if (!isNullOrEmpty(burstSizeString)) {
- burstSize = Long.parseLong(burstSizeString);
- } else {
- burstSize = 0L;
+ if (bandwidthString != null && bandwidthString.length == numBands &&
+ burstSizeString != null && burstSizeString.length == numBands) {
+ for (int i = 0; i < bandwidthString.length; i++) {
+ rates[i] = 500L;
+ bursts[i] = 0L;
+ if (!isNullOrEmpty(bandwidthString[i])) {
+ rates[i] = Long.parseLong(bandwidthString[i]);
+ }
+ if (!isNullOrEmpty(burstSizeString[i])) {
+ bursts[i] = Long.parseLong(burstSizeString[i]);
+ }
+ }
+ } else if (bandwidthString != null && bandwidthString.length < numBands &&
+ burstSizeString != null && burstSizeString.length < numBands) {
+ for (int i = 0; i < numBands; i++) {
+ rates[i] = 500L;
+ bursts[i] = 0L;
+ if (i < bandwidthString.length && !isNullOrEmpty(bandwidthString[i])) {
+ rates[i] = Long.parseLong(bandwidthString[i]);
+ }
+ if (i < burstSizeString.length && !isNullOrEmpty(burstSizeString[i])) {
+ bursts[i] = Long.parseLong(burstSizeString[i]);
+ }
+ }
}
// Create bands
+ int i = 0;
if (hasBandDrop) {
Band band = DefaultBand.builder()
.ofType(Band.Type.DROP)
- .withRate(rate)
- .burstSize(burstSize)
+ .withRate(rates[i])
+ .burstSize(bursts[i])
.build();
bands.add(band);
+ i++;
}
if (hasBandRemark) {
Band band = DefaultBand.builder()
.ofType(Band.Type.REMARK)
- .withRate(rate)
- .burstSize(burstSize)
+ .withRate(rates[i])
+ .burstSize(bursts[i])
+ .build();
+ bands.add(band);
+ i++;
+ }
+ if (hasBandYel) {
+ Band band = DefaultBand.builder()
+ .ofType(Band.Type.MARK_YELLOW)
+ .withRate(rates[i])
+ .burstSize(bursts[i])
+ .build();
+ bands.add(band);
+ i++;
+ }
+ if (hasBandRed) {
+ Band band = DefaultBand.builder()
+ .ofType(Band.Type.MARK_RED)
+ .withRate(rates[i])
+ .burstSize(bursts[i])
.build();
bands.add(band);
}
+
// default band is drop
if (bands.size() == 0) {
Band band = DefaultBand.builder()
.ofType(Band.Type.DROP)
- .withRate(rate)
- .burstSize(burstSize)
+ .withRate(500L)
+ .burstSize(0L)
.build();
bands.add(band);
}
+ if (!isNullOrEmpty(scopeString)) {
+ scope = MeterScope.of(scopeString);
+ }
-
+ if (!isNullOrEmpty(indexString) && scope != null) {
+ index = Long.parseLong(indexString);
+ }
}
@Override
@@ -151,22 +231,32 @@
checkOptions();
-
MeterRequest.Builder builder = DefaultMeterRequest.builder()
.forDevice(deviceId)
.fromApp(coreService.registerApplication(appId))
.withUnit(unit)
.withBands(bands);
-
if (isBurst) {
builder = builder.burst();
}
+ // Scope is by default global but we can still provide the index
+ // otherwise we can specify both scope and index or let the meter
+ // service allocate the meter for us. User defined index requires
+ // the user defined mode being active.
+ if (scope != null) {
+ builder = builder.withScope(scope);
+ }
+
+ if (index != null) {
+ builder = builder.withIndex(index);
+ }
+
MeterRequest request = builder.add();
Meter m = service.submit(request);
- log.info("Requested meter with id {}: {}", m.id().toString(), m.toString());
- print("Requested meter with id %s: %s", m.id().toString(), m.toString());
+ log.info("Requested meter with cellId {}: {}", m.meterCellId().toString(), m.toString());
+ print("Requested meter with cellId %s: %s", m.meterCellId().toString(), m.toString());
}
}
diff --git a/cli/src/main/java/org/onosproject/cli/net/MeterRemoveCommand.java b/cli/src/main/java/org/onosproject/cli/net/MeterRemoveCommand.java
index 6c3f1bb..941c910 100644
--- a/cli/src/main/java/org/onosproject/cli/net/MeterRemoveCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/MeterRemoveCommand.java
@@ -18,19 +18,21 @@
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.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
-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.MeterCellId;
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterScope;
import org.onosproject.net.meter.MeterService;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.runtime.PiMeterCellId;
-import java.util.Collections;
+import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Remove existing meter from device.
@@ -45,9 +47,13 @@
@Completion(DeviceIdCompleter.class)
private String uri = null;
- @Argument(index = 1, name = "meterId", description = "Meter ID hexadecimal value",
+ @Argument(index = 1, name = "index", description = "Index",
required = true, multiValued = false)
- private String meterIdstr = null;
+ private String indexString = null;
+
+ @Option(name = "-sc", aliases = "--scope", description = "Scope",
+ required = false, multiValued = false)
+ private String scopeString = null;
private final String appId = "org.onosproject.cli.meterCmd";
@@ -57,19 +63,27 @@
CoreService coreService = get(CoreService.class);
DeviceId deviceId = DeviceId.deviceId(uri);
- MeterId meterId = MeterId.meterId(Long.parseLong(meterIdstr, 16));
- Band b = new DefaultBand(Band.Type.DROP, 0L, 0L, (short) 0);
+ MeterScope scope = MeterScope.globalScope();
+ if (!isNullOrEmpty(scopeString)) {
+ scope = MeterScope.of(scopeString);
+ }
+
+ MeterCellId meterCellId;
+ long index = Long.parseLong(indexString);
+ if (scope.equals(MeterScope.globalScope())) {
+ meterCellId = MeterId.meterId(index);
+ } else {
+ meterCellId = PiMeterCellId.ofIndirect(PiMeterId.of(scope.id()), index);
+ }
MeterRequest.Builder builder = DefaultMeterRequest.builder()
.forDevice(deviceId)
- .withBands(Collections.singleton(b))
- .withUnit(Meter.Unit.PKTS_PER_SEC)
.fromApp(coreService.registerApplication(appId));
MeterRequest meterRequest = builder.remove();
- service.withdraw(meterRequest, meterId);
- log.info("Requested meter removal: {}", meterRequest.toString());
+ service.withdraw(builder.remove(), meterCellId);
- print("Requested meter removal: %s", meterRequest.toString());
+ log.info("Requested meter {} removal: {}", meterCellId.toString(), meterRequest.toString());
+ print("Requested meter %s removal: %s", meterCellId.toString(), meterRequest.toString());
}
}
diff --git a/cli/src/main/java/org/onosproject/cli/net/MetersListCommand.java b/cli/src/main/java/org/onosproject/cli/net/MetersListCommand.java
index 4fe3590..c5e7fbf 100644
--- a/cli/src/main/java/org/onosproject/cli/net/MetersListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/MetersListCommand.java
@@ -15,16 +15,20 @@
*/
package org.onosproject.cli.net;
-import com.google.common.collect.Collections2;
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.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.DeviceId;
import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterCellId;
import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterScope;
import org.onosproject.net.meter.MeterService;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.runtime.PiMeterCellId;
import java.util.Collection;
@@ -43,35 +47,60 @@
@Completion(DeviceIdCompleter.class)
String uri = null;
- @Argument(index = 1, name = "meter", description = "Meter ID",
+ @Argument(index = 1, name = "index", description = "Index",
required = false, multiValued = false)
- String meterstr = null;
+ private String indexString = null;
- MeterId meterId = null;
+ @Option(name = "-sc", aliases = "--scope", description = "Scope",
+ required = false, multiValued = false)
+ private String scopeString = null;
+
+ MeterScope meterScope;
+ Long index;
+ MeterCellId meterCellId;
@Override
protected void doExecute() {
- if (!isNullOrEmpty(meterstr)) {
- meterId = MeterId.meterId(Long.parseLong(meterstr));
+ if (!isNullOrEmpty(scopeString)) {
+ meterScope = MeterScope.of(scopeString);
+ }
+
+ if (!isNullOrEmpty(indexString)) {
+ index = Long.parseLong(indexString);
+ if (meterScope == null) {
+ meterScope = MeterScope.globalScope();
+ }
+ }
+
+ if (index != null) {
+ if (meterScope != null && meterScope.equals(MeterScope.globalScope())) {
+ meterCellId = MeterId.meterId(index);
+ } else if (meterScope != null) {
+ meterCellId = PiMeterCellId.ofIndirect(PiMeterId.of(meterScope.id()), index);
+ }
}
MeterService service = get(MeterService.class);
- if (meterId != null && uri != null) {
- Meter m = service.getMeter(DeviceId.deviceId(uri), meterId);
- if (m != null) {
- print("%s", m);
- } else {
- error("Meter %s not found for device %s", meterId, uri);
- }
+ Collection<Meter> meters;
+ if (isNullOrEmpty(uri)) {
+ meters = service.getAllMeters();
+ printMeters(meters);
} else {
- Collection<Meter> meters = service.getAllMeters();
- if (uri == null) {
+ if (meterCellId != null) {
+ Meter m = service.getMeter(DeviceId.deviceId(uri), meterCellId);
+ if (m != null) {
+ print("%s", m);
+ } else {
+ error("Meter %s not found for device %s", meterCellId, uri);
+ }
+ } else if (meterScope != null) {
+ meters = service.getMeters(DeviceId.deviceId(uri), meterScope);
printMeters(meters);
} else {
- printMeters(Collections2.filter(meters,
- m -> m.deviceId().equals(DeviceId.deviceId(uri))));
+ meters = service.getMeters(DeviceId.deviceId(uri));
+ printMeters(meters);
}
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/meter/Band.java b/core/api/src/main/java/org/onosproject/net/meter/Band.java
index 9f9479c..befbead 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/Band.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/Band.java
@@ -51,8 +51,27 @@
* Defines a meter band with no action, used to mark
* packets internally in the pipeline, i.e. without
* modifying the packet headers.
+ *
+ * @deprecated in onos-2.5, replace by MARK_YELLOW and MARK_RED
*/
+ @Deprecated
NONE,
+
+ /**
+ * Defines a meter band for the configuration of the committed
+ * rate AND the committed burst size. Used in conjunction with MARK_RED
+ * to implement a srTCM or trTCM, see RFCs 2697 and 2698 respectively.
+ */
+ MARK_YELLOW,
+
+ /**
+ * Defines a meter band for the configuration of the peak rate
+ * AND the peak burst size OR the excess burst size. When used to
+ * configure a srTCM excess rate must be 0. Used in conjunction with
+ * MARK_YELLOW to implement a srTCM or trTCM, see RFCs 2697 and 2698
+ * respectively.
+ */
+ MARK_RED,
}
/**
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 0dbd4f7..617151d 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
@@ -33,8 +33,6 @@
*/
public final class DefaultMeterRequest extends AbstractAnnotated implements MeterRequest {
-
-
private final ApplicationId appId;
private final Meter.Unit unit;
private final boolean burst;
@@ -122,6 +120,8 @@
}
public static final class Builder implements MeterRequest.Builder {
+ // Relevant only for delete
+ private static final Band DUMMY_BAND = new DefaultBand(Band.Type.DROP, 0L, 0L, (short) 0);
private ApplicationId appId;
private Meter.Unit unit = Meter.Unit.KB_PER_SEC;
@@ -196,6 +196,11 @@
@Override
public MeterRequest remove() {
+ // Allow to create the removal request without specifying bands
+ if (bands == null || bands.isEmpty()) {
+ bands = ImmutableSet.of(DUMMY_BAND);
+ }
+
validate();
return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, context,
Type.REMOVE, scope, desiredIndex, annotations);
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 5b3ca3b..2d37f87 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
@@ -91,6 +91,15 @@
Collection<Meter> getMeters(DeviceId deviceId);
/**
+ * Fetches the meters by the device id and scope.
+ *
+ * @param deviceId a device id
+ * @param scope meters scope
+ * @return a collection of meters
+ */
+ Collection<Meter> getMeters(DeviceId deviceId, MeterScope scope);
+
+ /**
* Allocates a new meter id in the system.
*
* @param deviceId the device id
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java b/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
index 7f4de4b..4abf233 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
@@ -118,6 +118,17 @@
Collection<Meter> getAllMeters(DeviceId deviceId);
/**
+ * Returns all meters stored in the store for a
+ * precise device and scope.
+ *
+ * @param deviceId a device id
+ * @param scope meters scope
+ * @return an immutable copy of the meters stored for a given device
+ * withing a given scope
+ */
+ Collection<Meter> getAllMeters(DeviceId deviceId, MeterScope scope);
+
+ /**
* Update the store by deleting the failed meter.
* Notifies the delegate that the meter failed to allow it
* to nofity the app.
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
index b1dbcf5..ea8c34d 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
@@ -27,21 +27,33 @@
*/
@Beta
public final class PiMeterBand {
+ private final PiMeterBandType type;
private final long rate;
private final long burst;
/**
* Creates a band with rate and burst.
*
+ * @param type type of this band
* @param rate rate of this band
* @param burst burst of this band
*/
- public PiMeterBand(long rate, long burst) {
+ public PiMeterBand(PiMeterBandType type, long rate, long burst) {
+ this.type = type;
this.rate = rate;
this.burst = burst;
}
/**
+ * Returns the type of this band.
+ *
+ * @return type of this band
+ */
+ public PiMeterBandType type() {
+ return type;
+ }
+
+ /**
* Returns the rate of this band.
*
* @return rate of this band
@@ -61,7 +73,7 @@
@Override
public int hashCode() {
- return Objects.hash(rate, burst);
+ return Objects.hash(type, rate, burst);
}
@Override
@@ -71,7 +83,8 @@
}
if (obj instanceof PiMeterBand) {
PiMeterBand that = (PiMeterBand) obj;
- return Objects.equals(rate, that.rate) &&
+ return Objects.equals(type, that.type) &&
+ Objects.equals(rate, that.rate) &&
Objects.equals(burst, that.burst);
}
@@ -80,6 +93,7 @@
public String toString() {
return toStringHelper(this)
+ .add("type", type)
.add("rate", rate)
.add("burst", burst).toString();
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBandType.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBandType.java
new file mode 100644
index 0000000..ee15a57
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBandType.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.onosproject.net.pi.runtime;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Type of meter band of a protocol-independent pipeline.
+ */
+@Beta
+public enum PiMeterBandType {
+ /**
+ * Committed band config.
+ */
+ COMMITTED("committed"),
+
+ /**
+ * Peak band config.
+ */
+ PEAK("peak");
+
+ private final String humanReadableName;
+
+ PiMeterBandType(String humanReadableName) {
+ this.humanReadableName = humanReadableName;
+ }
+
+ /**
+ * Returns a human readable representation of this PI meter band type (useful
+ * for logging).
+ *
+ * @return string
+ */
+ public String humanReadableName() {
+ return humanReadableName;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
index d3da340..ecbfe07 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
@@ -19,13 +19,12 @@
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import org.onosproject.net.DeviceId;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
-import java.util.List;
+import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -36,7 +35,7 @@
public final class PiMeterCellConfig implements PiEntity {
private final PiMeterCellId cellId;
- private final ImmutableList<PiMeterBand> piMeterBands;
+ private final ImmutableMap<PiMeterBandType, PiMeterBand> piMeterBands;
/**
* Creates a new meter cell configuration for the given cell identifier and meter bands.
@@ -44,9 +43,9 @@
* @param cellId meter cell identifier
* @param piMeterBands meter bands
*/
- private PiMeterCellConfig(PiMeterCellId cellId, Collection<PiMeterBand> piMeterBands) {
+ private PiMeterCellConfig(PiMeterCellId cellId, Map<PiMeterBandType, PiMeterBand> piMeterBands) {
this.cellId = cellId;
- this.piMeterBands = ImmutableList.copyOf(piMeterBands);
+ this.piMeterBands = ImmutableMap.copyOf(piMeterBands);
}
/**
@@ -59,11 +58,11 @@
}
/**
- * Returns the collection of bands of this cell.
+ * Returns the map of bands of this cell.
*
* @return meter bands
*/
- public Collection<PiMeterBand> meterBands() {
+ public Map<PiMeterBandType, PiMeterBand> meterBands() {
return piMeterBands;
}
@@ -88,6 +87,24 @@
}
/**
+ * Returns the committed configuration if present.
+ *
+ * @return the committed band. Null otherwise
+ */
+ public PiMeterBand committedBand() {
+ return piMeterBands.get(PiMeterBandType.COMMITTED);
+ }
+
+ /**
+ * Returns the peak configuration if present.
+ *
+ * @return the peak band. Null otherwise
+ */
+ public PiMeterBand peakBand() {
+ return piMeterBands.get(PiMeterBandType.PEAK);
+ }
+
+ /**
* Returns a PiMeterCellConfig with no bands.
* Used to reset a PI meter cell.
*
@@ -95,7 +112,7 @@
* @return a PiMeterCellConfig with no bands
*/
public static PiMeterCellConfig reset(PiMeterCellId piMeterCellId) {
- return new PiMeterCellConfig(piMeterCellId, Collections.emptyList());
+ return new PiMeterCellConfig(piMeterCellId, Collections.emptyMap());
}
@Override
@@ -118,8 +135,7 @@
}
PiMeterCellConfig that = (PiMeterCellConfig) o;
- return piMeterBands.containsAll((that.piMeterBands)) &&
- piMeterBands.size() == that.piMeterBands.size() &&
+ return Objects.equal(piMeterBands, that.piMeterBands) &&
Objects.equal(cellId, that.cellId);
}
@@ -146,8 +162,8 @@
}
public static final class Builder {
- private PiMeterCellId cellId;
- private List<PiMeterBand> bands = new ArrayList<>();
+ private PiMeterCellId cellId;
+ private Map<PiMeterBandType, PiMeterBand> bands = Maps.newHashMap();
private Builder() {
@@ -173,7 +189,31 @@
* @return this
*/
public PiMeterCellConfig.Builder withMeterBand(PiMeterBand band) {
- this.bands.add(band);
+ this.bands.put(band.type(), band);
+ return this;
+ }
+
+ /**
+ * Sets the committed band of this meter.
+ *
+ * @param rate committed rate
+ * @param burst committed burst
+ * @return this
+ */
+ public PiMeterCellConfig.Builder withCommittedBand(long rate, long burst) {
+ this.bands.put(PiMeterBandType.COMMITTED, new PiMeterBand(PiMeterBandType.COMMITTED, rate, burst));
+ return this;
+ }
+
+ /**
+ * Sets the peak band of this meter.
+ *
+ * @param rate peak rate
+ * @param burst peak burst
+ * @return this
+ */
+ public PiMeterCellConfig.Builder withPeakBand(long rate, long burst) {
+ this.bands.put(PiMeterBandType.PEAK, new PiMeterBand(PiMeterBandType.PEAK, rate, burst));
return this;
}
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 2a298b4..86795e9 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
@@ -61,6 +61,11 @@
}
@Override
+ public Collection<Meter> getMeters(DeviceId deviceId, MeterScope scope) {
+ return null;
+ }
+
+ @Override
public MeterId allocateMeterId(DeviceId deviceId) {
return null;
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/MeterBandCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/MeterBandCodec.java
index 4621e94..3cb68a0 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/MeterBandCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/MeterBandCodec.java
@@ -21,17 +21,14 @@
import org.onosproject.net.meter.Band;
import org.onosproject.net.meter.Band.Builder;
import org.onosproject.net.meter.DefaultBand;
-import org.slf4j.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
-import static org.slf4j.LoggerFactory.getLogger;
/**
* Meter band JSON codec.
*/
public final class MeterBandCodec extends JsonCodec<Band> {
- private final Logger log = getLogger(getClass());
// JSON field names
private static final String TYPE = "type";
@@ -93,6 +90,18 @@
builder.ofType(type);
builder.dropPrecedence(precedence);
break;
+ case "NONE":
+ type = Band.Type.NONE;
+ builder.ofType(type);
+ break;
+ case "MARK_YELLOW":
+ type = Band.Type.MARK_YELLOW;
+ builder.ofType(type);
+ break;
+ case "MARK_RED":
+ type = Band.Type.MARK_RED;
+ builder.ofType(type);
+ break;
default:
nullIsIllegal(type, "The requested type " + typeStr + " is not defined for band.");
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/MeterCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/MeterCodec.java
index 5cf1d13..26b6677 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/MeterCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/MeterCodec.java
@@ -21,17 +21,14 @@
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.meter.Band;
import org.onosproject.net.meter.Meter;
-import org.slf4j.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
/**
* Meter JSON codec.
*/
public final class MeterCodec extends JsonCodec<Meter> {
- private final Logger log = getLogger(getClass());
// JSON field names
private static final String ID = "id";
@@ -51,7 +48,7 @@
public ObjectNode encode(Meter meter, CodecContext context) {
checkNotNull(meter, "Meter cannot be null");
ObjectNode result = context.mapper().createObjectNode()
- .put(ID, meter.id().toString())
+ .put(ID, meter.meterCellId().toString())
.put(LIFE, meter.life())
.put(PACKETS, meter.packetsSeen())
.put(BYTES, meter.bytesSeen())
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/MeterRequestCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/MeterRequestCodec.java
index d254428..d46e257 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/MeterRequestCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/MeterRequestCodec.java
@@ -26,29 +26,32 @@
import org.onosproject.net.meter.DefaultMeterRequest;
import org.onosproject.net.meter.Meter;
import org.onosproject.net.meter.MeterRequest;
-import org.slf4j.Logger;
+import org.onosproject.net.meter.MeterScope;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.nullIsIllegal;
-import static org.slf4j.LoggerFactory.getLogger;
/**
* MeterRequest JSON codec.
*/
public final class MeterRequestCodec extends JsonCodec<MeterRequest> {
- private final Logger log = getLogger(getClass());
// JSON field names
private static final String DEVICE_ID = "deviceId";
private static final String UNIT = "unit";
private static final String BANDS = "bands";
- public static final String REST_APP_ID = "org.onosproject.rest";
+ private static final String SCOPE = "scope";
+ private static final String INDEX = "index";
+ private static final String REST_APP_ID = "org.onosproject.rest";
private static final String MISSING_MEMBER_MESSAGE = " member is required in MeterRequest";
+ private ApplicationId applicationId;
+
@Override
public MeterRequest decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
@@ -56,14 +59,17 @@
}
final JsonCodec<Band> meterBandCodec = context.codec(Band.class);
- CoreService coreService = context.getService(CoreService.class);
+
// parse device id
DeviceId deviceId = DeviceId.deviceId(nullIsIllegal(json.get(DEVICE_ID),
DEVICE_ID + MISSING_MEMBER_MESSAGE).asText());
// application id
- ApplicationId appId = coreService.registerApplication(REST_APP_ID);
+ if (applicationId == null) {
+ CoreService coreService = context.getService(CoreService.class);
+ applicationId = coreService.registerApplication(REST_APP_ID);
+ }
// parse burst
boolean burst = false;
@@ -83,6 +89,9 @@
case "PKTS_PER_SEC":
meterUnit = Meter.Unit.PKTS_PER_SEC;
break;
+ case "BYTES_PER_SEC":
+ meterUnit = Meter.Unit.BYTES_PER_SEC;
+ break;
default:
nullIsIllegal(meterUnit, "The requested unit " + unit + " is not defined for meter.");
}
@@ -98,22 +107,39 @@
});
}
- MeterRequest meterRequest;
- if (burst) {
- meterRequest = DefaultMeterRequest.builder()
- .fromApp(appId)
- .forDevice(deviceId)
- .withUnit(meterUnit)
- .withBands(bandList)
- .burst().add();
- } else {
- meterRequest = DefaultMeterRequest.builder()
- .fromApp(appId)
- .forDevice(deviceId)
- .withUnit(meterUnit)
- .withBands(bandList).add();
+ // parse scope and index
+ JsonNode scopeJson = json.get(SCOPE);
+ MeterScope scope = null;
+ if (scopeJson != null && !isNullOrEmpty(scopeJson.asText())) {
+ scope = MeterScope.of(scopeJson.asText());
}
- return meterRequest;
+ JsonNode indexJson = json.get(INDEX);
+ Long index = null;
+ if (indexJson != null && !isNullOrEmpty(indexJson.asText()) && scope != null) {
+ index = indexJson.asLong();
+ }
+
+ // build the final request
+ MeterRequest.Builder meterRequest = DefaultMeterRequest.builder();
+ if (scope != null) {
+ meterRequest.withScope(scope);
+ }
+
+ if (index != null) {
+ meterRequest.withIndex(index);
+ }
+
+ meterRequest.fromApp(applicationId)
+ .forDevice(deviceId)
+ .withUnit(meterUnit)
+ .withBands(bandList);
+
+ if (burst) {
+ meterRequest.burst();
+ }
+
+ return meterRequest.add();
}
+
}
diff --git a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterDriverProvider.java b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterDriverProvider.java
index cf7d198..b1422e8 100644
--- a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterDriverProvider.java
+++ b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterDriverProvider.java
@@ -152,7 +152,9 @@
private void getMeterFeatures(DeviceId deviceId) {
Collection<MeterFeatures> meterFeatures = Collections.emptySet();
try {
- meterFeatures = getMeterProgrammable(deviceId).getMeterFeatures().get(pollFrequency, TimeUnit.SECONDS);
+ if (isMeterProgrammable(deviceId)) {
+ meterFeatures = getMeterProgrammable(deviceId).getMeterFeatures().get(pollFrequency, TimeUnit.SECONDS);
+ }
} catch (Exception e) {
log.warn("Unable to get the Meter Features from {}, error: {}", deviceId, e.getMessage());
log.debug("Exception: ", e);
@@ -160,6 +162,11 @@
meterProviderService.pushMeterFeatures(deviceId, meterFeatures);
}
+ private boolean isMeterProgrammable(DeviceId deviceId) {
+ Device device = deviceService.getDevice(deviceId);
+ return device.is(MeterProgrammable.class);
+ }
+
private MeterProgrammable getMeterProgrammable(DeviceId deviceId) {
Device device = deviceService.getDevice(deviceId);
if (device.is(MeterProgrammable.class)) {
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 b2e6730..98e79a9 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
@@ -343,8 +343,12 @@
@Override
public Collection<Meter> getMeters(DeviceId deviceId) {
- return store.getAllMeters().stream().filter(m ->
- m.deviceId().equals(deviceId)).collect(Collectors.toList());
+ return store.getAllMeters(deviceId);
+ }
+
+ @Override
+ public Collection<Meter> getMeters(DeviceId deviceId, MeterScope scope) {
+ return store.getAllMeters(deviceId, scope);
}
@Override
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiMeterTranslatorImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiMeterTranslatorImpl.java
index 3831699..48cd4ba 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiMeterTranslatorImpl.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiMeterTranslatorImpl.java
@@ -20,7 +20,6 @@
import org.onosproject.net.meter.Band;
import org.onosproject.net.meter.Meter;
import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.runtime.PiMeterBand;
import org.onosproject.net.pi.runtime.PiMeterCellConfig;
import org.onosproject.net.pi.runtime.PiMeterCellId;
import org.onosproject.net.pi.service.PiTranslationException;
@@ -36,7 +35,7 @@
// Hides constructor.
}
- private static final int TRTCM_RATES = 2;
+ private static final int TCM_BANDS = 2;
/**
* Returns a PI meter config equivalent to the given meter, for the given pipeconf and device.
@@ -53,23 +52,52 @@
throw new PiTranslationException("PI meter cell type must be PIPELINE_INDEPENDENT!");
}
- // FIXME: we might want to move this check to P4Runtime driver or protocol layer.
- // In general, This check is more of P4Runtime limitation, we should do this check in the low level layer.
- if (meter.bands().size() > TRTCM_RATES) {
- throw new PiTranslationException("PI meter can not have more than 2 bands!");
+ // In general, this check is more of P4Runtime limitation, we should do this check in the low level layer.
+ // At the same time we could extend to support other configurations (for example srTCM).
+ // TODO implement SRTCM and TRTCM helper classes to improve readability of the code.
+ // Or in future when we support other markers we can simply create two different methods.
+ if (meter.bands().size() != TCM_BANDS) {
+ throw new PiTranslationException("PI meter must have 2 bands in order to implement TCM metering!");
}
-
- PiMeterCellConfig.Builder builder = PiMeterCellConfig.builder();
- for (Band band : meter.bands()) {
- if (band.type() != Band.Type.NONE) {
- throw new PiTranslationException("PI meter can not have band with other types except NONE!");
- }
-
- PiMeterBand piMeterBand = new PiMeterBand(band.rate(), band.burst());
- builder.withMeterBand(piMeterBand);
+ final Band[] bands = meter.bands().toArray(new Band[0]);
+ // Validate proper config of the TCM settings.
+ if ((bands[0].type() != Band.Type.MARK_YELLOW && bands[0].type() != Band.Type.MARK_RED) ||
+ (bands[1].type() != Band.Type.MARK_YELLOW && bands[1].type() != Band.Type.MARK_RED) ||
+ (bands[0].type() == bands[1].type())) {
+ throw new PiTranslationException("PI TCM meter must have a MARK_YELLOW band and a MARK_RED band!");
}
- return builder.withMeterCellId((PiMeterCellId) meter.meterCellId()).build();
+ // Validate proper config of the trTCM settings
+ if (bands[0].burst() <= 0 || bands[1].burst() <= 0) {
+ throw new PiTranslationException("PI trTCM meter can not have band with burst <= 0!");
+ }
+ if (bands[0].rate() <= 0 || bands[1].rate() <= 0) {
+ throw new PiTranslationException("PI trTCM meter can not have band with rate <= 0!");
+ }
+
+ long cir, cburst, pir, pburst;
+ if (bands[0].type() == Band.Type.MARK_YELLOW) {
+ cir = bands[0].rate();
+ cburst = bands[0].burst();
+ pir = bands[1].rate();
+ pburst = bands[1].burst();
+ } else {
+ pir = bands[0].rate();
+ pburst = bands[0].burst();
+ cir = bands[1].rate();
+ cburst = bands[1].burst();
+ }
+
+ if (cir > pir) {
+ throw new PiTranslationException("PI trTCM meter must have a pir >= cir!");
+ }
+
+ return PiMeterCellConfig.builder()
+ .withCommittedBand(cir, cburst)
+ .withPeakBand(pir, pburst)
+ .withMeterCellId((PiMeterCellId) meter.meterCellId())
+ .build();
}
+
}
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 afc6d94..7d8c7a5 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
@@ -365,6 +365,21 @@
}
@Override
+ public Collection<Meter> getAllMeters(DeviceId deviceId, MeterScope scope) {
+ if (scope.equals(MeterScope.globalScope())) {
+ return Collections2.transform(
+ Collections2.filter(ImmutableSet.copyOf(metersMap.values()),
+ (MeterData m) -> m.meter().meterCellId().type() == INDEX),
+ MeterData::meter);
+ }
+ return Collections2.transform(
+ Collections2.filter(ImmutableSet.copyOf(metersMap.values()),
+ (MeterData m) -> m.meter().meterCellId().type() == PIPELINE_INDEPENDENT &&
+ ((PiMeterCellId) m.meter().meterCellId()).meterId().id().equals(scope.id())),
+ MeterData::meter);
+ }
+
+ @Override
public void failedMeter(MeterOperation op, MeterFailReason reason) {
// Meter ops failed (got notification from the sb)
MeterKey key = MeterKey.key(op.meter().deviceId(), op.meter().meterCellId());
@@ -701,8 +716,9 @@
return null;
});
notifyDelegate(new MeterEvent(MeterEvent.Type.METER_ADDED, data.meter()));
- // Update stats case
- } else if (data.meter().referenceCount() == 0) {
+ // Update stats case - we report reference count zero only for INDEX based meters
+ } else if (data.meter().referenceCount() == 0 &&
+ data.meter().meterCellId().type() == INDEX) {
notifyDelegate(new MeterEvent(MeterEvent.Type.METER_REFERENCE_COUNT_ZERO,
data.meter()));
}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java
index a7dbadd..9a04a35 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeMeterProgrammable.java
@@ -23,7 +23,6 @@
import org.onosproject.drivers.p4runtime.mirror.TimedEntry;
import org.onosproject.net.DeviceId;
import org.onosproject.net.meter.Band;
-import org.onosproject.net.meter.DefaultBand;
import org.onosproject.net.meter.DefaultMeter;
import org.onosproject.net.meter.DefaultMeterFeatures;
import org.onosproject.net.meter.Meter;
@@ -42,7 +41,6 @@
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.net.pi.service.PiTranslationException;
import org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest;
-import org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteResponse;
import java.util.Collection;
import java.util.Collections;
@@ -52,12 +50,8 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.Lock;
-import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.meter.MeterOperation.Type.ADD;
-import static org.onosproject.net.meter.MeterOperation.Type.MODIFY;
-import static org.onosproject.net.meter.MeterOperation.Type.REMOVE;
import static org.onosproject.p4runtime.api.P4RuntimeWriteClient.UpdateType;
/**
@@ -178,15 +172,23 @@
}
}
- // Reset all inconsistent meter cells to default state
+ // Reset all inconsistent meter cells to the default config
if (!inconsistentOrDefaultCells.isEmpty()) {
WriteRequest request = client.write(p4DeviceId, pipeconf);
for (PiMeterCellId cellId : inconsistentOrDefaultCells) {
PiMeterCellHandle handle = PiMeterCellHandle.of(deviceId, cellId);
appendEntryToWriteRequestOrSkip(request, handle, PiMeterCellConfig.reset(cellId));
}
- WriteResponse response = request.submitSync();
- meterMirror.applyWriteResponse(response);
+
+ request.submit().whenComplete((response, ex) -> {
+ if (ex != null) {
+ log.error("Exception resetting inconsistent meter entries", ex);
+ } else {
+ log.debug("Successfully removed {} out of {} inconsistent meter entries",
+ response.success().size(), response.all().size());
+ }
+ response.success().forEach(entity -> meterMirror.remove((PiMeterCellHandle) entity.handle()));
+ });
}
return CompletableFuture.completedFuture(meters);
@@ -219,10 +221,11 @@
"one in in translation store: device={}, store=Default", deviceId, config);
} else {
log.debug("Configs obtained from device: {} and present in the store are default, " +
- "skipping the forge section");
+ "skipping the forge section", deviceId);
}
return null;
}
+
// The config is not consistent
if (!translatedEntity.get().translated().equals(config)) {
log.warn("Meter Cell Config obtained from device {} is different from " +
@@ -230,20 +233,20 @@
deviceId, config, translatedEntity.get().translated());
return null;
}
+
+ // Big problems in the mirror ? This could happen in case of issues with
+ // the eventual consistent maps used in the AbstractDistributedP4RuntimeMirror
if (timedEntry == null) {
log.warn("Meter entry handle not found in device mirror: {}", handle);
return null;
}
- // Forge a meter with MeterCellId, Bands and DeviceId
+ Meter original = translatedEntity.get().original();
+ // Forge a meter with MeterCellId, Bands and DeviceId using the original value.
// Other values are not required because we cannot retrieve them from the south
DefaultMeter meter = (DefaultMeter) DefaultMeter.builder()
- .withBands(config.meterBands().stream().map(b -> DefaultBand.builder()
- .withRate(b.rate())
- .burstSize(b.burst())
- .ofType(Band.Type.NONE)
- .build()).collect(Collectors.toList()))
- .withCellId(config.cellId())
+ .withBands(original.bands())
+ .withCellId(original.meterCellId())
.forDevice(deviceId)
.build();
meter.setState(MeterState.ADDED);
@@ -270,7 +273,7 @@
/**
* P4 meter features builder.
*/
- public class P4RuntimeMeterFeaturesBuilder {
+ public static class P4RuntimeMeterFeaturesBuilder {
private final PiMeterModel piMeterModel;
private DeviceId deviceId;
@@ -290,9 +293,7 @@
* @return the meter features object
*/
public MeterFeatures build() {
- /*
- * We set the basic values before to extract the other information.
- */
+ // We set the basic values before to extract the other information.
MeterFeatures.Builder builder = DefaultMeterFeatures.builder()
.forDevice(deviceId)
// The scope value will be PiMeterId
@@ -301,36 +302,31 @@
.withMaxColors(PI_METER_MAX_COLOR)
.withStartIndex(PI_METER_START_INDEX)
.withEndIndex(piMeterModel.size() - 1);
- /*
- * Pi meter only support NONE type
- */
+
+ // p4rt meters support MARK_YELLOW (committed config) and
+ // MARK_RED (peak config) band types.
Set<Band.Type> bands = Sets.newHashSet();
- bands.add(Band.Type.NONE);
+ bands.add(Band.Type.MARK_YELLOW);
+ bands.add(Band.Type.MARK_RED);
builder.withBandTypes(bands);
- /*
- * We extract the supported units;
- */
+
+ // We extract the supported units;
Set<Meter.Unit> units = Sets.newHashSet();
if (piMeterModel.unit() == PiMeterModel.Unit.BYTES) {
- units.add(Meter.Unit.KB_PER_SEC);
+ units.add(Meter.Unit.BYTES_PER_SEC);
} else if (piMeterModel.unit() == PiMeterModel.Unit.PACKETS) {
units.add(Meter.Unit.PKTS_PER_SEC);
}
- builder.withUnits(units);
- /*
- * Burst is supported ?
- */
- builder.hasBurst(true);
- /*
- * Stats are supported ?
- */
- builder.hasStats(false);
- return builder.build();
+ return builder.withUnits(units)
+ .hasBurst(true)
+ .hasStats(false)
+ .build();
}
/**
* To build an empty meter features.
+ *
* @param deviceId the device id
* @return the meter features
*/
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/MeterEntryCodec.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/MeterEntryCodec.java
index 88f0639..3584527 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/MeterEntryCodec.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/MeterEntryCodec.java
@@ -32,37 +32,19 @@
extends AbstractEntityCodec<PiMeterCellConfig, PiMeterCellHandle,
P4RuntimeOuterClass.MeterEntry, Object> {
- static P4RuntimeOuterClass.MeterConfig getP4Config(PiMeterCellConfig piConfig)
- throws CodecException {
+ static P4RuntimeOuterClass.MeterConfig getP4Config(PiMeterCellConfig piConfig) {
// The config has no band, we don't have to create a P4RT meter config
if (piConfig.isDefaultConfig()) {
return null;
}
- // If it is not a reset operation, the config must be a modify config and has exactly 2 bands
- if (!piConfig.isModifyConfig()) {
- throw new CodecException("Number of meter bands should be 2 (Modify) or 0 (Reset)");
- }
- final PiMeterBand[] bands = piConfig.meterBands().toArray(new PiMeterBand[0]);
- long cir, cburst, pir, pburst;
- // The band with bigger burst is peak if rate of them is equal.
- if (bands[0].rate() > bands[1].rate() ||
- (bands[0].rate() == bands[1].rate() &&
- bands[0].burst() >= bands[1].burst())) {
- cir = bands[1].rate();
- cburst = bands[1].burst();
- pir = bands[0].rate();
- pburst = bands[0].burst();
- } else {
- cir = bands[0].rate();
- cburst = bands[0].burst();
- pir = bands[1].rate();
- pburst = bands[1].burst();
- }
+
+ final PiMeterBand committedBand = piConfig.committedBand();
+ final PiMeterBand peakBand = piConfig.peakBand();
return P4RuntimeOuterClass.MeterConfig.newBuilder()
- .setCir(cir)
- .setCburst(cburst)
- .setPir(pir)
- .setPburst(pburst)
+ .setCir(committedBand.rate())
+ .setCburst(committedBand.burst())
+ .setPir(peakBand.rate())
+ .setPburst(peakBand.burst())
.build();
}
@@ -70,7 +52,7 @@
protected P4RuntimeOuterClass.MeterEntry encode(
PiMeterCellConfig piEntity, Object ignored, PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, CodecException {
+ throws P4InfoBrowser.NotFoundException {
final int meterId = browser.meters().getByName(
piEntity.cellId().meterId().id()).getPreamble().getId();
P4RuntimeOuterClass.MeterEntry.Builder builder =
@@ -139,9 +121,8 @@
PiMeterCellConfig.Builder builder =
PiMeterCellConfig.builder().withMeterCellId(cellId);
if (p4Config != null) {
- builder = builder
- .withMeterBand(new PiMeterBand(p4Config.getCir(), p4Config.getCburst()))
- .withMeterBand(new PiMeterBand(p4Config.getPir(), p4Config.getPburst()));
+ builder.withCommittedBand(p4Config.getCir(), p4Config.getCburst())
+ .withPeakBand(p4Config.getPir(), p4Config.getPburst());
}
return builder.build();
}
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/MetersWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/MetersWebResource.java
index 93d924a..f341bed 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/MetersWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/MetersWebResource.java
@@ -18,13 +18,19 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.meter.DefaultMeterRequest;
import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterCellId;
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterScope;
import org.onosproject.net.meter.MeterService;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.runtime.PiMeterCellId;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
@@ -63,6 +69,9 @@
private final ObjectNode root = mapper().createObjectNode();
private final ArrayNode metersNode = root.putArray("meters");
+ private static final String REST_APP_ID = "org.onosproject.rest";
+ private ApplicationId applicationId;
+
/**
* Returns all meters of all devices.
*
@@ -114,16 +123,72 @@
public Response getMeterByDeviceIdAndMeterId(@PathParam("deviceId") String deviceId,
@PathParam("meterId") String meterId) {
DeviceId did = DeviceId.deviceId(deviceId);
- MeterId mid = MeterId.meterId(Long.valueOf(meterId));
+ MeterCellId mid = MeterId.meterId(Long.valueOf(meterId));
MeterService meterService = get(MeterService.class);
final Meter meter = nullIsNotFound(meterService.getMeter(did, mid),
- METER_NOT_FOUND + mid.id());
+ METER_NOT_FOUND + mid);
metersNode.add(codec(Meter.class).encode(meter, this));
return ok(root).build();
}
/**
+ * Returns a meter by the meter cell id.
+ *
+ * @param deviceId device identifier
+ * @param scope scope identifier
+ * @param index index
+ * @return 200 OK with a meter, return 404 if no entry has been found
+ * @onos.rsModel Meter
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{deviceId}/{scope}/{index}")
+ public Response getMeterByDeviceIdAndMeterCellId(@PathParam("deviceId") String deviceId,
+ @PathParam("scope") String scope,
+ @PathParam("index") String index) {
+ DeviceId did = DeviceId.deviceId(deviceId);
+ MeterScope meterScope = MeterScope.of(scope);
+ long meterIndex = Long.parseLong(index);
+ MeterCellId meterCellId;
+ if (meterScope.equals(MeterScope.globalScope())) {
+ meterCellId = MeterId.meterId(meterIndex);
+ } else {
+ meterCellId = PiMeterCellId.ofIndirect(PiMeterId.of(meterScope.id()), meterIndex);
+ }
+
+ MeterService meterService = get(MeterService.class);
+ final Meter meter = nullIsNotFound(meterService.getMeter(did, meterCellId),
+ METER_NOT_FOUND + meterCellId);
+
+ metersNode.add(codec(Meter.class).encode(meter, this));
+ return ok(root).build();
+ }
+
+ /**
+ * Returns a collection of meters by the device id and meter scope.
+ *
+ * @param deviceId device identifier
+ * @param scope scope identifier
+ * @return 200 OK with array of meters which belongs to specified device
+ * @onos.rsModel Meters
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("scope/{deviceId}/{scope}")
+ public Response getMetersByDeviceIdAndScope(@PathParam("deviceId") String deviceId,
+ @PathParam("scope") String scope) {
+ DeviceId did = DeviceId.deviceId(deviceId);
+ MeterScope meterScope = MeterScope.of(scope);
+ MeterService meterService = get(MeterService.class);
+ final Iterable<Meter> meters = meterService.getMeters(did, meterScope);
+ if (meters != null) {
+ meters.forEach(meter -> metersNode.add(codec(Meter.class).encode(meter, this)));
+ }
+ return ok(root).build();
+ }
+
+ /**
* Creates new meter rule. Creates and installs a new meter rule for the
* specified device.
*
@@ -170,7 +235,7 @@
}
/**
- * Removes the specified meter.
+ * Removes the meter by device id and meter id.
*
* @param deviceId device identifier
* @param meterId meter identifier
@@ -179,65 +244,56 @@
@DELETE
@Path("{deviceId}/{meterId}")
public Response deleteMeterByDeviceIdAndMeterId(@PathParam("deviceId") String deviceId,
- @PathParam("meterId") String meterId) {
+ @PathParam("meterId") String meterId) {
DeviceId did = DeviceId.deviceId(deviceId);
- MeterId mid = MeterId.meterId(Long.valueOf(meterId));
+ MeterCellId mid = MeterId.meterId(Long.valueOf(meterId));
+ MeterRequest meterRequest = deleteRequest(did);
MeterService meterService = get(MeterService.class);
- final Meter tmpMeter = meterService.getMeter(did, mid);
- if (tmpMeter != null) {
- final MeterRequest meterRequest = meterToMeterRequest(tmpMeter, "REMOVE");
- if (meterRequest != null) {
- meterService.withdraw(meterRequest, tmpMeter.id());
- }
- } else {
- log.warn("Meter {}, is not present", tmpMeter);
- }
+ meterService.withdraw(meterRequest, mid);
+
return Response.noContent().build();
}
/**
- * Converts a meter instance to meterRequest instance with a certain operation.
+ * Removes the meter by the device id and meter cell id.
*
- * @param meter meter instance
- * @param operation operation
- * @return converted meterRequest instance
+ * @param deviceId device identifier
+ * @param scope scope identifier
+ * @param index index
+ * @return 204 NO CONTENT
*/
- private MeterRequest meterToMeterRequest(Meter meter, String operation) {
- MeterRequest.Builder builder;
- MeterRequest meterRequest;
-
- if (meter == null) {
- return null;
- }
-
- if (meter.isBurst()) {
- builder = DefaultMeterRequest.builder()
- .fromApp(meter.appId())
- .forDevice(meter.deviceId())
- .withUnit(meter.unit())
- .withBands(meter.bands())
- .burst();
+ @DELETE
+ @Path("{deviceId}/{scope}/{index}")
+ public Response deleteMeterByDeviceIdAndMeterCellId(@PathParam("deviceId") String deviceId,
+ @PathParam("scope") String scope,
+ @PathParam("index") String index) {
+ DeviceId did = DeviceId.deviceId(deviceId);
+ MeterScope meterScope = MeterScope.of(scope);
+ long meterIndex = Long.parseLong(index);
+ MeterCellId meterCellId;
+ if (meterScope.equals(MeterScope.globalScope())) {
+ meterCellId = MeterId.meterId(meterIndex);
} else {
- builder = DefaultMeterRequest.builder()
- .fromApp(meter.appId())
- .forDevice(meter.deviceId())
- .withUnit(meter.unit())
- .withBands(meter.bands());
+ meterCellId = PiMeterCellId.ofIndirect(PiMeterId.of(meterScope.id()), meterIndex);
+ }
+ MeterRequest meterRequest = deleteRequest(did);
+
+ MeterService meterService = get(MeterService.class);
+ meterService.withdraw(meterRequest, meterCellId);
+
+ return Response.noContent().build();
+ }
+
+ private MeterRequest deleteRequest(DeviceId did) {
+ CoreService coreService = getService(CoreService.class);
+ if (applicationId == null) {
+ applicationId = coreService.registerApplication(REST_APP_ID);
}
- switch (operation) {
- case "ADD":
- meterRequest = builder.add();
- break;
- case "REMOVE":
- meterRequest = builder.remove();
- break;
- default:
- log.warn("Invalid operation {}.", operation);
- return null;
- }
-
- return meterRequest;
+ return DefaultMeterRequest.builder()
+ .forDevice(did)
+ .fromApp(applicationId)
+ .remove();
}
}
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/MetersResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/MetersResourceTest.java
index d7db030..e9efb18 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/MetersResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/MetersResourceTest.java
@@ -442,7 +442,7 @@
public void testMeterSingleDeviceWithId() {
setupMockMeters();
- expect(mockMeterService.getMeter(anyObject(), anyObject()))
+ expect(mockMeterService.getMeter(anyObject(), anyObject(MeterCellId.class)))
.andReturn(meter5).anyTimes();
replay(mockMeterService);
replay(mockDeviceService);
@@ -467,7 +467,7 @@
public void testMeterByDeviceIdAndMeterId() {
setupMockMeters();
- expect(mockMeterService.getMeter(anyObject(), anyObject()))
+ expect(mockMeterService.getMeter(anyObject(), anyObject(MeterCellId.class)))
.andReturn(null).anyTimes();
replay(mockMeterService);
@@ -526,9 +526,7 @@
@Test
public void testDelete() {
setupMockMeters();
- expect(mockMeterService.getMeter(anyObject(), anyObject()))
- .andReturn(meter5).anyTimes();
- mockMeterService.withdraw(anyObject(), anyObject());
+ mockMeterService.withdraw(anyObject(), anyObject(MeterCellId.class));
expectLastCall();
replay(mockMeterService);