blob: f29ceecaa1c4ba3db0a4c72c3d9c9809039faa48 [file] [log] [blame]
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.net.intent.impl.installer;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.IntentInstallCoordinator;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.IntentOperationContext;
import org.onosproject.net.intent.IntentInstaller;
import org.onosproject.net.intent.impl.IntentManager;
import org.onosproject.net.intent.impl.ObjectiveTrackerService;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
import static org.onosproject.net.intent.IntentState.INSTALLED;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Installer for FlowRuleIntent.
*/
@Component(immediate = true)
public class FlowRuleIntentInstaller implements IntentInstaller<FlowRuleIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentExtensionService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ObjectiveTrackerService trackerService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentInstallCoordinator intentInstallCoordinator;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Activate
public void activate() {
intentExtensionService.registerInstaller(FlowRuleIntent.class, this);
}
@Deactivate
public void deactivated() {
intentExtensionService.unregisterInstaller(FlowRuleIntent.class);
}
protected final Logger log = getLogger(IntentManager.class);
@Override
public void apply(IntentOperationContext<FlowRuleIntent> context) {
Optional<IntentData> toUninstall = context.toUninstall();
Optional<IntentData> toInstall = context.toInstall();
List<FlowRuleIntent> uninstallIntents = context.intentsToUninstall();
List<FlowRuleIntent> installIntents = context.intentsToInstall();
if (!toInstall.isPresent() && !toUninstall.isPresent()) {
intentInstallCoordinator.intentInstallSuccess(context);
return;
} else if (!toInstall.isPresent()) {
// Uninstall only
trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
} else if (!toUninstall.isPresent()) {
// Install only
trackIntentResources(toInstall.get(), installIntents, ADD);
} else {
IntentData uninstall = toUninstall.get();
IntentData install = toInstall.get();
// Filter out same intents and intents with same flow rules
Iterator<FlowRuleIntent> iterator = installIntents.iterator();
while (iterator.hasNext()) {
FlowRuleIntent installIntent = iterator.next();
uninstallIntents.stream().filter(uIntent -> {
if (uIntent.equals(installIntent)) {
return true;
} else {
return !flowRuleIntentChanged(uIntent, installIntent);
}
}).findFirst().ifPresent(common -> {
uninstallIntents.remove(common);
if (INSTALLED.equals(uninstall.state())) {
// only remove the install intent if the existing
// intent (i.e. the uninstall one) is already
// installed or installing
iterator.remove();
}
});
}
trackIntentResources(uninstall, uninstallIntents, REMOVE);
trackIntentResources(install, installIntents, ADD);
}
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
builder.newStage();
toUninstall.ifPresent(intentData -> {
uninstallIntents.stream().map(FlowRuleIntent::flowRules)
.flatMap(Collection::stream).forEach(builder::remove);
});
toInstall.ifPresent(intentData -> {
installIntents.stream().map(FlowRuleIntent::flowRules)
.flatMap(Collection::stream).forEach(builder::add);
});
FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
intentInstallCoordinator.intentInstallSuccess(context);
}
@Override
public void onError(FlowRuleOperations ops) {
intentInstallCoordinator.intentInstallFailed(context);
}
};
FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
log.debug("applying intent {} -> {} with {} rules: {}",
toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
toInstall.map(x -> x.key().toString()).orElse("<empty>"),
operations.stages().stream().mapToLong(Set::size).sum(),
operations.stages());
flowRuleService.apply(operations);
}
/**
* Track or un-track network resource of a Intent and it's installable
* Intents.
*
* @param intentData the Intent data
* @param intentsToApply the list of flow rule Intents from the Intent
* @param direction the direction to determine track or un-track
*/
private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
switch (direction) {
case ADD:
trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
intentsToApply.forEach(installable ->
trackerService.addTrackedResources(intentData.key(),
installable.resources()));
break;
default:
trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
intentsToApply.forEach(installable ->
trackerService.removeTrackedResources(intentData.intent().key(),
installable.resources()));
break;
}
}
/**
* Determines whether there is any flow rule changed
* (i.e., different set of flow rules or different treatments)
* between FlowRuleIntents to be uninstalled and to be installed.
*
* @param uninstallIntent FlowRuleIntent to uninstall
* @param installIntent FlowRuleIntent to install
* @return true if flow rules which to be uninstalled contains all flow
* rules which to be installed; false otherwise
*/
private boolean flowRuleIntentChanged(FlowRuleIntent uninstallIntent,
FlowRuleIntent installIntent) {
Collection<FlowRule> flowRulesToUninstall = uninstallIntent.flowRules();
Collection<FlowRule> flowRulesToInstall = installIntent.flowRules();
// Check if any flow rule changed
for (FlowRule flowRuleToInstall : flowRulesToInstall) {
if (flowRulesToUninstall.stream().noneMatch(flowRuleToInstall::exactMatch)) {
return true;
}
}
return false;
}
}