Fix to reinstall flow rules when they are missing in FlowRuleService.
Change-Id: I1e7e0d62e27012cd090f3a72eb92eadc85afafdf
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
index 012f3b6..e2e743a 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
@@ -134,6 +134,11 @@
}
@Override
+ public FlowEntry getFlowEntry(FlowRule flowRule) {
+ return store.getFlowEntry(networkId(), flowRule);
+ }
+
+ @Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
return store.getFlowEntries(networkId(), deviceId);
}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index 2b29504..9cada03 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -64,6 +64,14 @@
}
/**
+ * Returns the stored flow.
+ *
+ * @param rule the rule to look for
+ * @return a flow rule
+ */
+ FlowEntry getFlowEntry(FlowRule rule);
+
+ /**
* Returns the collection of flow entries applied on the specified device.
* This will include flow rules which may not yet have been applied to
* the device.
diff --git a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
index 4f53b96..1ccbbc8 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
@@ -29,6 +29,11 @@
}
@Override
+ public FlowEntry getFlowEntry(FlowRule rule) {
+ return null;
+ }
+
+ @Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
return null;
}
diff --git a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index ac97636..9dc92d1 100644
--- a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -295,6 +295,13 @@
}
@Override
+ public FlowEntry getFlowEntry(FlowRule rule) {
+ checkPermission(FLOWRULE_READ);
+ checkNotNull(rule, FLOW_RULE_NULL);
+ return store.getFlowEntry(rule);
+ }
+
+ @Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
checkPermission(FLOWRULE_READ);
checkNotNull(deviceId, DEVICE_ID_NULL);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java b/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
index b2cdf5a..71cf28c 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
@@ -174,6 +174,7 @@
flowRulesToUninstall = uninstallIntents.stream()
.map(FlowRuleIntent::flowRules)
.flatMap(Collection::stream)
+ .filter(flowRule -> flowRuleService.getFlowEntry(flowRule) != null)
.collect(Collectors.toList());
} else {
// No flow rules to be uninstalled.
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 3801388..300b023 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -207,7 +207,7 @@
FlowRule rule = flowRule(hval, hval);
service.applyFlowRules(rule);
- assertNotNull("rule should be found", service.getFlowEntries(DID));
+ assertNotNull("rule should be found", service.getFlowEntry(rule));
return rule;
}
@@ -234,6 +234,24 @@
}
@Test
+ public void getFlowEntry() {
+ assertTrue("store should be empty",
+ Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
+ FlowRule f1 = addFlowRule(1);
+ FlowRule f2 = addFlowRule(2);
+
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+ assertEquals("2 rules should exist", 2, flowCount());
+
+ FlowEntry actual1 = service.getFlowEntry(f1);
+ FlowEntry actual2 = service.getFlowEntry(f2);
+
+ assertEquals(fe1, actual1);
+ assertEquals(fe2, actual2);
+ }
+
+ @Test
public void getFlowEntries() {
assertTrue("store should be empty",
Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
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 712f8bf..5c00a83 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
@@ -26,10 +26,13 @@
import org.onlab.packet.VlanId;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.NetworkResource;
+import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleOperation;
import org.onosproject.net.flow.FlowRuleOperations;
@@ -141,6 +144,8 @@
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+ flowRuleService.load(operationContext.intentsToUninstall());
+
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -156,6 +161,36 @@
}
/**
+ * Uninstalls Intents only, no Intents to be install. However, the flow rules do not exist
+ * in the FlowRuleService.
+ */
+ @Test
+ public void testUninstallOnlyMissing() {
+ List<Intent> intentsToInstall = Lists.newArrayList();
+ List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+ IntentData toInstall = null;
+ IntentData toUninstall = new IntentData(createP2PIntent(),
+ IntentState.WITHDRAWING,
+ new WallClockTimestamp());
+ toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+
+ assertEquals(0, flowRuleService.flowRulesRemove.size());
+ assertEquals(0, flowRuleService.flowRulesAdd.size());
+ assertEquals(0, flowRuleService.flowRulesModify.size());
+ }
+
+ /**
* Do both install and uninstall Intents with different flow rules.
*/
@Test
@@ -176,6 +211,8 @@
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+ flowRuleService.load(operationContext.intentsToUninstall());
+
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -199,6 +236,46 @@
}
/**
+ * Do both install and uninstall Intents with different flow rules. However, the flow rules do not exist
+ * in the FlowRuleService.
+ */
+ @Test
+ public void testUninstallAndInstallMissing() {
+ List<Intent> intentsToInstall = createAnotherFlowRuleIntents();
+ List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+ IntentData toInstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLING,
+ new WallClockTimestamp());
+ toInstall = IntentData.compiled(toInstall, intentsToInstall);
+ IntentData toUninstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLED,
+ new WallClockTimestamp());
+ toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+
+ Set<FlowRule> expectedFlowRules = Sets.newHashSet();
+
+ assertEquals(expectedFlowRules, flowRuleService.flowRulesRemove);
+
+ expectedFlowRules = intentsToInstall.stream()
+ .map(intent -> (FlowRuleIntent) intent)
+ .map(FlowRuleIntent::flowRules)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toSet());
+
+ assertEquals(expectedFlowRules, flowRuleService.flowRulesAdd);
+ }
+
+ /**
* Do both install and uninstall Intents with same flow rules.
*/
@Test
@@ -219,6 +296,8 @@
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+ flowRuleService.load(operationContext.intentsToUninstall());
+
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -230,6 +309,38 @@
}
/**
+ * Do both install and uninstall Intents with same flow rules. However, the flow rules do not exist
+ * in the FlowRuleService.
+ */
+ @Test
+ public void testUninstallAndInstallUnchangedMissing() {
+ List<Intent> intentsToInstall = createFlowRuleIntents();
+ List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+ IntentData toInstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLING,
+ new WallClockTimestamp());
+ toInstall = IntentData.compiled(toInstall, intentsToInstall);
+ IntentData toUninstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLED,
+ new WallClockTimestamp());
+ toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+
+ assertEquals(0, flowRuleService.flowRulesRemove.size());
+ assertEquals(1, flowRuleService.flowRulesAdd.size());
+ assertEquals(0, flowRuleService.flowRulesModify.size());
+ }
+
+ /**
* Do both install and uninstall Intents with same flow rule Intent.
*/
@Test
@@ -250,6 +361,8 @@
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+ flowRuleService.load(operationContext.intentsToUninstall());
+
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -261,6 +374,38 @@
}
/**
+ * Do both install and uninstall Intents with same flow rule Intent. However, the flow rules do not exist
+ * in the FlowRuleService.
+ */
+ @Test
+ public void testUninstallAndInstallSameMissing() {
+ List<Intent> intentsToInstall = createFlowRuleIntents();
+ List<Intent> intentsToUninstall = intentsToInstall;
+
+ IntentData toInstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLING,
+ new WallClockTimestamp());
+ toInstall = IntentData.compiled(toInstall, intentsToInstall);
+ IntentData toUninstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLED,
+ new WallClockTimestamp());
+ toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+
+ assertEquals(0, flowRuleService.flowRulesRemove.size());
+ assertEquals(1, flowRuleService.flowRulesAdd.size());
+ assertEquals(0, flowRuleService.flowRulesModify.size());
+ }
+
+ /**
* Nothing to uninstall or install.
*/
@Test
@@ -327,6 +472,8 @@
IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+ flowRuleService.load(operationContext.intentsToUninstall());
+
installer.apply(operationContext);
IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -342,6 +489,42 @@
}
/**
+ * Test intents with same match rules, should do modify instead of add. However, the flow rules do not exist
+ * in the FlowRuleService.
+ */
+ @Test
+ public void testRuleModifyMissing() {
+ List<Intent> intentsToInstall = createFlowRuleIntents();
+ List<Intent> intentsToUninstall = createFlowRuleIntentsWithSameMatch();
+
+ IntentData toInstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLING,
+ new WallClockTimestamp());
+ toInstall = IntentData.compiled(toInstall, intentsToInstall);
+ IntentData toUninstall = new IntentData(createP2PIntent(),
+ IntentState.INSTALLED,
+ new WallClockTimestamp());
+ toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+ IntentOperationContext<FlowRuleIntent> operationContext;
+ IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+ operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+ installer.apply(operationContext);
+
+ IntentOperationContext successContext = intentInstallCoordinator.successContext;
+ assertEquals(successContext, operationContext);
+
+ assertEquals(0, flowRuleService.flowRulesRemove.size());
+ assertEquals(1, flowRuleService.flowRulesAdd.size());
+ assertEquals(0, flowRuleService.flowRulesModify.size());
+
+ FlowRuleIntent installedIntent = (FlowRuleIntent) intentsToInstall.get(0);
+ assertEquals(flowRuleService.flowRulesAdd.size(), installedIntent.flowRules().size());
+ assertTrue(flowRuleService.flowRulesAdd.containsAll(installedIntent.flowRules()));
+ }
+
+ /**
* Testing the non-disruptive reallocation.
*/
@Test
@@ -690,15 +873,43 @@
return flowRuleIntents;
}
+
+
/**
* The FlowRuleService for test; always success for any flow rule operations.
*/
class TestFlowRuleService extends FlowRuleServiceAdapter {
+ Set<FlowEntry> flowEntries = Sets.newHashSet();
Set<FlowRule> flowRulesAdd = Sets.newHashSet();
Set<FlowRule> flowRulesModify = Sets.newHashSet();
Set<FlowRule> flowRulesRemove = Sets.newHashSet();
+ @Override
+ public FlowEntry getFlowEntry(FlowRule flowRule) {
+ for (FlowEntry entry : flowEntries) {
+ if (entry.id().equals(flowRule.id()) && entry.deviceId().equals(flowRule.deviceId())) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+ return flowEntries.stream()
+ .filter(flow -> flow.deviceId().equals(deviceId))
+ .collect(Collectors.toList());
+ }
+
+ public void load(List<FlowRuleIntent> intents) {
+ for (FlowRuleIntent flowRuleIntent : intents) {
+ for (FlowRule flowRule : flowRuleIntent.flowRules()) {
+ flowEntries.add(new DefaultFlowEntry(flowRule, FlowEntry.FlowEntryState.ADDED));
+ }
+ }
+ }
+
public void record(FlowRuleOperations ops) {
flowRulesAdd.clear();
flowRulesRemove.clear();
@@ -706,12 +917,15 @@
stage.forEach(op -> {
switch (op.type()) {
case ADD:
+ flowEntries.add(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
flowRulesAdd.add(op.rule());
break;
case REMOVE:
+ flowEntries.remove(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
flowRulesRemove.add(op.rule());
break;
case MODIFY:
+ flowEntries.add(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
flowRulesModify.add(op.rule());
default:
break;