mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-11-02 17:21:05 +01:00
[ONOS-7596] Support reading table entries with counter data in P4Runtime
Change-Id: I85bacb1697a6c881dd69ba74a2162c73ec0b8aee
This commit is contained in:
parent
a25251cdf5
commit
7632e150e1
@ -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<PiCounterCellData> counterEntryResponse;
|
||||
Collection<PiCounterCell> 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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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<PiTableEntry, PiCounterCellData> counterCellMap =
|
||||
readEntryCounters(deviceEntries);
|
||||
// Forge flow entries with counter values.
|
||||
@ -461,25 +461,22 @@ public class P4RuntimeFlowRuleProgrammable
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Collection<PiCounterCellData> 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<PiCounterCell> cells;
|
||||
Set<PiCounterCellId> 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) {
|
||||
|
||||
@ -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<PiCounterCellData> counterEntryResponse;
|
||||
Collection<PiCounterCell> 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);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@ -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<List<PiCounterCellData>> readAllCounterCells(
|
||||
CompletableFuture<List<PiCounterCell>> readAllCounterCells(
|
||||
Set<PiCounterId> counterIds, PiPipeconf pipeconf);
|
||||
|
||||
/**
|
||||
@ -189,7 +189,7 @@ public interface P4RuntimeClient {
|
||||
* @param pipeconf pipeconf
|
||||
* @return list of counter data
|
||||
*/
|
||||
CompletableFuture<List<PiCounterCellData>> readCounterCells(
|
||||
CompletableFuture<List<PiCounterCell>> readCounterCells(
|
||||
Set<PiCounterCellId> cellIds, PiPipeconf pipeconf);
|
||||
|
||||
/**
|
||||
|
||||
@ -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<PiCounterCellData> decodeCounterEntities(List<Entity> entities,
|
||||
PiPipeconf pipeconf) {
|
||||
static List<PiCounterCell> decodeCounterEntities(List<Entity> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<List<PiCounterCellData>> readCounterCells(Set<PiCounterCellId> cellIds,
|
||||
PiPipeconf pipeconf) {
|
||||
public CompletableFuture<List<PiCounterCell>> readCounterCells(Set<PiCounterCellId> cellIds,
|
||||
PiPipeconf pipeconf) {
|
||||
return supplyInContext(() -> doReadCounterCells(Lists.newArrayList(cellIds), pipeconf),
|
||||
"readCounterCells-" + cellIds.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<PiCounterCellData>> readAllCounterCells(Set<PiCounterId> counterIds,
|
||||
PiPipeconf pipeconf) {
|
||||
public CompletableFuture<List<PiCounterCell>> readAllCounterCells(Set<PiCounterId> 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<PiCounterCellData> doReadAllCounterCells(
|
||||
private List<PiCounterCell> doReadAllCounterCells(
|
||||
List<PiCounterId> counterIds, PiPipeconf pipeconf) {
|
||||
return doReadCounterEntities(
|
||||
CounterEntryCodec.readAllCellsEntities(counterIds, pipeconf),
|
||||
pipeconf);
|
||||
}
|
||||
|
||||
private List<PiCounterCellData> doReadCounterCells(
|
||||
private List<PiCounterCell> doReadCounterCells(
|
||||
List<PiCounterCellId> cellIds, PiPipeconf pipeconf) {
|
||||
return doReadCounterEntities(
|
||||
CounterEntryCodec.encodePiCounterCellIds(cellIds, pipeconf),
|
||||
pipeconf);
|
||||
}
|
||||
|
||||
private List<PiCounterCellData> doReadCounterEntities(
|
||||
private List<PiCounterCell> doReadCounterEntities(
|
||||
List<Entity> counterEntities, PiPipeconf pipeconf) {
|
||||
|
||||
if (counterEntities.size() == 0) {
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user