blob: 9e24a1761cfcc7df5b14d36d6b517372d6c0d167 [file] [log] [blame]
samuel3b2743d2015-07-29 10:44:30 +08001/*
2 * Copyright 2015 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 */
16package org.onosproject.driver.pipeline;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Collection;
21import java.util.Collections;
Sho SHIMIZU45906042016-01-13 23:05:54 -080022import java.util.Objects;
samuel3b2743d2015-07-29 10:44:30 +080023
24import org.onlab.osgi.ServiceDirectory;
lishuai4fa26342015-12-03 13:01:39 +080025import org.onlab.packet.EthType.EtherType;
lishuai4d6a0ee2015-10-19 19:05:48 +080026import org.onosproject.core.ApplicationId;
samuel3b2743d2015-07-29 10:44:30 +080027import org.onosproject.core.CoreService;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.behaviour.Pipeliner;
30import org.onosproject.net.behaviour.PipelinerContext;
31import org.onosproject.net.device.DeviceService;
samuel3b2743d2015-07-29 10:44:30 +080032import org.onosproject.net.flow.DefaultFlowRule;
lishuai4d6a0ee2015-10-19 19:05:48 +080033import org.onosproject.net.flow.DefaultTrafficSelector;
samuel3b2743d2015-07-29 10:44:30 +080034import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleOperations;
37import org.onosproject.net.flow.FlowRuleOperationsContext;
38import org.onosproject.net.flow.FlowRuleService;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
lishuai4fa26342015-12-03 13:01:39 +080041import org.onosproject.net.flow.criteria.Criteria;
samuel3b2743d2015-07-29 10:44:30 +080042import org.onosproject.net.flow.criteria.Criterion.Type;
43import org.onosproject.net.flow.instructions.Instructions;
44import org.onosproject.net.flowobjective.FilteringObjective;
45import org.onosproject.net.flowobjective.FlowObjectiveStore;
46import org.onosproject.net.flowobjective.ForwardingObjective;
47import org.onosproject.net.flowobjective.NextObjective;
48import org.onosproject.net.flowobjective.Objective;
49import org.onosproject.net.flowobjective.ObjectiveError;
50import org.slf4j.Logger;
51
52/**
53 * Driver for standard OpenVSwitch.
54 */
CNluciusa66c3972015-09-06 20:31:29 +080055public class OpenVSwitchPipeline extends DefaultSingleTablePipeline
samuel3b2743d2015-07-29 10:44:30 +080056 implements Pipeliner {
57
CNluciusa66c3972015-09-06 20:31:29 +080058 private static final String VTN_APP_ID = "org.onosproject.app.vtn";
samuel3b2743d2015-07-29 10:44:30 +080059 private final Logger log = getLogger(getClass());
60 private CoreService coreService;
61 private ServiceDirectory serviceDirectory;
62 protected FlowObjectiveStore flowObjectiveStore;
63 protected DeviceId deviceId;
lishuai4d6a0ee2015-10-19 19:05:48 +080064 protected ApplicationId appId;
samuel3b2743d2015-07-29 10:44:30 +080065 protected FlowRuleService flowRuleService;
66 protected DeviceService deviceService;
samuel3b2743d2015-07-29 10:44:30 +080067 private static final int TIME_OUT = 0;
lishuai4d6a0ee2015-10-19 19:05:48 +080068 private static final int CLASSIFIER_TABLE = 0;
lishuai4fa26342015-12-03 13:01:39 +080069 private static final int ARP_TABLE = 10;
70 private static final int DNAT_TABLE = 20;
71 private static final int L3FWD_TABLE = 30;
72 private static final int SNAT_TABLE = 40;
lishuai4d6a0ee2015-10-19 19:05:48 +080073 private static final int MAC_TABLE = 50;
74 private static final int TABLE_MISS_PRIORITY = 0;
samuel3b2743d2015-07-29 10:44:30 +080075
76 @Override
77 public void init(DeviceId deviceId, PipelinerContext context) {
CNluciusa66c3972015-09-06 20:31:29 +080078 super.init(deviceId, context);
samuel3b2743d2015-07-29 10:44:30 +080079 this.serviceDirectory = context.directory();
80 this.deviceId = deviceId;
81
82 coreService = serviceDirectory.get(CoreService.class);
83 flowRuleService = serviceDirectory.get(FlowRuleService.class);
84 flowObjectiveStore = context.store();
lishuai4d6a0ee2015-10-19 19:05:48 +080085 appId = coreService
samuel3b2743d2015-07-29 10:44:30 +080086 .registerApplication("org.onosproject.driver.OpenVSwitchPipeline");
lishuai4d6a0ee2015-10-19 19:05:48 +080087 initializePipeline();
samuel3b2743d2015-07-29 10:44:30 +080088 }
89
90 @Override
91 public void filter(FilteringObjective filteringObjective) {
CNluciusa66c3972015-09-06 20:31:29 +080092 super.filter(filteringObjective);
samuel3b2743d2015-07-29 10:44:30 +080093 }
94
95 @Override
96 public void forward(ForwardingObjective fwd) {
CNluciusa66c3972015-09-06 20:31:29 +080097 if (!VTN_APP_ID.equals(fwd.appId().name())) {
98 super.forward(fwd);
99 return;
100 }
samuel3b2743d2015-07-29 10:44:30 +0800101 Collection<FlowRule> rules;
102 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations
103 .builder();
104
105 rules = processForward(fwd);
106 switch (fwd.op()) {
107 case ADD:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800108 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800109 .forEach(flowOpsBuilder::add);
110 break;
111 case REMOVE:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800112 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800113 .forEach(flowOpsBuilder::remove);
114 break;
115 default:
116 fail(fwd, ObjectiveError.UNKNOWN);
117 log.warn("Unknown forwarding type {}", fwd.op());
118 }
119
120 flowRuleService.apply(flowOpsBuilder
121 .build(new FlowRuleOperationsContext() {
122 @Override
123 public void onSuccess(FlowRuleOperations ops) {
124 pass(fwd);
125 }
126
127 @Override
128 public void onError(FlowRuleOperations ops) {
129 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
130 }
131 }));
132 }
133
134 @Override
135 public void next(NextObjective nextObjective) {
CNluciusa66c3972015-09-06 20:31:29 +0800136 super.next(nextObjective);
samuel3b2743d2015-07-29 10:44:30 +0800137 }
138
lishuai4d6a0ee2015-10-19 19:05:48 +0800139 private void initializePipeline() {
140 processClassifierTable(true);
lishuai4fa26342015-12-03 13:01:39 +0800141 processArpTable(true);
142 processDnatTable(true);
143 processL3fwdTable(true);
144 processSnatTable(true);
lishuai4d6a0ee2015-10-19 19:05:48 +0800145 processMacTable(true);
146 }
147
148 private void processClassifierTable(boolean install) {
149 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
150 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
151
152 treatment.transition(MAC_TABLE);
153
154 FlowRule rule;
155 rule = DefaultFlowRule.builder().forDevice(deviceId)
156 .withSelector(selector.build())
157 .withTreatment(treatment.build())
158 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
159 .makePermanent().forTable(CLASSIFIER_TABLE).build();
160
161 applyRules(install, rule);
162 }
163
lishuai4fa26342015-12-03 13:01:39 +0800164 private void processArpTable(boolean install) {
165 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
166 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
167
168 treatment.transition(MAC_TABLE);
169
170 FlowRule rule;
171 rule = DefaultFlowRule.builder().forDevice(deviceId)
172 .withSelector(selector.build())
173 .withTreatment(treatment.build())
174 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
175 .makePermanent().forTable(ARP_TABLE).build();
176
177 applyRules(install, rule);
178 }
179
180 private void processDnatTable(boolean install) {
181 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
182 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
183
184 treatment.transition(MAC_TABLE);
185
186 FlowRule rule;
187 rule = DefaultFlowRule.builder().forDevice(deviceId)
188 .withSelector(selector.build())
189 .withTreatment(treatment.build())
190 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
191 .makePermanent().forTable(DNAT_TABLE).build();
192
193 applyRules(install, rule);
194 }
195
196 private void processL3fwdTable(boolean install) {
197 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
198 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
199
200 treatment.transition(SNAT_TABLE);
201
202 FlowRule rule;
203 rule = DefaultFlowRule.builder().forDevice(deviceId)
204 .withSelector(selector.build())
205 .withTreatment(treatment.build())
206 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
207 .makePermanent().forTable(L3FWD_TABLE).build();
208
209 applyRules(install, rule);
210 }
211
212 private void processSnatTable(boolean install) {
213 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
214 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
215
216 treatment.transition(MAC_TABLE);
217
218 FlowRule rule;
219 rule = DefaultFlowRule.builder().forDevice(deviceId)
220 .withSelector(selector.build())
221 .withTreatment(treatment.build())
222 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
223 .makePermanent().forTable(SNAT_TABLE).build();
224
225 applyRules(install, rule);
226 }
227
lishuai4d6a0ee2015-10-19 19:05:48 +0800228 private void processMacTable(boolean install) {
229 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
230 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
231
232 treatment.drop();
233
234 FlowRule rule;
235 rule = DefaultFlowRule.builder().forDevice(deviceId)
236 .withSelector(selector.build())
237 .withTreatment(treatment.build())
238 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
239 .makePermanent().forTable(MAC_TABLE).build();
240
241 applyRules(install, rule);
242 }
243
244 private void applyRules(boolean install, FlowRule rule) {
245 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
246
247 ops = install ? ops.add(rule) : ops.remove(rule);
248 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
249 @Override
250 public void onSuccess(FlowRuleOperations ops) {
251 log.info("ONOSW provisioned " + rule.tableId() + " table");
252 }
253
254 @Override
255 public void onError(FlowRuleOperations ops) {
256 log.info("ONOSW failed to provision " + rule.tableId() + " table");
257 }
258 }));
259 }
260
samuel3b2743d2015-07-29 10:44:30 +0800261 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
262 switch (fwd.flag()) {
263 case SPECIFIC:
264 return processSpecific(fwd);
265 case VERSATILE:
266 return processVersatile(fwd);
267 default:
268 fail(fwd, ObjectiveError.UNKNOWN);
269 log.warn("Unknown forwarding flag {}", fwd.flag());
270 }
271 return Collections.emptySet();
272 }
273
274 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
275 log.debug("Processing versatile forwarding objective");
276 return Collections.emptyList();
277 }
278
279 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
280 log.debug("Processing specific forwarding objective");
281 TrafficSelector selector = fwd.selector();
282 TrafficTreatment tb = fwd.treatment();
283 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
284 .fromApp(fwd.appId()).withPriority(fwd.priority())
285 .forDevice(deviceId).withSelector(selector)
CNluciusa66c3972015-09-06 20:31:29 +0800286 .withTreatment(tb).makeTemporary(TIME_OUT);
287 ruleBuilder.withPriority(fwd.priority());
samuel3b2743d2015-07-29 10:44:30 +0800288 if (fwd.permanent()) {
289 ruleBuilder.makePermanent();
290 }
lishuai4fa26342015-12-03 13:01:39 +0800291 Integer transition = null;
292 Integer forTable = null;
293 // MAC table flow rules
294 if ((selector.getCriterion(Type.TUNNEL_ID) != null && selector
295 .getCriterion(Type.ETH_DST) != null)
samuel3b2743d2015-07-29 10:44:30 +0800296 || tb.allInstructions().contains(Instructions.createDrop())) {
lishuai4fa26342015-12-03 13:01:39 +0800297 forTable = MAC_TABLE;
298 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
299 }
300 // CLASSIFIER table flow rules
301 if (selector.getCriterion(Type.IN_PORT) != null) {
302 forTable = CLASSIFIER_TABLE;
303 if (selector.getCriterion(Type.ETH_SRC) != null
304 && selector.getCriterion(Type.ETH_DST) != null) {
305 transition = L3FWD_TABLE;
306 } else if (selector.getCriterion(Type.ETH_SRC) != null
307 || selector.getCriterion(Type.TUNNEL_ID) != null) {
308 transition = MAC_TABLE;
309 } else if (selector.getCriterion(Type.IPV4_DST) != null) {
310 transition = DNAT_TABLE;
311 }
312 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
313 }
314 // ARP table flow rules
315 if (selector.getCriterion(Type.ETH_TYPE) != null
316 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
317 .matchEthType(EtherType.ARP.ethType().toShort()))) {
318 // CLASSIFIER table arp flow rules
319 if (selector.getCriterion(Type.TUNNEL_ID) == null) {
320 transition = ARP_TABLE;
321 forTable = CLASSIFIER_TABLE;
322 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
323 }
324 forTable = ARP_TABLE;
325 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
326 }
327 // L3FWD table flow rules
328 if (selector.getCriterion(Type.TUNNEL_ID) != null
329 && selector.getCriterion(Type.IPV4_DST) != null) {
330 transition = MAC_TABLE;
331 forTable = L3FWD_TABLE;
332 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
333 }
334 // DNAT table flow rules
335 if (selector.getCriterion(Type.IPV4_DST) != null) {
336 transition = L3FWD_TABLE;
337 forTable = DNAT_TABLE;
338 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
339 }
340 // SNAT table flow rules
341 if (selector.getCriterion(Type.TUNNEL_ID) != null
342 && selector.getCriterion(Type.IPV4_SRC) != null) {
343 transition = MAC_TABLE;
344 forTable = SNAT_TABLE;
345 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
346 }
347 return Collections.singletonList(ruleBuilder.build());
348 }
349
350 private Collection<FlowRule> reassemblyFlowRule(FlowRule.Builder ruleBuilder,
351 TrafficTreatment tb,
352 Integer transition,
353 Integer forTable) {
354 if (transition != null) {
355 TrafficTreatment.Builder newTraffic = DefaultTrafficTreatment
356 .builder();
samuel3b2743d2015-07-29 10:44:30 +0800357 tb.allInstructions().forEach(t -> newTraffic.add(t));
lishuai4fa26342015-12-03 13:01:39 +0800358 newTraffic.transition(transition);
samuel3b2743d2015-07-29 10:44:30 +0800359 ruleBuilder.withTreatment(newTraffic.build());
lishuai4fa26342015-12-03 13:01:39 +0800360 } else {
361 ruleBuilder.withTreatment(tb);
362 }
363 if (forTable != null) {
364 ruleBuilder.forTable(forTable);
samuel3b2743d2015-07-29 10:44:30 +0800365 }
366 return Collections.singletonList(ruleBuilder.build());
367 }
368
369 private void fail(Objective obj, ObjectiveError error) {
370 if (obj.context().isPresent()) {
371 obj.context().get().onError(obj, error);
372 }
373 }
374
375 private void pass(Objective obj) {
376 if (obj.context().isPresent()) {
377 obj.context().get().onSuccess(obj);
378 }
379 }
380}