blob: df2c28cd77401653f743e1c6d5068114a0155cef [file] [log] [blame]
Yi Tsengc927a062017-05-02 15:02:37 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.net.intent.impl.installer;
18
Yi Tseng49a2b2e2017-05-11 14:32:16 -070019import com.google.common.collect.Lists;
Yi Tsengc927a062017-05-02 15:02:37 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onosproject.net.flow.FlowRule;
26import org.onosproject.net.flow.FlowRuleOperations;
27import org.onosproject.net.flow.FlowRuleOperationsContext;
28import org.onosproject.net.flow.FlowRuleService;
29import org.onosproject.net.intent.FlowRuleIntent;
30import org.onosproject.net.intent.IntentInstallCoordinator;
31import org.onosproject.net.intent.IntentData;
32import org.onosproject.net.intent.IntentExtensionService;
33import org.onosproject.net.intent.IntentOperationContext;
34import org.onosproject.net.intent.IntentInstaller;
35import org.onosproject.net.intent.impl.IntentManager;
36import org.onosproject.net.intent.impl.ObjectiveTrackerService;
37import org.slf4j.Logger;
38
39import java.util.Collection;
40import java.util.Iterator;
41import java.util.List;
42import java.util.Optional;
43import java.util.Set;
Yi Tseng49a2b2e2017-05-11 14:32:16 -070044
Yi Tsengc927a062017-05-02 15:02:37 -070045import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
46import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
47import static org.onosproject.net.intent.IntentState.INSTALLED;
48import static org.slf4j.LoggerFactory.getLogger;
49
50/**
51 * Installer for FlowRuleIntent.
52 */
53@Component(immediate = true)
54public class FlowRuleIntentInstaller implements IntentInstaller<FlowRuleIntent> {
55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected IntentExtensionService intentExtensionService;
57
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected ObjectiveTrackerService trackerService;
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected IntentInstallCoordinator intentInstallCoordinator;
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected FlowRuleService flowRuleService;
66
67 @Activate
68 public void activate() {
69 intentExtensionService.registerInstaller(FlowRuleIntent.class, this);
70 }
71
72 @Deactivate
73 public void deactivated() {
74 intentExtensionService.unregisterInstaller(FlowRuleIntent.class);
75 }
76
77 protected final Logger log = getLogger(IntentManager.class);
78
79 @Override
80 public void apply(IntentOperationContext<FlowRuleIntent> context) {
81 Optional<IntentData> toUninstall = context.toUninstall();
82 Optional<IntentData> toInstall = context.toInstall();
83
Yi Tseng49a2b2e2017-05-11 14:32:16 -070084 List<FlowRuleIntent> uninstallIntents = Lists.newArrayList(context.intentsToUninstall());
85 List<FlowRuleIntent> installIntents = Lists.newArrayList(context.intentsToInstall());
Yi Tsengc927a062017-05-02 15:02:37 -070086
87 if (!toInstall.isPresent() && !toUninstall.isPresent()) {
88 intentInstallCoordinator.intentInstallSuccess(context);
89 return;
90 } else if (!toInstall.isPresent()) {
91 // Uninstall only
92 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
93 } else if (!toUninstall.isPresent()) {
94 // Install only
95 trackIntentResources(toInstall.get(), installIntents, ADD);
96 } else {
97 IntentData uninstall = toUninstall.get();
98 IntentData install = toInstall.get();
Yi Tsengc927a062017-05-02 15:02:37 -070099 // Filter out same intents and intents with same flow rules
100 Iterator<FlowRuleIntent> iterator = installIntents.iterator();
101 while (iterator.hasNext()) {
102 FlowRuleIntent installIntent = iterator.next();
103 uninstallIntents.stream().filter(uIntent -> {
104 if (uIntent.equals(installIntent)) {
105 return true;
106 } else {
107 return !flowRuleIntentChanged(uIntent, installIntent);
108 }
109 }).findFirst().ifPresent(common -> {
110 uninstallIntents.remove(common);
111 if (INSTALLED.equals(uninstall.state())) {
112 // only remove the install intent if the existing
113 // intent (i.e. the uninstall one) is already
114 // installed or installing
115 iterator.remove();
116 }
117 });
118 }
119 trackIntentResources(uninstall, uninstallIntents, REMOVE);
120 trackIntentResources(install, installIntents, ADD);
121 }
122
123 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
124 builder.newStage();
125
126 toUninstall.ifPresent(intentData -> {
127 uninstallIntents.stream().map(FlowRuleIntent::flowRules)
128 .flatMap(Collection::stream).forEach(builder::remove);
129 });
130
131 toInstall.ifPresent(intentData -> {
132 installIntents.stream().map(FlowRuleIntent::flowRules)
133 .flatMap(Collection::stream).forEach(builder::add);
134 });
135
136 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
137 @Override
138 public void onSuccess(FlowRuleOperations ops) {
139 intentInstallCoordinator.intentInstallSuccess(context);
140 }
141
142 @Override
143 public void onError(FlowRuleOperations ops) {
144 intentInstallCoordinator.intentInstallFailed(context);
145 }
146 };
147
148 FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
Yi Tsengc927a062017-05-02 15:02:37 -0700149 log.debug("applying intent {} -> {} with {} rules: {}",
150 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
151 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
152 operations.stages().stream().mapToLong(Set::size).sum(),
153 operations.stages());
154 flowRuleService.apply(operations);
155 }
156
157 /**
158 * Track or un-track network resource of a Intent and it's installable
159 * Intents.
160 *
161 * @param intentData the Intent data
162 * @param intentsToApply the list of flow rule Intents from the Intent
163 * @param direction the direction to determine track or un-track
164 */
165 private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
166 switch (direction) {
167 case ADD:
168 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
169 intentsToApply.forEach(installable ->
170 trackerService.addTrackedResources(intentData.key(),
171 installable.resources()));
172 break;
173 default:
174 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
175 intentsToApply.forEach(installable ->
176 trackerService.removeTrackedResources(intentData.intent().key(),
177 installable.resources()));
178 break;
179 }
180 }
181
182 /**
183 * Determines whether there is any flow rule changed
184 * (i.e., different set of flow rules or different treatments)
185 * between FlowRuleIntents to be uninstalled and to be installed.
186 *
187 * @param uninstallIntent FlowRuleIntent to uninstall
188 * @param installIntent FlowRuleIntent to install
189 * @return true if flow rules which to be uninstalled contains all flow
190 * rules which to be installed; false otherwise
191 */
192 private boolean flowRuleIntentChanged(FlowRuleIntent uninstallIntent,
193 FlowRuleIntent installIntent) {
194 Collection<FlowRule> flowRulesToUninstall = uninstallIntent.flowRules();
195 Collection<FlowRule> flowRulesToInstall = installIntent.flowRules();
196
197 // Check if any flow rule changed
198 for (FlowRule flowRuleToInstall : flowRulesToInstall) {
199 if (flowRulesToUninstall.stream().noneMatch(flowRuleToInstall::exactMatch)) {
200 return true;
201 }
202 }
203 return false;
204 }
205
206}