Merge remote-tracking branch 'origin/master' into dev/murrelet
diff --git a/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java b/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java
index 8827ecc..6e0ab42 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java
@@ -16,6 +16,7 @@
package org.onosproject.net.device;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
/**
* Default implementation of immutable port statistics.
@@ -23,7 +24,7 @@
public final class DefaultPortStatistics implements PortStatistics {
private final DeviceId deviceId;
- private final int port;
+ private final PortNumber portNumber;
private final long packetsReceived;
private final long packetsSent;
private final long bytesReceived;
@@ -36,7 +37,7 @@
private final long durationNano;
private DefaultPortStatistics(DeviceId deviceId,
- int port,
+ PortNumber portNumber,
long packetsReceived,
long packetsSent,
long bytesReceived,
@@ -48,7 +49,7 @@
long durationSec,
long durationNano) {
this.deviceId = deviceId;
- this.port = port;
+ this.portNumber = portNumber;
this.packetsReceived = packetsReceived;
this.packetsSent = packetsSent;
this.bytesReceived = bytesReceived;
@@ -64,7 +65,7 @@
// Constructor for serializer
private DefaultPortStatistics() {
this.deviceId = null;
- this.port = 0;
+ this.portNumber = null;
this.packetsReceived = 0;
this.packetsSent = 0;
this.bytesReceived = 0;
@@ -88,7 +89,12 @@
@Override
public int port() {
- return this.port;
+ return (int) this.portNumber.toLong();
+ }
+
+ @Override
+ public PortNumber portNumber() {
+ return this.portNumber;
}
@Override
@@ -154,7 +160,7 @@
@Override
public String toString() {
return "device: " + deviceId + ", " +
- "port: " + this.port + ", " +
+ "port: " + this.portNumber + ", " +
"pktRx: " + this.packetsReceived + ", " +
"pktTx: " + this.packetsSent + ", " +
"byteRx: " + this.bytesReceived + ", " +
@@ -168,7 +174,7 @@
public static final class Builder {
DeviceId deviceId;
- int port;
+ PortNumber portNumber;
long packetsReceived;
long packetsSent;
long bytesReceived;
@@ -189,9 +195,23 @@
*
* @param port port number
* @return builder object
+ * @deprecated ONOS 1.12 Magpie
*/
+ @Deprecated
public Builder setPort(int port) {
- this.port = port;
+ this.portNumber = PortNumber.portNumber(port);
+
+ return this;
+ }
+
+ /**
+ * Sets port number.
+ *
+ * @param portNumber port number
+ * @return builder object
+ */
+ public Builder setPort(PortNumber portNumber) {
+ this.portNumber = portNumber;
return this;
}
@@ -336,7 +356,7 @@
public DefaultPortStatistics build() {
return new DefaultPortStatistics(
deviceId,
- port,
+ portNumber,
packetsReceived,
packetsSent,
bytesReceived,
diff --git a/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java b/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java
index 25fb057..3b9f19a 100644
--- a/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java
+++ b/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.net.device;
+import org.onosproject.net.PortNumber;
+
/**
* Statistics of a port.
*/
@@ -24,10 +26,19 @@
* Returns the port number.
*
* @return port number
+ * @deprecated ONOS 1.12 Magpie please use portNumber()
*/
+ @Deprecated
int port();
/**
+ * Returns the port number.
+ *
+ * @return port number
+ */
+ PortNumber portNumber();
+
+ /**
* Returns the number of packets received.
*
* @return the number of packets received
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellData.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellData.java
new file mode 100644
index 0000000..f0aada5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellData.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-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;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+
+/**
+ * Data of a counter cell of a protocol-independent pipeline.
+ */
+@Beta
+public final class PiCounterCellData {
+
+ private final PiCounterCellId cellId;
+ private final long packets;
+ private final long bytes;
+
+ /**
+ * Creates a new counter cell data for the given cell identifier, number of packets and bytes.
+ *
+ * @param cellId counter cell identifier
+ * @param packets number of packets
+ * @param bytes number of bytes
+ */
+ public PiCounterCellData(PiCounterCellId cellId, long packets, long bytes) {
+ this.cellId = cellId;
+ this.packets = packets;
+ this.bytes = bytes;
+ }
+
+ /**
+ * Returns the cell identifier.
+ *
+ * @return cell identifier
+ */
+ public PiCounterCellId cellId() {
+ return cellId;
+ }
+
+ /**
+ * Returns the packet count value contained by this cell.
+ *
+ * @return number of packets
+ */
+ public long packets() {
+ return packets;
+ }
+
+ /**
+ * Returns the byte count value contained by this cell.
+ *
+ * @return number of bytes
+ */
+ public long bytes() {
+ return bytes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PiCounterCellData)) {
+ return false;
+ }
+ PiCounterCellData that = (PiCounterCellData) o;
+ return packets == that.packets &&
+ bytes == that.bytes &&
+ Objects.equal(cellId, that.cellId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(cellId, packets, bytes);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("cellId", cellId)
+ .add("packets", packets)
+ .add("bytes", bytes)
+ .toString();
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java
new file mode 100644
index 0000000..d762f23
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017-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;
+import com.google.common.base.Objects;
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Identifier of a counter cell of a protocol-independent pipeline.
+ */
+@Beta
+public final class PiCounterCellId extends Identifier<String> {
+
+ private final PiCounterId counterId;
+ private final long index;
+
+ private PiCounterCellId(PiCounterId counterId, long index) {
+ super(counterId.id() + "[" + index + "]");
+ this.counterId = counterId;
+ this.index = index;
+ }
+
+ /**
+ * Returns a counter cell identifier for the given counter identifier and index.
+ *
+ * @param counterId counter identifier
+ * @param index index
+ * @return counter cell identifier
+ */
+ public static PiCounterCellId of(PiCounterId counterId, long index) {
+ checkNotNull(counterId);
+ checkArgument(index >= 0, "Index must be a positive integer");
+ return new PiCounterCellId(counterId, index);
+ }
+
+ /**
+ * Returns the counter identifier of this cell.
+ *
+ * @return counter identifier
+ */
+ public PiCounterId counterId() {
+ return counterId;
+ }
+
+ /**
+ * Returns the index of this cell.
+ *
+ * @return cell index
+ */
+ public long index() {
+ return index;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PiCounterCellId)) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ PiCounterCellId that = (PiCounterCellId) o;
+ return index == that.index &&
+ Objects.equal(counterId, that.counterId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), counterId, index);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java
new file mode 100644
index 0000000..6fcd55e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-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;
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Identifier of a counter of a protocol-independent pipeline.
+ */
+@Beta
+public final class PiCounterId extends Identifier<String> {
+
+ private PiCounterId(String name) {
+ super(name);
+ }
+
+ /**
+ * Returns a counter identifier for the given name.
+ *
+ * @param name counter name
+ * @return counter identifier
+ */
+ public static PiCounterId of(String name) {
+ checkNotNull(name);
+ checkArgument(!name.isEmpty(), "Name name can't be empty");
+ return new PiCounterId(name);
+ }
+
+ /**
+ * Returns the name of the counter.
+ *
+ * @return counter name
+ */
+ public String name() {
+ return this.identifier;
+ }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
index 3dba8b6..41fe160 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
@@ -19,6 +19,7 @@
import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
import org.onosproject.drivers.p4runtime.DefaultP4Interpreter;
+import org.onosproject.drivers.p4runtime.DefaultP4PortStatisticsDiscovery;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.device.PortStatisticsDiscovery;
import org.onosproject.net.pi.model.DefaultPiPipeconf;
@@ -60,7 +61,7 @@
.withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
.addBehaviour(PiPipelineInterpreter.class, DefaultP4Interpreter.class)
.addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
- .addBehaviour(PortStatisticsDiscovery.class, Bmv2DefaultPortStatisticsDiscovery.class)
+ .addBehaviour(PortStatisticsDiscovery.class, DefaultP4PortStatisticsDiscovery.class)
.addExtension(P4_INFO_TEXT, p4InfoUrl)
.addExtension(BMV2_JSON, jsonUrl)
.build();
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPortStatisticsDiscovery.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPortStatisticsDiscovery.java
deleted file mode 100644
index 96081be..0000000
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPortStatisticsDiscovery.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2017-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.drivers.bmv2;
-
-import com.google.common.collect.ImmutableList;
-import org.onosproject.net.device.PortStatistics;
-import org.onosproject.net.device.PortStatisticsDiscovery;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-
-/**
- * Implementation of the behaviour for discovering the port statistics of a Bmv2 device with the default.p4 program.
- */
-public class Bmv2DefaultPortStatisticsDiscovery extends AbstractHandlerBehaviour implements PortStatisticsDiscovery {
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- @Override
- public Collection<PortStatistics> discoverPortStatistics() {
- log.debug("Discovering Port Statistics for device {}", handler().data().deviceId());
- return ImmutableList.of();
- }
-}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
new file mode 100644
index 0000000..8a5a2dd
--- /dev/null
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017-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.drivers.p4runtime;
+
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.netty.NettyChannelBuilder;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiPipeconfService;
+import org.onosproject.p4runtime.api.P4RuntimeClient;
+import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract implementation of a behaviour handler for a P4Runtime device.
+ */
+public class AbstractP4RuntimeHandlerBehaviour extends AbstractHandlerBehaviour {
+
+ public static final String P4RUNTIME_SERVER_ADDR_KEY = "p4runtime_ip";
+ public static final String P4RUNTIME_SERVER_PORT_KEY = "p4runtime_port";
+ public static final String P4RUNTIME_DEVICE_ID_KEY = "p4runtime_deviceId";
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ // Initialized by setupBehaviour()
+ protected DeviceId deviceId;
+ protected DeviceService deviceService;
+ protected Device device;
+ protected P4RuntimeController controller;
+ protected PiPipeconf pipeconf;
+ protected P4RuntimeClient client;
+
+ /**
+ * Initializes this behaviour attributes. Returns true if the operation was successful, false otherwise. This method
+ * assumes that the P4runtime controller already has a client for this device and that the device has been created
+ * in the core.
+ *
+ * @return true if successful, false otherwise
+ */
+ protected boolean setupBehaviour() {
+ deviceId = handler().data().deviceId();
+
+ deviceService = handler().get(DeviceService.class);
+ device = deviceService.getDevice(deviceId);
+ if (device == null) {
+ log.warn("Unable to find device with id {}, aborting operation", deviceId);
+ return false;
+ }
+
+ controller = handler().get(P4RuntimeController.class);
+ if (!controller.hasClient(deviceId)) {
+ log.warn("Unable to find client for {}, aborting operation", deviceId);
+ return false;
+ }
+ client = controller.getClient(deviceId);
+
+ PiPipeconfService piPipeconfService = handler().get(PiPipeconfService.class);
+ if (!piPipeconfService.ofDevice(deviceId).isPresent() ||
+ !piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).isPresent()) {
+ log.warn("Unable to get the pipeconf of {}, aborting operation", deviceId);
+ return false;
+ }
+ pipeconf = piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).get();
+
+ return true;
+ }
+
+ /**
+ * Create a P4Runtime client for this device. Returns true if the operation was successful, false otherwise.
+ *
+ * @return true if successful, false otherwise
+ */
+ protected boolean createClient() {
+ deviceId = handler().data().deviceId();
+ controller = handler().get(P4RuntimeController.class);
+
+ String serverAddr = this.data().value(P4RUNTIME_SERVER_ADDR_KEY);
+ String serverPortString = this.data().value(P4RUNTIME_SERVER_PORT_KEY);
+ String p4DeviceIdString = this.data().value(P4RUNTIME_DEVICE_ID_KEY);
+
+ if (serverAddr == null || serverPortString == null || p4DeviceIdString == null) {
+ log.warn("Unable to create client for {}, missing driver data key (required is {}, {}, and {})",
+ deviceId, P4RUNTIME_SERVER_ADDR_KEY, P4RUNTIME_SERVER_PORT_KEY, P4RUNTIME_DEVICE_ID_KEY);
+ return false;
+ }
+
+ ManagedChannelBuilder channelBuilder = NettyChannelBuilder
+ .forAddress(serverAddr, Integer.valueOf(serverPortString))
+ .usePlaintext(true);
+
+ if (!controller.createClient(deviceId, Long.parseUnsignedLong(p4DeviceIdString), channelBuilder)) {
+ log.warn("Unable to create client for {}, aborting operation", deviceId);
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
new file mode 100644
index 0000000..2946304
--- /dev/null
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2017-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.drivers.p4runtime;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.onosproject.net.device.DefaultPortStatistics;
+import org.onosproject.net.device.PortStatistics;
+import org.onosproject.net.device.PortStatisticsDiscovery;
+import org.onosproject.net.pi.runtime.PiCounterCellData;
+import org.onosproject.net.pi.runtime.PiCounterCellId;
+import org.onosproject.net.pi.runtime.PiCounterId;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of a PortStatisticsBehaviour that can be used for any P4 program based on default.p4 (i.e. those
+ * under onos/tools/test/p4src).
+ */
+public class DefaultP4PortStatisticsDiscovery extends AbstractP4RuntimeHandlerBehaviour
+ implements PortStatisticsDiscovery {
+
+ private static final PiCounterId INGRESS_COUNTER_ID = PiCounterId.of("ingress_port_counter");
+ private static final PiCounterId EGRESS_COUNTER_ID = PiCounterId.of("egress_port_counter");
+
+ @Override
+ public Collection<PortStatistics> discoverPortStatistics() {
+
+ if (!super.setupBehaviour()) {
+ return Collections.emptyList();
+ }
+
+ Map<Long, DefaultPortStatistics.Builder> portStatBuilders = Maps.newHashMap();
+
+ deviceService.getPorts(deviceId)
+ .forEach(p -> portStatBuilders.put(p.number().toLong(),
+ DefaultPortStatistics.builder()
+ .setPort((int) p.number().toLong())
+ .setDeviceId(deviceId)));
+
+ Set<PiCounterCellId> counterCellIds = Sets.newHashSet();
+ portStatBuilders.keySet().forEach(p -> {
+ // Counter cell/index = port number.
+ counterCellIds.add(PiCounterCellId.of(INGRESS_COUNTER_ID, p));
+ counterCellIds.add(PiCounterCellId.of(EGRESS_COUNTER_ID, p));
+ });
+
+ Collection<PiCounterCellData> counterEntryResponse;
+ try {
+ counterEntryResponse = client.readCounterCells(counterCellIds, pipeconf).get();
+ } catch (InterruptedException | ExecutionException e) {
+ log.warn("Exception while reading port counters from {}: {}", deviceId, e.toString());
+ log.debug("", e);
+ return Collections.emptyList();
+ }
+
+ counterEntryResponse.forEach(counterEntry -> {
+ if (!portStatBuilders.containsKey(counterEntry.cellId().index())) {
+ log.warn("Unrecognized counter index {}, skipping", counterEntry);
+ return;
+ }
+ DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(counterEntry.cellId().index());
+ if (counterEntry.cellId().counterId().equals(INGRESS_COUNTER_ID)) {
+ statsBuilder.setPacketsReceived(counterEntry.packets());
+ statsBuilder.setBytesReceived(counterEntry.bytes());
+ } else if (counterEntry.cellId().counterId().equals(EGRESS_COUNTER_ID)) {
+ statsBuilder.setPacketsSent(counterEntry.packets());
+ statsBuilder.setBytesSent(counterEntry.bytes());
+ } else {
+ log.warn("Unrecognized counter ID {}, skipping", counterEntry);
+ }
+ });
+
+ return portStatBuilders
+ .values()
+ .stream()
+ .map(DefaultPortStatistics.Builder::build)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
index 1a0b755..515640b 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
@@ -19,29 +19,19 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleProgrammable;
-import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipelineInterpreter;
import org.onosproject.net.pi.model.PiPipelineModel;
import org.onosproject.net.pi.model.PiTableModel;
import org.onosproject.net.pi.runtime.PiFlowRuleTranslationService;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
-import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType;
-import org.onosproject.p4runtime.api.P4RuntimeController;
import org.onosproject.p4runtime.api.P4RuntimeFlowRuleWrapper;
import org.onosproject.p4runtime.api.P4RuntimeTableEntryReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
@@ -58,9 +48,9 @@
import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.*;
/**
- * Implementation of the flow rule programmable behaviour for BMv2.
+ * Implementation of the flow rule programmable behaviour for P4Runtime.
*/
-public class P4RuntimeFlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+public class P4RuntimeFlowRuleProgrammable extends AbstractP4RuntimeHandlerBehaviour implements FlowRuleProgrammable {
// TODO: make this attribute configurable by child drivers (e.g. BMv2 or Tofino)
/*
@@ -75,8 +65,6 @@
*/
private boolean checkEntryStoreBeforeUpdate = true;
- private final Logger log = LoggerFactory.getLogger(getClass());
-
// Needed to synchronize operations over the same table entry.
private static final ConcurrentMap<P4RuntimeTableEntryReference, Lock> ENTRY_LOCKS = Maps.newConcurrentMap();
@@ -85,50 +73,31 @@
private static final ConcurrentMap<P4RuntimeTableEntryReference, P4RuntimeFlowRuleWrapper> ENTRY_STORE =
Maps.newConcurrentMap();
- private DeviceId deviceId;
- private P4RuntimeClient client;
- private PiPipeconf pipeconf;
private PiPipelineModel pipelineModel;
private PiPipelineInterpreter interpreter;
private PiFlowRuleTranslationService piFlowRuleTranslationService;
- private boolean init() {
+ @Override
+ protected boolean setupBehaviour() {
- deviceId = handler().data().deviceId();
-
- P4RuntimeController controller = handler().get(P4RuntimeController.class);
- if (!controller.hasClient(deviceId)) {
- log.warn("Unable to find client for {}, aborting flow rule operation", deviceId);
+ if (!super.setupBehaviour()) {
return false;
}
- PiPipeconfService piPipeconfService = handler().get(PiPipeconfService.class);
- if (!piPipeconfService.ofDevice(deviceId).isPresent() ||
- !piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).isPresent()) {
- log.warn("Unable to get the pipeconf of {}", deviceId);
- return false;
- }
-
- DeviceService deviceService = handler().get(DeviceService.class);
- Device device = deviceService.getDevice(deviceId);
if (!device.is(PiPipelineInterpreter.class)) {
log.warn("Unable to get interpreter of {}", deviceId);
return false;
}
-
- client = controller.getClient(deviceId);
- pipeconf = piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).get();
- pipelineModel = pipeconf.pipelineModel();
interpreter = device.as(PiPipelineInterpreter.class);
+ pipelineModel = pipeconf.pipelineModel();
piFlowRuleTranslationService = handler().get(PiFlowRuleTranslationService.class);
-
return true;
}
@Override
public Collection<FlowEntry> getFlowEntries() {
- if (!init()) {
+ if (!setupBehaviour()) {
return Collections.emptyList();
}
@@ -201,7 +170,7 @@
private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules, Operation operation) {
- if (!init()) {
+ if (!setupBehaviour()) {
return Collections.emptyList();
}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
index ee070eb..8416786 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeHandshaker.java
@@ -16,27 +16,17 @@
package org.onosproject.drivers.p4runtime;
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.netty.NettyChannelBuilder;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.device.DeviceHandshaker;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.driver.DriverData;
import org.onosproject.p4runtime.api.P4RuntimeController;
-import org.slf4j.Logger;
import java.util.concurrent.CompletableFuture;
-import static org.slf4j.LoggerFactory.getLogger;
-
/**
- * Implementation of DeviceHandshaker for BMv2.
+ * Implementation of DeviceHandshaker for P4Runtime.
*/
-public class P4RuntimeHandshaker extends AbstractHandlerBehaviour
- implements DeviceHandshaker {
-
- private final Logger log = getLogger(getClass());
+public class P4RuntimeHandshaker extends AbstractP4RuntimeHandlerBehaviour implements DeviceHandshaker {
// TODO: consider abstract class with empty connect method and implementation into a protected one for reusability.
@@ -46,29 +36,7 @@
}
private boolean doConnect() {
-
- P4RuntimeController controller = handler().get(P4RuntimeController.class);
-
- DeviceId deviceId = handler().data().deviceId();
- // DeviceKeyService deviceKeyService = handler().get(DeviceKeyService.class);
- DriverData data = data();
-
- String serverAddr = data.value("p4runtime_ip");
- int serverPort = Integer.valueOf(data.value("p4runtime_port"));
- long p4DeviceId = Long.parseUnsignedLong(data.value("p4runtime_deviceId"));
-
- ManagedChannelBuilder channelBuilder = NettyChannelBuilder
- .forAddress(serverAddr, serverPort)
- .usePlaintext(true);
-
- if (!controller.createClient(deviceId, p4DeviceId, channelBuilder)) {
- log.warn("Unable to create P4runtime client for {}", deviceId);
- return false;
- }
-
- // TODO: gNMI handling
-
- return true;
+ return super.createClient();
}
@Override
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimePacketProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimePacketProgrammable.java
index 7a11376..e21dd19 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimePacketProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimePacketProgrammable.java
@@ -16,57 +16,29 @@
package org.onosproject.drivers.p4runtime;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketProgrammable;
-import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipelineInterpreter;
import org.onosproject.net.pi.runtime.PiPacketOperation;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
-import org.onosproject.p4runtime.api.P4RuntimeClient;
-import org.onosproject.p4runtime.api.P4RuntimeController;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.Collection;
/**
- * Packet Programmable behaviour for BMv2 devices.
+ * Implementation of PacketProgrammable behaviour for P4Runtime.
*/
-public class P4RuntimePacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
- private final Logger log = LoggerFactory.getLogger(getClass());
+public class P4RuntimePacketProgrammable extends AbstractP4RuntimeHandlerBehaviour implements PacketProgrammable {
@Override
public void emit(OutboundPacket packet) {
- DeviceId deviceId = handler().data().deviceId();
- P4RuntimeController controller = handler().get(P4RuntimeController.class);
- if (!controller.hasClient(deviceId)) {
- log.warn("Unable to find client for {}, aborting the sending packet", deviceId);
+ if (!this.setupBehaviour()) {
return;
}
- P4RuntimeClient client = controller.getClient(deviceId);
- PiPipeconfService piPipeconfService = handler().get(PiPipeconfService.class);
-
- final PiPipeconf pipeconf;
- if (piPipeconfService.ofDevice(deviceId).isPresent() &&
- piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).isPresent()) {
- pipeconf = piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).get();
- } else {
- log.warn("Unable to get the pipeconf of {}", deviceId);
- return;
- }
-
- DeviceService deviceService = handler().get(DeviceService.class);
- Device device = deviceService.getDevice(deviceId);
final PiPipelineInterpreter interpreter = device.is(PiPipelineInterpreter.class)
? device.as(PiPipelineInterpreter.class) : null;
if (!device.is(PiPipelineInterpreter.class)) {
- log.warn("Device {} unable to instantiate interpreter of pipeconf {}", deviceId, pipeconf.id());
+ log.warn("Device {} with pipeconf {} has no interpreter, aborting emit operation", deviceId, pipeconf.id());
return;
}
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
index f709b46..9760ad4 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
@@ -18,12 +18,16 @@
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiCounterCellData;
+import org.onosproject.net.pi.runtime.PiCounterCellId;
+import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
import java.nio.ByteBuffer;
import java.util.Collection;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
@@ -86,7 +90,7 @@
PiPipeconf pipeconf);
/**
- * Dumps all entries currently installed in the given table.
+ * Dumps all entries currently installed in the given table, for the given pipeconf.
*
* @param tableId table identifier
* @param pipeconf pipeconf currently deployed on the device
@@ -95,7 +99,7 @@
CompletableFuture<Collection<PiTableEntry>> dumpTable(PiTableId tableId, PiPipeconf pipeconf);
/**
- * Executes a packet-out operation.
+ * Executes a packet-out operation for the given pipeconf.
*
* @param packet packet-out operation to be performed by the device
* @param pipeconf pipeconf currently deployed on the device
@@ -104,6 +108,27 @@
CompletableFuture<Boolean> packetOut(PiPacketOperation packet, PiPipeconf pipeconf);
/**
+ * Returns the value of all counter cells for the given set of counter identifiers and pipeconf.
+ *
+ * @param counterIds counter identifiers
+ * @param pipeconf pipeconf
+ * @return collection of counter data
+ */
+ CompletableFuture<Collection<PiCounterCellData>> readAllCounterCells(Set<PiCounterId> counterIds,
+ PiPipeconf pipeconf);
+
+ /**
+ * Returns a collection of counter data corresponding to the given set of counter cell identifiers, for the given
+ * pipeconf.
+ *
+ * @param cellIds set of counter cell identifiers
+ * @param pipeconf pipeconf
+ * @return collection of counter data
+ */
+ CompletableFuture<Collection<PiCounterCellData>> readCounterCells(Set<PiCounterCellId> cellIds,
+ PiPipeconf pipeconf);
+
+ /**
* Shutdown the client by terminating any active RPC such as the stream channel.
*/
void shutdown();
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index 3ae9464..87652c3 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -16,7 +16,9 @@
package org.onosproject.p4runtime.ctl;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import com.google.protobuf.ByteString;
import io.grpc.Context;
import io.grpc.ManagedChannel;
@@ -26,6 +28,9 @@
import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiCounterCellData;
+import org.onosproject.net.pi.runtime.PiCounterCellId;
+import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -34,6 +39,7 @@
import org.onosproject.p4runtime.api.P4RuntimeEvent;
import org.slf4j.Logger;
import p4.P4RuntimeGrpc;
+import p4.P4RuntimeOuterClass.CounterEntry;
import p4.P4RuntimeOuterClass.Entity;
import p4.P4RuntimeOuterClass.ForwardingPipelineConfig;
import p4.P4RuntimeOuterClass.MasterArbitrationUpdate;
@@ -57,6 +63,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -71,6 +78,7 @@
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
import static org.slf4j.LoggerFactory.getLogger;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.COUNTER_ENTRY;
import static p4.P4RuntimeOuterClass.Entity.EntityCase.TABLE_ENTRY;
import static p4.P4RuntimeOuterClass.PacketOut;
import static p4.P4RuntimeOuterClass.SetForwardingPipelineConfigRequest.Action.VERIFY_AND_COMMIT;
@@ -175,6 +183,25 @@
return supplyInContext(() -> doPacketOut(packet, pipeconf), "packetOut");
}
+ @Override
+ public CompletableFuture<Collection<PiCounterCellData>> readCounterCells(Set<PiCounterCellId> cellIds,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doReadCounterCells(cellIds, pipeconf),
+ "readCounterCells-" + cellIds.hashCode());
+ }
+
+ @Override
+ public CompletableFuture<Collection<PiCounterCellData>> readAllCounterCells(Set<PiCounterId> counterIds,
+ PiPipeconf pipeconf) {
+ Set<PiCounterCellId> cellIds = counterIds.stream()
+ // Cell with index 0 means all cells.
+ .map(counterId -> PiCounterCellId.of(counterId, 0))
+ .collect(Collectors.toSet());
+
+ return supplyInContext(() -> doReadCounterCells(cellIds, pipeconf),
+ "readAllCounterCells-" + cellIds.hashCode());
+ }
+
/* Blocking method implementations below */
private boolean doInitStreamChannel() {
@@ -404,6 +431,66 @@
log.warn("Received arbitration update from {} (NOT IMPLEMENTED YET): {}", deviceId, arbitrationMsg);
}
+ private Collection<PiCounterCellData> doReadCounterCells(Collection<PiCounterCellId> cellIds, PiPipeconf pipeconf) {
+
+ // From p4runtime.proto:
+ // For ReadRequest, the scope is defined as follows:
+ // - All counter cells for all meters if counter_id = 0 (default).
+ // - All counter cells for given counter_id if index = 0 (default).
+
+ final ReadRequest.Builder requestBuilder = ReadRequest.newBuilder().setDeviceId(p4DeviceId);
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ final Map<Integer, PiCounterId> counterIdMap = Maps.newHashMap();
+
+ for (PiCounterCellId cellId : cellIds) {
+ int counterId;
+ try {
+ counterId = browser.counters().getByNameOrAlias(cellId.counterId().id()).getPreamble().getId();
+ } catch (P4InfoBrowser.NotFoundException e) {
+ log.warn("Skipping counter cell {}: {}", cellId, e.getMessage());
+ continue;
+ }
+ requestBuilder
+ .addEntities(Entity.newBuilder()
+ .setCounterEntry(CounterEntry.newBuilder()
+ .setCounterId(counterId)
+ .setIndex(cellId.index())
+ .build()));
+ counterIdMap.put(counterId, cellId.counterId());
+ }
+
+ final Iterator<ReadResponse> responses;
+ try {
+ responses = blockingStub.read(requestBuilder.build());
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read counters: {}", e.getMessage());
+ return Collections.emptyList();
+ }
+
+ final Iterable<ReadResponse> responseIterable = () -> responses;
+ final ImmutableList.Builder<PiCounterCellData> piCounterEntryListBuilder = ImmutableList.builder();
+
+ StreamSupport
+ .stream(responseIterable.spliterator(), false)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(entity -> entity.getEntityCase() == COUNTER_ENTRY)
+ .map(Entity::getCounterEntry)
+ .forEach(counterEntryMsg -> {
+ if (!counterIdMap.containsKey(counterEntryMsg.getCounterId())) {
+ log.warn("Unrecognized counter ID '{}', skipping", counterEntryMsg.getCounterId());
+ return;
+ }
+ PiCounterCellId cellId = PiCounterCellId.of(counterIdMap.get(counterEntryMsg.getCounterId()),
+ counterEntryMsg.getIndex());
+ piCounterEntryListBuilder.add(new PiCounterCellData(cellId,
+ counterEntryMsg.getData().getPacketCount(),
+ counterEntryMsg.getData().getByteCount()));
+ });
+
+ return piCounterEntryListBuilder.build();
+ }
+
/**
* Returns the internal P4 device ID associated with this client.
*
diff --git a/tools/dev/bin/onos-setup-p4-dev b/tools/dev/bin/onos-setup-p4-dev
index b4638d4..56eb6d3 100755
--- a/tools/dev/bin/onos-setup-p4-dev
+++ b/tools/dev/bin/onos-setup-p4-dev
@@ -16,7 +16,7 @@
BUILD_DIR=~/p4tools
BMV2_COMMIT="1683392d8859907b8367cc0188d3d4ed8bea268c"
-PI_COMMIT="b7053f7ad32eb8cddab2ed1f4a7e1e6a30fc5e57"
+PI_COMMIT="6b47641344c2b0bc77e51876517b98eda51eda45"
P4C_COMMIT="55067fd0e5f9e25fef06e58e49033da3493f796d"
PROTOBUF_COMMIT="tags/v3.0.2"
GRPC_COMMIT="tags/v1.3.0"