ONOS-7058 Refactored default pipeconfs in new pipelines directory
- Minimal refactoring of P4 programs
- Removed symlinks to BMv2 JSON/P4Info
- Bumped p4c commit (which fixes known parser bug)
- Renamed "default" pipeconf to "basic" (ONOS-6818)
Change-Id: I319f8b142ab22dba9b15457e28cd62d17f78a423
diff --git a/drivers/bmv2/BUCK b/drivers/bmv2/BUCK
index d9b09bb..c8224f5 100644
--- a/drivers/bmv2/BUCK
+++ b/drivers/bmv2/BUCK
@@ -9,6 +9,7 @@
'//drivers/p4runtime:onos-drivers-p4runtime',
'//incubator/grpc-dependencies:grpc-core-repkg-' + GRPC_VER,
'//lib:grpc-netty-' + GRPC_VER,
+ '//pipelines/basic:onos-pipelines-basic',
]
BUNDLES = [
@@ -29,5 +30,6 @@
included_bundles = BUNDLES,
required_apps = [
'org.onosproject.drivers.p4runtime',
+ 'org.onosproject.pipelines.basic',
],
)
\ No newline at end of file
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
deleted file mode 100644
index 448da71..0000000
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
+++ /dev/null
@@ -1,68 +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 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;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
-
-import java.net.URL;
-
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
-
-/**
- * Factory of pipeconf implementation for the default.p4 program on BMv2.
- */
-public final class Bmv2DefaultPipeconfFactory {
-
- private static final String PIPECONF_ID = "bmv2-default-pipeconf";
- private static final String JSON_PATH = "/default.json";
- private static final String P4INFO_PATH = "/default.p4info";
-
- private static final PiPipeconf PIPECONF = buildPipeconf();
-
- private Bmv2DefaultPipeconfFactory() {
- // Hides constructor.
- }
-
- public static PiPipeconf get() {
- return PIPECONF;
- }
-
- private static PiPipeconf buildPipeconf() {
-
- final URL jsonUrl = Bmv2DefaultPipeconfFactory.class.getResource(JSON_PATH);
- final URL p4InfoUrl = Bmv2DefaultPipeconfFactory.class.getResource(P4INFO_PATH);
- return DefaultPiPipeconf.builder()
- .withId(new PiPipeconfId(PIPECONF_ID))
- .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
- .addBehaviour(PiPipelineInterpreter.class, DefaultP4Interpreter.class)
- .addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.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/Bmv2DriversLoader.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
index ff4f2d9..8ee87d4 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
@@ -17,10 +17,7 @@
package org.onosproject.drivers.bmv2;
import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.driver.AbstractDriverLoader;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
/**
* Loader for P4Runtime device drivers.
@@ -28,22 +25,7 @@
@Component(immediate = true)
public class Bmv2DriversLoader extends AbstractDriverLoader {
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected PiPipeconfService pipeconfService;
-
public Bmv2DriversLoader() {
super("/bmv2-drivers.xml");
}
-
- @Override
- public void activate() {
- pipeconfService.register(Bmv2DefaultPipeconfFactory.get());
- super.activate();
- }
-
- @Override
- public void deactivate() {
- pipeconfService.remove(Bmv2DefaultPipeconfFactory.get().id());
- super.deactivate();
- }
}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
index 0eef5ed..bf88238 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
@@ -23,6 +23,7 @@
import org.onosproject.net.pi.model.PiPipelineProgrammable;
import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.onosproject.pipelines.basic.PipeconfLoader;
import org.slf4j.Logger;
import java.util.Optional;
@@ -37,8 +38,6 @@
*/
public class Bmv2PipelineProgrammable extends AbstractHandlerBehaviour implements PiPipelineProgrammable {
- private static final PiPipeconf DEFAULT_PIPECONF = Bmv2DefaultPipeconfFactory.get();
-
private final Logger log = getLogger(getClass());
@Override
@@ -87,6 +86,6 @@
@Override
public Optional<PiPipeconf> getDefaultPipeconf() {
- return Optional.of(DEFAULT_PIPECONF);
+ return Optional.of(PipeconfLoader.BASIC_PIPECONF);
}
}
diff --git a/drivers/bmv2/src/main/resources/default.json b/drivers/bmv2/src/main/resources/default.json
deleted file mode 120000
index c5028d8..0000000
--- a/drivers/bmv2/src/main/resources/default.json
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../tools/test/p4src/p4-16/p4c-out/default.json
\ No newline at end of file
diff --git a/drivers/bmv2/src/main/resources/default.p4info b/drivers/bmv2/src/main/resources/default.p4info
deleted file mode 120000
index 8f71cbe..0000000
--- a/drivers/bmv2/src/main/resources/default.p4info
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../tools/test/p4src/p4-16/p4c-out/default.p4info
\ No newline at end of file
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
deleted file mode 100644
index f716a63..0000000
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
+++ /dev/null
@@ -1,331 +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.p4runtime;
-
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableList;
-import org.onlab.packet.DeserializationException;
-import org.onlab.packet.Ethernet;
-import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flow.instructions.PiInstruction;
-import org.onosproject.net.packet.DefaultInboundPacket;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.net.pi.model.PiHeaderFieldModel;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-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.PiAction;
-import org.onosproject.net.pi.runtime.PiActionId;
-import org.onosproject.net.pi.runtime.PiActionParam;
-import org.onosproject.net.pi.runtime.PiActionParamId;
-import org.onosproject.net.pi.runtime.PiCounterId;
-import org.onosproject.net.pi.runtime.PiCounterType;
-import org.onosproject.net.pi.runtime.PiHeaderFieldId;
-import org.onosproject.net.pi.runtime.PiPacketMetadata;
-import org.onosproject.net.pi.runtime.PiPacketMetadataId;
-import org.onosproject.net.pi.runtime.PiPacketOperation;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
-import org.onosproject.net.pi.runtime.PiTableId;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-
-import static java.lang.String.format;
-import static java.util.stream.Collectors.toList;
-import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
-import static org.onosproject.net.PortNumber.CONTROLLER;
-import static org.onosproject.net.PortNumber.FLOOD;
-import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
-import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
-
-/**
- * Implementation of an interpreter that can be used for any P4 program based on default.p4 (i.e. those under
- * onos/tools/test/p4src).
- */
-public class DefaultP4Interpreter extends AbstractHandlerBehaviour implements PiPipelineInterpreter {
-
- // FIXME: Should move this class out of the p4runtime drivers.
- // e.g. in a dedicated onos/pipeconf directory, along with any related P4 source code.
-
- public static final String TABLE0 = "table0";
- public static final String TABLE0_COUNTER = "table0_counter";
- public static final String ECMP = "ecmp";
- public static final String SEND_TO_CPU = "send_to_cpu";
- public static final String PORT = "port";
- public static final String DROP = "_drop";
- public static final String SET_EGRESS_PORT = "set_egress_port";
- public static final String EGRESS_PORT = "egress_port";
- public static final String INGRESS_PORT = "ingress_port";
-
- private static final PiTableId TABLE0_ID = PiTableId.of(TABLE0);
- private static final PiTableId ECMP_ID = PiTableId.of(ECMP);
-
- protected static final PiHeaderFieldId ETH_DST_ID = PiHeaderFieldId.of("ethernet", "dstAddr");
- protected static final PiHeaderFieldId ETH_SRC_ID = PiHeaderFieldId.of("ethernet", "srcAddr");
- protected static final PiHeaderFieldId ETH_TYPE_ID = PiHeaderFieldId.of("ethernet", "etherType");
-
- private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
- 0, TABLE0_ID,
- 1, ECMP_ID);
-
- private static final ImmutableBiMap<PiTableId, PiCounterId> TABLE_COUNTER_MAP = ImmutableBiMap.of(
- TABLE0_ID, PiCounterId.of(TABLE0_COUNTER, PiCounterType.DIRECT));
-
- private boolean targetAttributesInitialized = false;
-
- /*
- The following attributes are target-specific, i.e. they might change from one target to another.
- */
- private ImmutableBiMap<Criterion.Type, PiHeaderFieldId> criterionMap;
- private int portFieldBitWidth;
-
- /**
- * Populates target-specific attributes based on this device's pipeline model.
- */
- private synchronized void initTargetSpecificAttributes() {
- if (targetAttributesInitialized) {
- return;
- }
-
- DeviceId deviceId = this.handler().data().deviceId();
- PiPipeconfService pipeconfService = this.handler().get(PiPipeconfService.class);
- PiPipeconfId pipeconfId = pipeconfService.ofDevice(deviceId)
- .orElseThrow(() -> new RuntimeException(format(
- "Unable to get current pipeconf for device %s", this.data().deviceId())));
- PiPipeconf pipeconf = pipeconfService.getPipeconf(pipeconfId)
- .orElseThrow(() -> new RuntimeException(format(
- "Pipeconf %s is not registered", pipeconfId)));
- PiPipelineModel model = pipeconf.pipelineModel();
-
- this.portFieldBitWidth = extractPortFieldBitWidth(model);
- this.criterionMap = new ImmutableBiMap.Builder<Criterion.Type, PiHeaderFieldId>()
- .put(Criterion.Type.IN_PORT, extractInPortFieldId(model))
- .put(Criterion.Type.ETH_DST, ETH_DST_ID)
- .put(Criterion.Type.ETH_SRC, ETH_SRC_ID)
- .put(Criterion.Type.ETH_TYPE, ETH_TYPE_ID)
- .build();
-
- this.targetAttributesInitialized = true;
- }
-
- private static PiHeaderFieldId extractInPortFieldId(PiPipelineModel model) {
- /*
- For the targets we currently support, the field name is "ingress_port", but we miss the header name, which is
- target-specific. We know table0 defines that field as a match key, we look for it and we get the header name.
- */
- PiTableModel tableModel = model.table(TABLE0).orElseThrow(() -> new RuntimeException(format(
- "No such table '%s' in pipeline model", TABLE0)));
- PiHeaderFieldModel fieldModel = tableModel.matchFields().stream()
- .filter(m -> m.field().type().name().equals(INGRESS_PORT))
- .findFirst()
- .orElseThrow(() -> new RuntimeException(format(
- "No such match field in table '%s' with name '%s'", TABLE0, INGRESS_PORT)))
- .field();
- return PiHeaderFieldId.of(fieldModel.header().name(), INGRESS_PORT);
- }
-
- private static int extractPortFieldBitWidth(PiPipelineModel model) {
- /*
- Get it form the set_egress_port action parameters.
- */
- return model
- .action(SET_EGRESS_PORT).orElseThrow(() -> new RuntimeException(format(
- "No such action '%s' in pipeline model", SET_EGRESS_PORT)))
- .param(PORT).orElseThrow(() -> new RuntimeException(format(
- "No such parameter '%s' of action '%s' in pipeline model", PORT, SET_EGRESS_PORT)))
- .bitWidth();
- }
-
-
- @Override
- public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId) throws PiInterpreterException {
- initTargetSpecificAttributes();
- if (treatment.allInstructions().size() == 0) {
- // No instructions means drop for us.
- return actionWithName(DROP);
- } else if (treatment.allInstructions().size() > 1) {
- // Otherwise, we understand treatments with only 1 instruction.
- throw new PiPipelineInterpreter.PiInterpreterException("Treatment has multiple instructions");
- }
-
- Instruction instruction = treatment.allInstructions().get(0);
-
- switch (instruction.type()) {
- case OUTPUT:
- Instructions.OutputInstruction outInstruction = (Instructions.OutputInstruction) instruction;
- return outputPiAction(outInstruction);
- case PROTOCOL_INDEPENDENT:
- PiInstruction piInstruction = (PiInstruction) instruction;
- return (PiAction) piInstruction.action();
- case NOACTION:
- return actionWithName(DROP);
- default:
- throw new PiInterpreterException(format("Instruction type '%s' not supported", instruction.type()));
- }
- }
-
- private PiAction outputPiAction(Instructions.OutputInstruction outInstruction) throws PiInterpreterException {
- PortNumber port = outInstruction.port();
- if (!port.isLogical()) {
- try {
- return PiAction.builder()
- .withId(PiActionId.of(SET_EGRESS_PORT))
- .withParameter(new PiActionParam(PiActionParamId.of(PORT),
- fit(copyFrom(port.toLong()), portFieldBitWidth)))
- .build();
- } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- throw new PiInterpreterException(e.getMessage());
- }
- } else if (port.equals(CONTROLLER)) {
- return actionWithName(SEND_TO_CPU);
- } else {
- throw new PiInterpreterException(format("Egress on logical port '%s' not supported", port));
- }
- }
-
- @Override
- public Optional<PiCounterId> mapTableCounter(PiTableId piTableId) {
- return Optional.ofNullable(TABLE_COUNTER_MAP.get(piTableId));
- }
-
- @Override
- public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
- throws PiInterpreterException {
- TrafficTreatment treatment = packet.treatment();
-
- // default.p4 supports only OUTPUT instructions.
- List<Instructions.OutputInstruction> outInstructions = treatment.allInstructions()
- .stream()
- .filter(i -> i.type().equals(OUTPUT))
- .map(i -> (Instructions.OutputInstruction) i)
- .collect(toList());
-
- if (treatment.allInstructions().size() != outInstructions.size()) {
- // There are other instructions that are not of type OUTPUT.
- throw new PiInterpreterException("Treatment not supported: " + treatment);
- }
-
- ImmutableList.Builder<PiPacketOperation> builder = ImmutableList.builder();
- for (Instructions.OutputInstruction outInst : outInstructions) {
- if (outInst.port().isLogical() && !outInst.port().equals(FLOOD)) {
- throw new PiInterpreterException(format("Output on logical port '%s' not supported", outInst.port()));
- } else if (outInst.port().equals(FLOOD)) {
- // Since default.p4 does not support flooding, we create a packet operation for each switch port.
- for (Port port : handler().get(DeviceService.class).getPorts(packet.sendThrough())) {
- builder.add(createPiPacketOperation(packet.data(), port.number().toLong()));
- }
- } else {
- builder.add(createPiPacketOperation(packet.data(), outInst.port().toLong()));
- }
- }
- return builder.build();
- }
-
- @Override
- public InboundPacket mapInboundPacket(DeviceId deviceId, PiPacketOperation packetIn)
- throws PiInterpreterException {
- // Assuming that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
- Ethernet ethPkt;
- try {
- ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
- } catch (DeserializationException dex) {
- throw new PiInterpreterException(dex.getMessage());
- }
-
- // Returns the ingress port packet metadata.
- Optional<PiPacketMetadata> packetMetadata = packetIn.metadatas()
- .stream().filter(metadata -> metadata.id().name().equals(INGRESS_PORT))
- .findFirst();
-
- if (packetMetadata.isPresent()) {
- ImmutableByteSequence portByteSequence = packetMetadata.get().value();
- short s = portByteSequence.asReadOnlyBuffer().getShort();
- ConnectPoint receivedFrom = new ConnectPoint(deviceId, PortNumber.portNumber(s));
- ByteBuffer rawData = ByteBuffer.wrap(packetIn.data().asArray());
- return new DefaultInboundPacket(receivedFrom, ethPkt, rawData);
- } else {
- throw new PiInterpreterException(format(
- "Missing metadata '%s' in packet-in received from '%s': %s", INGRESS_PORT, deviceId, packetIn));
- }
- }
-
- private PiPacketOperation createPiPacketOperation(ByteBuffer data, long portNumber) throws PiInterpreterException {
- PiPacketMetadata metadata = createPacketMetadata(portNumber);
- return PiPacketOperation.builder()
- .withType(PACKET_OUT)
- .withData(copyFrom(data))
- .withMetadatas(ImmutableList.of(metadata))
- .build();
- }
-
- private PiPacketMetadata createPacketMetadata(long portNumber) throws PiInterpreterException {
- initTargetSpecificAttributes();
- try {
- return PiPacketMetadata.builder()
- .withId(PiPacketMetadataId.of(EGRESS_PORT))
- .withValue(fit(copyFrom(portNumber), portFieldBitWidth))
- .build();
- } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- throw new PiInterpreterException(format("Port number %d too big, %s", portNumber, e.getMessage()));
- }
- }
-
- /**
- * Returns an action instance with no runtime parameters.
- */
- private PiAction actionWithName(String name) {
- return PiAction.builder().withId(PiActionId.of(name)).build();
- }
-
- @Override
- public Optional<PiHeaderFieldId> mapCriterionType(Criterion.Type type) {
- initTargetSpecificAttributes();
- return Optional.ofNullable(criterionMap.get(type));
- }
-
- @Override
- public Optional<Criterion.Type> mapPiHeaderFieldId(PiHeaderFieldId headerFieldId) {
- initTargetSpecificAttributes();
- return Optional.ofNullable(criterionMap.inverse().get(headerFieldId));
- }
-
- @Override
- public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
- return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
- }
-
- @Override
- public Optional<Integer> mapPiTableId(PiTableId piTableId) {
- return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
- }
-}
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
deleted file mode 100644
index b2b3760..0000000
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
+++ /dev/null
@@ -1,133 +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.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 org.onosproject.net.pi.runtime.PiIndirectCounterCellId;
-
-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;
-
-import static org.onosproject.net.pi.runtime.PiCounterType.INDIRECT;
-
-/**
- * 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 {
-
- // FIXME: hard-coding the scope here will break support for the P4_14 version of the program.
- // With P4_14, counter names in the generated P4Info won't have any scope.
- // A solution could be that of dynamically building counter IDs based on the P4Info (as in DefaultP4Interpreter).
- private static final String DEFAULT_SCOPE = "port_counters_control";
- private static final PiCounterId DEFAULT_INGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
- "ingress_port_counter",
- INDIRECT);
- private static final PiCounterId DEFAULT_EGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
- "egress_port_counter",
- INDIRECT);
-
- /**
- * Returns the ID of the ingress port counter.
- *
- * @return counter ID
- */
- public PiCounterId ingressCounterId() {
- return DEFAULT_INGRESS_COUNTER_ID;
- }
-
- /**
- * Returns the ID of the egress port counter.
- *
- * @return counter ID
- */
- public PiCounterId egressCounterId() {
- return DEFAULT_EGRESS_COUNTER_ID;
- }
-
- @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(p.number())
- .setDeviceId(deviceId)));
-
- Set<PiCounterCellId> counterCellIds = Sets.newHashSet();
- portStatBuilders.keySet().forEach(p -> {
- // Counter cell/index = port number.
- counterCellIds.add(PiIndirectCounterCellId.of(ingressCounterId(), p));
- counterCellIds.add(PiIndirectCounterCellId.of(egressCounterId(), 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(counterData -> {
- if (counterData.cellId().type() != INDIRECT) {
- log.warn("Invalid counter data type {}, skipping", counterData.cellId().type());
- return;
- }
- PiIndirectCounterCellId indCellId = (PiIndirectCounterCellId) counterData.cellId();
- if (!portStatBuilders.containsKey(indCellId.index())) {
- log.warn("Unrecognized counter index {}, skipping", counterData);
- return;
- }
- DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(indCellId.index());
- if (counterData.cellId().counterId().equals(ingressCounterId())) {
- statsBuilder.setPacketsReceived(counterData.packets());
- statsBuilder.setBytesReceived(counterData.bytes());
- } else if (counterData.cellId().counterId().equals(egressCounterId())) {
- statsBuilder.setPacketsSent(counterData.packets());
- statsBuilder.setBytesSent(counterData.bytes());
- } else {
- log.warn("Unrecognized counter ID {}, skipping", counterData);
- }
- });
-
- return portStatBuilders
- .values()
- .stream()
- .map(DefaultPortStatistics.Builder::build)
- .collect(Collectors.toList());
- }
-}