blob: 306f80138a7f17897cd362a75742b4253d34401c [file] [log] [blame]
alshabibfaa1e362015-04-02 15:01:54 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
alshabibfaa1e362015-04-02 15:01:54 -07003 *
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 */
16package org.onosproject.driver.pipeline;
17
Michele Santuarid2c8b152016-03-30 17:57:56 -070018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
alshabibfaa1e362015-04-02 15:01:54 -070022import org.onlab.osgi.ServiceDirectory;
Michele Santuarid2c8b152016-03-30 17:57:56 -070023import org.onlab.util.KryoNamespace;
alshabibfaa1e362015-04-02 15:01:54 -070024import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080025import org.onosproject.net.behaviour.NextGroup;
alshabibfaa1e362015-04-02 15:01:54 -070026import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070027import org.onosproject.net.behaviour.PipelinerContext;
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070028import org.onosproject.net.driver.AbstractHandlerBehaviour;
alshabibfaa1e362015-04-02 15:01:54 -070029import org.onosproject.net.flow.DefaultFlowRule;
alshabibc61e18c2016-02-02 23:05:25 -080030import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070031import org.onosproject.net.flow.DefaultTrafficTreatment;
alshabibfaa1e362015-04-02 15:01:54 -070032import org.onosproject.net.flow.FlowRule;
33import org.onosproject.net.flow.FlowRuleOperations;
34import org.onosproject.net.flow.FlowRuleOperationsContext;
35import org.onosproject.net.flow.FlowRuleService;
36import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070037import org.onosproject.net.flow.TrafficTreatment;
alshabibfaa1e362015-04-02 15:01:54 -070038import org.onosproject.net.flowobjective.FilteringObjective;
Michele Santuarid2c8b152016-03-30 17:57:56 -070039import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabibfaa1e362015-04-02 15:01:54 -070040import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.flowobjective.NextObjective;
alshabibc61e18c2016-02-02 23:05:25 -080042import org.onosproject.net.flowobjective.Objective;
alshabib2a441c62015-04-13 18:39:38 -070043import org.onosproject.net.flowobjective.ObjectiveError;
Pier Luigib69b6cc2017-01-10 15:13:14 -080044import org.onosproject.store.serializers.KryoNamespaces;
alshabibfaa1e362015-04-02 15:01:54 -070045import org.slf4j.Logger;
46
Yi Tsenge935a642017-06-19 15:19:07 -070047import java.util.Collection;
Pier Luigib69b6cc2017-01-10 15:13:14 -080048import java.util.Collections;
Saurav Das24431192016-03-07 19:13:00 -080049import java.util.List;
Michele Santuarid2c8b152016-03-30 17:57:56 -070050import java.util.concurrent.TimeUnit;
51
Pier Luigib69b6cc2017-01-10 15:13:14 -080052import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
Michele Santuarid2c8b152016-03-30 17:57:56 -070053import static org.slf4j.LoggerFactory.getLogger;
Saurav Das24431192016-03-07 19:13:00 -080054
alshabibfaa1e362015-04-02 15:01:54 -070055/**
56 * Simple single table pipeline abstraction.
57 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070058public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibfaa1e362015-04-02 15:01:54 -070059
60 private final Logger log = getLogger(getClass());
61
62 private ServiceDirectory serviceDirectory;
63 private FlowRuleService flowRuleService;
Michele Santuarid2c8b152016-03-30 17:57:56 -070064 private FlowObjectiveStore flowObjectiveStore;
alshabibfaa1e362015-04-02 15:01:54 -070065 private DeviceId deviceId;
66
Michele Santuarid2c8b152016-03-30 17:57:56 -070067 private KryoNamespace appKryo = new KryoNamespace.Builder()
Pier Luigib69b6cc2017-01-10 15:13:14 -080068 .register(KryoNamespaces.API)
Michele Santuarid2c8b152016-03-30 17:57:56 -070069 .register(SingleGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -070070 .build("DefaultSingleTablePipeline");
Michele Santuarid2c8b152016-03-30 17:57:56 -070071
Pier Luigib69b6cc2017-01-10 15:13:14 -080072 // Fast path for the installation. If we don't find the nextobjective in
73 // the cache, as fallback mechanism we will try to retrieve the treatments
74 // from the store. It is safe to use this cache for the addition, while it
75 // should be avoided for the removal. This cache from Guava does not offer
76 // thread-safe read (the read does not take the lock).
77 private Cache<Integer, NextObjective> pendingAddNext = CacheBuilder.newBuilder()
78 .expireAfterWrite(20, TimeUnit.SECONDS)
79 .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
80 if (notification.getCause() == RemovalCause.EXPIRED) {
81 notification.getValue().context()
82 .ifPresent(c -> c.onError(notification.getValue(),
83 ObjectiveError.FLOWINSTALLATIONFAILED));
84 }
85 }).build();
86
Michele Santuarid2c8b152016-03-30 17:57:56 -070087
alshabibfaa1e362015-04-02 15:01:54 -070088 @Override
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070089 public void init(DeviceId deviceId, PipelinerContext context) {
90 this.serviceDirectory = context.directory();
alshabibfaa1e362015-04-02 15:01:54 -070091 this.deviceId = deviceId;
92
93 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Michele Santuarid2c8b152016-03-30 17:57:56 -070094 flowObjectiveStore = serviceDirectory.get(FlowObjectiveStore.class);
95
alshabibfaa1e362015-04-02 15:01:54 -070096 }
97
98 @Override
alshabibc61e18c2016-02-02 23:05:25 -080099 public void filter(FilteringObjective filter) {
alshabibc61e18c2016-02-02 23:05:25 -0800100 TrafficTreatment.Builder actions;
101 switch (filter.type()) {
102 case PERMIT:
103 actions = (filter.meta() == null) ?
104 DefaultTrafficTreatment.builder().punt() :
105 DefaultTrafficTreatment.builder(filter.meta());
106 break;
107 case DENY:
108 actions = (filter.meta() == null) ?
109 DefaultTrafficTreatment.builder() :
110 DefaultTrafficTreatment.builder(filter.meta());
111 actions.drop();
112 break;
113 default:
114 log.warn("Unknown filter type: {}", filter.type());
115 actions = DefaultTrafficTreatment.builder().drop();
116 }
117
118 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
119
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700120 filter.conditions().forEach(selector::add);
alshabibc61e18c2016-02-02 23:05:25 -0800121
122 if (filter.key() != null) {
123 selector.add(filter.key());
124 }
125
126 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
127 .forDevice(deviceId)
128 .withSelector(selector.build())
129 .withTreatment(actions.build())
130 .fromApp(filter.appId())
131 .withPriority(filter.priority());
132
133 if (filter.permanent()) {
134 ruleBuilder.makePermanent();
135 } else {
136 ruleBuilder.makeTemporary(filter.timeout());
137 }
alshabibc61e18c2016-02-02 23:05:25 -0800138 installObjective(ruleBuilder, filter);
alshabibc61e18c2016-02-02 23:05:25 -0800139 }
alshabibfaa1e362015-04-02 15:01:54 -0700140
141 @Override
alshabib2a441c62015-04-13 18:39:38 -0700142 public void forward(ForwardingObjective fwd) {
alshabib2a441c62015-04-13 18:39:38 -0700143 TrafficSelector selector = fwd.selector();
Michele Santuarid2c8b152016-03-30 17:57:56 -0700144 if (fwd.treatment() != null) {
145 // Deal with SPECIFIC and VERSATILE in the same manner.
146 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
147 .forDevice(deviceId)
148 .withSelector(selector)
149 .fromApp(fwd.appId())
150 .withPriority(fwd.priority())
151 .withTreatment(fwd.treatment());
alshabibb452fd72015-04-22 20:46:20 -0700152
Michele Santuarid2c8b152016-03-30 17:57:56 -0700153 if (fwd.permanent()) {
154 ruleBuilder.makePermanent();
155 } else {
156 ruleBuilder.makeTemporary(fwd.timeout());
157 }
158 installObjective(ruleBuilder, fwd);
159
alshabibb452fd72015-04-22 20:46:20 -0700160 } else {
Pier Luigib69b6cc2017-01-10 15:13:14 -0800161 NextObjective nextObjective;
162 NextGroup next;
163 TrafficTreatment treatment;
164 if (fwd.op() == ADD) {
165 // Give a try to the cache. Doing an operation
166 // on the store seems to be very expensive.
167 nextObjective = pendingAddNext.getIfPresent(fwd.nextId());
168 // If the next objective is not present
169 // We will try with the store
170 if (nextObjective == null) {
171 next = flowObjectiveStore.getNextGroup(fwd.nextId());
172 // We verify that next was in the store and then de-serialize
173 // the treatment in order to re-build the flow rule.
174 if (next == null) {
175 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
176 return;
Michele Santuarid2c8b152016-03-30 17:57:56 -0700177 }
Pier Luigib69b6cc2017-01-10 15:13:14 -0800178 treatment = appKryo.deserialize(next.data());
179 } else {
180 pendingAddNext.invalidate(fwd.nextId());
Yi Tsenge935a642017-06-19 15:19:07 -0700181 treatment = getTreatment(nextObjective);
182 if (treatment == null) {
183 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.UNSUPPORTED));
184 return;
185 }
Pier Luigib69b6cc2017-01-10 15:13:14 -0800186 }
Michele Santuarid2c8b152016-03-30 17:57:56 -0700187 } else {
Pier Luigib69b6cc2017-01-10 15:13:14 -0800188 // We get the NextGroup from the remove operation.
189 // Doing an operation on the store seems to be very expensive.
Yi Tseng32c053c2017-05-15 14:17:34 -0700190 next = flowObjectiveStore.getNextGroup(fwd.nextId());
Yi Tsenge935a642017-06-19 15:19:07 -0700191 treatment = (next != null) ? appKryo.deserialize(next.data()) : null;
Michele Santuarid2c8b152016-03-30 17:57:56 -0700192 }
Pier Luigib69b6cc2017-01-10 15:13:14 -0800193 // If the treatment is null we cannot re-build the original flow
194 if (treatment == null) {
195 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
196 return;
197 }
Yi Tsenge935a642017-06-19 15:19:07 -0700198 // Finally we build the flow rule and push to the flow rule subsystem.
Pier Luigib69b6cc2017-01-10 15:13:14 -0800199 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
200 .forDevice(deviceId)
201 .withSelector(selector)
202 .fromApp(fwd.appId())
203 .withPriority(fwd.priority())
204 .withTreatment(treatment);
205 if (fwd.permanent()) {
206 ruleBuilder.makePermanent();
207 } else {
208 ruleBuilder.makeTemporary(fwd.timeout());
209 }
210 installObjective(ruleBuilder, fwd);
alshabibb452fd72015-04-22 20:46:20 -0700211 }
alshabibc61e18c2016-02-02 23:05:25 -0800212 }
213
214 private void installObjective(FlowRule.Builder ruleBuilder, Objective objective) {
215 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
216 switch (objective.op()) {
alshabib2a441c62015-04-13 18:39:38 -0700217 case ADD:
alshabibb452fd72015-04-22 20:46:20 -0700218 flowBuilder.add(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700219 break;
220 case REMOVE:
alshabibb452fd72015-04-22 20:46:20 -0700221 flowBuilder.remove(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700222 break;
223 default:
alshabibc61e18c2016-02-02 23:05:25 -0800224 log.warn("Unknown operation {}", objective.op());
alshabib2a441c62015-04-13 18:39:38 -0700225 }
226
alshabibfaa1e362015-04-02 15:01:54 -0700227 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
228 @Override
229 public void onSuccess(FlowRuleOperations ops) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800230 objective.context().ifPresent(context -> context.onSuccess(objective));
alshabibfaa1e362015-04-02 15:01:54 -0700231 }
232
233 @Override
234 public void onError(FlowRuleOperations ops) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800235 objective.context()
236 .ifPresent(context -> context.onError(objective, ObjectiveError.FLOWINSTALLATIONFAILED));
alshabibfaa1e362015-04-02 15:01:54 -0700237 }
238 }));
alshabibfaa1e362015-04-02 15:01:54 -0700239 }
alshabib77b88482015-04-07 15:47:50 -0700240
241 @Override
alshabibc61e18c2016-02-02 23:05:25 -0800242 public void next(NextObjective nextObjective) {
Pier Luigib69b6cc2017-01-10 15:13:14 -0800243 switch (nextObjective.op()) {
244 case ADD:
Yi Tsenge935a642017-06-19 15:19:07 -0700245 // Check next objective
246 TrafficTreatment treatment = getTreatment(nextObjective);
247 if (treatment == null) {
248 // unsupported next objective
249 nextObjective.context().ifPresent(context -> context.onError(nextObjective,
250 ObjectiveError.UNSUPPORTED));
251 return;
252 }
Pier Luigib69b6cc2017-01-10 15:13:14 -0800253 // We insert the value in the cache
254 pendingAddNext.put(nextObjective.id(), nextObjective);
Yi Tsenge935a642017-06-19 15:19:07 -0700255
Pier Luigib69b6cc2017-01-10 15:13:14 -0800256 // Then in the store, this will unblock the queued fwd obj
257 flowObjectiveStore.putNextGroup(
258 nextObjective.id(),
Yi Tsenge935a642017-06-19 15:19:07 -0700259 new SingleGroup(treatment)
Pier Luigib69b6cc2017-01-10 15:13:14 -0800260 );
261 break;
262 case REMOVE:
Yi Tseng32c053c2017-05-15 14:17:34 -0700263 NextGroup next = flowObjectiveStore.removeNextGroup(nextObjective.id());
264 if (next == null) {
265 nextObjective.context().ifPresent(context -> context.onError(nextObjective,
266 ObjectiveError.GROUPMISSING));
267 return;
268 }
Pier Luigib69b6cc2017-01-10 15:13:14 -0800269 break;
270 default:
271 log.warn("Unsupported operation {}", nextObjective.op());
272 }
Ray Milkeyce7db1b2016-05-24 13:33:48 -0700273 nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
alshabibc61e18c2016-02-02 23:05:25 -0800274 }
alshabib77b88482015-04-07 15:47:50 -0700275
Saurav Das24431192016-03-07 19:13:00 -0800276 @Override
277 public List<String> getNextMappings(NextGroup nextGroup) {
278 // Default single table pipeline does not use nextObjectives or groups
Pier Luigib69b6cc2017-01-10 15:13:14 -0800279 return Collections.emptyList();
Saurav Das24431192016-03-07 19:13:00 -0800280 }
281
Yi Tsenge935a642017-06-19 15:19:07 -0700282 /**
283 * Gets traffic treatment from a next objective.
284 * Merge traffic treatments from next objective if the next objective is
285 * BROADCAST type and contains multiple traffic treatments.
286 * Returns first treatment from next objective if the next objective is
287 * SIMPLE type and it contains only one treatment.
288 *
289 * @param nextObjective the next objective
290 * @return the treatment from next objective; null if not supported
291 */
292 private TrafficTreatment getTreatment(NextObjective nextObjective) {
293 Collection<TrafficTreatment> treatments = nextObjective.next();
294 switch (nextObjective.type()) {
295 case SIMPLE:
296 if (treatments.size() != 1) {
297 log.error("Next Objectives of type SIMPLE should have only " +
298 "one traffic treatment. NexObjective: {}",
299 nextObjective.toString());
300 return null;
301 }
302 return treatments.iterator().next();
303 case BROADCAST:
304 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
305 treatments.forEach(builder::addTreatment);
306 return builder.build();
307 default:
308 log.error("Unsupported next objective type {}.", nextObjective.type());
309 return null;
310 }
311 }
312
Michele Santuarid2c8b152016-03-30 17:57:56 -0700313 private class SingleGroup implements NextGroup {
314
Pier Luigib69b6cc2017-01-10 15:13:14 -0800315 private TrafficTreatment nextActions;
Michele Santuarid2c8b152016-03-30 17:57:56 -0700316
Pier Luigib69b6cc2017-01-10 15:13:14 -0800317 SingleGroup(TrafficTreatment next) {
318 this.nextActions = next;
Michele Santuarid2c8b152016-03-30 17:57:56 -0700319 }
320
321 @Override
322 public byte[] data() {
Pier Luigib69b6cc2017-01-10 15:13:14 -0800323 return appKryo.serialize(nextActions);
324 }
325
326 public TrafficTreatment treatment() {
327 return nextActions;
Michele Santuarid2c8b152016-03-30 17:57:56 -0700328 }
329
330 }
alshabibfaa1e362015-04-02 15:01:54 -0700331}