Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDFAB-1178] Allow and write in/e-gress counter separately #519

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 {

Expand All @@ -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" +
Expand Down Expand Up @@ -120,9 +134,9 @@ public class FabricUpfProgrammableTest {
);
private static final List<PiMeterModel> 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)
);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -380,26 +432,88 @@ public void testClearInterfaces() throws Exception {

@Test
public void testReadAllCounters() throws Exception {
Collection<? extends UpfEntity> allStats = upfProgrammable.readAll(UpfEntityType.COUNTER);
upfProgrammable.apply(UPLINK_COUNTER);
upfProgrammable.apply(DOWNLINK_COUNTER);

Collection<? extends UpfEntity> 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<? extends UpfEntity> 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<? extends UpfEntity> 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<UpfCounter> allStats = upfProgrammable.readCounters(10);
Collection<UpfCounter> allStats = upfProgrammable.readCounters(10, COUNTER);
assertThat(allStats.size(), equalTo(10));
}

@Test
public void testReadAllCountersPhysicalLimit() throws Exception {
Collection<UpfCounter> allStats = upfProgrammable.readCounters(1024);
Collection<UpfCounter> allStats = upfProgrammable.readCounters(1024, COUNTER);
assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Long, PiCounterCell> igCounters;
final Map<Long, PiCounterCell> 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<Boolean> probeService() {
return null;
}

@Override
public CompletableFuture<Boolean> setPipelineConfig(long p4DeviceId, PiPipeconf pipeconf, ByteBuffer deviceData) {
return null;
}

@Override
public CompletableFuture<Boolean> isPipelineConfigSet(long p4DeviceId, PiPipeconf pipeconf) {
return null;
}

@Override
public CompletableFuture<Boolean> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down