From 384572db83e9306b8aee39d7edd94e85e1c298a7 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Thu, 21 Apr 2022 17:09:22 +0200 Subject: [PATCH 01/12] Allow to modify UPF counters --- .../behaviour/upf/FabricUpfProgrammable.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index 20b0f5abc..aef21b394 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -46,9 +46,12 @@ 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.PiCounterCellHandle; import org.onosproject.net.pi.runtime.PiCounterCellId; +import org.onosproject.net.pi.runtime.PiEntity; import org.onosproject.net.pi.runtime.PiMeterCellId; +import org.onosproject.p4runtime.api.P4RuntimeWriteClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.stratumproject.fabric.tna.Constants; @@ -547,6 +550,26 @@ private Collection getUpfTerminationsDownlink() throws UpfProgrammabl return upfTerminations; } + private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableException { + PiEntity piIngressCounter = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), + new PiCounterCellData(upfCounter.getIngressPkts(), upfCounter.getIngressBytes())); + PiEntity piEgressCounter = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), + new PiCounterCellData(upfCounter.getEgressPkts(), upfCounter.getEgressBytes())); + // Query the device. + P4RuntimeWriteClient.WriteResponse writeResponse = client.write( + DEFAULT_P4_DEVICE_ID, pipeconf) + .modify(Lists.newArrayList(piIngressCounter, piEgressCounter)) + .submitSync(); + if (!writeResponse.failed().isEmpty()) { + writeResponse.failed().stream().filter(counterEntryResp -> !counterEntryResp.isSuccess()) + .forEach(counterEntryResp -> log.warn("A counter was not modified correctly: {}", + counterEntryResp.explanation())); + throw new UpfProgrammableException("Failed to modify counters"); + } + } + @Override public Collection readCounters(long maxCounterId) { if (!setupBehaviour("readCounters()")) { @@ -717,12 +740,14 @@ public void apply(UpfEntity entity) throws UpfProgrammableException { case APPLICATION: addUpfApplication((UpfApplication) entity); break; + case COUNTER: + applyUpfCounter((UpfCounter) entity); + break; case SESSION_METER: case APPLICATION_METER: case SLICE_METER: applyUpfMeter((UpfMeter) entity); break; - case COUNTER: default: throw new UpfProgrammableException(format("Adding entity type %s not supported.", entity.type().humanReadableName())); @@ -854,8 +879,8 @@ public void delete(UpfEntity entity) throws UpfProgrammableException { case SESSION_METER: case APPLICATION_METER: case SLICE_METER: - // Meter cannot be deleted, only modified. case COUNTER: + // Entities cannot be deleted, only modified. default: throw new UpfProgrammableException(format("Deleting entity type %s not supported.", entity.type().humanReadableName())); From dd024950305fd69fe1856ea16c292ef649d594a9 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Fri, 22 Apr 2022 14:20:11 +0200 Subject: [PATCH 02/12] Add unit test and mocks --- .../behaviour/upf/FabricUpfProgrammable.java | 4 +- .../upf/FabricUpfProgrammableTest.java | 85 ++++++++---- .../behaviour/upf/MockP4RuntimeClient.java | 120 +++++++++++++++++ .../upf/MockP4RuntimeController.java | 24 +--- .../tna/behaviour/upf/MockReadRequest.java | 47 ++++--- .../tna/behaviour/upf/MockReadResponse.java | 35 +++-- .../tna/behaviour/upf/MockWriteRequest.java | 125 ++++++++++++++++++ .../tna/behaviour/upf/MockWriteResponse.java | 59 +++++++++ .../tna/behaviour/upf/TestUpfConstants.java | 31 ++++- 9 files changed, 450 insertions(+), 80 deletions(-) create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index aef21b394..cd7c32db6 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -557,14 +557,14 @@ private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableExcept PiEntity piEgressCounter = new PiCounterCell( PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), new PiCounterCellData(upfCounter.getEgressPkts(), upfCounter.getEgressBytes())); - // Query the device. + // Write on the device in sync mode. P4RuntimeWriteClient.WriteResponse writeResponse = client.write( DEFAULT_P4_DEVICE_ID, pipeconf) .modify(Lists.newArrayList(piIngressCounter, piEgressCounter)) .submitSync(); if (!writeResponse.failed().isEmpty()) { writeResponse.failed().stream().filter(counterEntryResp -> !counterEntryResp.isSuccess()) - .forEach(counterEntryResp -> log.warn("A counter was not modified correctly: {}", + .forEach(counterEntryResp -> log.error("A counter was not modified correctly: {}", counterEntryResp.explanation())); throw new UpfProgrammableException("Failed to modify counters"); } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java index 83426e493..18977e53b 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java @@ -1,3 +1,4 @@ +// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; @@ -57,26 +58,12 @@ import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; -import static org.easymock.EasyMock.anyString; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.stratumproject.fabric.tna.Constants.TNA; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_QOS_SLICE_TC_METER; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APPLICATIONS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APP_METER; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_DOWNLINK_SESSIONS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_DOWNLINK_TERMINATIONS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_IG_TUNNEL_PEERS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_SESSION_METER; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_SESSIONS; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_TERMINATIONS; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.SLICE_MOBILE; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.*; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.*; public class FabricUpfProgrammableTest { @@ -120,9 +107,9 @@ public class FabricUpfProgrammableTest { ); private static final List METER_MODELS = ImmutableList.of( new MockMeterModel(FABRIC_INGRESS_UPF_SESSION_METER, - TestUpfConstants.PHYSICAL_SESSION_METER_SIZE), + TestUpfConstants.PHYSICAL_SESSION_METER_SIZE), new MockMeterModel(FABRIC_INGRESS_UPF_APP_METER, - TestUpfConstants.PHYSICAL_APP_METER_SIZE), + TestUpfConstants.PHYSICAL_APP_METER_SIZE), new MockMeterModel(FABRIC_INGRESS_QOS_SLICE_TC_METER, TestUpfConstants.PHYSICAL_MAX_SLICE_METERS) ); @@ -173,8 +160,6 @@ public void setUp() throws Exception { .anyTimes(); expect(driverHandler.get(P4RuntimeController.class)) .andReturn(new MockP4RuntimeController(TestUpfConstants.DEVICE_ID, - TestUpfConstants.COUNTER_PKTS, - TestUpfConstants.COUNTER_BYTES, TestUpfConstants.PHYSICAL_COUNTER_SIZE)) .anyTimes(); expect(driverHandler.data()).andReturn(driverData).anyTimes(); @@ -351,6 +336,24 @@ public void testSliceMeter() throws Exception { assertTrue(upfProgrammable.readAll(UpfEntityType.SLICE_METER).isEmpty()); } + @Test + public void testCounter() throws Exception { + assertThat( + upfProgrammable.readCounter(TestUpfConstants.UPLINK_COUNTER.getCellId()), + equalTo(ZERO_UPLINK_COUNTER) + ); + UpfCounter expectedCounter = TestUpfConstants.UPLINK_COUNTER; + upfProgrammable.apply(expectedCounter); + UpfCounter installedCounter = + upfProgrammable.readCounter(expectedCounter.getCellId()); + assertThat(installedCounter, equalTo(expectedCounter)); + upfProgrammable.apply(ZERO_UPLINK_COUNTER); + assertThat( + upfProgrammable.readCounter(TestUpfConstants.UPLINK_COUNTER.getCellId()), + equalTo(ZERO_UPLINK_COUNTER) + ); + } + @Test public void testInvalidSliceIdSliceMeter() throws Exception { exceptionRule.expect(UpfProgrammableException.class); @@ -380,14 +383,46 @@ public void testClearInterfaces() throws Exception { @Test public void testReadAllCounters() throws Exception { + assertAllZeroCounters(); + + upfProgrammable.apply(UPLINK_COUNTER); + upfProgrammable.apply(DOWNLINK_COUNTER); + Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); + assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); + for (UpfEntity entity : allStats) { + UpfCounter stat = (UpfCounter) entity; + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertThat(stat.getIngressBytes(), equalTo(UL_COUNTER_BYTES)); + assertThat(stat.getEgressBytes(), equalTo(UL_COUNTER_BYTES)); + assertThat(stat.getIngressPkts(), equalTo(UL_COUNTER_PKTS)); + assertThat(stat.getEgressPkts(), equalTo(UL_COUNTER_PKTS)); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertThat(stat.getIngressBytes(), equalTo(DL_COUNTER_BYTES)); + assertThat(stat.getEgressBytes(), equalTo(DL_COUNTER_BYTES)); + assertThat(stat.getIngressPkts(), equalTo(DL_COUNTER_PKTS)); + assertThat(stat.getEgressPkts(), equalTo(UL_COUNTER_PKTS)); + } else { + assertThat(stat.getIngressBytes(), equalTo(0L)); + assertThat(stat.getEgressBytes(), equalTo(0L)); + assertThat(stat.getIngressPkts(), equalTo(0L)); + assertThat(stat.getEgressPkts(), equalTo(0L)); + } + } + + upfProgrammable.apply(ZERO_UPLINK_COUNTER); + upfProgrammable.apply(ZERO_DOWNLINK_COUNTER); + assertAllZeroCounters(); + } + + private void assertAllZeroCounters() throws UpfProgrammableException { Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); for (UpfEntity entity : allStats) { UpfCounter stat = (UpfCounter) entity; - assertThat(stat.getIngressBytes(), equalTo(TestUpfConstants.COUNTER_BYTES)); - assertThat(stat.getEgressBytes(), equalTo(TestUpfConstants.COUNTER_BYTES)); - assertThat(stat.getIngressPkts(), equalTo(TestUpfConstants.COUNTER_PKTS)); - assertThat(stat.getEgressPkts(), equalTo(TestUpfConstants.COUNTER_PKTS)); + assertThat(stat.getIngressBytes(), equalTo(0L)); + assertThat(stat.getEgressBytes(), equalTo(0L)); + assertThat(stat.getIngressPkts(), equalTo(0L)); + assertThat(stat.getEgressPkts(), equalTo(0L)); } } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java new file mode 100644 index 000000000..11304e93b --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java @@ -0,0 +1,120 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import com.google.common.collect.Maps; +import org.onosproject.net.DeviceId; +import org.onosproject.net.pi.model.PiPipeconf; +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.PiPacketOperation; +import org.onosproject.p4runtime.api.P4RuntimeClient; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.LongStream; + +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; + +/** + * Used to mock P4Runtime client used only for read/write requests for counters. + */ +public class MockP4RuntimeClient implements P4RuntimeClient { + + private final DeviceId deviceId; + private final Map igCounters; + private final Map egCounters; + + /** + * Used to mock P4Runtime client. + * + * @param deviceId The ID of the device + * @param counterSize The size of the counter array + */ + public MockP4RuntimeClient(DeviceId deviceId, int counterSize) { + this.deviceId = deviceId; + igCounters = Maps.newHashMap(); + egCounters = Maps.newHashMap(); + LongStream.range(0, counterSize).forEach(i -> { + + }); + for (long i = 0; i < counterSize; i++) { + igCounters.put(i, new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, i), + new PiCounterCellData(0, 0))); + egCounters.put(i, new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, i), + new PiCounterCellData(0, 0))); + } + } + + @Override + public void shutdown() { + + } + + @Override + public boolean isServerReachable() { + return false; + } + + @Override + public CompletableFuture probeService() { + return null; + } + + @Override + public CompletableFuture setPipelineConfig(long p4DeviceId, PiPipeconf pipeconf, ByteBuffer deviceData) { + return null; + } + + @Override + public CompletableFuture isPipelineConfigSet(long p4DeviceId, PiPipeconf pipeconf) { + return null; + } + + @Override + public CompletableFuture isAnyPipelineConfigSet(long p4DeviceId) { + return null; + } + + @Override + public ReadRequest read(long p4DeviceId, PiPipeconf pipeconf) { + return new MockReadRequest(deviceId, igCounters, egCounters); + } + + @Override + public void setMastership(long p4DeviceId, boolean master, BigInteger electionId) { + + } + + @Override + public boolean isSessionOpen(long p4DeviceId) { + return false; + } + + @Override + public void closeSession(long p4DeviceId) { + + } + + @Override + public boolean isMaster(long p4DeviceId) { + return false; + } + + @Override + public void packetOut(long p4DeviceId, PiPacketOperation packet, PiPipeconf pipeconf) { + + } + + @Override + public WriteRequest write(long p4DeviceId, PiPipeconf pipeconf) { + return new MockWriteRequest(deviceId, igCounters, egCounters); + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java index 63fb63305..d23b27f4f 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java @@ -1,3 +1,4 @@ +// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; @@ -5,39 +6,26 @@ import io.grpc.ManagedChannel; import org.onosproject.net.DeviceId; import org.onosproject.net.device.DeviceAgentListener; -import org.onosproject.net.pi.model.PiPipeconf; import org.onosproject.net.provider.ProviderId; import org.onosproject.p4runtime.api.P4RuntimeClient; import org.onosproject.p4runtime.api.P4RuntimeController; import org.onosproject.p4runtime.api.P4RuntimeEventListener; -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; - /** - * Currently only used to get mock clients that mock counter read requests. + * Currently only used to get mock clients that mock counter read/write requests. */ public class MockP4RuntimeController implements P4RuntimeController { private final P4RuntimeClient mockP4rtClient; /** - * Used to mock counter read requests. + * Used to mock counter read/write requests. * - * @param deviceId The ID of the device - * @param packets Packets counter value - * @param bytes Bytes counter value + * @param deviceId The ID of the device * @param counterSize The size of the counter array */ - public MockP4RuntimeController(DeviceId deviceId, long packets, long bytes, int counterSize) { - mockP4rtClient = createMock(P4RuntimeClient.class); - expect(mockP4rtClient.read(anyLong(), anyObject(PiPipeconf.class))) - .andReturn(new MockReadRequest(deviceId, packets, bytes, counterSize)) - .anyTimes(); - replay(mockP4rtClient); + public MockP4RuntimeController(DeviceId deviceId, int counterSize) { + mockP4rtClient = new MockP4RuntimeClient(deviceId, counterSize); } @Override diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java index 766e08070..9addb1458 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java @@ -1,3 +1,4 @@ +// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; @@ -7,47 +8,49 @@ import org.onosproject.net.pi.model.PiCounterId; import org.onosproject.net.pi.model.PiMeterId; import org.onosproject.net.pi.model.PiTableId; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellHandle; -import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiHandle; import org.onosproject.p4runtime.api.P4RuntimeReadClient; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.stream.LongStream; import static com.google.common.base.Preconditions.checkNotNull; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; /** - * For faking reads to a p4runtime client. Currently only used for testing + * For faking reads to a p4runtime client. Currently, only used for testing * UP4-specific counter reads, because all other P4 entities that UP4 reads can * be read via other ONOS services. */ public class MockReadRequest implements P4RuntimeReadClient.ReadRequest { List handles; DeviceId deviceId; - long packets; - long bytes; - int counterSize; + Map igCounters; + Map egCounters; - public MockReadRequest(DeviceId deviceId, long packets, long bytes, int counterSize) { + public MockReadRequest(DeviceId deviceId, + Map igCounters, + Map egCounters) { this.handles = new ArrayList<>(); this.deviceId = deviceId; - this.packets = packets; - this.bytes = bytes; - this.counterSize = counterSize; + this.igCounters = igCounters; + this.egCounters = egCounters; } @Override public CompletableFuture submit() { return CompletableFuture.completedFuture( - new MockReadResponse(this.handles, this.packets, this.bytes)); + new MockReadResponse(this.handles, this.igCounters, this.egCounters)); } @Override public P4RuntimeReadClient.ReadResponse submitSync() { - return new MockReadResponse(this.handles, this.packets, this.bytes); + return new MockReadResponse(this.handles, this.igCounters, this.egCounters); } @@ -106,21 +109,21 @@ public P4RuntimeReadClient.ReadRequest actionProfileMembers(Iterable { + this.handles.add(PiCounterCellHandle.of(this.deviceId, counterCell.cellId())); + }); + } else if (counterId.equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + egCounters.values().forEach(counterCell -> { + this.handles.add(PiCounterCellHandle.of(this.deviceId, counterCell.cellId())); + }); + } return this; } @Override public P4RuntimeReadClient.ReadRequest counterCells(Iterable counterIds) { - counterIds.forEach(counterId -> { - LongStream.range(0, this.counterSize) - .forEach(index -> { - PiCounterCellId cellId = - PiCounterCellId.ofIndirect(counterId, index); - PiCounterCellHandle handle = - PiCounterCellHandle.of(this.deviceId, cellId); - this.handle(handle); - }); - }); + counterIds.forEach(this::counterCells); return this; } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java index f3eff5d84..bd4268fb5 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java @@ -1,10 +1,11 @@ +// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; import org.onosproject.net.pi.runtime.PiCounterCell; -import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiCounterCellHandle; +import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiEntity; import org.onosproject.net.pi.runtime.PiEntityType; import org.onosproject.net.pi.runtime.PiHandle; @@ -13,8 +14,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; /** * For faking reads to a p4runtime client. Currently only used for testing @@ -23,13 +27,15 @@ */ public class MockReadResponse implements P4RuntimeReadClient.ReadResponse { List entities; - long packets; - long bytes; + Map igCounters; + Map egCounters; - public MockReadResponse(Iterable handles, long packets, long bytes) { + public MockReadResponse(Iterable handles, + Map igCounters, + Map egCounters) { this.entities = new ArrayList<>(); - this.packets = packets; - this.bytes = bytes; + this.igCounters = igCounters; + this.egCounters = egCounters; checkNotNull(handles); handles.forEach(this::handle); } @@ -42,13 +48,20 @@ public boolean isSuccess() { public MockReadResponse handle(PiHandle handle) { if (handle.entityType().equals(PiEntityType.COUNTER_CELL)) { PiCounterCellHandle counterHandle = (PiCounterCellHandle) handle; - PiCounterCellData data = - new PiCounterCellData(this.packets, this.bytes); - PiEntity entity = new PiCounterCell(counterHandle.cellId(), data); - this.entities.add(entity); + PiCounterCellId cellId = counterHandle.cellId(); + if (cellId.counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { + PiEntity entity = new PiCounterCell( + counterHandle.cellId(), + igCounters.get(cellId.index()).data()); + this.entities.add(entity); + } else if (cellId.counterId().equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + PiEntity entity = new PiCounterCell( + counterHandle.cellId(), + egCounters.get(cellId.index()).data()); + this.entities.add(entity); + } } // Only handles counter cell so far - return this; } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java new file mode 100644 index 000000000..bc4917ca2 --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java @@ -0,0 +1,125 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.pi.runtime.PiCounterCell; +import org.onosproject.net.pi.runtime.PiCounterCellId; +import org.onosproject.net.pi.runtime.PiEntity; +import org.onosproject.net.pi.runtime.PiEntityType; +import org.onosproject.net.pi.runtime.PiHandle; +import org.onosproject.p4runtime.api.P4RuntimeWriteClient; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; + +/** + * For faking writes to a p4runtime client. Currently, only used for testing + * UP4-specific counter writes, all other entities are accessed via other ONOS + * services. + */ +public class MockWriteRequest implements P4RuntimeWriteClient.WriteRequest { + private final List toModifyEntities; + private final DeviceId deviceId; + private final Map igCounters; + private final Map egCounters; + + public MockWriteRequest(DeviceId deviceId, + Map igCounters, + Map egCounters) { + this.toModifyEntities = new ArrayList<>(); + this.deviceId = deviceId; + this.igCounters = igCounters; + this.egCounters = egCounters; + } + + @Override + public P4RuntimeWriteClient.WriteRequest withAtomicity(P4RuntimeWriteClient.Atomicity atomicity) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest insert(PiEntity entity) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest insert(Iterable entities) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest modify(PiEntity entity) { + toModifyEntities.add(entity); + return this; + } + + @Override + public P4RuntimeWriteClient.WriteRequest modify(Iterable entities) { + entities.forEach(toModifyEntities::add); + return this; + } + + @Override + public P4RuntimeWriteClient.WriteRequest delete(PiHandle handle) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest delete(Iterable handles) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest entity(PiEntity entity, P4RuntimeWriteClient.UpdateType updateType) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest entities(Iterable entities, + P4RuntimeWriteClient.UpdateType updateType) { + return null; + } + + @Override + public CompletableFuture submit() { + modifyEntities(); + return CompletableFuture.completedFuture( + new MockWriteResponse(toModifyEntities.size())); + } + + @Override + public P4RuntimeWriteClient.WriteResponse submitSync() { + modifyEntities(); + return new MockWriteResponse(toModifyEntities.size()); + } + + private void modifyEntities() { + // Only handles counter cell so far + toModifyEntities.forEach( + entity -> { + if (entity.piEntityType().equals(PiEntityType.COUNTER_CELL)) { + PiCounterCell counterCell = (PiCounterCell) entity; + PiCounterCellId cellId = counterCell.cellId(); + if (cellId.counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { + igCounters.computeIfPresent(cellId.index(), (k, v) -> counterCell); + } else if (cellId.counterId().equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + egCounters.computeIfPresent(cellId.index(), (k, v) -> counterCell); + } + } + } + ); + } + + @Override + public Collection pendingUpdates() { + return null; + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java new file mode 100644 index 000000000..dabc086aa --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java @@ -0,0 +1,59 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import com.google.common.collect.Lists; +import org.onosproject.p4runtime.api.P4RuntimeWriteClient; + +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +import static org.easymock.EasyMock.*; + +/** + * For faking writes to a p4runtime client. Currently, only used for testing + * UP4-specific counter writes, all other entities are accessed via other ONOS + * services. + */ +public class MockWriteResponse implements P4RuntimeWriteClient.WriteResponse { + + int numEntities; + + public MockWriteResponse(int numEntities) { + this.numEntities = numEntities; + } + + @Override + public boolean isSuccess() { + return true; + } + + @Override + public Collection all() { + P4RuntimeWriteClient.EntityUpdateResponse mockPosResponse = + createMock(P4RuntimeWriteClient.EntityUpdateResponse.class); + expect(mockPosResponse.isSuccess()) + .andReturn(true) + .anyTimes(); + replay(mockPosResponse); + return LongStream.range(0, numEntities).mapToObj(i -> mockPosResponse).collect(Collectors.toList()); + } + + @Override + public Collection success() { + return all(); + } + + @Override + public Collection failed() { + return Lists.newArrayList(); + } + + @Override + public Collection status( + P4RuntimeWriteClient.EntityUpdateStatus status) { + return null; + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java index 4ba528fd1..c41a24567 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java @@ -11,6 +11,7 @@ import org.onosproject.core.DefaultApplicationId; import org.onosproject.net.DeviceId; import org.onosproject.net.behaviour.upf.UpfApplication; +import org.onosproject.net.behaviour.upf.UpfCounter; import org.onosproject.net.behaviour.upf.UpfGtpTunnelPeer; import org.onosproject.net.behaviour.upf.UpfInterface; import org.onosproject.net.behaviour.upf.UpfMeter; @@ -121,8 +122,10 @@ public final class TestUpfConstants { public static final int PHYSICAL_MAX_SLICE_METERS = 1 << 6; - public static final long COUNTER_BYTES = 12; - public static final long COUNTER_PKTS = 15; + public static final long UL_COUNTER_BYTES = 12; + public static final long UL_COUNTER_PKTS = 15; + public static final long DL_COUNTER_BYTES = 12; + public static final long DL_COUNTER_PKTS = 15; public static final byte APP_FILTERING_ID = 10; public static final byte DEFAULT_APP_ID = 0; @@ -254,6 +257,30 @@ public final class TestUpfConstants { public static final UpfMeter SLICE_METER_RESET = UpfMeter.resetSlice(SLICE_METER_CELL_ID); + public static final UpfCounter UPLINK_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setIngress(UL_COUNTER_PKTS, UL_COUNTER_BYTES) + .setEgress(UL_COUNTER_PKTS, UL_COUNTER_BYTES) + .build(); + + public static final UpfCounter ZERO_UPLINK_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setIngress(0, 0) + .setEgress(0, 0) + .build(); + + public static final UpfCounter DOWNLINK_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setIngress(DL_COUNTER_PKTS, DL_COUNTER_BYTES) + .setEgress(DL_COUNTER_PKTS, DL_COUNTER_BYTES) + .build(); + + public static final UpfCounter ZERO_DOWNLINK_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setIngress(0, 0) + .setEgress(0, 0) + .build(); + public static final FlowRule FABRIC_INGRESS_GTP_TUNNEL_PEER = DefaultFlowRule.builder() .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent() .forTable(FABRIC_INGRESS_UPF_IG_TUNNEL_PEERS) From dca8fba86876e49631687e75dd15e40f12a8ebaf Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Tue, 26 Apr 2022 13:54:25 +0200 Subject: [PATCH 03/12] Address review comments --- .../upf/FabricUpfProgrammableTest.java | 31 ++++++++++++++++--- .../upf/MockP4RuntimeController.java | 1 - .../tna/behaviour/upf/MockReadRequest.java | 1 - .../tna/behaviour/upf/MockReadResponse.java | 1 - .../tna/behaviour/upf/MockWriteResponse.java | 4 ++- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java index 18977e53b..7c5a66474 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java @@ -1,4 +1,3 @@ -// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; @@ -58,12 +57,34 @@ import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; -import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.anyString; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.stratumproject.fabric.tna.Constants.TNA; -import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.*; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.*; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_QOS_SLICE_TC_METER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APPLICATIONS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APP_METER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_DOWNLINK_SESSIONS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_DOWNLINK_TERMINATIONS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_IG_TUNNEL_PEERS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_SESSION_METER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_SESSIONS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_TERMINATIONS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.SLICE_MOBILE; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.ZERO_DOWNLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.ZERO_UPLINK_COUNTER; public class FabricUpfProgrammableTest { @@ -337,7 +358,7 @@ public void testSliceMeter() throws Exception { } @Test - public void testCounter() throws Exception { + public void testApplyCounter() throws Exception { assertThat( upfProgrammable.readCounter(TestUpfConstants.UPLINK_COUNTER.getCellId()), equalTo(ZERO_UPLINK_COUNTER) diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java index d23b27f4f..f8a3f4fb5 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java @@ -1,4 +1,3 @@ -// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java index 9addb1458..83fad09df 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java @@ -1,4 +1,3 @@ -// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java index bd4268fb5..5c7289bfa 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java @@ -1,4 +1,3 @@ -// Copyright 2022-present Intel Corporation // Copyright 2020-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java index dabc086aa..1a5dec965 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java @@ -10,7 +10,9 @@ import java.util.stream.Collectors; import java.util.stream.LongStream; -import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; /** * For faking writes to a p4runtime client. Currently, only used for testing From e728a6a48363a889f45438b4f76c49534014aa1e Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Tue, 26 Apr 2022 13:59:08 +0200 Subject: [PATCH 04/12] Empty-Commit From 4428070a516d36947bbce6a6b5e6aa65b969514c Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Tue, 26 Apr 2022 14:11:24 +0200 Subject: [PATCH 05/12] Empty-Commit From a78cf66dc3e3603ae3cc1df06c6991ce0019e5f9 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Tue, 26 Apr 2022 15:25:00 +0200 Subject: [PATCH 06/12] Use ONF copyright on new files --- .../fabric/tna/behaviour/upf/MockP4RuntimeClient.java | 2 +- .../fabric/tna/behaviour/upf/MockWriteRequest.java | 2 +- .../fabric/tna/behaviour/upf/MockWriteResponse.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java index 11304e93b..26254e1a9 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java @@ -1,4 +1,4 @@ -// Copyright 2022-present Intel Corporation +// Copyright 2022-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java index bc4917ca2..d0540512e 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright 2022-present Intel Corporation +// Copyright 2022-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java index 1a5dec965..b2a20c3a7 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java @@ -1,4 +1,4 @@ -// Copyright 2022-present Intel Corporation +// Copyright 2022-present Open Networking Foundation // SPDX-License-Identifier: Apache-2.0 package org.stratumproject.fabric.tna.behaviour.upf; From cfb687b5e87a744d074451492f88fa7da3d45ee0 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Thu, 28 Apr 2022 10:13:25 +0200 Subject: [PATCH 07/12] Fix --- .../fabric/tna/behaviour/upf/MockP4RuntimeClient.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java index 26254e1a9..080f87d0d 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java @@ -41,16 +41,13 @@ public MockP4RuntimeClient(DeviceId deviceId, int counterSize) { igCounters = Maps.newHashMap(); egCounters = Maps.newHashMap(); LongStream.range(0, counterSize).forEach(i -> { - - }); - for (long i = 0; i < counterSize; i++) { igCounters.put(i, new PiCounterCell( PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, i), new PiCounterCellData(0, 0))); egCounters.put(i, new PiCounterCell( PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, i), new PiCounterCellData(0, 0))); - } + }); } @Override From 0fb66e79729170e828338da73f7c182390050d71 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Wed, 4 May 2022 16:53:37 +0200 Subject: [PATCH 08/12] [SDFAB-1178] Allow to read and write IG/EG counter separately --- .../behaviour/upf/FabricUpfProgrammable.java | 96 ++++++++-- .../upf/FabricUpfProgrammableTest.java | 181 ++++++++++++++---- .../tna/behaviour/upf/TestUpfConstants.java | 40 +++- 3 files changed, 253 insertions(+), 64 deletions(-) diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index cd7c32db6..69057fc97 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -6,6 +6,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.lang3.tuple.Pair; +import org.glassfish.jersey.internal.guava.Sets; import org.onlab.packet.Ip4Prefix; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; @@ -70,6 +71,7 @@ import java.util.stream.Collectors; import static java.lang.String.format; +import static org.onosproject.net.behaviour.upf.UpfProgrammableException.Type.UNSUPPORTED_OPERATION; import static org.onosproject.net.pi.model.PiCounterType.INDIRECT; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_GTPU_ENCAP; @@ -104,6 +106,9 @@ public class FabricUpfProgrammable extends AbstractP4RuntimeHandlerBehaviour private static final int DEFAULT_PRIORITY = 128; private static final long DEFAULT_P4_DEVICE_ID = 1; + private static final ImmutableSet COUNTER_TYPES = + ImmutableSet.of(UpfEntityType.COUNTER, UpfEntityType.INGRESS_COUNTER, UpfEntityType.EGRESS_COUNTER); + protected FlowRuleService flowRuleService; protected MeterService meterService; protected PacketService packetService; @@ -262,7 +267,7 @@ private boolean computeHardwareResourceSizes() { long sessionMeterSize = 0; long appMeterSize = 0; long sliceMeterSize = 0; - for (PiMeterModel piMeter: pipeconf.pipelineModel().meters()) { + for (PiMeterModel piMeter : pipeconf.pipelineModel().meters()) { if (piMeter.id().equals(FABRIC_INGRESS_UPF_SESSION_METER)) { sessionMeterSize = piMeter.size(); } else if (piMeter.id().equals(FABRIC_INGRESS_UPF_APP_METER)) { @@ -435,7 +440,11 @@ public Collection readAll(UpfEntityType entityType) case TUNNEL_PEER: return getGtpTunnelPeers(); case COUNTER: - return readCounters(-1); + return readCounters(-1, UpfEntityType.COUNTER); + case INGRESS_COUNTER: + return readCounters(-1, UpfEntityType.INGRESS_COUNTER); + case EGRESS_COUNTER: + return readCounters(-1, UpfEntityType.EGRESS_COUNTER); case APPLICATION: return getUpfApplication(); case SESSION_METER: @@ -551,16 +560,29 @@ private Collection getUpfTerminationsDownlink() throws UpfProgrammabl } private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableException { - PiEntity piIngressCounter = new PiCounterCell( - PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), - new PiCounterCellData(upfCounter.getIngressPkts(), upfCounter.getIngressBytes())); - PiEntity piEgressCounter = new PiCounterCell( - PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), - new PiCounterCellData(upfCounter.getEgressPkts(), upfCounter.getEgressBytes())); + final List counterRequests = Lists.newArrayList(); + if (isIngressCounter(upfCounter.type())) { + if (upfCounter.getIngressPkts().isEmpty() || upfCounter.getIngressBytes().isEmpty()) { + throw new UpfProgrammableException("INGRESS counter without ingress packets or bytes!"); + } + counterRequests.add(new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), + new PiCounterCellData(upfCounter.getIngressPkts().get(), upfCounter.getIngressBytes().get())) + ); + } + if (isEgressCounter(upfCounter.type())) { + if (upfCounter.getEgressPkts().isEmpty() || upfCounter.getEgressBytes().isEmpty()) { + throw new UpfProgrammableException("INGRESS counter without ingress packets or bytes!"); + } + counterRequests.add(new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), + new PiCounterCellData(upfCounter.getEgressPkts().get(), upfCounter.getEgressBytes().get())) + ); + } // Write on the device in sync mode. P4RuntimeWriteClient.WriteResponse writeResponse = client.write( DEFAULT_P4_DEVICE_ID, pipeconf) - .modify(Lists.newArrayList(piIngressCounter, piEgressCounter)) + .modify(counterRequests) .submitSync(); if (!writeResponse.failed().isEmpty()) { writeResponse.failed().stream().filter(counterEntryResp -> !counterEntryResp.isSuccess()) @@ -571,7 +593,8 @@ private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableExcept } @Override - public Collection readCounters(long maxCounterId) { + public Collection readCounters(long maxCounterId, UpfEntityType type) throws UpfProgrammableException { + assertCounterType(type); if (!setupBehaviour("readCounters()")) { return null; } @@ -588,14 +611,17 @@ public Collection readCounters(long maxCounterId) { } // Generate the counter cell IDs. - Set counterIds = ImmutableSet.of( - FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, - FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER - ); + Set counterIds = Sets.newHashSet(); + if (isIngressCounter(type)) { + counterIds.add(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER); + } + if (isEgressCounter(type)) { + counterIds.add(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER); + } // Query the device. Collection counterEntryResponse = client.read( - DEFAULT_P4_DEVICE_ID, pipeconf) + DEFAULT_P4_DEVICE_ID, pipeconf) .counterCells(counterIds) .submitSync() .all(PiCounterCell.class); @@ -668,7 +694,8 @@ public long tableSize(UpfEntityType entityType) throws UpfProgrammableException } @Override - public UpfCounter readCounter(int cellId) throws UpfProgrammableException { + public UpfCounter readCounter(int cellId, UpfEntityType type) throws UpfProgrammableException { + assertCounterType(type); if (!setupBehaviour("readCounter()")) { return null; } @@ -679,11 +706,19 @@ public UpfCounter readCounter(int cellId) throws UpfProgrammableException { UpfCounter.Builder stats = UpfCounter.builder().withCellId(cellId); // Make list of cell handles we want to read. - List counterCellHandles = List.of( - PiCounterCellHandle.of(deviceId, - PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId)), - PiCounterCellHandle.of(deviceId, - PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId))); + List counterCellHandles = Lists.newArrayList(); + if (isIngressCounter(type)) { + counterCellHandles.add(PiCounterCellHandle.of( + deviceId, + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId) + )); + } + if (isEgressCounter(type)) { + counterCellHandles.add(PiCounterCellHandle.of( + deviceId, + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId) + )); + } // Query the device. Collection counterEntryResponse = client.read( @@ -741,6 +776,8 @@ public void apply(UpfEntity entity) throws UpfProgrammableException { addUpfApplication((UpfApplication) entity); break; case COUNTER: + case INGRESS_COUNTER: + case EGRESS_COUNTER: applyUpfCounter((UpfCounter) entity); break; case SESSION_METER: @@ -891,6 +928,7 @@ private boolean removeEntry(PiCriterion match, PiTableId tableId, boolean failSi throws UpfProgrammableException { return removeEntry(match, tableId, failSilent, DEFAULT_PRIORITY); } + private boolean removeEntry(PiCriterion match, PiTableId tableId, boolean failSilent, int priority) throws UpfProgrammableException { return removeEntries(Lists.newArrayList(Pair.of(tableId, match)), failSilent, priority); @@ -1059,4 +1097,20 @@ private void assertTrafficClass(int sliceId, int tc) throws UpfProgrammableExcep )); } } + + private void assertCounterType(UpfEntityType type) throws UpfProgrammableException { + if (!COUNTER_TYPES.contains(type)) { + throw new UpfProgrammableException( + String.format("Unsupported counter type (%s)!", type.toString()), + UNSUPPORTED_OPERATION + ); + } + } + + private boolean isIngressCounter(UpfEntityType type) { + return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.INGRESS_COUNTER); + } + private boolean isEgressCounter(UpfEntityType type) { + return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.EGRESS_COUNTER); + } } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java index 7c5a66474..bbf7dd34b 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java @@ -55,6 +55,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentMap; +import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; import static org.easymock.EasyMock.anyString; @@ -63,6 +64,10 @@ import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.onosproject.net.behaviour.upf.UpfEntityType.COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.EGRESS_COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.INGRESS_COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.SLICE_METER; import static org.stratumproject.fabric.tna.Constants.TNA; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; @@ -76,13 +81,21 @@ import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_SESSIONS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_TERMINATIONS; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_COUNTER_BYTES; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_EG_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_EG_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_IG_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DL_IG_COUNTER_PKTS; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_IG_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.SLICE_MOBILE; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_COUNTER_BYTES; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_EG_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_EG_COUNTER_PKTS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_IG_COUNTER_BYTES; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UL_IG_COUNTER_PKTS; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_IG_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.ZERO_DOWNLINK_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.ZERO_UPLINK_COUNTER; @@ -359,20 +372,43 @@ public void testSliceMeter() throws Exception { @Test public void testApplyCounter() throws Exception { - assertThat( - upfProgrammable.readCounter(TestUpfConstants.UPLINK_COUNTER.getCellId()), - equalTo(ZERO_UPLINK_COUNTER) - ); - UpfCounter expectedCounter = TestUpfConstants.UPLINK_COUNTER; + UpfCounter expectedCounter = UPLINK_COUNTER; upfProgrammable.apply(expectedCounter); UpfCounter installedCounter = - upfProgrammable.readCounter(expectedCounter.getCellId()); + upfProgrammable.readCounter(expectedCounter.getCellId(), COUNTER); assertThat(installedCounter, equalTo(expectedCounter)); - upfProgrammable.apply(ZERO_UPLINK_COUNTER); - assertThat( - upfProgrammable.readCounter(TestUpfConstants.UPLINK_COUNTER.getCellId()), - equalTo(ZERO_UPLINK_COUNTER) - ); + } + + @Test + public void testApplyIngressCounter() throws Exception { + UpfCounter expectedCounter = UPLINK_IG_COUNTER; + upfProgrammable.apply(expectedCounter); + UpfCounter installedCounter = + upfProgrammable.readCounter(expectedCounter.getCellId(), INGRESS_COUNTER); + assertThat(installedCounter, equalTo(expectedCounter)); + } + + @Test + public void testApplyEgressCounter() throws Exception { + UpfCounter expectedCounter = UPLINK_EG_COUNTER; + upfProgrammable.apply(expectedCounter); + UpfCounter installedCounter = + upfProgrammable.readCounter(expectedCounter.getCellId(), EGRESS_COUNTER); + assertThat(installedCounter, equalTo(expectedCounter)); + } + + @Test + public void testInvalidCounterTypeOnReadCounter() throws Exception { + exceptionRule.expect(UpfProgrammableException.class); + exceptionRule.expectMessage("Unsupported counter type (SLICE_METER)!"); + upfProgrammable.readCounter(0, SLICE_METER); + } + + @Test + public void testInvalidCounterTypeOnReadCounters() throws Exception { + exceptionRule.expect(UpfProgrammableException.class); + exceptionRule.expectMessage("Unsupported counter type (SLICE_METER)!"); + upfProgrammable.readCounters(0, SLICE_METER); } @Test @@ -408,25 +444,100 @@ public void testReadAllCounters() throws Exception { upfProgrammable.apply(UPLINK_COUNTER); upfProgrammable.apply(DOWNLINK_COUNTER); - Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); + Collection allStats = upfProgrammable.readAll(COUNTER); + assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); + for (UpfEntity entity : allStats) { + UpfCounter stat = (UpfCounter) entity; + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(UL_IG_COUNTER_BYTES)); + assertThat(stat.getEgressBytes().get(), equalTo(UL_EG_COUNTER_BYTES)); + assertThat(stat.getIngressPkts().get(), equalTo(UL_IG_COUNTER_PKTS)); + assertThat(stat.getEgressPkts().get(), equalTo(UL_EG_COUNTER_PKTS)); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(DL_IG_COUNTER_BYTES)); + assertThat(stat.getEgressBytes().get(), equalTo(DL_EG_COUNTER_BYTES)); + assertThat(stat.getIngressPkts().get(), equalTo(DL_IG_COUNTER_PKTS)); + assertThat(stat.getEgressPkts().get(), equalTo(DL_EG_COUNTER_PKTS)); + } else { + assertEquals(stat.type(), COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(0L)); + assertThat(stat.getEgressBytes().get(), equalTo(0L)); + assertThat(stat.getIngressPkts().get(), equalTo(0L)); + assertThat(stat.getEgressPkts().get(), equalTo(0L)); + } + } + + upfProgrammable.apply(ZERO_UPLINK_COUNTER); + upfProgrammable.apply(ZERO_DOWNLINK_COUNTER); + assertAllZeroCounters(); + } + + @Test + public void testReadAllIngressCounters() throws Exception { + assertAllZeroCounters(); + + upfProgrammable.apply(UPLINK_IG_COUNTER); + upfProgrammable.apply(DOWNLINK_IG_COUNTER); + Collection allStats = upfProgrammable.readAll(INGRESS_COUNTER); + assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); + for (UpfEntity entity : allStats) { + UpfCounter stat = (UpfCounter) entity; + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), INGRESS_COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(UL_IG_COUNTER_BYTES)); + assertThat(stat.getIngressPkts().get(), equalTo(UL_IG_COUNTER_PKTS)); + assertTrue(stat.getEgressBytes().isEmpty()); + assertTrue(stat.getEgressPkts().isEmpty()); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), INGRESS_COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(DL_IG_COUNTER_BYTES)); + assertThat(stat.getIngressPkts().get(), equalTo(DL_IG_COUNTER_PKTS)); + assertTrue(stat.getEgressBytes().isEmpty()); + assertTrue(stat.getEgressPkts().isEmpty()); + } else { + assertEquals(stat.type(), INGRESS_COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(0L)); + assertThat(stat.getIngressPkts().get(), equalTo(0L)); + assertTrue(stat.getEgressBytes().isEmpty()); + assertTrue(stat.getEgressPkts().isEmpty()); + } + } + + upfProgrammable.apply(ZERO_UPLINK_COUNTER); + upfProgrammable.apply(ZERO_DOWNLINK_COUNTER); + assertAllZeroCounters(); + } + + @Test + public void testReadAllEgressCounters() throws Exception { + assertAllZeroCounters(); + + upfProgrammable.apply(UPLINK_EG_COUNTER); + upfProgrammable.apply(DOWNLINK_EG_COUNTER); + Collection allStats = upfProgrammable.readAll(EGRESS_COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); for (UpfEntity entity : allStats) { UpfCounter stat = (UpfCounter) entity; if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { - assertThat(stat.getIngressBytes(), equalTo(UL_COUNTER_BYTES)); - assertThat(stat.getEgressBytes(), equalTo(UL_COUNTER_BYTES)); - assertThat(stat.getIngressPkts(), equalTo(UL_COUNTER_PKTS)); - assertThat(stat.getEgressPkts(), equalTo(UL_COUNTER_PKTS)); + assertEquals(stat.type(), EGRESS_COUNTER); + assertThat(stat.getEgressBytes().get(), equalTo(UL_EG_COUNTER_BYTES)); + assertThat(stat.getEgressPkts().get(), equalTo(UL_EG_COUNTER_PKTS)); + assertTrue(stat.getIngressBytes().isEmpty()); + assertTrue(stat.getIngressPkts().isEmpty()); } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { - assertThat(stat.getIngressBytes(), equalTo(DL_COUNTER_BYTES)); - assertThat(stat.getEgressBytes(), equalTo(DL_COUNTER_BYTES)); - assertThat(stat.getIngressPkts(), equalTo(DL_COUNTER_PKTS)); - assertThat(stat.getEgressPkts(), equalTo(UL_COUNTER_PKTS)); + assertEquals(stat.type(), EGRESS_COUNTER); + assertThat(stat.getEgressBytes().get(), equalTo(DL_EG_COUNTER_BYTES)); + assertThat(stat.getEgressPkts().get(), equalTo(DL_EG_COUNTER_PKTS)); + assertTrue(stat.getIngressBytes().isEmpty()); + assertTrue(stat.getIngressPkts().isEmpty()); } else { - assertThat(stat.getIngressBytes(), equalTo(0L)); - assertThat(stat.getEgressBytes(), equalTo(0L)); - assertThat(stat.getIngressPkts(), equalTo(0L)); - assertThat(stat.getEgressPkts(), equalTo(0L)); + assertEquals(stat.type(), EGRESS_COUNTER); + assertThat(stat.getEgressBytes().get(), equalTo(0L)); + assertThat(stat.getEgressPkts().get(), equalTo(0L)); + assertTrue(stat.getIngressBytes().isEmpty()); + assertTrue(stat.getIngressPkts().isEmpty()); } } @@ -436,26 +547,26 @@ public void testReadAllCounters() throws Exception { } private void assertAllZeroCounters() throws UpfProgrammableException { - Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); + Collection allStats = upfProgrammable.readAll(COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); for (UpfEntity entity : allStats) { UpfCounter stat = (UpfCounter) entity; - assertThat(stat.getIngressBytes(), equalTo(0L)); - assertThat(stat.getEgressBytes(), equalTo(0L)); - assertThat(stat.getIngressPkts(), equalTo(0L)); - assertThat(stat.getEgressPkts(), equalTo(0L)); + assertThat(stat.getIngressBytes().get(), equalTo(0L)); + assertThat(stat.getEgressBytes().get(), equalTo(0L)); + assertThat(stat.getIngressPkts().get(), equalTo(0L)); + assertThat(stat.getEgressPkts().get(), equalTo(0L)); } } @Test public void testReadAllCountersLimitedCounters() throws Exception { - Collection allStats = upfProgrammable.readCounters(10); + Collection allStats = upfProgrammable.readCounters(10, COUNTER); assertThat(allStats.size(), equalTo(10)); } @Test public void testReadAllCountersPhysicalLimit() throws Exception { - Collection allStats = upfProgrammable.readCounters(1024); + Collection allStats = upfProgrammable.readCounters(1024, COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java index c41a24567..e977b17a6 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java @@ -122,10 +122,14 @@ public final class TestUpfConstants { public static final int PHYSICAL_MAX_SLICE_METERS = 1 << 6; - public static final long UL_COUNTER_BYTES = 12; - public static final long UL_COUNTER_PKTS = 15; - public static final long DL_COUNTER_BYTES = 12; - public static final long DL_COUNTER_PKTS = 15; + public static final long UL_IG_COUNTER_BYTES = 12; + public static final long UL_IG_COUNTER_PKTS = 13; + public static final long UL_EG_COUNTER_BYTES = 14; + public static final long UL_EG_COUNTER_PKTS = 15; + public static final long DL_IG_COUNTER_BYTES = 16; + public static final long DL_IG_COUNTER_PKTS = 17; + public static final long DL_EG_COUNTER_BYTES = 18; + public static final long DL_EG_COUNTER_PKTS = 19; public static final byte APP_FILTERING_ID = 10; public static final byte DEFAULT_APP_ID = 0; @@ -259,8 +263,18 @@ public final class TestUpfConstants { public static final UpfCounter UPLINK_COUNTER = UpfCounter.builder() .withCellId(UPLINK_COUNTER_CELL_ID) - .setIngress(UL_COUNTER_PKTS, UL_COUNTER_BYTES) - .setEgress(UL_COUNTER_PKTS, UL_COUNTER_BYTES) + .setIngress(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + .setEgress(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) + .build(); + + public static final UpfCounter UPLINK_IG_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setIngress(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + .build(); + + public static final UpfCounter UPLINK_EG_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setEgress(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) .build(); public static final UpfCounter ZERO_UPLINK_COUNTER = UpfCounter.builder() @@ -271,8 +285,18 @@ public final class TestUpfConstants { public static final UpfCounter DOWNLINK_COUNTER = UpfCounter.builder() .withCellId(DOWNLINK_COUNTER_CELL_ID) - .setIngress(DL_COUNTER_PKTS, DL_COUNTER_BYTES) - .setEgress(DL_COUNTER_PKTS, DL_COUNTER_BYTES) + .setIngress(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + .setEgress(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) + .build(); + + public static final UpfCounter DOWNLINK_IG_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setIngress(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + .build(); + + public static final UpfCounter DOWNLINK_EG_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setEgress(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) .build(); public static final UpfCounter ZERO_DOWNLINK_COUNTER = UpfCounter.builder() From 3af2a5d228dc780ba6d62a106dfc999367d5862f Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Wed, 4 May 2022 22:07:08 +0200 Subject: [PATCH 09/12] Address review comments --- .../tna/behaviour/upf/FabricUpfProgrammable.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index 69057fc97..b770b58b3 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -5,8 +5,8 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.commons.lang3.tuple.Pair; -import org.glassfish.jersey.internal.guava.Sets; import org.onlab.packet.Ip4Prefix; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; @@ -563,7 +563,7 @@ private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableExcept final List counterRequests = Lists.newArrayList(); if (isIngressCounter(upfCounter.type())) { if (upfCounter.getIngressPkts().isEmpty() || upfCounter.getIngressBytes().isEmpty()) { - throw new UpfProgrammableException("INGRESS counter without ingress packets or bytes!"); + throw new UpfProgrammableException("Ingress counter without ingress packets or bytes!"); } counterRequests.add(new PiCounterCell( PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), @@ -572,7 +572,7 @@ private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableExcept } if (isEgressCounter(upfCounter.type())) { if (upfCounter.getEgressPkts().isEmpty() || upfCounter.getEgressBytes().isEmpty()) { - throw new UpfProgrammableException("INGRESS counter without ingress packets or bytes!"); + throw new UpfProgrammableException("Egress counter without ingress packets or bytes!"); } counterRequests.add(new PiCounterCell( PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, upfCounter.getCellId()), @@ -709,14 +709,12 @@ public UpfCounter readCounter(int cellId, UpfEntityType type) throws UpfProgramm List counterCellHandles = Lists.newArrayList(); if (isIngressCounter(type)) { counterCellHandles.add(PiCounterCellHandle.of( - deviceId, - PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId) + deviceId, PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId) )); } if (isEgressCounter(type)) { counterCellHandles.add(PiCounterCellHandle.of( - deviceId, - PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId) + deviceId, PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId) )); } @@ -1110,6 +1108,7 @@ private void assertCounterType(UpfEntityType type) throws UpfProgrammableExcepti private boolean isIngressCounter(UpfEntityType type) { return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.INGRESS_COUNTER); } + private boolean isEgressCounter(UpfEntityType type) { return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.EGRESS_COUNTER); } From bd01ecbb67aff20bc903583938dca50c85880a6e Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Thu, 5 May 2022 12:38:55 +0200 Subject: [PATCH 10/12] Changes to use updated ONOS APIs --- .../behaviour/upf/FabricUpfProgrammable.java | 32 ++++++++++++++----- .../tna/behaviour/upf/TestUpfConstants.java | 4 +++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index b770b58b3..45fb6c16d 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -561,7 +561,7 @@ private Collection getUpfTerminationsDownlink() throws UpfProgrammabl private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableException { final List counterRequests = Lists.newArrayList(); - if (isIngressCounter(upfCounter.type())) { + if (isIngressCounter(upfCounter.type()) || isBiCounter(upfCounter.type())) { if (upfCounter.getIngressPkts().isEmpty() || upfCounter.getIngressBytes().isEmpty()) { throw new UpfProgrammableException("Ingress counter without ingress packets or bytes!"); } @@ -570,7 +570,7 @@ private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableExcept new PiCounterCellData(upfCounter.getIngressPkts().get(), upfCounter.getIngressBytes().get())) ); } - if (isEgressCounter(upfCounter.type())) { + if (isEgressCounter(upfCounter.type()) || isBiCounter(upfCounter.type())) { if (upfCounter.getEgressPkts().isEmpty() || upfCounter.getEgressBytes().isEmpty()) { throw new UpfProgrammableException("Egress counter without ingress packets or bytes!"); } @@ -612,10 +612,10 @@ public Collection readCounters(long maxCounterId, UpfEntityType type // Generate the counter cell IDs. Set counterIds = Sets.newHashSet(); - if (isIngressCounter(type)) { + if (isIngressCounter(type) || isBiCounter(type)) { counterIds.add(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER); } - if (isEgressCounter(type)) { + if (isEgressCounter(type) || isBiCounter(type)) { counterIds.add(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER); } @@ -649,6 +649,12 @@ public Collection readCounters(long maxCounterId, UpfEntityType type } else { log.warn("Unrecognized counter ID {}, skipping", counterCell); } + if (isIngressCounter(type)) { + statsBuilder.isIngressCounter(); + } + if (isEgressCounter(type)) { + statsBuilder.isEgressCounter(); + } }); return upfCounterBuilders @@ -707,12 +713,12 @@ public UpfCounter readCounter(int cellId, UpfEntityType type) throws UpfProgramm // Make list of cell handles we want to read. List counterCellHandles = Lists.newArrayList(); - if (isIngressCounter(type)) { + if (isIngressCounter(type) || isBiCounter(type)) { counterCellHandles.add(PiCounterCellHandle.of( deviceId, PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId) )); } - if (isEgressCounter(type)) { + if (isEgressCounter(type) || isBiCounter(type)) { counterCellHandles.add(PiCounterCellHandle.of( deviceId, PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId) )); @@ -741,6 +747,12 @@ public UpfCounter readCounter(int cellId, UpfEntityType type) throws UpfProgramm } else { log.warn("Unrecognized counter ID {}, skipping", counterCell); } + if (isIngressCounter(type)) { + stats.isIngressCounter(); + } + if (isEgressCounter(type)) { + stats.isEgressCounter(); + } }); return stats.build(); } @@ -1106,10 +1118,14 @@ private void assertCounterType(UpfEntityType type) throws UpfProgrammableExcepti } private boolean isIngressCounter(UpfEntityType type) { - return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.INGRESS_COUNTER); + return type.equals(UpfEntityType.INGRESS_COUNTER); + } + + private boolean isBiCounter(UpfEntityType type) { + return type.equals(UpfEntityType.COUNTER); } private boolean isEgressCounter(UpfEntityType type) { - return type.equals(UpfEntityType.COUNTER) || type.equals(UpfEntityType.EGRESS_COUNTER); + return type.equals(UpfEntityType.EGRESS_COUNTER); } } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java index e977b17a6..ff4a001bf 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java @@ -270,11 +270,13 @@ public final class TestUpfConstants { public static final UpfCounter UPLINK_IG_COUNTER = UpfCounter.builder() .withCellId(UPLINK_COUNTER_CELL_ID) .setIngress(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + .isIngressCounter() .build(); public static final UpfCounter UPLINK_EG_COUNTER = UpfCounter.builder() .withCellId(UPLINK_COUNTER_CELL_ID) .setEgress(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) + .isEgressCounter() .build(); public static final UpfCounter ZERO_UPLINK_COUNTER = UpfCounter.builder() @@ -292,11 +294,13 @@ public final class TestUpfConstants { public static final UpfCounter DOWNLINK_IG_COUNTER = UpfCounter.builder() .withCellId(DOWNLINK_COUNTER_CELL_ID) .setIngress(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + .isIngressCounter() .build(); public static final UpfCounter DOWNLINK_EG_COUNTER = UpfCounter.builder() .withCellId(DOWNLINK_COUNTER_CELL_ID) .setEgress(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) + .isEgressCounter() .build(); public static final UpfCounter ZERO_DOWNLINK_COUNTER = UpfCounter.builder() From e0b3d5fbd1f52f60e8ffcb71e0ac95dcb83e4e36 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Mon, 9 May 2022 16:38:13 +0200 Subject: [PATCH 11/12] Allows to read ingress and egress counter separately --- .../behaviour/upf/FabricUpfProgrammable.java | 163 ++++++++++++------ .../upf/FabricUpfProgrammableTest.java | 127 ++++++++++++-- .../behaviour/upf/MockP4RuntimeClient.java | 117 +++++++++++++ .../upf/MockP4RuntimeController.java | 25 +-- .../tna/behaviour/upf/MockReadRequest.java | 46 ++--- .../tna/behaviour/upf/MockReadResponse.java | 34 ++-- .../tna/behaviour/upf/MockWriteRequest.java | 125 ++++++++++++++ .../tna/behaviour/upf/MockWriteResponse.java | 61 +++++++ .../tna/behaviour/upf/TestUpfConstants.java | 72 +++++++- 9 files changed, 651 insertions(+), 119 deletions(-) create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java create mode 100644 src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java diff --git a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java index 20b0f5abc..5fe22efee 100644 --- a/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java +++ b/src/main/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammable.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.commons.lang3.tuple.Pair; import org.onlab.packet.Ip4Prefix; import org.onosproject.core.ApplicationId; @@ -65,8 +66,10 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.LongStream; import static java.lang.String.format; +import static org.onosproject.net.behaviour.upf.UpfProgrammableException.Type.UNSUPPORTED_OPERATION; import static org.onosproject.net.pi.model.PiCounterType.INDIRECT; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_GTPU_ENCAP; @@ -101,6 +104,9 @@ public class FabricUpfProgrammable extends AbstractP4RuntimeHandlerBehaviour private static final int DEFAULT_PRIORITY = 128; private static final long DEFAULT_P4_DEVICE_ID = 1; + private static final ImmutableSet COUNTER_TYPES = + ImmutableSet.of(UpfEntityType.COUNTER, UpfEntityType.INGRESS_COUNTER, UpfEntityType.EGRESS_COUNTER); + protected FlowRuleService flowRuleService; protected MeterService meterService; protected PacketService packetService; @@ -112,7 +118,8 @@ public class FabricUpfProgrammable extends AbstractP4RuntimeHandlerBehaviour private long downlinkUeSessionsTableSize; private long uplinkUpfTerminationsTableSize; private long downlinkUpfTerminationsTableSize; - private long upfCounterSize; + private long ingressUpfCounterSize; + private long egressUpfCounterSize; private long gtpTunnelPeersTableSize; private long applicationsTableSize; private long appMeterSize; @@ -259,7 +266,7 @@ private boolean computeHardwareResourceSizes() { long sessionMeterSize = 0; long appMeterSize = 0; long sliceMeterSize = 0; - for (PiMeterModel piMeter: pipeconf.pipelineModel().meters()) { + for (PiMeterModel piMeter : pipeconf.pipelineModel().meters()) { if (piMeter.id().equals(FABRIC_INGRESS_UPF_SESSION_METER)) { sessionMeterSize = piMeter.size(); } else if (piMeter.id().equals(FABRIC_INGRESS_UPF_APP_METER)) { @@ -280,7 +287,8 @@ private boolean computeHardwareResourceSizes() { this.uplinkUpfTerminationsTableSize = uplinkUpfTerminationsTableSize; this.downlinkUpfTerminationsTableSize = downlinkUpfTerminationsTableSize; this.applicationsTableSize = applicationsTableSize; - this.upfCounterSize = Math.min(ingressCounterSize, egressCounterSize); + this.ingressUpfCounterSize = ingressCounterSize; + this.egressUpfCounterSize = egressCounterSize; this.gtpTunnelPeersTableSize = Math.min(ingressGtpTunnelPeersTableSize, egressGtpTunnelPeersTableSize); this.sessionMeterSize = sessionMeterSize; this.sliceMeterSize = sliceMeterSize; @@ -432,7 +440,11 @@ public Collection readAll(UpfEntityType entityType) case TUNNEL_PEER: return getGtpTunnelPeers(); case COUNTER: - return readCounters(-1); + return readCounters(-1, UpfEntityType.COUNTER); + case INGRESS_COUNTER: + return readCounters(-1, UpfEntityType.INGRESS_COUNTER); + case EGRESS_COUNTER: + return readCounters(-1, UpfEntityType.EGRESS_COUNTER); case APPLICATION: return getUpfApplication(); case SESSION_METER: @@ -548,27 +560,25 @@ private Collection getUpfTerminationsDownlink() throws UpfProgrammabl } @Override - public Collection readCounters(long maxCounterId) { + public Collection readCounters(long maxCounterId, UpfEntityType type) throws UpfProgrammableException { + assertCounterType(type); if (!setupBehaviour("readCounters()")) { return null; } - long counterSize = upfCounterSize; + long counterSize = getEntitySize(type); if (maxCounterId != -1) { counterSize = Math.min(maxCounterId, counterSize); } - // Prepare UpfCounter object builders, one for each counter ID currently in use - Map upfCounterBuilders = Maps.newHashMap(); - for (int cellId = 0; cellId < counterSize; cellId++) { - upfCounterBuilders.put(cellId, UpfCounter.builder().withCellId(cellId)); - } - // Generate the counter cell IDs. - Set counterIds = ImmutableSet.of( - FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, - FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER - ); + Set counterIds = Sets.newHashSet(); + if (isIngressCounter(type) || isBiCounter(type)) { + counterIds.add(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER); + } + if (isEgressCounter(type) || isBiCounter(type)) { + counterIds.add(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER); + } // Query the device. Collection counterEntryResponse = client.read( @@ -577,20 +587,42 @@ public Collection readCounters(long maxCounterId) { .submitSync() .all(PiCounterCell.class); - // Process response. - counterEntryResponse.forEach(counterCell -> { + // Generate list of requested cell indexes + List cellIds = LongStream.range(0, counterSize) + .boxed().collect(Collectors.toList()); + + return processCounterEntryResponse( + counterEntryResponse, cellIds, type); + } + + /** + * Process the counters read from the device given the expected counter indexes + * and the UpfCounter Type. + */ + private List processCounterEntryResponse( + Collection readCounterEntries, + List expectedCounterIndex, + UpfEntityType type + ) { + // Prepare UpfCounter object builders, one for each expected counter index + Map upfCounterBuilders = Maps.newHashMap(); + expectedCounterIndex.forEach(cellId -> + upfCounterBuilders.put(cellId, UpfCounter.builder().withCellId(cellId.intValue())) + ); + readCounterEntries.forEach(counterCell -> { if (counterCell.cellId().counterType() != INDIRECT) { log.warn("Invalid counter data type {}, skipping", counterCell.cellId().counterType()); return; } - if (!upfCounterBuilders.containsKey((int) counterCell.cellId().index())) { - // Most likely Up4config.maxUes() is set to a value smaller than what the switch - // pipeline can hold. - log.debug("Unrecognized index {} when reading all counters, " + + if (!expectedCounterIndex.contains(counterCell.cellId().index())) { + // This can happen if the Up4Config.maxUes() is set to a value + // smaller than what the switch pipeline can hold, and we do a + // wild card read + log.debug("Unrecognized index {} when reading counters, " + "that's expected if we are manually limiting maxUes", counterCell); return; } - UpfCounter.Builder statsBuilder = upfCounterBuilders.get((int) counterCell.cellId().index()); + UpfCounter.Builder statsBuilder = upfCounterBuilders.get(counterCell.cellId().index()); if (counterCell.cellId().counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { statsBuilder.setIngress(counterCell.data().packets(), counterCell.data().bytes()); @@ -600,8 +632,14 @@ public Collection readCounters(long maxCounterId) { } else { log.warn("Unrecognized counter ID {}, skipping", counterCell); } + // UpfCounter builder defaults to type COUNTER + if (isIngressCounter(type)) { + statsBuilder.isIngressCounter(); + } + if (isEgressCounter(type)) { + statsBuilder.isEgressCounter(); + } }); - return upfCounterBuilders .values() .stream() @@ -614,7 +652,10 @@ public long tableSize(UpfEntityType entityType) throws UpfProgrammableException if (!setupBehaviour("tableSize()")) { return -1; } + return getEntitySize(entityType); + } + private long getEntitySize(UpfEntityType entityType) throws UpfProgrammableException { switch (entityType) { case INTERFACE: return interfaceTableSize; @@ -629,7 +670,11 @@ public long tableSize(UpfEntityType entityType) throws UpfProgrammableException case TERMINATION_DOWNLINK: return this.downlinkUpfTerminationsTableSize; case COUNTER: - return upfCounterSize; + return Math.min(ingressUpfCounterSize, egressUpfCounterSize); + case INGRESS_COUNTER: + return ingressUpfCounterSize; + case EGRESS_COUNTER: + return egressUpfCounterSize; case APPLICATION: return applicationsTableSize; case APPLICATION_METER: @@ -645,22 +690,29 @@ public long tableSize(UpfEntityType entityType) throws UpfProgrammableException } @Override - public UpfCounter readCounter(int cellId) throws UpfProgrammableException { + public UpfCounter readCounter(int cellId, UpfEntityType type) throws UpfProgrammableException { + assertCounterType(type); if (!setupBehaviour("readCounter()")) { return null; } - if (cellId >= upfCounterSize || cellId < 0) { + if (cellId >= getEntitySize(type) || cellId < 0) { throw new UpfProgrammableException("Requested UPF counter cell index is out of bounds.", UpfProgrammableException.Type.ENTITY_OUT_OF_RANGE); } UpfCounter.Builder stats = UpfCounter.builder().withCellId(cellId); // Make list of cell handles we want to read. - List counterCellHandles = List.of( - PiCounterCellHandle.of(deviceId, - PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId)), - PiCounterCellHandle.of(deviceId, - PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId))); + List counterCellHandles = Lists.newArrayList(); + if (isIngressCounter(type) || isBiCounter(type)) { + counterCellHandles.add(PiCounterCellHandle.of( + deviceId, PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, cellId) + )); + } + if (isEgressCounter(type) || isBiCounter(type)) { + counterCellHandles.add(PiCounterCellHandle.of( + deviceId, PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, cellId) + )); + } // Query the device. Collection counterEntryResponse = client.read( @@ -668,25 +720,8 @@ public UpfCounter readCounter(int cellId) throws UpfProgrammableException { .handles(counterCellHandles).submitSync() .all(PiCounterCell.class); - // Process response. - counterEntryResponse.forEach(counterCell -> { - if (counterCell.cellId().counterType() != INDIRECT) { - log.warn("Invalid counter data type {}, skipping", counterCell.cellId().counterType()); - return; - } - if (cellId != counterCell.cellId().index()) { - log.warn("Unrecognized counter index {}, skipping", counterCell); - return; - } - if (counterCell.cellId().counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { - stats.setIngress(counterCell.data().packets(), counterCell.data().bytes()); - } else if (counterCell.cellId().counterId().equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { - stats.setEgress(counterCell.data().packets(), counterCell.data().bytes()); - } else { - log.warn("Unrecognized counter ID {}, skipping", counterCell); - } - }); - return stats.build(); + return processCounterEntryResponse(counterEntryResponse, Lists.newArrayList((long) cellId), type) + .get(0); } @Override @@ -723,6 +758,8 @@ public void apply(UpfEntity entity) throws UpfProgrammableException { applyUpfMeter((UpfMeter) entity); break; case COUNTER: + case INGRESS_COUNTER: + case EGRESS_COUNTER: default: throw new UpfProgrammableException(format("Adding entity type %s not supported.", entity.type().humanReadableName())); @@ -854,8 +891,8 @@ public void delete(UpfEntity entity) throws UpfProgrammableException { case SESSION_METER: case APPLICATION_METER: case SLICE_METER: - // Meter cannot be deleted, only modified. case COUNTER: + // Entities cannot be deleted, only modified. default: throw new UpfProgrammableException(format("Deleting entity type %s not supported.", entity.type().humanReadableName())); @@ -866,6 +903,7 @@ private boolean removeEntry(PiCriterion match, PiTableId tableId, boolean failSi throws UpfProgrammableException { return removeEntry(match, tableId, failSilent, DEFAULT_PRIORITY); } + private boolean removeEntry(PiCriterion match, PiTableId tableId, boolean failSilent, int priority) throws UpfProgrammableException { return removeEntries(Lists.newArrayList(Pair.of(tableId, match)), failSilent, priority); @@ -1034,4 +1072,25 @@ private void assertTrafficClass(int sliceId, int tc) throws UpfProgrammableExcep )); } } + + private void assertCounterType(UpfEntityType type) throws UpfProgrammableException { + if (!COUNTER_TYPES.contains(type)) { + throw new UpfProgrammableException( + String.format("Unsupported counter type (%s)!", type.toString()), + UNSUPPORTED_OPERATION + ); + } + } + + private boolean isIngressCounter(UpfEntityType type) { + return type.equals(UpfEntityType.INGRESS_COUNTER); + } + + private boolean isBiCounter(UpfEntityType type) { + return type.equals(UpfEntityType.COUNTER); + } + + private boolean isEgressCounter(UpfEntityType type) { + return type.equals(UpfEntityType.EGRESS_COUNTER); + } } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java index 83426e493..2a049ceba 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java @@ -55,6 +55,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentMap; +import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; import static org.easymock.EasyMock.anyString; @@ -63,6 +64,10 @@ import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.onosproject.net.behaviour.upf.UpfEntityType.COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.EGRESS_COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.INGRESS_COUNTER; +import static org.onosproject.net.behaviour.upf.UpfEntityType.SLICE_METER; import static org.stratumproject.fabric.tna.Constants.TNA; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; @@ -76,7 +81,17 @@ import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_SESSIONS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_TERMINATIONS; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_IG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_DOWNLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_DOWNLINK_IG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_UPLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_UPLINK_IG_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.SLICE_MOBILE; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_EG_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_IG_COUNTER; public class FabricUpfProgrammableTest { @@ -86,6 +101,9 @@ public class FabricUpfProgrammableTest { private MockPacketService packetService; private FabricUpfProgrammable upfProgrammable; + private MockP4RuntimeController mockP4RtController = new MockP4RuntimeController( + TestUpfConstants.DEVICE_ID, TestUpfConstants.PHYSICAL_COUNTER_SIZE); + // Bytes of a random but valid Ethernet frame. private static final byte[] ETH_FRAME_BYTES = HexString.fromHexString( "00060708090a0001020304058100000a08004500006a000100004011f92ec0a80001c0a8000204d2005" + @@ -120,9 +138,9 @@ public class FabricUpfProgrammableTest { ); private static final List METER_MODELS = ImmutableList.of( new MockMeterModel(FABRIC_INGRESS_UPF_SESSION_METER, - TestUpfConstants.PHYSICAL_SESSION_METER_SIZE), + TestUpfConstants.PHYSICAL_SESSION_METER_SIZE), new MockMeterModel(FABRIC_INGRESS_UPF_APP_METER, - TestUpfConstants.PHYSICAL_APP_METER_SIZE), + TestUpfConstants.PHYSICAL_APP_METER_SIZE), new MockMeterModel(FABRIC_INGRESS_QOS_SLICE_TC_METER, TestUpfConstants.PHYSICAL_MAX_SLICE_METERS) ); @@ -172,10 +190,7 @@ public void setUp() throws Exception { TABLE_MODELS, COUNTER_MODELS, METER_MODELS, TNA)) .anyTimes(); expect(driverHandler.get(P4RuntimeController.class)) - .andReturn(new MockP4RuntimeController(TestUpfConstants.DEVICE_ID, - TestUpfConstants.COUNTER_PKTS, - TestUpfConstants.COUNTER_BYTES, - TestUpfConstants.PHYSICAL_COUNTER_SIZE)) + .andReturn(mockP4RtController) .anyTimes(); expect(driverHandler.data()).andReturn(driverData).anyTimes(); replay(driverHandler); @@ -351,6 +366,20 @@ public void testSliceMeter() throws Exception { assertTrue(upfProgrammable.readAll(UpfEntityType.SLICE_METER).isEmpty()); } + @Test + public void testInvalidCounterTypeOnReadCounter() throws Exception { + exceptionRule.expect(UpfProgrammableException.class); + exceptionRule.expectMessage("Unsupported counter type (SLICE_METER)!"); + upfProgrammable.readCounter(0, SLICE_METER); + } + + @Test + public void testInvalidCounterTypeOnReadCounters() throws Exception { + exceptionRule.expect(UpfProgrammableException.class); + exceptionRule.expectMessage("Unsupported counter type (SLICE_METER)!"); + upfProgrammable.readCounters(0, SLICE_METER); + } + @Test public void testInvalidSliceIdSliceMeter() throws Exception { exceptionRule.expect(UpfProgrammableException.class); @@ -380,26 +409,98 @@ public void testClearInterfaces() throws Exception { @Test public void testReadAllCounters() throws Exception { - Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); + mockP4RtController.mockP4rtClient.igCounters.put( + FABRIC_UPLINK_IG_COUNTER.cellId().index(), FABRIC_UPLINK_IG_COUNTER); + mockP4RtController.mockP4rtClient.igCounters.put( + FABRIC_DOWNLINK_IG_COUNTER.cellId().index(), FABRIC_DOWNLINK_IG_COUNTER); + mockP4RtController.mockP4rtClient.egCounters.put( + FABRIC_UPLINK_EG_COUNTER.cellId().index(), FABRIC_UPLINK_EG_COUNTER); + mockP4RtController.mockP4rtClient.egCounters.put( + FABRIC_DOWNLINK_EG_COUNTER.cellId().index(), FABRIC_DOWNLINK_EG_COUNTER); + + Collection allStats = upfProgrammable.readAll(COUNTER); + assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); + for (UpfEntity entity : allStats) { + UpfCounter stat = (UpfCounter) entity; + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), COUNTER); + assertTrue(stat.exactlyEquals(UPLINK_COUNTER)); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), COUNTER); + assertTrue(stat.exactlyEquals(DOWNLINK_COUNTER)); + } else { + assertEquals(stat.type(), COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(0L)); + assertThat(stat.getEgressBytes().get(), equalTo(0L)); + assertThat(stat.getIngressPkts().get(), equalTo(0L)); + assertThat(stat.getEgressPkts().get(), equalTo(0L)); + } + } + } + + @Test + public void testReadAllIngressCounters() throws Exception { + mockP4RtController.mockP4rtClient.igCounters.put( + FABRIC_UPLINK_IG_COUNTER.cellId().index(), FABRIC_UPLINK_IG_COUNTER); + mockP4RtController.mockP4rtClient.igCounters.put( + FABRIC_DOWNLINK_IG_COUNTER.cellId().index(), FABRIC_DOWNLINK_IG_COUNTER); + + Collection allStats = upfProgrammable.readAll(INGRESS_COUNTER); + assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); + for (UpfEntity entity : allStats) { + UpfCounter stat = (UpfCounter) entity; + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), INGRESS_COUNTER); + assertTrue(stat.exactlyEquals(UPLINK_IG_COUNTER)); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), INGRESS_COUNTER); + assertTrue(stat.exactlyEquals(DOWNLINK_IG_COUNTER)); + } else { + assertEquals(stat.type(), INGRESS_COUNTER); + assertThat(stat.getIngressBytes().get(), equalTo(0L)); + assertThat(stat.getIngressPkts().get(), equalTo(0L)); + assertTrue(stat.getEgressBytes().isEmpty()); + assertTrue(stat.getEgressPkts().isEmpty()); + } + } + } + + @Test + public void testReadAllEgressCounters() throws Exception { + mockP4RtController.mockP4rtClient.egCounters.put( + FABRIC_UPLINK_EG_COUNTER.cellId().index(), FABRIC_UPLINK_EG_COUNTER); + mockP4RtController.mockP4rtClient.egCounters.put( + FABRIC_DOWNLINK_EG_COUNTER.cellId().index(), FABRIC_DOWNLINK_EG_COUNTER); + + Collection allStats = upfProgrammable.readAll(EGRESS_COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); for (UpfEntity entity : allStats) { UpfCounter stat = (UpfCounter) entity; - assertThat(stat.getIngressBytes(), equalTo(TestUpfConstants.COUNTER_BYTES)); - assertThat(stat.getEgressBytes(), equalTo(TestUpfConstants.COUNTER_BYTES)); - assertThat(stat.getIngressPkts(), equalTo(TestUpfConstants.COUNTER_PKTS)); - assertThat(stat.getEgressPkts(), equalTo(TestUpfConstants.COUNTER_PKTS)); + if (stat.getCellId() == UPLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), EGRESS_COUNTER); + assertTrue(stat.exactlyEquals(UPLINK_EG_COUNTER)); + } else if (stat.getCellId() == DOWNLINK_COUNTER.getCellId()) { + assertEquals(stat.type(), EGRESS_COUNTER); + assertTrue(stat.exactlyEquals(DOWNLINK_EG_COUNTER)); + } else { + assertEquals(stat.type(), EGRESS_COUNTER); + assertThat(stat.getEgressBytes().get(), equalTo(0L)); + assertThat(stat.getEgressPkts().get(), equalTo(0L)); + assertTrue(stat.getIngressBytes().isEmpty()); + assertTrue(stat.getIngressPkts().isEmpty()); + } } } @Test public void testReadAllCountersLimitedCounters() throws Exception { - Collection allStats = upfProgrammable.readCounters(10); + Collection allStats = upfProgrammable.readCounters(10, COUNTER); assertThat(allStats.size(), equalTo(10)); } @Test public void testReadAllCountersPhysicalLimit() throws Exception { - Collection allStats = upfProgrammable.readCounters(1024); + Collection allStats = upfProgrammable.readCounters(1024, COUNTER); assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE)); } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java new file mode 100644 index 000000000..e37ed5abf --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeClient.java @@ -0,0 +1,117 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import com.google.common.collect.Maps; +import org.onosproject.net.DeviceId; +import org.onosproject.net.pi.model.PiPipeconf; +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.PiPacketOperation; +import org.onosproject.p4runtime.api.P4RuntimeClient; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.LongStream; + +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; + +/** + * Used to mock P4Runtime client used only for read/write requests for counters. + */ +public class MockP4RuntimeClient implements P4RuntimeClient { + + private final DeviceId deviceId; + final Map igCounters; + final Map egCounters; + + /** + * Used to mock P4Runtime client. + * + * @param deviceId The ID of the device + * @param counterSize The size of the counter array + */ + public MockP4RuntimeClient(DeviceId deviceId, int counterSize) { + this.deviceId = deviceId; + igCounters = Maps.newHashMap(); + egCounters = Maps.newHashMap(); + LongStream.range(0, counterSize).forEach(i -> { + igCounters.put(i, new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, i), + new PiCounterCellData(0, 0))); + egCounters.put(i, new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, i), + new PiCounterCellData(0, 0))); + }); + } + + @Override + public void shutdown() { + + } + + @Override + public boolean isServerReachable() { + return false; + } + + @Override + public CompletableFuture probeService() { + return null; + } + + @Override + public CompletableFuture setPipelineConfig(long p4DeviceId, PiPipeconf pipeconf, ByteBuffer deviceData) { + return null; + } + + @Override + public CompletableFuture isPipelineConfigSet(long p4DeviceId, PiPipeconf pipeconf) { + return null; + } + + @Override + public CompletableFuture isAnyPipelineConfigSet(long p4DeviceId) { + return null; + } + + @Override + public ReadRequest read(long p4DeviceId, PiPipeconf pipeconf) { + return new MockReadRequest(deviceId, igCounters, egCounters); + } + + @Override + public void setMastership(long p4DeviceId, boolean master, BigInteger electionId) { + + } + + @Override + public boolean isSessionOpen(long p4DeviceId) { + return false; + } + + @Override + public void closeSession(long p4DeviceId) { + + } + + @Override + public boolean isMaster(long p4DeviceId) { + return false; + } + + @Override + public void packetOut(long p4DeviceId, PiPacketOperation packet, PiPipeconf pipeconf) { + + } + + @Override + public WriteRequest write(long p4DeviceId, PiPipeconf pipeconf) { + return new MockWriteRequest(deviceId, igCounters, egCounters); + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java index 63fb63305..86dfdc7cc 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockP4RuntimeController.java @@ -5,39 +5,26 @@ import io.grpc.ManagedChannel; import org.onosproject.net.DeviceId; import org.onosproject.net.device.DeviceAgentListener; -import org.onosproject.net.pi.model.PiPipeconf; import org.onosproject.net.provider.ProviderId; import org.onosproject.p4runtime.api.P4RuntimeClient; import org.onosproject.p4runtime.api.P4RuntimeController; import org.onosproject.p4runtime.api.P4RuntimeEventListener; -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; - /** - * Currently only used to get mock clients that mock counter read requests. + * Currently only used to get mock clients that mock counter read/write requests. */ public class MockP4RuntimeController implements P4RuntimeController { - private final P4RuntimeClient mockP4rtClient; + final MockP4RuntimeClient mockP4rtClient; /** - * Used to mock counter read requests. + * Used to mock counter read/write requests. * - * @param deviceId The ID of the device - * @param packets Packets counter value - * @param bytes Bytes counter value + * @param deviceId The ID of the device * @param counterSize The size of the counter array */ - public MockP4RuntimeController(DeviceId deviceId, long packets, long bytes, int counterSize) { - mockP4rtClient = createMock(P4RuntimeClient.class); - expect(mockP4rtClient.read(anyLong(), anyObject(PiPipeconf.class))) - .andReturn(new MockReadRequest(deviceId, packets, bytes, counterSize)) - .anyTimes(); - replay(mockP4rtClient); + public MockP4RuntimeController(DeviceId deviceId, int counterSize) { + mockP4rtClient = new MockP4RuntimeClient(deviceId, counterSize); } @Override diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java index 766e08070..83fad09df 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadRequest.java @@ -7,47 +7,49 @@ import org.onosproject.net.pi.model.PiCounterId; import org.onosproject.net.pi.model.PiMeterId; import org.onosproject.net.pi.model.PiTableId; +import org.onosproject.net.pi.runtime.PiCounterCell; import org.onosproject.net.pi.runtime.PiCounterCellHandle; -import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiHandle; import org.onosproject.p4runtime.api.P4RuntimeReadClient; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.stream.LongStream; import static com.google.common.base.Preconditions.checkNotNull; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; /** - * For faking reads to a p4runtime client. Currently only used for testing + * For faking reads to a p4runtime client. Currently, only used for testing * UP4-specific counter reads, because all other P4 entities that UP4 reads can * be read via other ONOS services. */ public class MockReadRequest implements P4RuntimeReadClient.ReadRequest { List handles; DeviceId deviceId; - long packets; - long bytes; - int counterSize; + Map igCounters; + Map egCounters; - public MockReadRequest(DeviceId deviceId, long packets, long bytes, int counterSize) { + public MockReadRequest(DeviceId deviceId, + Map igCounters, + Map egCounters) { this.handles = new ArrayList<>(); this.deviceId = deviceId; - this.packets = packets; - this.bytes = bytes; - this.counterSize = counterSize; + this.igCounters = igCounters; + this.egCounters = egCounters; } @Override public CompletableFuture submit() { return CompletableFuture.completedFuture( - new MockReadResponse(this.handles, this.packets, this.bytes)); + new MockReadResponse(this.handles, this.igCounters, this.egCounters)); } @Override public P4RuntimeReadClient.ReadResponse submitSync() { - return new MockReadResponse(this.handles, this.packets, this.bytes); + return new MockReadResponse(this.handles, this.igCounters, this.egCounters); } @@ -106,21 +108,21 @@ public P4RuntimeReadClient.ReadRequest actionProfileMembers(Iterable { + this.handles.add(PiCounterCellHandle.of(this.deviceId, counterCell.cellId())); + }); + } else if (counterId.equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + egCounters.values().forEach(counterCell -> { + this.handles.add(PiCounterCellHandle.of(this.deviceId, counterCell.cellId())); + }); + } return this; } @Override public P4RuntimeReadClient.ReadRequest counterCells(Iterable counterIds) { - counterIds.forEach(counterId -> { - LongStream.range(0, this.counterSize) - .forEach(index -> { - PiCounterCellId cellId = - PiCounterCellId.ofIndirect(counterId, index); - PiCounterCellHandle handle = - PiCounterCellHandle.of(this.deviceId, cellId); - this.handle(handle); - }); - }); + counterIds.forEach(this::counterCells); return this; } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java index f3eff5d84..5c7289bfa 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockReadResponse.java @@ -3,8 +3,8 @@ package org.stratumproject.fabric.tna.behaviour.upf; import org.onosproject.net.pi.runtime.PiCounterCell; -import org.onosproject.net.pi.runtime.PiCounterCellData; import org.onosproject.net.pi.runtime.PiCounterCellHandle; +import org.onosproject.net.pi.runtime.PiCounterCellId; import org.onosproject.net.pi.runtime.PiEntity; import org.onosproject.net.pi.runtime.PiEntityType; import org.onosproject.net.pi.runtime.PiHandle; @@ -13,8 +13,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; /** * For faking reads to a p4runtime client. Currently only used for testing @@ -23,13 +26,15 @@ */ public class MockReadResponse implements P4RuntimeReadClient.ReadResponse { List entities; - long packets; - long bytes; + Map igCounters; + Map egCounters; - public MockReadResponse(Iterable handles, long packets, long bytes) { + public MockReadResponse(Iterable handles, + Map igCounters, + Map egCounters) { this.entities = new ArrayList<>(); - this.packets = packets; - this.bytes = bytes; + this.igCounters = igCounters; + this.egCounters = egCounters; checkNotNull(handles); handles.forEach(this::handle); } @@ -42,13 +47,20 @@ public boolean isSuccess() { public MockReadResponse handle(PiHandle handle) { if (handle.entityType().equals(PiEntityType.COUNTER_CELL)) { PiCounterCellHandle counterHandle = (PiCounterCellHandle) handle; - PiCounterCellData data = - new PiCounterCellData(this.packets, this.bytes); - PiEntity entity = new PiCounterCell(counterHandle.cellId(), data); - this.entities.add(entity); + PiCounterCellId cellId = counterHandle.cellId(); + if (cellId.counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { + PiEntity entity = new PiCounterCell( + counterHandle.cellId(), + igCounters.get(cellId.index()).data()); + this.entities.add(entity); + } else if (cellId.counterId().equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + PiEntity entity = new PiCounterCell( + counterHandle.cellId(), + egCounters.get(cellId.index()).data()); + this.entities.add(entity); + } } // Only handles counter cell so far - return this; } diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java new file mode 100644 index 000000000..bc4917ca2 --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteRequest.java @@ -0,0 +1,125 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.pi.runtime.PiCounterCell; +import org.onosproject.net.pi.runtime.PiCounterCellId; +import org.onosproject.net.pi.runtime.PiEntity; +import org.onosproject.net.pi.runtime.PiEntityType; +import org.onosproject.net.pi.runtime.PiHandle; +import org.onosproject.p4runtime.api.P4RuntimeWriteClient; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; + +/** + * For faking writes to a p4runtime client. Currently, only used for testing + * UP4-specific counter writes, all other entities are accessed via other ONOS + * services. + */ +public class MockWriteRequest implements P4RuntimeWriteClient.WriteRequest { + private final List toModifyEntities; + private final DeviceId deviceId; + private final Map igCounters; + private final Map egCounters; + + public MockWriteRequest(DeviceId deviceId, + Map igCounters, + Map egCounters) { + this.toModifyEntities = new ArrayList<>(); + this.deviceId = deviceId; + this.igCounters = igCounters; + this.egCounters = egCounters; + } + + @Override + public P4RuntimeWriteClient.WriteRequest withAtomicity(P4RuntimeWriteClient.Atomicity atomicity) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest insert(PiEntity entity) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest insert(Iterable entities) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest modify(PiEntity entity) { + toModifyEntities.add(entity); + return this; + } + + @Override + public P4RuntimeWriteClient.WriteRequest modify(Iterable entities) { + entities.forEach(toModifyEntities::add); + return this; + } + + @Override + public P4RuntimeWriteClient.WriteRequest delete(PiHandle handle) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest delete(Iterable handles) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest entity(PiEntity entity, P4RuntimeWriteClient.UpdateType updateType) { + return null; + } + + @Override + public P4RuntimeWriteClient.WriteRequest entities(Iterable entities, + P4RuntimeWriteClient.UpdateType updateType) { + return null; + } + + @Override + public CompletableFuture submit() { + modifyEntities(); + return CompletableFuture.completedFuture( + new MockWriteResponse(toModifyEntities.size())); + } + + @Override + public P4RuntimeWriteClient.WriteResponse submitSync() { + modifyEntities(); + return new MockWriteResponse(toModifyEntities.size()); + } + + private void modifyEntities() { + // Only handles counter cell so far + toModifyEntities.forEach( + entity -> { + if (entity.piEntityType().equals(PiEntityType.COUNTER_CELL)) { + PiCounterCell counterCell = (PiCounterCell) entity; + PiCounterCellId cellId = counterCell.cellId(); + if (cellId.counterId().equals(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER)) { + igCounters.computeIfPresent(cellId.index(), (k, v) -> counterCell); + } else if (cellId.counterId().equals(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER)) { + egCounters.computeIfPresent(cellId.index(), (k, v) -> counterCell); + } + } + } + ); + } + + @Override + public Collection pendingUpdates() { + return null; + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java new file mode 100644 index 000000000..1a5dec965 --- /dev/null +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/MockWriteResponse.java @@ -0,0 +1,61 @@ +// Copyright 2022-present Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package org.stratumproject.fabric.tna.behaviour.upf; + +import com.google.common.collect.Lists; +import org.onosproject.p4runtime.api.P4RuntimeWriteClient; + +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; + +/** + * For faking writes to a p4runtime client. Currently, only used for testing + * UP4-specific counter writes, all other entities are accessed via other ONOS + * services. + */ +public class MockWriteResponse implements P4RuntimeWriteClient.WriteResponse { + + int numEntities; + + public MockWriteResponse(int numEntities) { + this.numEntities = numEntities; + } + + @Override + public boolean isSuccess() { + return true; + } + + @Override + public Collection all() { + P4RuntimeWriteClient.EntityUpdateResponse mockPosResponse = + createMock(P4RuntimeWriteClient.EntityUpdateResponse.class); + expect(mockPosResponse.isSuccess()) + .andReturn(true) + .anyTimes(); + replay(mockPosResponse); + return LongStream.range(0, numEntities).mapToObj(i -> mockPosResponse).collect(Collectors.toList()); + } + + @Override + public Collection success() { + return all(); + } + + @Override + public Collection failed() { + return Lists.newArrayList(); + } + + @Override + public Collection status( + P4RuntimeWriteClient.EntityUpdateStatus status) { + return null; + } +} diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java index 4ba528fd1..5b5bcd728 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/TestUpfConstants.java @@ -11,6 +11,7 @@ import org.onosproject.core.DefaultApplicationId; import org.onosproject.net.DeviceId; import org.onosproject.net.behaviour.upf.UpfApplication; +import org.onosproject.net.behaviour.upf.UpfCounter; import org.onosproject.net.behaviour.upf.UpfGtpTunnelPeer; import org.onosproject.net.behaviour.upf.UpfInterface; import org.onosproject.net.behaviour.upf.UpfMeter; @@ -32,6 +33,9 @@ import org.onosproject.net.meter.MeterScope; import org.onosproject.net.pi.runtime.PiAction; import org.onosproject.net.pi.runtime.PiActionParam; +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.PiMeterCellId; import org.stratumproject.fabric.tna.behaviour.P4InfoConstants; @@ -42,6 +46,7 @@ import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.CTR_ID; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_EG_TUNNEL_PEERS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_LOAD_TUNNEL_PARAMS; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_QOS_SLICE_TC_METER; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APPLICATIONS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_APP_FWD; @@ -60,6 +65,7 @@ import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_SET_DOWNLINK_SESSION_BUF; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_SET_ROUTING_IPV4_DST; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_SET_UPLINK_SESSION; +import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_DROP; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_SESSIONS; import static org.stratumproject.fabric.tna.behaviour.P4InfoConstants.FABRIC_INGRESS_UPF_UPLINK_TERMINATIONS; @@ -121,8 +127,14 @@ public final class TestUpfConstants { public static final int PHYSICAL_MAX_SLICE_METERS = 1 << 6; - public static final long COUNTER_BYTES = 12; - public static final long COUNTER_PKTS = 15; + public static final long UL_IG_COUNTER_BYTES = 12; + public static final long UL_IG_COUNTER_PKTS = 13; + public static final long UL_EG_COUNTER_BYTES = 14; + public static final long UL_EG_COUNTER_PKTS = 15; + public static final long DL_IG_COUNTER_BYTES = 16; + public static final long DL_IG_COUNTER_PKTS = 17; + public static final long DL_EG_COUNTER_BYTES = 18; + public static final long DL_EG_COUNTER_PKTS = 19; public static final byte APP_FILTERING_ID = 10; public static final byte DEFAULT_APP_ID = 0; @@ -254,6 +266,42 @@ public final class TestUpfConstants { public static final UpfMeter SLICE_METER_RESET = UpfMeter.resetSlice(SLICE_METER_CELL_ID); + public static final UpfCounter UPLINK_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setIngress(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + .setEgress(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) + .build(); + + public static final UpfCounter UPLINK_IG_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setIngress(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + .isIngressCounter() + .build(); + + public static final UpfCounter UPLINK_EG_COUNTER = UpfCounter.builder() + .withCellId(UPLINK_COUNTER_CELL_ID) + .setEgress(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) + .isEgressCounter() + .build(); + + public static final UpfCounter DOWNLINK_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setIngress(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + .setEgress(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) + .build(); + + public static final UpfCounter DOWNLINK_IG_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setIngress(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + .isIngressCounter() + .build(); + + public static final UpfCounter DOWNLINK_EG_COUNTER = UpfCounter.builder() + .withCellId(DOWNLINK_COUNTER_CELL_ID) + .setEgress(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) + .isEgressCounter() + .build(); + public static final FlowRule FABRIC_INGRESS_GTP_TUNNEL_PEER = DefaultFlowRule.builder() .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent() .forTable(FABRIC_INGRESS_UPF_IG_TUNNEL_PEERS) @@ -573,6 +621,26 @@ public final class TestUpfConstants { .withUnit(BYTES_PER_SEC) .remove(); + public static final PiCounterCell FABRIC_UPLINK_IG_COUNTER = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, UPLINK_COUNTER_CELL_ID), + new PiCounterCellData(UL_IG_COUNTER_PKTS, UL_IG_COUNTER_BYTES) + ); + + public static final PiCounterCell FABRIC_UPLINK_EG_COUNTER = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, UPLINK_COUNTER_CELL_ID), + new PiCounterCellData(UL_EG_COUNTER_PKTS, UL_EG_COUNTER_BYTES) + ); + + public static final PiCounterCell FABRIC_DOWNLINK_IG_COUNTER = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_INGRESS_UPF_TERMINATIONS_COUNTER, DOWNLINK_COUNTER_CELL_ID), + new PiCounterCellData(DL_IG_COUNTER_PKTS, DL_IG_COUNTER_BYTES) + ); + + public static final PiCounterCell FABRIC_DOWNLINK_EG_COUNTER = new PiCounterCell( + PiCounterCellId.ofIndirect(FABRIC_EGRESS_UPF_TERMINATIONS_COUNTER, DOWNLINK_COUNTER_CELL_ID), + new PiCounterCellData(DL_EG_COUNTER_PKTS, DL_EG_COUNTER_BYTES) + ); + /** * Hidden constructor for utility class. */ From dbd64c54e8abe3abcb577faf5cd6e5161d36c364 Mon Sep 17 00:00:00 2001 From: Daniele Moro Date: Mon, 9 May 2022 17:25:01 +0200 Subject: [PATCH 12/12] Fix checkstyle --- .../fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java index ddea99080..c02c7a868 100644 --- a/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java +++ b/src/test/java/org/stratumproject/fabric/tna/behaviour/upf/FabricUpfProgrammableTest.java @@ -84,10 +84,6 @@ import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_EG_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.DOWNLINK_IG_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_DOWNLINK_EG_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_DOWNLINK_IG_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_UPLINK_EG_COUNTER; -import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.FABRIC_UPLINK_IG_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.SLICE_MOBILE; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_COUNTER; import static org.stratumproject.fabric.tna.behaviour.upf.TestUpfConstants.UPLINK_EG_COUNTER;