blob: dd275355d440406a7f932ca218bcb5f5f0f73ab7 [file] [log] [blame]
samuel3b2743d2015-07-29 10:44:30 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
samuel3b2743d2015-07-29 10:44:30 +08003 *
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;
samuel3b2743d2015-07-29 10:44:30 +080043import org.onosproject.net.flowobjective.FilteringObjective;
44import org.onosproject.net.flowobjective.FlowObjectiveStore;
45import org.onosproject.net.flowobjective.ForwardingObjective;
46import org.onosproject.net.flowobjective.NextObjective;
47import org.onosproject.net.flowobjective.Objective;
48import org.onosproject.net.flowobjective.ObjectiveError;
49import org.slf4j.Logger;
50
51/**
52 * Driver for standard OpenVSwitch.
53 */
CNluciusa66c3972015-09-06 20:31:29 +080054public class OpenVSwitchPipeline extends DefaultSingleTablePipeline
samuel3b2743d2015-07-29 10:44:30 +080055 implements Pipeliner {
56
CNluciusa66c3972015-09-06 20:31:29 +080057 private static final String VTN_APP_ID = "org.onosproject.app.vtn";
samuel3b2743d2015-07-29 10:44:30 +080058 private final Logger log = getLogger(getClass());
59 private CoreService coreService;
60 private ServiceDirectory serviceDirectory;
61 protected FlowObjectiveStore flowObjectiveStore;
62 protected DeviceId deviceId;
lishuai4d6a0ee2015-10-19 19:05:48 +080063 protected ApplicationId appId;
samuel3b2743d2015-07-29 10:44:30 +080064 protected FlowRuleService flowRuleService;
65 protected DeviceService deviceService;
samuel3b2743d2015-07-29 10:44:30 +080066 private static final int TIME_OUT = 0;
lishuai4d6a0ee2015-10-19 19:05:48 +080067 private static final int CLASSIFIER_TABLE = 0;
lishuai4fa26342015-12-03 13:01:39 +080068 private static final int ARP_TABLE = 10;
69 private static final int DNAT_TABLE = 20;
70 private static final int L3FWD_TABLE = 30;
71 private static final int SNAT_TABLE = 40;
lishuai4d6a0ee2015-10-19 19:05:48 +080072 private static final int MAC_TABLE = 50;
73 private static final int TABLE_MISS_PRIORITY = 0;
samuel3b2743d2015-07-29 10:44:30 +080074
75 @Override
76 public void init(DeviceId deviceId, PipelinerContext context) {
CNluciusa66c3972015-09-06 20:31:29 +080077 super.init(deviceId, context);
samuel3b2743d2015-07-29 10:44:30 +080078 this.serviceDirectory = context.directory();
79 this.deviceId = deviceId;
80
81 coreService = serviceDirectory.get(CoreService.class);
82 flowRuleService = serviceDirectory.get(FlowRuleService.class);
83 flowObjectiveStore = context.store();
lishuai4d6a0ee2015-10-19 19:05:48 +080084 appId = coreService
samuel3b2743d2015-07-29 10:44:30 +080085 .registerApplication("org.onosproject.driver.OpenVSwitchPipeline");
lishuai4d6a0ee2015-10-19 19:05:48 +080086 initializePipeline();
samuel3b2743d2015-07-29 10:44:30 +080087 }
88
89 @Override
90 public void filter(FilteringObjective filteringObjective) {
CNluciusa66c3972015-09-06 20:31:29 +080091 super.filter(filteringObjective);
samuel3b2743d2015-07-29 10:44:30 +080092 }
93
94 @Override
95 public void forward(ForwardingObjective fwd) {
CNluciusa66c3972015-09-06 20:31:29 +080096 if (!VTN_APP_ID.equals(fwd.appId().name())) {
97 super.forward(fwd);
98 return;
99 }
samuel3b2743d2015-07-29 10:44:30 +0800100 Collection<FlowRule> rules;
101 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations
102 .builder();
103
104 rules = processForward(fwd);
105 switch (fwd.op()) {
106 case ADD:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800107 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800108 .forEach(flowOpsBuilder::add);
109 break;
110 case REMOVE:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800111 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800112 .forEach(flowOpsBuilder::remove);
113 break;
114 default:
115 fail(fwd, ObjectiveError.UNKNOWN);
116 log.warn("Unknown forwarding type {}", fwd.op());
117 }
118
119 flowRuleService.apply(flowOpsBuilder
120 .build(new FlowRuleOperationsContext() {
121 @Override
122 public void onSuccess(FlowRuleOperations ops) {
123 pass(fwd);
124 }
125
126 @Override
127 public void onError(FlowRuleOperations ops) {
128 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
129 }
130 }));
131 }
132
133 @Override
134 public void next(NextObjective nextObjective) {
CNluciusa66c3972015-09-06 20:31:29 +0800135 super.next(nextObjective);
samuel3b2743d2015-07-29 10:44:30 +0800136 }
137
lishuai4d6a0ee2015-10-19 19:05:48 +0800138 private void initializePipeline() {
139 processClassifierTable(true);
lishuai4fa26342015-12-03 13:01:39 +0800140 processArpTable(true);
141 processDnatTable(true);
142 processL3fwdTable(true);
143 processSnatTable(true);
lishuai4d6a0ee2015-10-19 19:05:48 +0800144 processMacTable(true);
145 }
146
147 private void processClassifierTable(boolean install) {
148 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
149 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
150
151 treatment.transition(MAC_TABLE);
152
153 FlowRule rule;
154 rule = DefaultFlowRule.builder().forDevice(deviceId)
155 .withSelector(selector.build())
156 .withTreatment(treatment.build())
157 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
158 .makePermanent().forTable(CLASSIFIER_TABLE).build();
159
160 applyRules(install, rule);
161 }
162
lishuai4fa26342015-12-03 13:01:39 +0800163 private void processArpTable(boolean install) {
164 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
165 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
166
167 treatment.transition(MAC_TABLE);
168
169 FlowRule rule;
170 rule = DefaultFlowRule.builder().forDevice(deviceId)
171 .withSelector(selector.build())
172 .withTreatment(treatment.build())
173 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
174 .makePermanent().forTable(ARP_TABLE).build();
175
176 applyRules(install, rule);
177 }
178
179 private void processDnatTable(boolean install) {
180 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
181 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
182
183 treatment.transition(MAC_TABLE);
184
185 FlowRule rule;
186 rule = DefaultFlowRule.builder().forDevice(deviceId)
187 .withSelector(selector.build())
188 .withTreatment(treatment.build())
189 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
190 .makePermanent().forTable(DNAT_TABLE).build();
191
192 applyRules(install, rule);
193 }
194
195 private void processL3fwdTable(boolean install) {
196 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
197 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
198
199 treatment.transition(SNAT_TABLE);
200
201 FlowRule rule;
202 rule = DefaultFlowRule.builder().forDevice(deviceId)
203 .withSelector(selector.build())
204 .withTreatment(treatment.build())
205 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
206 .makePermanent().forTable(L3FWD_TABLE).build();
207
208 applyRules(install, rule);
209 }
210
211 private void processSnatTable(boolean install) {
212 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
213 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
214
215 treatment.transition(MAC_TABLE);
216
217 FlowRule rule;
218 rule = DefaultFlowRule.builder().forDevice(deviceId)
219 .withSelector(selector.build())
220 .withTreatment(treatment.build())
221 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
222 .makePermanent().forTable(SNAT_TABLE).build();
223
224 applyRules(install, rule);
225 }
226
lishuai4d6a0ee2015-10-19 19:05:48 +0800227 private void processMacTable(boolean install) {
228 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
229 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
230
231 treatment.drop();
232
233 FlowRule rule;
234 rule = DefaultFlowRule.builder().forDevice(deviceId)
235 .withSelector(selector.build())
236 .withTreatment(treatment.build())
237 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
238 .makePermanent().forTable(MAC_TABLE).build();
239
240 applyRules(install, rule);
241 }
242
243 private void applyRules(boolean install, FlowRule rule) {
244 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
245
246 ops = install ? ops.add(rule) : ops.remove(rule);
247 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
248 @Override
249 public void onSuccess(FlowRuleOperations ops) {
250 log.info("ONOSW provisioned " + rule.tableId() + " table");
251 }
252
253 @Override
254 public void onError(FlowRuleOperations ops) {
255 log.info("ONOSW failed to provision " + rule.tableId() + " table");
256 }
257 }));
258 }
259
samuel3b2743d2015-07-29 10:44:30 +0800260 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
261 switch (fwd.flag()) {
262 case SPECIFIC:
263 return processSpecific(fwd);
264 case VERSATILE:
265 return processVersatile(fwd);
266 default:
267 fail(fwd, ObjectiveError.UNKNOWN);
268 log.warn("Unknown forwarding flag {}", fwd.flag());
269 }
270 return Collections.emptySet();
271 }
272
273 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
274 log.debug("Processing versatile forwarding objective");
275 return Collections.emptyList();
276 }
277
278 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
279 log.debug("Processing specific forwarding objective");
280 TrafficSelector selector = fwd.selector();
281 TrafficTreatment tb = fwd.treatment();
282 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
283 .fromApp(fwd.appId()).withPriority(fwd.priority())
284 .forDevice(deviceId).withSelector(selector)
CNluciusa66c3972015-09-06 20:31:29 +0800285 .withTreatment(tb).makeTemporary(TIME_OUT);
286 ruleBuilder.withPriority(fwd.priority());
samuel3b2743d2015-07-29 10:44:30 +0800287 if (fwd.permanent()) {
288 ruleBuilder.makePermanent();
289 }
lishuai4fa26342015-12-03 13:01:39 +0800290 Integer transition = null;
291 Integer forTable = null;
292 // MAC table flow rules
lishuai90b3b6c2016-05-04 16:32:17 +0800293 if (selector.getCriterion(Type.TUNNEL_ID) != null && selector
294 .getCriterion(Type.ETH_DST) != null) {
lishuai4fa26342015-12-03 13:01:39 +0800295 forTable = MAC_TABLE;
296 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
297 }
298 // CLASSIFIER table flow rules
299 if (selector.getCriterion(Type.IN_PORT) != null) {
300 forTable = CLASSIFIER_TABLE;
301 if (selector.getCriterion(Type.ETH_SRC) != null
302 && selector.getCriterion(Type.ETH_DST) != null) {
303 transition = L3FWD_TABLE;
304 } else if (selector.getCriterion(Type.ETH_SRC) != null
305 || selector.getCriterion(Type.TUNNEL_ID) != null) {
306 transition = MAC_TABLE;
307 } else if (selector.getCriterion(Type.IPV4_DST) != null) {
308 transition = DNAT_TABLE;
309 }
310 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
311 }
312 // ARP table flow rules
313 if (selector.getCriterion(Type.ETH_TYPE) != null
314 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
315 .matchEthType(EtherType.ARP.ethType().toShort()))) {
316 // CLASSIFIER table arp flow rules
317 if (selector.getCriterion(Type.TUNNEL_ID) == null) {
318 transition = ARP_TABLE;
319 forTable = CLASSIFIER_TABLE;
320 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
321 }
322 forTable = ARP_TABLE;
323 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
324 }
325 // L3FWD table flow rules
326 if (selector.getCriterion(Type.TUNNEL_ID) != null
327 && selector.getCriterion(Type.IPV4_DST) != null) {
328 transition = MAC_TABLE;
329 forTable = L3FWD_TABLE;
330 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
331 }
332 // DNAT table flow rules
333 if (selector.getCriterion(Type.IPV4_DST) != null) {
334 transition = L3FWD_TABLE;
335 forTable = DNAT_TABLE;
336 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
337 }
338 // SNAT table flow rules
339 if (selector.getCriterion(Type.TUNNEL_ID) != null
340 && selector.getCriterion(Type.IPV4_SRC) != null) {
341 transition = MAC_TABLE;
342 forTable = SNAT_TABLE;
343 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
344 }
345 return Collections.singletonList(ruleBuilder.build());
346 }
347
348 private Collection<FlowRule> reassemblyFlowRule(FlowRule.Builder ruleBuilder,
349 TrafficTreatment tb,
350 Integer transition,
351 Integer forTable) {
352 if (transition != null) {
353 TrafficTreatment.Builder newTraffic = DefaultTrafficTreatment
354 .builder();
samuel3b2743d2015-07-29 10:44:30 +0800355 tb.allInstructions().forEach(t -> newTraffic.add(t));
lishuai4fa26342015-12-03 13:01:39 +0800356 newTraffic.transition(transition);
samuel3b2743d2015-07-29 10:44:30 +0800357 ruleBuilder.withTreatment(newTraffic.build());
lishuai4fa26342015-12-03 13:01:39 +0800358 } else {
359 ruleBuilder.withTreatment(tb);
360 }
361 if (forTable != null) {
362 ruleBuilder.forTable(forTable);
samuel3b2743d2015-07-29 10:44:30 +0800363 }
364 return Collections.singletonList(ruleBuilder.build());
365 }
366
367 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800368 obj.context().ifPresent(context -> context.onError(obj, error));
samuel3b2743d2015-07-29 10:44:30 +0800369 }
370
371 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800372 obj.context().ifPresent(context -> context.onSuccess(obj));
samuel3b2743d2015-07-29 10:44:30 +0800373 }
374}