ONOS-6613 Non-disruptive intent reallocation
Change-Id: I5d051c20402a226ad540b8bc08695b602ff75273
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/AbstractIntentInstallerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/AbstractIntentInstallerTest.java
index b4e51aa..a439103 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/AbstractIntentInstallerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/AbstractIntentInstallerTest.java
@@ -16,24 +16,31 @@
package org.onosproject.net.intent.impl.installer;
+import com.google.common.collect.ImmutableList;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Link;
import org.onosproject.net.ResourceGroup;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.IntentInstallCoordinator;
import org.onosproject.net.intent.IntentOperationContext;
import org.onosproject.net.intent.Key;
-import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.ObjectiveTrackerService;
+import org.onosproject.net.intent.PointToPointIntent;
+
+import java.util.List;
import static org.easymock.EasyMock.createMock;
+import static org.onosproject.net.NetTestTools.link;
+import static org.onosproject.net.intent.constraint.NonDisruptiveConstraint.nonDisruptive;
/**
* Abstract class to hold the common variables and pieces of code for Intent
@@ -41,9 +48,26 @@
*/
public class AbstractIntentInstallerTest extends AbstractIntentTest {
protected static final ApplicationId APP_ID = TestApplicationId.create("IntentInstallerTest");
+
protected static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("s1/1");
protected static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("s1/2");
protected static final ConnectPoint CP3 = ConnectPoint.deviceConnectPoint("s1/3");
+
+ protected static final ConnectPoint CP2_1 = ConnectPoint.deviceConnectPoint("s2/1");
+ protected static final ConnectPoint CP2_2 = ConnectPoint.deviceConnectPoint("s2/2");
+
+ protected static final ConnectPoint CP3_1 = ConnectPoint.deviceConnectPoint("s3/1");
+ protected static final ConnectPoint CP3_2 = ConnectPoint.deviceConnectPoint("s3/2");
+
+ protected static final ConnectPoint CP4_1 = ConnectPoint.deviceConnectPoint("s4/1");
+ protected static final ConnectPoint CP4_2 = ConnectPoint.deviceConnectPoint("s4/2");
+ protected static final ConnectPoint CP4_3 = ConnectPoint.deviceConnectPoint("s4/3");
+
+ protected static final Link S1_S2 = link(CP2, CP2_1);
+ protected static final Link S2_S4 = link(CP2_2, CP4_2);
+ protected static final Link S1_S3 = link(CP3, CP3_1);
+ protected static final Link S3_S4 = link(CP3_2, CP4_3);
+
protected static final Key KEY1 = Key.of("test intent 1", APP_ID);
protected static final ResourceGroup RG1 = ResourceGroup.of("test resource group 1");
protected static final int DEFAULT_PRIORITY = 30000;
@@ -84,6 +108,33 @@
}
/**
+ * Creates point to point Intent for testing non-disruptive reallocation.
+ *
+ * @return the point to point Intent
+ */
+ public PointToPointIntent createP2PIntentNonDisruptive() {
+ PointToPointIntent intent;
+ TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ FilteredConnectPoint ingress = new FilteredConnectPoint(CP1);
+ FilteredConnectPoint egress = new FilteredConnectPoint(CP4_1);
+
+ List<Constraint> constraints = ImmutableList.of(nonDisruptive());
+
+ intent = PointToPointIntent.builder()
+ .selector(selector)
+ .treatment(treatment)
+ .filteredIngressPoint(ingress)
+ .filteredEgressPoint(egress)
+ .constraints(constraints)
+ .appId(APP_ID)
+ .build();
+
+ return intent;
+ }
+
+ /**
* The Intent install coordinator for test.
* Records success and fail context.
*/
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
index f979f27..fdef627 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
@@ -18,11 +18,14 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.VlanId;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -40,13 +43,17 @@
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.PathIntent;
import org.onosproject.store.service.WallClockTimestamp;
+import org.onosproject.store.trivial.SimpleIntentStore;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-import static org.junit.Assert.*;
+import static org.easymock.EasyMock.mock;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
/**
* Tests for flow rule Intent installer.
@@ -54,17 +61,21 @@
public class FlowRuleIntentInstallerTest extends AbstractIntentInstallerTest {
private TestFlowRuleService flowRuleService;
+ private TestFlowRuleServiceNonDisruptive flowRuleServiceNonDisruptive;
private FlowRuleIntentInstaller installer;
@Before
public void setup() {
super.setup();
flowRuleService = new TestFlowRuleService();
+ flowRuleServiceNonDisruptive = new TestFlowRuleServiceNonDisruptive();
installer = new FlowRuleIntentInstaller();
installer.flowRuleService = flowRuleService;
+ installer.store = new SimpleIntentStore();
installer.intentExtensionService = intentExtensionService;
installer.intentInstallCoordinator = intentInstallCoordinator;
installer.trackerService = trackerService;
+ installer.configService = mock(ComponentConfigService.class);
installer.activate();
}
@@ -328,6 +339,109 @@
}
/**
+ * Testing the non-disruptive reallocation.
+ */
+ @Test
+ public void testUninstallAndInstallNonDisruptive() throws InterruptedException {
+
+ installer.flowRuleService = flowRuleServiceNonDisruptive;
+
+ List<Intent> intentsToInstall = createAnotherFlowRuleIntentsNonDisruptive();
+ List<Intent> intentsToUninstall = createFlowRuleIntentsNonDisruptive();
+
+ IntentData toInstall = new IntentData(createP2PIntentNonDisruptive(),
+ IntentState.INSTALLING,
+ new WallClockTimestamp());
+ toInstall = new IntentData(toInstall, intentsToInstall);
+ IntentData toUninstall = new IntentData(createP2PIntentNonDisruptive(),
+ IntentState.INSTALLED,
+ new WallClockTimestamp());
+ toUninstall = new IntentData(toUninstall, intentsToUninstall);
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ //A single FlowRule is evaluated for every non-disruptive stage
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(CP1.port())
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(CP3.port())
+ .build();
+
+ FlowRule firstStageInstalledRule = DefaultFlowRule.builder()
+ .forDevice(CP1.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY - 1)
+ .makePermanent()
+ .build();
+
+ assertTrue(flowRuleServiceNonDisruptive.flowRulesAdd.contains(firstStageInstalledRule));
+
+ selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(CP4_2.port())
+ .build();
+ treatment = DefaultTrafficTreatment.builder()
+ .setOutput(CP4_1.port())
+ .build();
+
+ FlowRule secondStageUninstalledRule = DefaultFlowRule.builder()
+ .forDevice(CP4_1.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY)
+ .makePermanent()
+ .build();
+
+ assertTrue(flowRuleServiceNonDisruptive.flowRulesRemove.contains(secondStageUninstalledRule));
+
+ selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(CP4_3.port())
+ .build();
+ treatment = DefaultTrafficTreatment.builder()
+ .setOutput(CP4_1.port())
+ .build();
+
+ FlowRule thirdStageInstalledRule = DefaultFlowRule.builder()
+ .forDevice(CP4_1.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY)
+ .makePermanent()
+ .build();
+
+ assertTrue(flowRuleServiceNonDisruptive.flowRulesAdd.contains(thirdStageInstalledRule));
+
+ selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(CP2_1.port())
+ .build();
+ treatment = DefaultTrafficTreatment.builder()
+ .setOutput(CP2_2.port())
+ .build();
+
+ FlowRule lastStageUninstalledRule = DefaultFlowRule.builder()
+ .forDevice(CP2_1.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY)
+ .makePermanent()
+ .build();
+
+ assertTrue(flowRuleServiceNonDisruptive.flowRulesRemove.contains(lastStageUninstalledRule));
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+ }
+
+ /**
* Generates FlowRuleIntents for test.
*
* @return the FlowRuleIntents for test
@@ -442,6 +556,107 @@
}
/**
+ * Generates FlowRuleIntents for testing non-disruptive reallocation.
+ *
+ * @return the FlowRuleIntents for test
+ */
+ public List<Intent> createFlowRuleIntentsNonDisruptive() {
+
+ Map<ConnectPoint, ConnectPoint> portsAssociation = Maps.newHashMap();
+ portsAssociation.put(CP1, CP2);
+ portsAssociation.put(CP2_1, CP2_2);
+ portsAssociation.put(CP4_2, CP4_1);
+
+ List<FlowRule> flowRules = Lists.newArrayList();
+
+ for (ConnectPoint srcPoint : portsAssociation.keySet()) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(srcPoint.port())
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(portsAssociation.get(srcPoint).port())
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .forDevice(srcPoint.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY)
+ .makePermanent()
+ .build();
+ flowRules.add(flowRule);
+ }
+
+
+
+ List<NetworkResource> resources = ImmutableList.of(S1_S2, S2_S4);
+
+ FlowRuleIntent intent = new FlowRuleIntent(APP_ID,
+ KEY1,
+ flowRules,
+ resources,
+ PathIntent.ProtectionType.PRIMARY,
+ RG1);
+
+ List<Intent> flowRuleIntents = Lists.newArrayList();
+ flowRuleIntents.add(intent);
+
+ return flowRuleIntents;
+ }
+
+ /**
+ * Generates another FlowRuleIntent, going through a different path, for testing non-disruptive reallocation.
+ *
+ * @return the FlowRuleIntents for test
+ */
+ public List<Intent> createAnotherFlowRuleIntentsNonDisruptive() {
+ Map<ConnectPoint, ConnectPoint> portsAssociation = Maps.newHashMap();
+ portsAssociation.put(CP1, CP3);
+ portsAssociation.put(CP3_1, CP3_2);
+ portsAssociation.put(CP4_3, CP4_1);
+
+ List<FlowRule> flowRules = Lists.newArrayList();
+
+ for (ConnectPoint srcPoint : portsAssociation.keySet()) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPhyPort(srcPoint.port())
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(portsAssociation.get(srcPoint).port())
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .forDevice(srcPoint.deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .fromApp(APP_ID)
+ .withPriority(DEFAULT_PRIORITY)
+ .makePermanent()
+ .build();
+ flowRules.add(flowRule);
+ }
+
+
+
+ List<NetworkResource> resources = ImmutableList.of(S1_S3, S3_S4);
+
+ FlowRuleIntent intent = new FlowRuleIntent(APP_ID,
+ KEY1,
+ flowRules,
+ resources,
+ PathIntent.ProtectionType.PRIMARY,
+ RG1);
+
+ List<Intent> flowRuleIntents = Lists.newArrayList();
+ flowRuleIntents.add(intent);
+
+ return flowRuleIntents;
+ }
+
+ /**
* The FlowRuleService for test; always success for any flow rule operations.
*/
class TestFlowRuleService extends FlowRuleServiceAdapter {
@@ -489,4 +704,37 @@
}
}
+ /**
+ * The FlowRuleService for testing non-disruptive reallocation.
+ * It keeps all the FlowRules installed/uninstalled.
+ */
+ class TestFlowRuleServiceNonDisruptive extends FlowRuleServiceAdapter {
+
+ Set<FlowRule> flowRulesAdd = Sets.newHashSet();
+ Set<FlowRule> flowRulesRemove = Sets.newHashSet();
+
+ public void record(FlowRuleOperations ops) {
+ ops.stages().forEach(stage -> {
+ stage.forEach(op -> {
+ switch (op.type()) {
+ case ADD:
+ flowRulesAdd.add(op.rule());
+ break;
+ case REMOVE:
+ flowRulesRemove.add(op.rule());
+ break;
+ default:
+ break;
+ }
+ });
+ });
+ }
+
+ @Override
+ public void apply(FlowRuleOperations ops) {
+ record(ops);
+ ops.callback().onSuccess(ops);
+ }
+ }
+
}