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..97f22ead0 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; @@ -46,9 +47,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; @@ -65,8 +69,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 +107,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 +121,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 +269,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 +290,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 +443,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: @@ -547,28 +562,59 @@ private Collection getUpfTerminationsDownlink() throws UpfProgrammabl return upfTerminations; } + private void applyUpfCounter(UpfCounter upfCounter) throws UpfProgrammableException { + final List counterRequests = Lists.newArrayList(); + if (isIngressCounter(upfCounter.type()) || isBiCounter(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()) || isBiCounter(upfCounter.type())) { + if (upfCounter.getEgressPkts().isEmpty() || upfCounter.getEgressBytes().isEmpty()) { + throw new UpfProgrammableException("Egress 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(counterRequests) + .submitSync(); + if (!writeResponse.failed().isEmpty()) { + writeResponse.failed().stream().filter(counterEntryResp -> !counterEntryResp.isSuccess()) + .forEach(counterEntryResp -> log.error("A counter was not modified correctly: {}", + counterEntryResp.explanation())); + throw new UpfProgrammableException("Failed to modify counters"); + } + } + @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 +623,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 +668,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 +688,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 +706,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 +726,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 +756,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 @@ -717,12 +788,16 @@ public void apply(UpfEntity entity) throws UpfProgrammableException { case APPLICATION: addUpfApplication((UpfApplication) entity); break; + case COUNTER: + case INGRESS_COUNTER: + case EGRESS_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 +929,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 +941,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 +1110,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..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 @@ -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,13 @@ 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.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 +97,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 +134,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 +186,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 +362,47 @@ public void testSliceMeter() throws Exception { assertTrue(upfProgrammable.readAll(UpfEntityType.SLICE_METER).isEmpty()); } + @Test + public void testApplyCounter() throws Exception { + UpfCounter expectedCounter = UPLINK_COUNTER; + upfProgrammable.apply(expectedCounter); + UpfCounter installedCounter = + upfProgrammable.readCounter(expectedCounter.getCellId(), COUNTER); + assertThat(installedCounter, equalTo(expectedCounter)); + } + + @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 public void testInvalidSliceIdSliceMeter() throws Exception { exceptionRule.expect(UpfProgrammableException.class); @@ -380,26 +432,88 @@ public void testClearInterfaces() throws Exception { @Test public void testReadAllCounters() throws Exception { - Collection allStats = upfProgrammable.readAll(UpfEntityType.COUNTER); + upfProgrammable.apply(UPLINK_COUNTER); + upfProgrammable.apply(DOWNLINK_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 { + 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); + 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 { + 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; - 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. */