[SDFAB-189] UpfProgrammable implementation for fabric v1model
Change-Id: I4ea7980830d761a0da8a78943c08229c2da9410d
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfProgrammableTest.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfProgrammableTest.java
new file mode 100644
index 0000000..50fd8bc
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfProgrammableTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.util.HexString;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.upf.ForwardingActionRule;
+import org.onosproject.net.behaviour.upf.PacketDetectionRule;
+import org.onosproject.net.behaviour.upf.PdrStats;
+import org.onosproject.net.behaviour.upf.UpfInterface;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiTableModel;
+import org.onosproject.net.pi.service.PiPipeconfService;
+import org.onosproject.net.pi.service.PiTranslationService;
+import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.onosproject.pipelines.fabric.impl.FabricPipeconfLoader;
+import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
+
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+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.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_EGRESS_SPGW_PDR_COUNTER;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_DOWNLINK_PDRS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_FARS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_PDR_COUNTER;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_UPLINK_PDRS;
+
+public class FabricUpfProgrammableTest {
+
+ private static final ApplicationId APP_ID =
+ TestApplicationId.create(FabricPipeconfLoader.PIPELINE_APP_NAME);
+
+ private final DistributedFabricUpfStore upfStore = TestDistributedFabricUpfStore.build();
+ private MockPacketService packetService;
+ private FabricUpfProgrammable upfProgrammable;
+
+ // Bytes of a random but valid Ethernet frame.
+ private static final byte[] ETH_FRAME_BYTES = HexString.fromHexString(
+ "00060708090a0001020304058100000a08004500006a000100004011f92ec0a80001c0a8000204d2005" +
+ "00056a8d5000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" +
+ "2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454" +
+ "64748494a4b4c4d", "");
+ private static final TrafficTreatment TABLE_OUTPUT_TREATMENT = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.TABLE)
+ .build();
+
+ private static final List<PiTableModel> TABLE_MODELS = ImmutableList.of(
+ new MockTableModel(FABRIC_INGRESS_SPGW_UPLINK_PDRS,
+ TestUpfConstants.PHYSICAL_MAX_PDRS / 2),
+ new MockTableModel(FABRIC_INGRESS_SPGW_DOWNLINK_PDRS,
+ TestUpfConstants.PHYSICAL_MAX_PDRS / 2),
+ new MockTableModel(FABRIC_INGRESS_SPGW_FARS,
+ TestUpfConstants.PHYSICAL_MAX_FARS)
+ );
+ private static final List<PiCounterModel> COUNTER_MODELS = ImmutableList.of(
+ new MockCounterModel(FABRIC_INGRESS_SPGW_PDR_COUNTER,
+ TestUpfConstants.PHYSICAL_COUNTER_SIZE),
+ new MockCounterModel(FABRIC_EGRESS_SPGW_PDR_COUNTER,
+ TestUpfConstants.PHYSICAL_COUNTER_SIZE)
+ );
+
+ @Before
+ public void setUp() throws Exception {
+ FabricCapabilities capabilities = createMock(FabricCapabilities.class);
+ expect(capabilities.supportUpf()).andReturn(true).anyTimes();
+ replay(capabilities);
+
+ // Services mock
+ packetService = new MockPacketService();
+ CoreService coreService = createMock(CoreService.class);
+ NetworkConfigService netcfgService = createMock(NetworkConfigService.class);
+ DeviceService deviceService = createMock(DeviceService.class);
+ PiTranslationService piTranslationService = createMock(PiTranslationService.class);
+ expect(coreService.getAppId(anyString())).andReturn(APP_ID).anyTimes();
+ expect(netcfgService.getConfig(TestUpfConstants.DEVICE_ID, BasicDeviceConfig.class))
+ .andReturn(TestUpfUtils.getBasicConfig(TestUpfConstants.DEVICE_ID, "/basic.json"))
+ .anyTimes();
+ replay(coreService, netcfgService);
+
+ // Mock driverData to get the right device ID
+ DriverData driverData = createMock(DriverData.class);
+ expect(driverData.deviceId()).andReturn(TestUpfConstants.DEVICE_ID).anyTimes();
+ replay(driverData);
+
+ // Mock DriverHandler to get all the required mocked services
+ DriverHandler driverHandler = createMock(DriverHandler.class);
+ expect(driverHandler.get(FlowRuleService.class)).andReturn(new MockFlowRuleService()).anyTimes();
+ expect(driverHandler.get(PacketService.class)).andReturn(packetService).anyTimes();
+ expect(driverHandler.get(FabricUpfStore.class)).andReturn(upfStore).anyTimes();
+ expect(driverHandler.get(NetworkConfigService.class)).andReturn(netcfgService).anyTimes();
+ expect(driverHandler.get(CoreService.class)).andReturn(coreService).anyTimes();
+ expect(driverHandler.get(DeviceService.class)).andReturn(deviceService).anyTimes();
+ expect(driverHandler.get(PiTranslationService.class)).andReturn(piTranslationService).anyTimes();
+ expect(driverHandler.get(PiPipeconfService.class))
+ .andReturn(new MockPiPipeconfService(TABLE_MODELS, COUNTER_MODELS))
+ .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();
+ replay(driverHandler);
+
+ upfProgrammable = new FabricUpfProgrammable();
+ TestUtils.setField(upfProgrammable, "handler", driverHandler);
+ TestUtils.setField(upfProgrammable, "data", driverData);
+ ConcurrentMap<DeviceId, URI> channelUris = TestUtils.getField(upfProgrammable, "CHANNEL_URIS");
+ channelUris.put(TestUpfConstants.DEVICE_ID, new URI("grpc://localhost:1234?device_id=1"));
+ }
+
+ @Test
+ public void testUplinkPdr() throws Exception {
+ assertTrue(upfProgrammable.getPdrs().isEmpty());
+ PacketDetectionRule expectedPdr = TestUpfConstants.UPLINK_PDR;
+ upfProgrammable.addPdr(expectedPdr);
+ Collection<PacketDetectionRule> installedPdrs = upfProgrammable.getPdrs();
+ assertThat(installedPdrs.size(), equalTo(1));
+ for (var readPdr : installedPdrs) {
+ assertThat(readPdr, equalTo(expectedPdr));
+ }
+ upfProgrammable.removePdr(expectedPdr.withoutActionParams());
+ assertTrue(upfProgrammable.getPdrs().isEmpty());
+ }
+
+ @Test
+ public void testDownlinkPdr() throws Exception {
+ assertTrue(upfProgrammable.getPdrs().isEmpty());
+ PacketDetectionRule expectedPdr = TestUpfConstants.DOWNLINK_PDR;
+ upfProgrammable.addPdr(expectedPdr);
+ Collection<PacketDetectionRule> installedPdrs = upfProgrammable.getPdrs();
+ assertThat(installedPdrs.size(), equalTo(1));
+ for (var readPdr : installedPdrs) {
+ assertThat(readPdr, equalTo(expectedPdr));
+ }
+ upfProgrammable.removePdr(expectedPdr.withoutActionParams());
+ assertTrue(upfProgrammable.getPdrs().isEmpty());
+ }
+
+ @Test
+ public void testUplinkFar() throws Exception {
+ assertTrue(upfProgrammable.getFars().isEmpty());
+ ForwardingActionRule expectedFar = TestUpfConstants.UPLINK_FAR;
+ upfProgrammable.addFar(expectedFar);
+ Collection<ForwardingActionRule> installedFars = upfProgrammable.getFars();
+ assertThat(installedFars.size(), equalTo(1));
+ for (var readFar : installedFars) {
+ assertThat(readFar, equalTo(expectedFar));
+ }
+ upfProgrammable.removeFar(expectedFar.withoutActionParams());
+ assertTrue(upfProgrammable.getFars().isEmpty());
+ }
+
+ @Test
+ public void testDownlinkFar() throws Exception {
+ assertTrue(upfProgrammable.getFars().isEmpty());
+ ForwardingActionRule expectedFar = TestUpfConstants.DOWNLINK_FAR;
+ upfProgrammable.addFar(expectedFar);
+ Collection<ForwardingActionRule> installedFars = upfProgrammable.getFars();
+ assertThat(installedFars.size(), equalTo(1));
+ for (var readFar : installedFars) {
+ assertThat(readFar, equalTo(expectedFar));
+ }
+ upfProgrammable.removeFar(expectedFar.withoutActionParams());
+ assertTrue(upfProgrammable.getFars().isEmpty());
+ }
+
+ @Test
+ public void testUplinkInterface() throws Exception {
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ UpfInterface expectedInterface = TestUpfConstants.UPLINK_INTERFACE;
+ upfProgrammable.addInterface(expectedInterface);
+ Collection<UpfInterface> installedInterfaces = upfProgrammable.getInterfaces();
+ assertThat(installedInterfaces.size(), equalTo(1));
+ for (var readInterface : installedInterfaces) {
+ assertThat(readInterface, equalTo(expectedInterface));
+ }
+ upfProgrammable.removeInterface(expectedInterface);
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ }
+
+ @Test
+ public void testDownlinkInterface() throws Exception {
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ UpfInterface expectedInterface = TestUpfConstants.DOWNLINK_INTERFACE;
+ upfProgrammable.addInterface(expectedInterface);
+ Collection<UpfInterface> installedInterfaces = upfProgrammable.getInterfaces();
+ assertThat(installedInterfaces.size(), equalTo(1));
+ for (var readInterface : installedInterfaces) {
+ assertThat(readInterface, equalTo(expectedInterface));
+ }
+ upfProgrammable.removeInterface(expectedInterface);
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ }
+
+ @Test
+ public void testClearInterfaces() throws Exception {
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ upfProgrammable.addInterface(TestUpfConstants.UPLINK_INTERFACE);
+ upfProgrammable.addInterface(TestUpfConstants.DOWNLINK_INTERFACE);
+ assertThat(upfProgrammable.getInterfaces().size(), equalTo(2));
+ upfProgrammable.clearInterfaces();
+ assertTrue(upfProgrammable.getInterfaces().isEmpty());
+ }
+
+ @Test
+ public void testReadAllCounters() {
+ Collection<PdrStats> allStats = upfProgrammable.readAllCounters(-1);
+ assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE));
+ for (PdrStats stat : allStats) {
+ 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));
+ }
+ }
+
+ @Test
+ public void testReadAllCountersLimitedCounters() {
+ Collection<PdrStats> allStats = upfProgrammable.readAllCounters(10);
+ assertThat(allStats.size(), equalTo(10));
+ }
+
+ @Test
+ public void testReadAllCountersPhysicalLimit() {
+ Collection<PdrStats> allStats = upfProgrammable.readAllCounters(1024);
+ assertThat(allStats.size(), equalTo(TestUpfConstants.PHYSICAL_COUNTER_SIZE));
+ }
+
+ @Test
+ public void testSendPacketOut() {
+ upfProgrammable.sendPacketOut(ByteBuffer.wrap(ETH_FRAME_BYTES));
+ var emittedPkt = packetService.emittedPackets.poll();
+ assertNotNull(emittedPkt);
+ assertThat(emittedPkt.data().array(), equalTo(ETH_FRAME_BYTES));
+ assertThat(emittedPkt.treatment(), equalTo(TABLE_OUTPUT_TREATMENT));
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfTranslatorTest.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfTranslatorTest.java
new file mode 100644
index 0000000..e490572
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/FabricUpfTranslatorTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.junit.Test;
+import org.onosproject.net.behaviour.upf.ForwardingActionRule;
+import org.onosproject.net.behaviour.upf.PacketDetectionRule;
+import org.onosproject.net.behaviour.upf.UpfInterface;
+import org.onosproject.net.behaviour.upf.UpfProgrammableException;
+import org.onosproject.net.flow.FlowRule;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class FabricUpfTranslatorTest {
+
+ private final FabricUpfTranslator upfTranslator = new FabricUpfTranslator(TestDistributedFabricUpfStore.build());
+
+ @Test
+ public void fabricEntryToUplinkPdrTest() {
+ PacketDetectionRule expectedPdr = TestUpfConstants.UPLINK_PDR;
+ PacketDetectionRule translatedPdr;
+ try {
+ translatedPdr = upfTranslator.fabricEntryToPdr(TestUpfConstants.FABRIC_UPLINK_PDR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric uplink PDR should translate to abstract PDR without error.", false);
+ return;
+ }
+ assertThat("Translated PDR should be uplink.", translatedPdr.matchesEncapped());
+ assertThat(translatedPdr, equalTo(expectedPdr));
+ }
+
+ @Test
+ public void fabricEntryToUplinkPriorityPdrTest() {
+ PacketDetectionRule expectedPdr = TestUpfConstants.UPLINK_PRIORITY_PDR;
+ PacketDetectionRule translatedPdr;
+ try {
+ translatedPdr = upfTranslator.fabricEntryToPdr(TestUpfConstants.FABRIC_UPLINK_PRIORITY_PDR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric uplink PDR should translate to abstract PDR without error.", false);
+ return;
+ }
+ assertThat("Translated PDR should be uplink.", translatedPdr.matchesEncapped());
+ assertThat(translatedPdr, equalTo(expectedPdr));
+ }
+
+ @Test
+ public void fabricEntryToDownlinkPdrTest() {
+ PacketDetectionRule expectedPdr = TestUpfConstants.DOWNLINK_PDR;
+ PacketDetectionRule translatedPdr;
+ try {
+ translatedPdr = upfTranslator.fabricEntryToPdr(TestUpfConstants.FABRIC_DOWNLINK_PDR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric downlink PDR should translate to abstract PDR without error.", false);
+ return;
+ }
+
+ assertThat("Translated PDR should be downlink.", translatedPdr.matchesUnencapped());
+ assertThat(translatedPdr, equalTo(expectedPdr));
+ }
+
+ @Test
+ public void fabricEntryToDownlinkPriorityPdrTest() {
+ PacketDetectionRule expectedPdr = TestUpfConstants.DOWNLINK_PRIORITY_PDR;
+ PacketDetectionRule translatedPdr;
+ try {
+ translatedPdr = upfTranslator.fabricEntryToPdr(TestUpfConstants.FABRIC_DOWNLINK_PRIORITY_PDR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric downlink PDR should translate to abstract PDR without error.", false);
+ return;
+ }
+
+ assertThat("Translated PDR should be downlink.", translatedPdr.matchesUnencapped());
+ assertThat(translatedPdr, equalTo(expectedPdr));
+ }
+
+ @Test
+ public void fabricEntryToUplinkFarTest() {
+ ForwardingActionRule translatedFar;
+ ForwardingActionRule expectedFar = TestUpfConstants.UPLINK_FAR;
+ try {
+ translatedFar = upfTranslator.fabricEntryToFar(TestUpfConstants.FABRIC_UPLINK_FAR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric uplink FAR should correctly translate to abstract FAR without error",
+ false);
+ return;
+ }
+ assertThat("Translated FAR should be uplink.", translatedFar.forwards());
+ assertThat(translatedFar, equalTo(expectedFar));
+ }
+
+ @Test
+ public void fabricEntryToDownlinkFarTest() {
+ ForwardingActionRule translatedFar;
+ ForwardingActionRule expectedFar = TestUpfConstants.DOWNLINK_FAR;
+ try {
+ translatedFar = upfTranslator.fabricEntryToFar(TestUpfConstants.FABRIC_DOWNLINK_FAR);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric downlink FAR should correctly translate to abstract FAR without error",
+ false);
+ return;
+ }
+ assertThat("Translated FAR should be downlink.", translatedFar.encaps());
+ assertThat(translatedFar, equalTo(expectedFar));
+ }
+
+ @Test
+ public void fabricEntryToUplinkInterfaceTest() {
+ UpfInterface translatedInterface;
+ UpfInterface expectedInterface = TestUpfConstants.UPLINK_INTERFACE;
+ try {
+ translatedInterface = upfTranslator.fabricEntryToInterface(TestUpfConstants.FABRIC_UPLINK_INTERFACE);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric uplink interface should correctly translate to abstract interface without error",
+ false);
+ return;
+ }
+ assertThat("Translated interface should be uplink.", translatedInterface.isAccess());
+ assertThat(translatedInterface, equalTo(expectedInterface));
+ }
+
+ @Test
+ public void fabricEntryToDownlinkInterfaceTest() {
+ UpfInterface translatedInterface;
+ UpfInterface expectedInterface = TestUpfConstants.DOWNLINK_INTERFACE;
+ try {
+ translatedInterface = upfTranslator.fabricEntryToInterface(TestUpfConstants.FABRIC_DOWNLINK_INTERFACE);
+ } catch (UpfProgrammableException e) {
+ assertThat("Fabric downlink interface should correctly translate to abstract interface without error",
+ false);
+ return;
+ }
+ assertThat("Translated interface should be downlink.", translatedInterface.isCore());
+ assertThat(translatedInterface, equalTo(expectedInterface));
+ }
+
+ @Test
+ public void uplinkInterfaceToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_UPLINK_INTERFACE;
+ try {
+ translatedRule = upfTranslator.interfaceToFabricEntry(TestUpfConstants.UPLINK_INTERFACE,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract uplink interface should correctly translate to Fabric interface without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void downlinkInterfaceToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_DOWNLINK_INTERFACE;
+ try {
+ translatedRule = upfTranslator.interfaceToFabricEntry(TestUpfConstants.DOWNLINK_INTERFACE,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract downlink interface should correctly translate to Fabric interface without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void downlinkPdrToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_DOWNLINK_PDR;
+ try {
+ translatedRule = upfTranslator.pdrToFabricEntry(TestUpfConstants.DOWNLINK_PDR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract downlink PDR should correctly translate to Fabric PDR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void downlinkPdrToFabricPriorityEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_DOWNLINK_PRIORITY_PDR;
+ try {
+ translatedRule = upfTranslator.pdrToFabricEntry(TestUpfConstants.DOWNLINK_PRIORITY_PDR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract downlink PDR should correctly translate to Fabric PDR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void uplinkFarToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_UPLINK_FAR;
+ try {
+ translatedRule = upfTranslator.farToFabricEntry(TestUpfConstants.UPLINK_FAR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract uplink FAR should correctly translate to Fabric FAR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void uplinkPdrToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_UPLINK_PDR;
+ try {
+ translatedRule = upfTranslator.pdrToFabricEntry(TestUpfConstants.UPLINK_PDR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract uplink PDR should correctly translate to Fabric PDR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void uplinkPriorityPdrToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_UPLINK_PRIORITY_PDR;
+ try {
+ translatedRule = upfTranslator.pdrToFabricEntry(TestUpfConstants.UPLINK_PRIORITY_PDR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract uplink PDR should correctly translate to Fabric PDR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+
+ @Test
+ public void downlinkFarToFabricEntryTest() {
+ FlowRule translatedRule;
+ FlowRule expectedRule = TestUpfConstants.FABRIC_DOWNLINK_FAR;
+ try {
+ translatedRule = upfTranslator.farToFabricEntry(TestUpfConstants.DOWNLINK_FAR,
+ TestUpfConstants.DEVICE_ID,
+ TestUpfConstants.APP_ID,
+ TestUpfConstants.DEFAULT_PRIORITY);
+ } catch (UpfProgrammableException e) {
+ assertThat("Abstract downlink FAR should correctly translate to Fabric FAR without error",
+ false);
+ return;
+ }
+ assertThat(translatedRule, equalTo(expectedRule));
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockCounterModel.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockCounterModel.java
new file mode 100644
index 0000000..dcf667b
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockCounterModel.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiCounterType;
+import org.onosproject.net.pi.model.PiTableId;
+
+public class MockCounterModel implements PiCounterModel {
+ PiCounterId id;
+ int size;
+
+ public MockCounterModel(PiCounterId id, int size) {
+ this.id = id;
+ this.size = size;
+ }
+
+ @Override
+ public PiCounterId id() {
+ return this.id;
+ }
+
+ @Override
+ public PiCounterType counterType() {
+ return null;
+ }
+
+ @Override
+ public Unit unit() {
+ return null;
+ }
+
+ @Override
+ public PiTableId table() {
+ return null;
+ }
+
+ @Override
+ public long size() {
+ return this.size;
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockFlowRuleService.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockFlowRuleService.java
new file mode 100644
index 0000000..055a4be
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockFlowRuleService.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import com.google.common.collect.Sets;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleServiceAdapter;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+public class MockFlowRuleService extends FlowRuleServiceAdapter {
+
+ final Set<FlowRule> flows = Sets.newHashSet();
+ boolean success;
+
+ int errorFlow = -1;
+
+ public void setErrorFlow(int errorFlow) {
+ this.errorFlow = errorFlow;
+ }
+
+ public void setFuture(boolean success) {
+ this.success = success;
+ }
+
+ @Override
+ public void apply(FlowRuleOperations ops) {
+ AtomicBoolean thisSuccess = new AtomicBoolean(success);
+ ops.stages().forEach(stage -> stage.forEach(flow -> {
+ if (errorFlow == flow.rule().id().value()) {
+ thisSuccess.set(false);
+ } else {
+ switch (flow.type()) {
+ case ADD:
+ case MODIFY: //TODO is this the right behavior for modify?
+ flows.add(flow.rule());
+ break;
+ case REMOVE:
+ flows.remove(flow.rule());
+ break;
+ default:
+ break;
+ }
+ }
+ }));
+ if (thisSuccess.get()) {
+ ops.callback().onSuccess(ops);
+ } else {
+ ops.callback().onError(ops);
+ }
+ }
+
+ @Override
+ public int getFlowRuleCount() {
+ return flows.size();
+ }
+
+ @Override
+ public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+ return flows.stream()
+ .filter(flow -> flow.deviceId().equals(deviceId))
+ .map(DefaultFlowEntry::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void applyFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.add(flow);
+ }
+ }
+
+ @Override
+ public void removeFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.remove(flow);
+ }
+ }
+
+ @Override
+ public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == appId.id() && flow.groupId().id() == groupId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterable<FlowEntry> getFlowEntriesById(ApplicationId id) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == id.id())
+ .map(DefaultFlowEntry::new)
+ .collect(Collectors.toList());
+ }
+}
+
+
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockP4RuntimeController.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockP4RuntimeController.java
new file mode 100644
index 0000000..5fc42d5
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockP4RuntimeController.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+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.
+ */
+public class MockP4RuntimeController implements P4RuntimeController {
+
+ private final P4RuntimeClient mockP4rtClient;
+
+ /**
+ * Used to mock counter read requests.
+ *
+ * @param deviceId The ID of the device
+ * @param packets Packets counter value
+ * @param bytes Bytes counter value
+ * @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);
+ }
+
+ @Override
+ public P4RuntimeClient get(DeviceId deviceId) {
+ return mockP4rtClient;
+ }
+
+ @Override
+ public void addListener(P4RuntimeEventListener listener) {
+
+ }
+
+ @Override
+ public void removeListener(P4RuntimeEventListener listener) {
+
+ }
+
+ @Override
+ public boolean create(DeviceId deviceId, ManagedChannel channel) {
+ return false;
+ }
+
+ @Override
+ public void remove(DeviceId deviceId) {
+
+ }
+
+ @Override
+ public void addDeviceAgentListener(DeviceId deviceId, ProviderId providerId,
+ DeviceAgentListener listener) {
+
+ }
+
+ @Override
+ public void removeDeviceAgentListener(DeviceId deviceId,
+ ProviderId providerId) {
+
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPacketService.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPacketService.java
new file mode 100644
index 0000000..8dc0928
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPacketService.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import com.google.common.collect.Queues;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketProcessorEntry;
+import org.onosproject.net.packet.PacketRequest;
+import org.onosproject.net.packet.PacketService;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Queue;
+
+public class MockPacketService implements PacketService {
+
+ Queue<OutboundPacket> emittedPackets = Queues.newArrayDeque();
+
+ @Override
+ public void addProcessor(PacketProcessor processor, int priority) {
+
+ }
+
+ @Override
+ public void removeProcessor(PacketProcessor processor) {
+
+ }
+
+ @Override
+ public List<PacketProcessorEntry> getProcessors() {
+ return null;
+ }
+
+ @Override
+ public void requestPackets(TrafficSelector selector, PacketPriority priority, ApplicationId appId) {
+
+ }
+
+ @Override
+ public void requestPackets(TrafficSelector selector, PacketPriority priority,
+ ApplicationId appId, Optional<DeviceId> deviceId) {
+
+ }
+
+ @Override
+ public void cancelPackets(TrafficSelector selector, PacketPriority priority, ApplicationId appId) {
+
+ }
+
+ @Override
+ public void cancelPackets(TrafficSelector selector, PacketPriority priority,
+ ApplicationId appId, Optional<DeviceId> deviceId) {
+
+ }
+
+ @Override
+ public List<PacketRequest> getRequests() {
+ return null;
+ }
+
+ @Override
+ public void emit(OutboundPacket packet) {
+ emittedPackets.add(packet);
+ }
+}
+
+
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipeconfService.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipeconfService.java
new file mode 100644
index 0000000..20c7839
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipeconfService.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.model.PiTableModel;
+import org.onosproject.net.pi.service.PiPipeconfListener;
+import org.onosproject.net.pi.service.PiPipeconfService;
+
+import java.util.Collection;
+import java.util.Optional;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+public class MockPiPipeconfService implements PiPipeconfService {
+
+ private final PiPipeconf mockPiPipeconf;
+
+ public MockPiPipeconfService(Collection<PiTableModel> tables,
+ Collection<PiCounterModel> counters) {
+ mockPiPipeconf = createMock(PiPipeconf.class);
+ expect(mockPiPipeconf.pipelineModel())
+ .andReturn(new MockPiPipelineModel(tables, counters))
+ .anyTimes();
+ replay(mockPiPipeconf);
+ }
+
+ @Override
+ public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
+ return Optional.of(mockPiPipeconf);
+ }
+
+ @Override
+ public Optional<PiPipeconf> getPipeconf(DeviceId deviceId) {
+ return Optional.of(mockPiPipeconf);
+ }
+
+ @Override
+ public void register(PiPipeconf pipeconf) throws IllegalStateException {
+
+ }
+
+ @Override
+ public void unregister(PiPipeconfId pipeconfId) throws IllegalStateException {
+
+ }
+
+ @Override
+ public Iterable<PiPipeconf> getPipeconfs() {
+ return null;
+ }
+
+ @Override
+ public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
+
+ }
+
+ @Override
+ public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
+ return null;
+ }
+
+ @Override
+ public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public void addListener(PiPipeconfListener listener) {
+
+ }
+
+ @Override
+ public void removeListener(PiPipeconfListener listener) {
+
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java
new file mode 100644
index 0000000..db438b5
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import com.google.common.collect.Maps;
+import org.onosproject.net.pi.model.PiActionProfileId;
+import org.onosproject.net.pi.model.PiActionProfileModel;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.model.PiMeterModel;
+import org.onosproject.net.pi.model.PiPacketOperationModel;
+import org.onosproject.net.pi.model.PiPacketOperationType;
+import org.onosproject.net.pi.model.PiPipelineModel;
+import org.onosproject.net.pi.model.PiRegisterId;
+import org.onosproject.net.pi.model.PiRegisterModel;
+import org.onosproject.net.pi.model.PiTableId;
+import org.onosproject.net.pi.model.PiTableModel;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+
+public class MockPiPipelineModel implements PiPipelineModel {
+
+ private final Map<PiTableId, PiTableModel> tableMap = Maps.newHashMap();
+
+ private final List<PiCounterModel> counters;
+
+ public MockPiPipelineModel(Collection<PiTableModel> tables, Collection<PiCounterModel> counters) {
+ tables.forEach(tableModel -> tableMap.put(tableModel.id(), tableModel));
+ this.counters = List.copyOf(counters);
+ }
+
+ @Override
+ public Optional<PiTableModel> table(PiTableId tableId) {
+ return Optional.ofNullable(tableMap.getOrDefault(tableId, null));
+ }
+
+ @Override
+ public Collection<PiTableModel> tables() {
+ return tableMap.values();
+ }
+
+ @Override
+ public Optional<PiCounterModel> counter(PiCounterId counterId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Collection<PiCounterModel> counters() {
+ return counters;
+ }
+
+ @Override
+ public Optional<PiMeterModel> meter(PiMeterId meterId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Collection<PiMeterModel> meters() {
+ return null;
+ }
+
+ @Override
+ public Optional<PiRegisterModel> register(PiRegisterId registerId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Collection<PiRegisterModel> registers() {
+ return null;
+ }
+
+ @Override
+ public Optional<PiActionProfileModel> actionProfiles(PiActionProfileId actionProfileId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Collection<PiActionProfileModel> actionProfiles() {
+ return null;
+ }
+
+ @Override
+ public Optional<PiPacketOperationModel> packetOperationModel(PiPacketOperationType type) {
+ return Optional.empty();
+ }
+
+
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadRequest.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadRequest.java
new file mode 100644
index 0000000..32be8d9
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadRequest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.model.PiActionProfileId;
+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.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.concurrent.CompletableFuture;
+import java.util.stream.LongStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * 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<PiHandle> handles;
+ DeviceId deviceId;
+ long packets;
+ long bytes;
+ int counterSize;
+
+ public MockReadRequest(DeviceId deviceId, long packets, long bytes, int counterSize) {
+ this.handles = new ArrayList<>();
+ this.deviceId = deviceId;
+ this.packets = packets;
+ this.bytes = bytes;
+ this.counterSize = counterSize;
+ }
+
+ @Override
+ public CompletableFuture<P4RuntimeReadClient.ReadResponse> submit() {
+ return CompletableFuture.completedFuture(
+ new MockReadResponse(this.handles, this.packets, this.bytes));
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadResponse submitSync() {
+ return new MockReadResponse(this.handles, this.packets, this.bytes);
+ }
+
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest handle(PiHandle handle) {
+ this.handles.add(handle);
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest handles(Iterable<? extends PiHandle> handles) {
+ checkNotNull(handles);
+ handles.forEach(this::handle);
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest tableEntries(PiTableId tableId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest tableEntries(Iterable<PiTableId> tableIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest defaultTableEntry(PiTableId tableId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest defaultTableEntry(Iterable<PiTableId> tableIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest allTableEntries() {
+ return null;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest allDefaultTableEntries() {
+ return null;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest actionProfileGroups(PiActionProfileId actionProfileId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest actionProfileGroups(Iterable<PiActionProfileId> actionProfileIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest actionProfileMembers(PiActionProfileId actionProfileId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest actionProfileMembers(Iterable<PiActionProfileId> actionProfileIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest counterCells(PiCounterId counterId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest counterCells(Iterable<PiCounterId> 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);
+ });
+ });
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest directCounterCells(PiTableId tableId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest directCounterCells(Iterable<PiTableId> tableIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest meterCells(PiMeterId meterId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest meterCells(Iterable<PiMeterId> meterIds) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest directMeterCells(PiTableId tableId) {
+ return this;
+ }
+
+ @Override
+ public P4RuntimeReadClient.ReadRequest directMeterCells(Iterable<PiTableId> tableIds) {
+ return this;
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadResponse.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadResponse.java
new file mode 100644
index 0000000..2dbc11f
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockReadResponse.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.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.PiEntity;
+import org.onosproject.net.pi.runtime.PiEntityType;
+import org.onosproject.net.pi.runtime.PiHandle;
+import org.onosproject.p4runtime.api.P4RuntimeReadClient;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * 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 MockReadResponse implements P4RuntimeReadClient.ReadResponse {
+ List<PiEntity> entities;
+ long packets;
+ long bytes;
+
+ public MockReadResponse(Iterable<? extends PiHandle> handles, long packets, long bytes) {
+ this.entities = new ArrayList<>();
+ this.packets = packets;
+ this.bytes = bytes;
+ checkNotNull(handles);
+ handles.forEach(this::handle);
+ }
+
+ @Override
+ public boolean isSuccess() {
+ return true;
+ }
+
+ 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);
+ }
+ // Only handles counter cell so far
+
+ return this;
+ }
+
+ @Override
+ public Collection<PiEntity> all() {
+ return this.entities;
+ }
+
+ @Override
+ public <E extends PiEntity> Collection<E> all(Class<E> clazz) {
+ List<E> results = new ArrayList<>();
+ this.entities.forEach(ent -> {
+ if (ent.getClass().equals(clazz)) {
+ results.add(clazz.cast(ent));
+ }
+ });
+ return results;
+ }
+
+ @Override
+ public String explanation() {
+ return null;
+ }
+
+ @Override
+ public Throwable throwable() {
+ return null;
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockTableModel.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockTableModel.java
new file mode 100644
index 0000000..6584c18
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockTableModel.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onosproject.net.pi.model.PiActionId;
+import org.onosproject.net.pi.model.PiActionModel;
+import org.onosproject.net.pi.model.PiActionProfileModel;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiMatchFieldId;
+import org.onosproject.net.pi.model.PiMatchFieldModel;
+import org.onosproject.net.pi.model.PiMeterModel;
+import org.onosproject.net.pi.model.PiTableId;
+import org.onosproject.net.pi.model.PiTableModel;
+import org.onosproject.net.pi.model.PiTableType;
+
+import java.util.Collection;
+import java.util.Optional;
+
+public class MockTableModel implements PiTableModel {
+ PiTableId id;
+ int size;
+
+ public MockTableModel(PiTableId id, int size) {
+ this.id = id;
+ this.size = size;
+ }
+
+ @Override
+ public PiTableId id() {
+ return this.id;
+ }
+
+ @Override
+ public PiTableType tableType() {
+ return null;
+ }
+
+ @Override
+ public PiActionProfileModel actionProfile() {
+ return null;
+ }
+
+ @Override
+ public long maxSize() {
+ return size;
+ }
+
+ @Override
+ public Collection<PiCounterModel> counters() {
+ return null;
+ }
+
+ @Override
+ public Collection<PiMeterModel> meters() {
+ return null;
+ }
+
+ @Override
+ public boolean supportsAging() {
+ return false;
+ }
+
+ @Override
+ public Collection<PiMatchFieldModel> matchFields() {
+ return null;
+ }
+
+ @Override
+ public Collection<PiActionModel> actions() {
+ return null;
+ }
+
+ @Override
+ public Optional<PiActionModel> constDefaultAction() {
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean isConstantTable() {
+ return false;
+ }
+
+ @Override
+ public Optional<PiActionModel> action(PiActionId actionId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<PiMatchFieldModel> matchField(PiMatchFieldId matchFieldId) {
+ return Optional.empty();
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestDistributedFabricUpfStore.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestDistributedFabricUpfStore.java
new file mode 100644
index 0000000..8500b9a
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestDistributedFabricUpfStore.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.TestConsistentMap;
+import org.onosproject.store.service.TestDistributedSet;
+
+import java.util.Set;
+
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.DistributedFabricUpfStore.BUFFER_FAR_ID_SET_NAME;
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.DistributedFabricUpfStore.FAR_ID_MAP_NAME;
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.DistributedFabricUpfStore.FAR_ID_UE_MAP_NAME;
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.DistributedFabricUpfStore.SERIALIZER;
+
+
+public final class TestDistributedFabricUpfStore {
+
+ private TestDistributedFabricUpfStore() {
+ }
+
+ public static DistributedFabricUpfStore build() {
+ var store = new DistributedFabricUpfStore();
+ TestConsistentMap.Builder<UpfRuleIdentifier, Integer> farIdMapBuilder =
+ TestConsistentMap.builder();
+ farIdMapBuilder.withName(FAR_ID_MAP_NAME)
+ .withRelaxedReadConsistency()
+ .withSerializer(Serializer.using(SERIALIZER.build()));
+ store.farIdMap = farIdMapBuilder.build();
+
+ TestDistributedSet.Builder<UpfRuleIdentifier> bufferFarIdsBuilder =
+ TestDistributedSet.builder();
+ bufferFarIdsBuilder
+ .withName(BUFFER_FAR_ID_SET_NAME)
+ .withRelaxedReadConsistency()
+ .withSerializer(Serializer.using(SERIALIZER.build()));
+ store.bufferFarIds = bufferFarIdsBuilder.build().asDistributedSet();
+
+ TestConsistentMap.Builder<UpfRuleIdentifier, Set<Ip4Address>> farIdToUeAddrsBuilder =
+ TestConsistentMap.builder();
+ farIdToUeAddrsBuilder
+ .withName(FAR_ID_UE_MAP_NAME)
+ .withRelaxedReadConsistency()
+ .withSerializer(Serializer.using(SERIALIZER.build()));
+ store.farIdToUeAddrs = farIdToUeAddrsBuilder.build();
+
+ store.activate();
+
+ // Init with some translation state.
+ store.farIdMap.put(
+ new UpfRuleIdentifier(TestUpfConstants.SESSION_ID, TestUpfConstants.UPLINK_FAR_ID),
+ TestUpfConstants.UPLINK_PHYSICAL_FAR_ID);
+ store.farIdMap.put(
+ new UpfRuleIdentifier(TestUpfConstants.SESSION_ID, TestUpfConstants.DOWNLINK_FAR_ID),
+ TestUpfConstants.DOWNLINK_PHYSICAL_FAR_ID);
+
+ return store;
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfConstants.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfConstants.java
new file mode 100644
index 0000000..c24f382
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfConstants.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.upf.ForwardingActionRule;
+import org.onosproject.net.behaviour.upf.PacketDetectionRule;
+import org.onosproject.net.behaviour.upf.UpfInterface;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.criteria.PiCriterion;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionParam;
+
+import java.util.Arrays;
+
+import static org.onosproject.pipelines.fabric.FabricConstants.CTR_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.DROP;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_DOWNLINK_PDRS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_FARS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_INTERFACES;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_LOAD_IFACE;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_LOAD_NORMAL_FAR;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_LOAD_PDR;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_LOAD_PDR_QOS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_LOAD_TUNNEL_FAR;
+import static org.onosproject.pipelines.fabric.FabricConstants.FABRIC_INGRESS_SPGW_UPLINK_PDRS;
+import static org.onosproject.pipelines.fabric.FabricConstants.FAR_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_FAR_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_GTPU_IS_VALID;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_IPV4_DST_ADDR;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_TEID;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_TUNNEL_IPV4_DST;
+import static org.onosproject.pipelines.fabric.FabricConstants.HDR_UE_ADDR;
+import static org.onosproject.pipelines.fabric.FabricConstants.NEEDS_GTPU_DECAP;
+import static org.onosproject.pipelines.fabric.FabricConstants.NOTIFY_CP;
+import static org.onosproject.pipelines.fabric.FabricConstants.QID;
+import static org.onosproject.pipelines.fabric.FabricConstants.SRC_IFACE;
+import static org.onosproject.pipelines.fabric.FabricConstants.TEID;
+import static org.onosproject.pipelines.fabric.FabricConstants.TUNNEL_DST_ADDR;
+import static org.onosproject.pipelines.fabric.FabricConstants.TUNNEL_SRC_ADDR;
+import static org.onosproject.pipelines.fabric.FabricConstants.TUNNEL_SRC_PORT;
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.FabricUpfTranslator.INTERFACE_ACCESS;
+import static org.onosproject.pipelines.fabric.impl.behaviour.upf.FabricUpfTranslator.INTERFACE_CORE;
+
+
+public final class TestUpfConstants {
+ public static final DeviceId DEVICE_ID = DeviceId.deviceId("CoolSwitch91");
+ public static final ApplicationId APP_ID = new DefaultApplicationId(5000, "up4");
+ public static final int DEFAULT_PRIORITY = 10;
+ // SESSION_ID_BITWIDTH / 8 = 12
+ public static final ImmutableByteSequence SESSION_ID = ImmutableByteSequence.ofOnes(12);
+ public static final int UPLINK_COUNTER_CELL_ID = 1;
+ public static final int DOWNLINK_COUNTER_CELL_ID = 2;
+ public static final int PDR_ID = 0; // TODO: PDR ID currently not stored on writes, so all reads are 0
+ public static final int UPLINK_FAR_ID = 1;
+ public static final int UPLINK_PHYSICAL_FAR_ID = 4;
+ public static final int DOWNLINK_FAR_ID = 2;
+ public static final int DOWNLINK_PHYSICAL_FAR_ID = 5;
+
+ public static final int UPLINK_PRIORITY = 9;
+ public static final int DOWNLINK_PRIORITY = 1;
+ public static final int UPLINK_QID = 1;
+ public static final int DOWNLINK_QID = 5;
+ public static final int DEFAULT_SCHEDULING_PRIORITY = 0;
+
+ public static final ImmutableByteSequence TEID_VALUE = ImmutableByteSequence.copyFrom(0xff);
+ public static final Ip4Address UE_ADDR = Ip4Address.valueOf("17.0.0.1");
+ public static final Ip4Address S1U_ADDR = Ip4Address.valueOf("192.168.0.1");
+ public static final Ip4Address ENB_ADDR = Ip4Address.valueOf("192.168.0.2");
+ public static final Ip4Prefix UE_POOL = Ip4Prefix.valueOf("17.0.0.0/16");
+ // TODO: tunnel source port currently not stored on writes, so all reads are 0
+ public static final short TUNNEL_SPORT = 2160;
+ public static final int PHYSICAL_COUNTER_SIZE = 512;
+ public static final int PHYSICAL_MAX_PDRS = 512;
+ public static final int PHYSICAL_MAX_FARS = 512;
+
+ public static final long COUNTER_BYTES = 12;
+ public static final long COUNTER_PKTS = 15;
+
+ public static final PacketDetectionRule UPLINK_PDR = PacketDetectionRule.builder()
+ .withTunnelDst(S1U_ADDR)
+ .withTeid(TEID_VALUE)
+ .withLocalFarId(UPLINK_FAR_ID)
+ .withSessionId(SESSION_ID)
+ .withCounterId(UPLINK_COUNTER_CELL_ID)
+ .withSchedulingPriority(DEFAULT_SCHEDULING_PRIORITY)
+ .build();
+
+ public static final PacketDetectionRule DOWNLINK_PDR = PacketDetectionRule.builder()
+ .withUeAddr(UE_ADDR)
+ .withLocalFarId(DOWNLINK_FAR_ID)
+ .withSessionId(SESSION_ID)
+ .withCounterId(DOWNLINK_COUNTER_CELL_ID)
+ .withSchedulingPriority(DEFAULT_SCHEDULING_PRIORITY)
+ .build();
+
+ public static final PacketDetectionRule UPLINK_PRIORITY_PDR = PacketDetectionRule.builder()
+ .withTunnelDst(S1U_ADDR)
+ .withTeid(TEID_VALUE)
+ .withLocalFarId(UPLINK_FAR_ID)
+ .withSessionId(SESSION_ID)
+ .withCounterId(UPLINK_COUNTER_CELL_ID)
+ .withSchedulingPriority(UPLINK_PRIORITY)
+ .build();
+
+ public static final PacketDetectionRule DOWNLINK_PRIORITY_PDR = PacketDetectionRule.builder()
+ .withUeAddr(UE_ADDR)
+ .withLocalFarId(DOWNLINK_FAR_ID)
+ .withSessionId(SESSION_ID)
+ .withCounterId(DOWNLINK_COUNTER_CELL_ID)
+ .withSchedulingPriority(DOWNLINK_PRIORITY)
+ .build();
+
+ public static final ForwardingActionRule UPLINK_FAR = ForwardingActionRule.builder()
+ .setFarId(UPLINK_FAR_ID)
+ .withSessionId(SESSION_ID).build();
+
+ public static final ForwardingActionRule DOWNLINK_FAR = ForwardingActionRule.builder()
+ .setFarId(DOWNLINK_FAR_ID)
+ .withSessionId(SESSION_ID)
+ .setTunnel(S1U_ADDR, ENB_ADDR, TEID_VALUE, TUNNEL_SPORT)
+ .build();
+
+ public static final UpfInterface UPLINK_INTERFACE = UpfInterface.createS1uFrom(S1U_ADDR);
+
+ public static final UpfInterface DOWNLINK_INTERFACE = UpfInterface.createUePoolFrom(UE_POOL);
+
+ public static final FlowRule FABRIC_UPLINK_PRIORITY_PDR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_UPLINK_PDRS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_TEID, TEID_VALUE.asArray())
+ .matchExact(HDR_TUNNEL_IPV4_DST, S1U_ADDR.toInt())
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_PDR_QOS)
+ .withParameters(Arrays.asList(
+ new PiActionParam(CTR_ID, UPLINK_COUNTER_CELL_ID),
+ new PiActionParam(FAR_ID, UPLINK_PHYSICAL_FAR_ID),
+ new PiActionParam(NEEDS_GTPU_DECAP, 1),
+ new PiActionParam(QID, UPLINK_QID)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_DOWNLINK_PRIORITY_PDR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_DOWNLINK_PDRS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_UE_ADDR, UE_ADDR.toInt())
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_PDR_QOS)
+ .withParameters(Arrays.asList(
+ new PiActionParam(CTR_ID, DOWNLINK_COUNTER_CELL_ID),
+ new PiActionParam(FAR_ID, DOWNLINK_PHYSICAL_FAR_ID),
+ new PiActionParam(NEEDS_GTPU_DECAP, 0),
+ new PiActionParam(QID, DOWNLINK_QID)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_UPLINK_PDR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_UPLINK_PDRS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_TEID, TEID_VALUE.asArray())
+ .matchExact(HDR_TUNNEL_IPV4_DST, S1U_ADDR.toInt())
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_PDR)
+ .withParameters(Arrays.asList(
+ new PiActionParam(CTR_ID, UPLINK_COUNTER_CELL_ID),
+ new PiActionParam(FAR_ID, UPLINK_PHYSICAL_FAR_ID),
+ new PiActionParam(NEEDS_GTPU_DECAP, 1)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_DOWNLINK_PDR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_DOWNLINK_PDRS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_UE_ADDR, UE_ADDR.toInt())
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_PDR)
+ .withParameters(Arrays.asList(
+ new PiActionParam(CTR_ID, DOWNLINK_COUNTER_CELL_ID),
+ new PiActionParam(FAR_ID, DOWNLINK_PHYSICAL_FAR_ID),
+ new PiActionParam(NEEDS_GTPU_DECAP, 0)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_UPLINK_FAR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_FARS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_FAR_ID, UPLINK_PHYSICAL_FAR_ID)
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_NORMAL_FAR)
+ .withParameters(Arrays.asList(
+ new PiActionParam(DROP, 0),
+ new PiActionParam(NOTIFY_CP, 0)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_DOWNLINK_FAR = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_FARS)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchExact(HDR_FAR_ID, DOWNLINK_PHYSICAL_FAR_ID)
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_TUNNEL_FAR)
+ .withParameters(Arrays.asList(
+ new PiActionParam(DROP, 0),
+ new PiActionParam(NOTIFY_CP, 0),
+ new PiActionParam(TEID, TEID_VALUE),
+ new PiActionParam(TUNNEL_SRC_ADDR, S1U_ADDR.toInt()),
+ new PiActionParam(TUNNEL_DST_ADDR, ENB_ADDR.toInt()),
+ new PiActionParam(TUNNEL_SRC_PORT, TUNNEL_SPORT)
+ ))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_UPLINK_INTERFACE = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_INTERFACES)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchLpm(HDR_IPV4_DST_ADDR,
+ S1U_ADDR.toInt(),
+ 32)
+ .matchExact(HDR_GTPU_IS_VALID, 1)
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(
+ PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_IFACE)
+ .withParameter(new PiActionParam(SRC_IFACE, INTERFACE_ACCESS))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ public static final FlowRule FABRIC_DOWNLINK_INTERFACE = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent()
+ .forTable(FABRIC_INGRESS_SPGW_INTERFACES)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(PiCriterion.builder()
+ .matchLpm(HDR_IPV4_DST_ADDR,
+ UE_POOL.address().toInt(),
+ UE_POOL.prefixLength())
+ .matchExact(HDR_GTPU_IS_VALID, 0)
+ .build()).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FABRIC_INGRESS_SPGW_LOAD_IFACE)
+ .withParameter(new PiActionParam(SRC_IFACE, INTERFACE_CORE))
+ .build()).build())
+ .withPriority(DEFAULT_PRIORITY)
+ .build();
+
+ /**
+ * Hidden constructor for utility class.
+ */
+ private TestUpfConstants() {
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfUtils.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfUtils.java
new file mode 100644
index 0000000..6280f8e
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/TestUpfUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class TestUpfUtils {
+
+ private static final String BASIC_CONFIG_KEY = "basic";
+
+ private TestUpfUtils() {
+ // hide constructor
+ }
+
+ public static BasicDeviceConfig getBasicConfig(DeviceId deviceId, String fileName)
+ throws IOException {
+ BasicDeviceConfig basicCfg = new BasicDeviceConfig();
+ InputStream jsonStream = TestUpfUtils.class.getResourceAsStream(fileName);
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode jsonNode = mapper.readTree(jsonStream);
+ basicCfg.init(deviceId, BASIC_CONFIG_KEY, jsonNode, mapper, config -> {
+ });
+ return basicCfg;
+ }
+}
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/package-info.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/package-info.java
new file mode 100644
index 0000000..fe4c590
--- /dev/null
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Unit tests for UPF programmable behaviour.
+ */
+package org.onosproject.pipelines.fabric.impl.behaviour.upf;