diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java index 2afbce0387..8043ae7080 100644 --- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java +++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java @@ -26,7 +26,7 @@ import org.onosproject.net.device.PortStatisticsDiscovery; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.pi.model.PiCounterId; import org.onosproject.net.pi.model.PiPipeconf; -import org.onosproject.net.pi.runtime.PiCounterCellData; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.service.PiPipeconfService; import org.onosproject.p4runtime.api.P4RuntimeClient; @@ -95,7 +95,7 @@ public final class PortStatisticsDiscoveryImpl extends AbstractHandlerBehaviour }); // Query the device. - Collection counterEntryResponse; + Collection counterEntryResponse; try { counterEntryResponse = client.readCounterCells(counterCellIds, pipeconf).get(); } catch (InterruptedException | ExecutionException e) { @@ -105,24 +105,24 @@ public final class PortStatisticsDiscoveryImpl extends AbstractHandlerBehaviour } // Process response. - counterEntryResponse.forEach(counterData -> { - if (counterData.cellId().counterType() != INDIRECT) { - log.warn("Invalid counter data type {}, skipping", counterData.cellId().counterType()); + counterEntryResponse.forEach(counterCell -> { + if (counterCell.cellId().counterType() != INDIRECT) { + log.warn("Invalid counter data type {}, skipping", counterCell.cellId().counterType()); return; } - if (!portStatBuilders.containsKey(counterData.cellId().index())) { - log.warn("Unrecognized counter index {}, skipping", counterData); + if (!portStatBuilders.containsKey(counterCell.cellId().index())) { + log.warn("Unrecognized counter index {}, skipping", counterCell); return; } - DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(counterData.cellId().index()); - if (counterData.cellId().counterId().equals(INGRESS_COUNTER_ID)) { - statsBuilder.setPacketsReceived(counterData.packets()); - statsBuilder.setBytesReceived(counterData.bytes()); - } else if (counterData.cellId().counterId().equals(EGRESS_COUNTER_ID)) { - statsBuilder.setPacketsSent(counterData.packets()); - statsBuilder.setBytesSent(counterData.bytes()); + DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(counterCell.cellId().index()); + if (counterCell.cellId().counterId().equals(INGRESS_COUNTER_ID)) { + statsBuilder.setPacketsReceived(counterCell.data().packets()); + statsBuilder.setBytesReceived(counterCell.data().bytes()); + } else if (counterCell.cellId().counterId().equals(EGRESS_COUNTER_ID)) { + statsBuilder.setPacketsSent(counterCell.data().packets()); + statsBuilder.setBytesSent(counterCell.data().bytes()); } else { - log.warn("Unrecognized counter ID {}, skipping", counterData); + log.warn("Unrecognized counter ID {}, skipping", counterCell); } }); diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java new file mode 100644 index 0000000000..9508cbca3e --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java @@ -0,0 +1,98 @@ +/* + * 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; + +/** + * Counter cell of a protocol-independent pipeline. + */ +@Beta +public final class PiCounterCell { + + private final PiCounterCellId cellId; + private final PiCounterCellData counterData; + + /** + * Creates a new counter cell for the given cell identifier and counter cell data. + * + * @param cellId counter cell identifier + * @param piCounterCellData counter cell data + */ + public PiCounterCell(PiCounterCellId cellId, PiCounterCellData piCounterCellData) { + this.cellId = cellId; + this.counterData = piCounterCellData; + } + + /** + * Creates a new counter cell 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 PiCounterCell(PiCounterCellId cellId, long packets, long bytes) { + this.cellId = cellId; + this.counterData = new PiCounterCellData(packets, bytes); + } + + /** + * Returns the cell identifier. + * + * @return cell identifier + */ + public PiCounterCellId cellId() { + return cellId; + } + + /** + * Returns the data contained by this cell. + * + * @return counter cell data + */ + public PiCounterCellData data() { + return counterData; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PiCounterCell)) { + return false; + } + PiCounterCell that = (PiCounterCell) o; + return Objects.equal(cellId, that.cellId) && + Objects.equal(counterData, that.counterData); + } + + @Override + public int hashCode() { + return Objects.hashCode(cellId, counterData); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("cellId", cellId) + .add("counterData", counterData) + .toString(); + } +} 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 index f0aada511f..b640970512 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2017-present Open Networking Foundation + * Copyright 2018-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. @@ -23,37 +23,26 @@ 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. + * Creates a new counter cell data for the given number of packets and bytes. * - * @param cellId counter cell identifier - * @param packets number of packets - * @param bytes number of bytes + * @param packets number of packets + * @param bytes number of bytes */ - public PiCounterCellData(PiCounterCellId cellId, long packets, long bytes) { - this.cellId = cellId; + public PiCounterCellData(long packets, long bytes) { 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. + * Returns the packet count value contained by this counter data. * * @return number of packets */ @@ -62,7 +51,7 @@ public final class PiCounterCellData { } /** - * Returns the byte count value contained by this cell. + * Returns the byte count value contained by this counter data. * * @return number of bytes */ @@ -80,19 +69,17 @@ public final class PiCounterCellData { } PiCounterCellData that = (PiCounterCellData) o; return packets == that.packets && - bytes == that.bytes && - Objects.equal(cellId, that.cellId); + bytes == that.bytes; } @Override public int hashCode() { - return Objects.hashCode(cellId, packets, bytes); + return Objects.hashCode(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/PiTableEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java index f8a14601c0..ac73bbef22 100644 --- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java +++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java @@ -42,10 +42,11 @@ public final class PiTableEntry implements PiEntity { private final long cookie; private final int priority; private final double timeout; + private final PiCounterCellData counterData; private PiTableEntry(PiTableId tableId, PiMatchKey matchKey, PiTableAction tableAction, boolean isDefaultAction, - long cookie, int priority, double timeout) { + long cookie, int priority, double timeout, PiCounterCellData data) { this.tableId = tableId; this.matchKey = matchKey; this.tableAction = tableAction; @@ -53,6 +54,7 @@ public final class PiTableEntry implements PiEntity { this.cookie = cookie; this.priority = priority; this.timeout = timeout; + this.counterData = data; } /** @@ -125,6 +127,18 @@ public final class PiTableEntry implements PiEntity { return timeout == NO_TIMEOUT ? Optional.empty() : Optional.of(timeout); } + /** + * Returns the data of the counter cell associated with this table entry. + * This method is meaningful only if the table entry was read from the + * infrastructure device and the table has direct counters, otherwise + * returns null. + * + * @return counter cell data + */ + public PiCounterCellData counter() { + return counterData; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -197,6 +211,7 @@ public final class PiTableEntry implements PiEntity { private long cookie = 0; private int priority = NO_PRIORITY; private double timeout = NO_TIMEOUT; + private PiCounterCellData counterData; private Builder() { // Hides constructor. @@ -271,6 +286,17 @@ public final class PiTableEntry implements PiEntity { return this; } + /** + * Sets the counter cell data of this table entry. + * + * @param data counter cell data + * @return this + */ + public Builder withCounterCellData(PiCounterCellData data) { + this.counterData = checkNotNull(data, "Counter cell data cannot be null"); + return this; + } + /** * Builds the table entry. * @@ -281,7 +307,7 @@ public final class PiTableEntry implements PiEntity { checkNotNull(matchKey); final boolean isDefaultAction = matchKey.equals(PiMatchKey.EMPTY); return new PiTableEntry(tableId, matchKey, tableAction, - isDefaultAction, cookie, priority, timeout); + isDefaultAction, cookie, priority, timeout, counterData); } } } diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellDataTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellDataTest.java index 667647069a..bfb8782ad7 100644 --- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellDataTest.java +++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-present Open Networking Foundation + * Copyright 2018-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. @@ -18,48 +18,25 @@ package org.onosproject.net.pi.runtime; import com.google.common.testing.EqualsTester; import org.junit.Test; -import org.onosproject.net.pi.model.PiActionId; -import org.onosproject.net.pi.model.PiTableId; import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; -import static org.onosproject.net.pi.runtime.PiConstantsTest.DROP; /** - * Unit tests for PiCounterCellData class. + * Unit tests for PiCounterData class. */ public class PiCounterCellDataTest { - private static final PiTableEntry PI_TABLE_ENTRY_1 = PiTableEntry.builder() - .forTable(PiTableId.of("T10")) - .withCookie(0xac) - .withPriority(10) - .withAction(PiAction.builder().withId(PiActionId.of(DROP)).build()) - .withTimeout(100) - .build(); - private static final PiTableEntry PI_TABLE_ENTRY_2 = PiTableEntry.builder() - .forTable(PiTableId.of("T20")) - .withCookie(0xac) - .withPriority(10) - .withAction(PiAction.builder().withId(PiActionId.of(DROP)).build()) - .withTimeout(1000) - .build(); - - private static final PiCounterCellId PI_COUNTER_CELL_ID_1 = - PiCounterCellId.ofDirect(PI_TABLE_ENTRY_1); - private static final PiCounterCellId PI_COUNTER_CELL_ID_2 = - PiCounterCellId.ofDirect(PI_TABLE_ENTRY_2); - private static final long PACKETS_1 = 10; private static final long PACKETS_2 = 20; private static final long BYTES_1 = 100; private static final long BYTES_2 = 200; - private static final PiCounterCellData PI_COUNTER_CELL_DATA_1 = - new PiCounterCellData(PI_COUNTER_CELL_ID_1, PACKETS_1, BYTES_1); - private static final PiCounterCellData SAME_AS_PI_COUNTER_CELL_DATA_1 = - new PiCounterCellData(PI_COUNTER_CELL_ID_1, PACKETS_1, BYTES_1); - private static final PiCounterCellData PI_COUNTER_CELL_DATA_2 = - new PiCounterCellData(PI_COUNTER_CELL_ID_2, PACKETS_2, BYTES_2); + private static final PiCounterCellData PI_COUNTER_DATA_1 = + new PiCounterCellData(PACKETS_1, BYTES_1); + private static final PiCounterCellData SAME_AS_PI_COUNTER_DATA_1 = + new PiCounterCellData(PACKETS_1, BYTES_1); + private static final PiCounterCellData PI_COUNTER_DATA_2 = + new PiCounterCellData(PACKETS_2, BYTES_2); /** * Checks that the PiCounterCellData class is immutable. @@ -75,8 +52,8 @@ public class PiCounterCellDataTest { @Test public void testEquals() { new EqualsTester() - .addEqualityGroup(PI_COUNTER_CELL_DATA_1, SAME_AS_PI_COUNTER_CELL_DATA_1) - .addEqualityGroup(PI_COUNTER_CELL_DATA_2) + .addEqualityGroup(PI_COUNTER_DATA_1, SAME_AS_PI_COUNTER_DATA_1) + .addEqualityGroup(PI_COUNTER_DATA_2) .testEquals(); } } diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellTest.java new file mode 100644 index 0000000000..ab65efe9e9 --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiCounterCellTest.java @@ -0,0 +1,82 @@ +/* + * 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.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.pi.model.PiActionId; +import org.onosproject.net.pi.model.PiTableId; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.pi.runtime.PiConstantsTest.DROP; + +/** + * Unit tests for PiCounterCell class. + */ +public class PiCounterCellTest { + + private static final PiTableEntry PI_TABLE_ENTRY_1 = PiTableEntry.builder() + .forTable(PiTableId.of("T10")) + .withCookie(0xac) + .withPriority(10) + .withAction(PiAction.builder().withId(PiActionId.of(DROP)).build()) + .withTimeout(100) + .build(); + private static final PiTableEntry PI_TABLE_ENTRY_2 = PiTableEntry.builder() + .forTable(PiTableId.of("T20")) + .withCookie(0xac) + .withPriority(10) + .withAction(PiAction.builder().withId(PiActionId.of(DROP)).build()) + .withTimeout(1000) + .build(); + + private static final PiCounterCellId PI_COUNTER_CELL_ID_1 = + PiCounterCellId.ofDirect(PI_TABLE_ENTRY_1); + private static final PiCounterCellId PI_COUNTER_CELL_ID_2 = + PiCounterCellId.ofDirect(PI_TABLE_ENTRY_2); + + private static final long PACKETS_1 = 10; + private static final long PACKETS_2 = 20; + private static final long BYTES_1 = 100; + private static final long BYTES_2 = 200; + + private static final PiCounterCell PI_COUNTER_CELL_1 = + new PiCounterCell(PI_COUNTER_CELL_ID_1, PACKETS_1, BYTES_1); + private static final PiCounterCell SAME_AS_PI_COUNTER_CELL_1 = + new PiCounterCell(PI_COUNTER_CELL_ID_1, PACKETS_1, BYTES_1); + private static final PiCounterCell PI_COUNTER_CELL_2 = + new PiCounterCell(PI_COUNTER_CELL_ID_2, PACKETS_2, BYTES_2); + + /** + * Checks that the PiCounterCell class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(PiCounterCell.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(PI_COUNTER_CELL_1, SAME_AS_PI_COUNTER_CELL_1) + .addEqualityGroup(PI_COUNTER_CELL_2) + .testEquals(); + } +} diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java index 0e684fe049..0fd964e1e6 100644 --- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java +++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java @@ -231,6 +231,7 @@ import org.onosproject.net.pi.runtime.PiActionGroupMemberHandle; import org.onosproject.net.pi.runtime.PiActionGroupMemberId; import org.onosproject.net.pi.runtime.PiActionParam; import org.onosproject.net.pi.runtime.PiControlMetadata; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiEntity; @@ -692,6 +693,7 @@ public final class KryoNamespaces { PiActionGroupMemberId.class, PiActionParam.class, PiControlMetadata.class, + PiCounterCell.class, PiCounterCellData.class, PiCounterCellId.class, PiEntity.class, 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 d0acdee80d..5a233ef40b 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 @@ -31,6 +31,7 @@ import org.onosproject.net.pi.model.PiPipelineInterpreter; import org.onosproject.net.pi.model.PiPipelineModel; import org.onosproject.net.pi.model.PiTableId; import org.onosproject.net.pi.model.PiTableModel; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiTableEntry; @@ -89,11 +90,11 @@ public class P4RuntimeFlowRuleProgrammable private static final String SUPPORT_TABLE_COUNTERS = "supportTableCounters"; private static final boolean DEFAULT_SUPPORT_TABLE_COUNTERS = true; - // If true, we read all direct counters of a table with one request. - // Otherwise, we send as many requests as the number of table entries. - private static final String READ_ALL_DIRECT_COUNTERS = "tableReadAllDirectCounters"; - // FIXME: set to true as soon as the feature is implemented in P4Runtime. - private static final boolean DEFAULT_READ_ALL_DIRECT_COUNTERS = false; + // If true, assumes that the device returns table entry message populated + // with direct counter values. If false, we issue a second P4Runtime request + // to read the direct counter values. + private static final String READ_COUNTERS_WITH_TABLE_ENTRIES = "tableReadCountersWithTableEntries"; + private static final boolean DEFAULT_READ_COUNTERS_WITH_TABLE_ENTRIES = true; // For default entries, P4Runtime mandates that only MODIFY messages are // allowed. If true, treats default entries as normal table entries, @@ -153,7 +154,6 @@ public class P4RuntimeFlowRuleProgrammable // Synchronize mirror with the device state. syncMirror(deviceEntries); - // TODO: ONOS-7596 read counters with table entries final Map counterCellMap = readEntryCounters(deviceEntries); // Forge flow entries with counter values. @@ -461,25 +461,22 @@ public class P4RuntimeFlowRuleProgrammable return Collections.emptyMap(); } - Collection cellDatas; - - if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS, - DEFAULT_READ_ALL_DIRECT_COUNTERS)) { - // FIXME: read counters when dumping table entries ONOS-7596 - cellDatas = Collections.emptyList(); + if (driverBoolProperty(READ_COUNTERS_WITH_TABLE_ENTRIES, + DEFAULT_READ_COUNTERS_WITH_TABLE_ENTRIES)) { + return tableEntries.stream().collect(Collectors.toMap(c -> c, PiTableEntry::counter)); } else { + Collection cells; Set cellIds = tableEntries.stream() // Ignore counter for default entry. .filter(e -> !e.isDefaultAction()) .filter(e -> tableHasCounter(e.table())) .map(PiCounterCellId::ofDirect) .collect(Collectors.toSet()); - cellDatas = getFutureWithDeadline(client.readCounterCells(cellIds, pipeconf), + cells = getFutureWithDeadline(client.readCounterCells(cellIds, pipeconf), "reading table counters", Collections.emptyList()); + return cells.stream() + .collect(Collectors.toMap(c -> c.cellId().tableEntry(), PiCounterCell::data)); } - return cellDatas.stream() - .collect(Collectors.toMap(c -> c.cellId().tableEntry(), c -> c)); - } private boolean tableHasCounter(PiTableId tableId) { diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java index ec8d5cf4d0..0e3923086a 100644 --- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java +++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java @@ -28,7 +28,7 @@ import org.onosproject.net.device.PortStatisticsDiscovery; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.pi.model.PiCounterId; import org.onosproject.net.pi.model.PiPipeconf; -import org.onosproject.net.pi.runtime.PiCounterCellData; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.service.PiPipeconfService; import org.onosproject.p4runtime.api.P4RuntimeClient; @@ -112,7 +112,7 @@ public class PortStatisticsDiscoveryImpl extends AbstractHandlerBehaviour implem counterCellIds.add(PiCounterCellId.ofIndirect(egressCounterId(), p)); }); - Collection counterEntryResponse; + Collection counterEntryResponse; try { counterEntryResponse = client.readCounterCells(counterCellIds, pipeconf).get(); } catch (InterruptedException | ExecutionException e) { @@ -121,25 +121,25 @@ public class PortStatisticsDiscoveryImpl extends AbstractHandlerBehaviour implem return Collections.emptyList(); } - counterEntryResponse.forEach(counterData -> { - if (counterData.cellId().counterType() != INDIRECT) { - log.warn("Invalid counter data type {}, skipping", counterData.cellId().counterType()); + counterEntryResponse.forEach(counterCell -> { + if (counterCell.cellId().counterType() != INDIRECT) { + log.warn("Invalid counter data type {}, skipping", counterCell.cellId().counterType()); return; } - PiCounterCellId indCellId = counterData.cellId(); + PiCounterCellId indCellId = counterCell.cellId(); if (!portStatBuilders.containsKey(indCellId.index())) { - log.warn("Unrecognized counter index {}, skipping", counterData); + log.warn("Unrecognized counter index {}, skipping", counterCell); 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()); + if (counterCell.cellId().counterId().equals(ingressCounterId())) { + statsBuilder.setPacketsReceived(counterCell.data().packets()); + statsBuilder.setBytesReceived(counterCell.data().bytes()); + } else if (counterCell.cellId().counterId().equals(egressCounterId())) { + statsBuilder.setPacketsSent(counterCell.data().packets()); + statsBuilder.setBytesSent(counterCell.data().bytes()); } else { - log.warn("Unrecognized counter ID {}, skipping", counterData); + log.warn("Unrecognized counter ID {}, skipping", counterCell); } }); 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 8c1d7d9af0..f30ec28f34 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 @@ -25,7 +25,7 @@ import org.onosproject.net.pi.model.PiTableId; import org.onosproject.net.pi.runtime.PiActionGroup; import org.onosproject.net.pi.runtime.PiActionGroupMember; import org.onosproject.net.pi.runtime.PiActionGroupMemberId; -import org.onosproject.net.pi.runtime.PiCounterCellData; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiMeterCellConfig; import org.onosproject.net.pi.runtime.PiMeterCellId; @@ -178,7 +178,7 @@ public interface P4RuntimeClient { * @param pipeconf pipeconf * @return list of counter data */ - CompletableFuture> readAllCounterCells( + CompletableFuture> readAllCounterCells( Set counterIds, PiPipeconf pipeconf); /** @@ -189,7 +189,7 @@ public interface P4RuntimeClient { * @param pipeconf pipeconf * @return list of counter data */ - CompletableFuture> readCounterCells( + CompletableFuture> readCounterCells( Set cellIds, PiPipeconf pipeconf); /** diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java index e88382183d..6c29062ce5 100644 --- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java +++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java @@ -20,7 +20,7 @@ import org.onosproject.net.pi.model.PiCounterId; import org.onosproject.net.pi.model.PiCounterType; import org.onosproject.net.pi.model.PiPipeconf; import org.onosproject.net.pi.model.PiTableId; -import org.onosproject.net.pi.runtime.PiCounterCellData; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiTableEntry; import org.slf4j.Logger; @@ -135,8 +135,8 @@ final class CounterEntryCodec { * @param pipeconf pipeconf * @return collection of PI counter cell data */ - static List decodeCounterEntities(List entities, - PiPipeconf pipeconf) { + static List decodeCounterEntities(List entities, + PiPipeconf pipeconf) { final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf); @@ -248,9 +248,9 @@ final class CounterEntryCodec { } } - private static PiCounterCellData decodeCounterEntity(Entity entity, - PiPipeconf pipeconf, - P4InfoBrowser browser) + private static PiCounterCell decodeCounterEntity(Entity entity, + PiPipeconf pipeconf, + P4InfoBrowser browser) throws EncodeException, P4InfoBrowser.NotFoundException { CounterData counterData; @@ -276,8 +276,8 @@ final class CounterEntryCodec { entity.getEntityCase().name())); } - return new PiCounterCellData(piCellId, - counterData.getPacketCount(), - counterData.getByteCount()); + return new PiCounterCell(piCellId, + counterData.getPacketCount(), + counterData.getByteCount()); } } 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 fa85056b6f..a06d67e9c0 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 @@ -43,7 +43,7 @@ import org.onosproject.net.pi.model.PiTableId; import org.onosproject.net.pi.runtime.PiActionGroup; import org.onosproject.net.pi.runtime.PiActionGroupMember; import org.onosproject.net.pi.runtime.PiActionGroupMemberId; -import org.onosproject.net.pi.runtime.PiCounterCellData; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiMeterCellConfig; import org.onosproject.net.pi.runtime.PiMeterCellId; @@ -281,15 +281,15 @@ final class P4RuntimeClientImpl implements P4RuntimeClient { } @Override - public CompletableFuture> readCounterCells(Set cellIds, - PiPipeconf pipeconf) { + public CompletableFuture> readCounterCells(Set cellIds, + PiPipeconf pipeconf) { return supplyInContext(() -> doReadCounterCells(Lists.newArrayList(cellIds), pipeconf), "readCounterCells-" + cellIds.hashCode()); } @Override - public CompletableFuture> readAllCounterCells(Set counterIds, - PiPipeconf pipeconf) { + public CompletableFuture> readAllCounterCells(Set counterIds, + PiPipeconf pipeconf) { return supplyInContext(() -> doReadAllCounterCells(Lists.newArrayList(counterIds), pipeconf), "readAllCounterCells-" + counterIds.hashCode()); } @@ -559,6 +559,7 @@ final class P4RuntimeClientImpl implements P4RuntimeClient { TableEntry.newBuilder() .setTableId(tableId) .setIsDefaultAction(defaultEntries) + .setCounterData(P4RuntimeOuterClass.CounterData.getDefaultInstance()) .build()) .build()) .build()); @@ -651,21 +652,21 @@ final class P4RuntimeClientImpl implements P4RuntimeClient { isClientMaster.set(isMaster); } - private List doReadAllCounterCells( + private List doReadAllCounterCells( List counterIds, PiPipeconf pipeconf) { return doReadCounterEntities( CounterEntryCodec.readAllCellsEntities(counterIds, pipeconf), pipeconf); } - private List doReadCounterCells( + private List doReadCounterCells( List cellIds, PiPipeconf pipeconf) { return doReadCounterEntities( CounterEntryCodec.encodePiCounterCellIds(cellIds, pipeconf), pipeconf); } - private List doReadCounterEntities( + private List doReadCounterEntities( List counterEntities, PiPipeconf pipeconf) { if (counterEntities.size() == 0) { diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java index d5d909f1c9..7e2df982f1 100644 --- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java +++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java @@ -29,6 +29,7 @@ import org.onosproject.net.pi.runtime.PiAction; import org.onosproject.net.pi.runtime.PiActionGroupId; import org.onosproject.net.pi.runtime.PiActionGroupMemberId; import org.onosproject.net.pi.runtime.PiActionParam; +import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiExactFieldMatch; import org.onosproject.net.pi.runtime.PiFieldMatch; import org.onosproject.net.pi.runtime.PiLpmFieldMatch; @@ -40,6 +41,7 @@ import org.onosproject.net.pi.runtime.PiTernaryFieldMatch; import org.slf4j.Logger; import p4.config.v1.P4InfoOuterClass; import p4.v1.P4RuntimeOuterClass.Action; +import p4.v1.P4RuntimeOuterClass.CounterData; import p4.v1.P4RuntimeOuterClass.FieldMatch; import p4.v1.P4RuntimeOuterClass.TableAction; import p4.v1.P4RuntimeOuterClass.TableEntry; @@ -249,6 +251,11 @@ final class TableEntryEncoder { } } + // Counter. + if (piTableEntry.counter() != null) { + tableEntryMsgBuilder.setCounterData(encodeCounter(piTableEntry.counter())); + } + return tableEntryMsgBuilder.build(); } @@ -281,6 +288,9 @@ final class TableEntryEncoder { // Match key for field matches. piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser)); + // Counter. + piTableEntryBuilder.withCounterCellData(decodeCounter(tableEntryMsg.getCounterData())); + return piTableEntryBuilder.build(); } @@ -505,4 +515,13 @@ final class TableEntryEncoder { } return PiAction.builder().withId(id).withParameters(params).build(); } -} + + static CounterData encodeCounter(PiCounterCellData piCounterCellData) { + return CounterData.newBuilder().setPacketCount(piCounterCellData.packets()) + .setByteCount(piCounterCellData.bytes()).build(); + } + + static PiCounterCellData decodeCounter(CounterData counterData) { + return new PiCounterCellData(counterData.getPacketCount(), counterData.getByteCount()); + } +} \ No newline at end of file diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java index 07991087a3..d9e5f9a75f 100644 --- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java +++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java @@ -32,11 +32,13 @@ import org.onosproject.net.pi.model.PiTableId; import org.onosproject.net.pi.runtime.PiAction; import org.onosproject.net.pi.runtime.PiActionGroupId; import org.onosproject.net.pi.runtime.PiActionParam; +import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiExactFieldMatch; import org.onosproject.net.pi.runtime.PiMatchKey; import org.onosproject.net.pi.runtime.PiTableEntry; import org.onosproject.net.pi.runtime.PiTernaryFieldMatch; import p4.v1.P4RuntimeOuterClass.Action; +import p4.v1.P4RuntimeOuterClass.CounterData; import p4.v1.P4RuntimeOuterClass.TableEntry; import java.net.URL; @@ -72,6 +74,9 @@ public class TableEntryEncoderTest { private static final String ETHER_TYPE = "etherType"; private static final String ECMP_GROUP_ID = "ecmp_group_id"; + private static final long PACKETS = 10; + private static final long BYTES = 100; + private final Random rand = new Random(); private final URL p4InfoUrl = this.getClass().getResource("/test.p4info"); @@ -94,6 +99,7 @@ public class TableEntryEncoderTest { private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT); private final PiTableId tableId = PiTableId.of(TABLE_0); private final PiTableId ecmpTableId = PiTableId.of(TABLE_ECMP); + private final PiCounterCellData counterCellData = new PiCounterCellData(PACKETS, BYTES); private final PiTableEntry piTableEntry = PiTableEntry .builder() @@ -111,6 +117,7 @@ public class TableEntryEncoderTest { .build()) .withPriority(1) .withCookie(2) + .withCounterCellData(counterCellData) .build(); private final PiTableEntry piTableEntryWithoutAction = PiTableEntry @@ -124,6 +131,7 @@ public class TableEntryEncoderTest { .build()) .withPriority(1) .withCookie(2) + .withCounterCellData(counterCellData) .build(); private final PiTableEntry piTableEntryWithGroupAction = PiTableEntry @@ -135,6 +143,7 @@ public class TableEntryEncoderTest { .withAction(PiActionGroupId.of(1)) .withPriority(1) .withCookie(2) + .withCounterCellData(counterCellData) .build(); public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException { @@ -198,6 +207,12 @@ public class TableEntryEncoderTest { byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray(); assertThat(encodedActionParam, is(portValue.asArray())); + // Counter + CounterData counterData = tableEntryMsg.getCounterData(); + PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(), + counterData.getByteCount()); + assertThat(encodedCounterData, is(counterCellData)); + // TODO: improve, assert other field match types (ternary, LPM) } @@ -257,6 +272,12 @@ public class TableEntryEncoderTest { // no action assertThat(tableEntryMsg.hasAction(), is(false)); + // Counter + CounterData counterData = tableEntryMsg.getCounterData(); + PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(), + counterData.getByteCount()); + assertThat(encodedCounterData, is(counterCellData)); + // TODO: improve, assert other field match types (ternary, LPM) } }