blob: eca9014d1871806ff011ad0a816913005ba8923e [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;
Michele Santuarid2c8b152016-03-30 17:57:56 -070044import org.onosproject.net.group.DefaultGroupKey;
45import org.onosproject.net.group.GroupKey;
alshabibfaa1e362015-04-02 15:01:54 -070046import org.slf4j.Logger;
47
Saurav Das24431192016-03-07 19:13:00 -080048import java.util.List;
Michele Santuarid2c8b152016-03-30 17:57:56 -070049import java.util.concurrent.TimeUnit;
50
51import static org.slf4j.LoggerFactory.getLogger;
Saurav Das24431192016-03-07 19:13:00 -080052
alshabibfaa1e362015-04-02 15:01:54 -070053/**
54 * Simple single table pipeline abstraction.
55 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070056public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibfaa1e362015-04-02 15:01:54 -070057
58 private final Logger log = getLogger(getClass());
59
60 private ServiceDirectory serviceDirectory;
61 private FlowRuleService flowRuleService;
Michele Santuarid2c8b152016-03-30 17:57:56 -070062 private FlowObjectiveStore flowObjectiveStore;
alshabibfaa1e362015-04-02 15:01:54 -070063 private DeviceId deviceId;
64
Michele Santuarid2c8b152016-03-30 17:57:56 -070065 private Cache<Integer, NextObjective> pendingNext;
66
67 private KryoNamespace appKryo = new KryoNamespace.Builder()
68 .register(GroupKey.class)
69 .register(DefaultGroupKey.class)
70 .register(SingleGroup.class)
71 .register(byte[].class)
Charles Chaneefdedf2016-05-23 16:45:45 -070072 .build("DefaultSingleTablePipeline");
Michele Santuarid2c8b152016-03-30 17:57:56 -070073
74
alshabibfaa1e362015-04-02 15:01:54 -070075 @Override
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070076 public void init(DeviceId deviceId, PipelinerContext context) {
77 this.serviceDirectory = context.directory();
alshabibfaa1e362015-04-02 15:01:54 -070078 this.deviceId = deviceId;
79
80 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Michele Santuarid2c8b152016-03-30 17:57:56 -070081 flowObjectiveStore = serviceDirectory.get(FlowObjectiveStore.class);
82
83 pendingNext = CacheBuilder.newBuilder()
84 .expireAfterWrite(20, TimeUnit.SECONDS)
85 .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
86 if (notification.getCause() == RemovalCause.EXPIRED) {
87 notification.getValue().context()
88 .ifPresent(c -> c.onError(notification.getValue(),
89 ObjectiveError.FLOWINSTALLATIONFAILED));
90 }
91 }).build();
alshabibfaa1e362015-04-02 15:01:54 -070092 }
93
94 @Override
alshabibc61e18c2016-02-02 23:05:25 -080095 public void filter(FilteringObjective filter) {
96
97 TrafficTreatment.Builder actions;
98 switch (filter.type()) {
99 case PERMIT:
100 actions = (filter.meta() == null) ?
101 DefaultTrafficTreatment.builder().punt() :
102 DefaultTrafficTreatment.builder(filter.meta());
103 break;
104 case DENY:
105 actions = (filter.meta() == null) ?
106 DefaultTrafficTreatment.builder() :
107 DefaultTrafficTreatment.builder(filter.meta());
108 actions.drop();
109 break;
110 default:
111 log.warn("Unknown filter type: {}", filter.type());
112 actions = DefaultTrafficTreatment.builder().drop();
113 }
114
115 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
116
117 filter.conditions().stream().forEach(selector::add);
118
119 if (filter.key() != null) {
120 selector.add(filter.key());
121 }
122
123 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
124 .forDevice(deviceId)
125 .withSelector(selector.build())
126 .withTreatment(actions.build())
127 .fromApp(filter.appId())
128 .withPriority(filter.priority());
129
130 if (filter.permanent()) {
131 ruleBuilder.makePermanent();
132 } else {
133 ruleBuilder.makeTemporary(filter.timeout());
134 }
135
136 installObjective(ruleBuilder, filter);
137
138 }
alshabibfaa1e362015-04-02 15:01:54 -0700139
140 @Override
alshabib2a441c62015-04-13 18:39:38 -0700141 public void forward(ForwardingObjective fwd) {
alshabib2a441c62015-04-13 18:39:38 -0700142 TrafficSelector selector = fwd.selector();
alshabibfaa1e362015-04-02 15:01:54 -0700143
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 {
Michele Santuarid2c8b152016-03-30 17:57:56 -0700161 NextObjective nextObjective = pendingNext.getIfPresent(fwd.nextId());
162 if (nextObjective != null) {
163 pendingNext.invalidate(fwd.nextId());
164 nextObjective.next().forEach(treat -> {
165 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
166 .forDevice(deviceId)
167 .withSelector(selector)
168 .fromApp(fwd.appId())
169 .withPriority(fwd.priority())
170 .withTreatment(treat);
171
172 if (fwd.permanent()) {
173 ruleBuilder.makePermanent();
174 } else {
175 ruleBuilder.makeTemporary(fwd.timeout());
176 }
177 installObjective(ruleBuilder, fwd);
178 });
179 } else {
180 fwd.context().ifPresent(c -> c.onError(fwd,
181 ObjectiveError.GROUPMISSING));
182 }
alshabibb452fd72015-04-22 20:46:20 -0700183 }
alshabibc61e18c2016-02-02 23:05:25 -0800184 }
185
186 private void installObjective(FlowRule.Builder ruleBuilder, Objective objective) {
187 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
188 switch (objective.op()) {
alshabibfaa1e362015-04-02 15:01:54 -0700189
alshabib2a441c62015-04-13 18:39:38 -0700190 case ADD:
alshabibb452fd72015-04-22 20:46:20 -0700191 flowBuilder.add(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700192 break;
193 case REMOVE:
alshabibb452fd72015-04-22 20:46:20 -0700194 flowBuilder.remove(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700195 break;
196 default:
alshabibc61e18c2016-02-02 23:05:25 -0800197 log.warn("Unknown operation {}", objective.op());
alshabib2a441c62015-04-13 18:39:38 -0700198 }
199
alshabibfaa1e362015-04-02 15:01:54 -0700200 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
201 @Override
202 public void onSuccess(FlowRuleOperations ops) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800203 objective.context().ifPresent(context -> context.onSuccess(objective));
alshabibfaa1e362015-04-02 15:01:54 -0700204 }
205
206 @Override
207 public void onError(FlowRuleOperations ops) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800208 objective.context()
209 .ifPresent(context -> context.onError(objective, ObjectiveError.FLOWINSTALLATIONFAILED));
alshabibfaa1e362015-04-02 15:01:54 -0700210 }
211 }));
alshabibfaa1e362015-04-02 15:01:54 -0700212 }
alshabib77b88482015-04-07 15:47:50 -0700213
214 @Override
alshabibc61e18c2016-02-02 23:05:25 -0800215 public void next(NextObjective nextObjective) {
Michele Santuarid2c8b152016-03-30 17:57:56 -0700216
217 pendingNext.put(nextObjective.id(), nextObjective);
218 flowObjectiveStore.putNextGroup(nextObjective.id(),
219 new SingleGroup(new DefaultGroupKey(appKryo.serialize(nextObjective.id()))));
Ray Milkeyce7db1b2016-05-24 13:33:48 -0700220 nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
alshabibc61e18c2016-02-02 23:05:25 -0800221 }
alshabib77b88482015-04-07 15:47:50 -0700222
Saurav Das24431192016-03-07 19:13:00 -0800223 @Override
224 public List<String> getNextMappings(NextGroup nextGroup) {
225 // Default single table pipeline does not use nextObjectives or groups
226 return null;
227 }
228
Michele Santuarid2c8b152016-03-30 17:57:56 -0700229 private class SingleGroup implements NextGroup {
230
231 private final GroupKey key;
232
233 public SingleGroup(GroupKey key) {
234 this.key = key;
235 }
236
237 public GroupKey key() {
238 return key;
239 }
240
241 @Override
242 public byte[] data() {
243 return appKryo.serialize(key);
244 }
245
246 }
alshabibfaa1e362015-04-02 15:01:54 -0700247}