blob: f606a92edfe41208e11aa08ae1bbea54c3c1528e [file] [log] [blame]
samuel3b2743d2015-07-29 10:44:30 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
Bob zhoue9795fd2016-05-12 20:18:45 +080026import org.onlab.packet.IpAddress;
27import org.onlab.packet.IpPrefix;
lishuai4d6a0ee2015-10-19 19:05:48 +080028import org.onosproject.core.ApplicationId;
samuel3b2743d2015-07-29 10:44:30 +080029import org.onosproject.core.CoreService;
30import org.onosproject.net.DeviceId;
Bob zhoue9795fd2016-05-12 20:18:45 +080031import org.onosproject.net.PortNumber;
samuel3b2743d2015-07-29 10:44:30 +080032import org.onosproject.net.behaviour.Pipeliner;
33import org.onosproject.net.behaviour.PipelinerContext;
34import org.onosproject.net.device.DeviceService;
samuel3b2743d2015-07-29 10:44:30 +080035import org.onosproject.net.flow.DefaultFlowRule;
lishuai4d6a0ee2015-10-19 19:05:48 +080036import org.onosproject.net.flow.DefaultTrafficSelector;
samuel3b2743d2015-07-29 10:44:30 +080037import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleOperations;
40import org.onosproject.net.flow.FlowRuleOperationsContext;
41import org.onosproject.net.flow.FlowRuleService;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
lishuai4fa26342015-12-03 13:01:39 +080044import org.onosproject.net.flow.criteria.Criteria;
samuel3b2743d2015-07-29 10:44:30 +080045import org.onosproject.net.flow.criteria.Criterion.Type;
Bob zhoue9795fd2016-05-12 20:18:45 +080046import org.onosproject.net.flow.criteria.IPCriterion;
47import org.onosproject.net.flow.instructions.Instructions;
samuel3b2743d2015-07-29 10:44:30 +080048import org.onosproject.net.flowobjective.FilteringObjective;
49import org.onosproject.net.flowobjective.FlowObjectiveStore;
50import org.onosproject.net.flowobjective.ForwardingObjective;
51import org.onosproject.net.flowobjective.NextObjective;
52import org.onosproject.net.flowobjective.Objective;
53import org.onosproject.net.flowobjective.ObjectiveError;
54import org.slf4j.Logger;
55
56/**
57 * Driver for standard OpenVSwitch.
58 */
CNluciusa66c3972015-09-06 20:31:29 +080059public class OpenVSwitchPipeline extends DefaultSingleTablePipeline
samuel3b2743d2015-07-29 10:44:30 +080060 implements Pipeliner {
61
CNluciusa66c3972015-09-06 20:31:29 +080062 private static final String VTN_APP_ID = "org.onosproject.app.vtn";
samuel3b2743d2015-07-29 10:44:30 +080063 private final Logger log = getLogger(getClass());
64 private CoreService coreService;
65 private ServiceDirectory serviceDirectory;
66 protected FlowObjectiveStore flowObjectiveStore;
67 protected DeviceId deviceId;
lishuai4d6a0ee2015-10-19 19:05:48 +080068 protected ApplicationId appId;
samuel3b2743d2015-07-29 10:44:30 +080069 protected FlowRuleService flowRuleService;
70 protected DeviceService deviceService;
samuel3b2743d2015-07-29 10:44:30 +080071 private static final int TIME_OUT = 0;
lishuai4d6a0ee2015-10-19 19:05:48 +080072 private static final int CLASSIFIER_TABLE = 0;
Phaneendra Manda8db7d092016-06-04 00:17:24 +053073 private static final int ENCAP_OUTPUT_TABLE = 4;
74 private static final int TUN_SEND_TABLE = 7;
lishuai4fa26342015-12-03 13:01:39 +080075 private static final int ARP_TABLE = 10;
76 private static final int DNAT_TABLE = 20;
77 private static final int L3FWD_TABLE = 30;
78 private static final int SNAT_TABLE = 40;
lishuai4d6a0ee2015-10-19 19:05:48 +080079 private static final int MAC_TABLE = 50;
80 private static final int TABLE_MISS_PRIORITY = 0;
Bob zhoue9795fd2016-05-12 20:18:45 +080081 private static final String USERDATA_IP = "169.254.169.254";
samuel3b2743d2015-07-29 10:44:30 +080082
83 @Override
84 public void init(DeviceId deviceId, PipelinerContext context) {
CNluciusa66c3972015-09-06 20:31:29 +080085 super.init(deviceId, context);
samuel3b2743d2015-07-29 10:44:30 +080086 this.serviceDirectory = context.directory();
87 this.deviceId = deviceId;
88
89 coreService = serviceDirectory.get(CoreService.class);
90 flowRuleService = serviceDirectory.get(FlowRuleService.class);
91 flowObjectiveStore = context.store();
lishuai4d6a0ee2015-10-19 19:05:48 +080092 appId = coreService
samuel3b2743d2015-07-29 10:44:30 +080093 .registerApplication("org.onosproject.driver.OpenVSwitchPipeline");
lishuai4d6a0ee2015-10-19 19:05:48 +080094 initializePipeline();
samuel3b2743d2015-07-29 10:44:30 +080095 }
96
97 @Override
98 public void filter(FilteringObjective filteringObjective) {
CNluciusa66c3972015-09-06 20:31:29 +080099 super.filter(filteringObjective);
samuel3b2743d2015-07-29 10:44:30 +0800100 }
101
102 @Override
103 public void forward(ForwardingObjective fwd) {
CNluciusa66c3972015-09-06 20:31:29 +0800104 if (!VTN_APP_ID.equals(fwd.appId().name())) {
105 super.forward(fwd);
106 return;
107 }
samuel3b2743d2015-07-29 10:44:30 +0800108 Collection<FlowRule> rules;
109 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations
110 .builder();
111
112 rules = processForward(fwd);
113 switch (fwd.op()) {
114 case ADD:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800115 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800116 .forEach(flowOpsBuilder::add);
117 break;
118 case REMOVE:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800119 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800120 .forEach(flowOpsBuilder::remove);
121 break;
122 default:
123 fail(fwd, ObjectiveError.UNKNOWN);
124 log.warn("Unknown forwarding type {}", fwd.op());
125 }
126
127 flowRuleService.apply(flowOpsBuilder
128 .build(new FlowRuleOperationsContext() {
129 @Override
130 public void onSuccess(FlowRuleOperations ops) {
131 pass(fwd);
132 }
133
134 @Override
135 public void onError(FlowRuleOperations ops) {
136 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
137 }
138 }));
139 }
140
141 @Override
142 public void next(NextObjective nextObjective) {
CNluciusa66c3972015-09-06 20:31:29 +0800143 super.next(nextObjective);
samuel3b2743d2015-07-29 10:44:30 +0800144 }
145
lishuai4d6a0ee2015-10-19 19:05:48 +0800146 private void initializePipeline() {
147 processClassifierTable(true);
lishuai4fa26342015-12-03 13:01:39 +0800148 processArpTable(true);
149 processDnatTable(true);
150 processL3fwdTable(true);
151 processSnatTable(true);
lishuai4d6a0ee2015-10-19 19:05:48 +0800152 processMacTable(true);
153 }
154
155 private void processClassifierTable(boolean install) {
156 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
157 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
158
159 treatment.transition(MAC_TABLE);
160
161 FlowRule rule;
162 rule = DefaultFlowRule.builder().forDevice(deviceId)
163 .withSelector(selector.build())
164 .withTreatment(treatment.build())
165 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
166 .makePermanent().forTable(CLASSIFIER_TABLE).build();
167
168 applyRules(install, rule);
169 }
170
lishuai4fa26342015-12-03 13:01:39 +0800171 private void processArpTable(boolean install) {
172 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
173 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
174
175 treatment.transition(MAC_TABLE);
176
177 FlowRule rule;
178 rule = DefaultFlowRule.builder().forDevice(deviceId)
179 .withSelector(selector.build())
180 .withTreatment(treatment.build())
181 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
182 .makePermanent().forTable(ARP_TABLE).build();
183
184 applyRules(install, rule);
185 }
186
187 private void processDnatTable(boolean install) {
188 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
189 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
190
191 treatment.transition(MAC_TABLE);
192
193 FlowRule rule;
194 rule = DefaultFlowRule.builder().forDevice(deviceId)
195 .withSelector(selector.build())
196 .withTreatment(treatment.build())
197 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
198 .makePermanent().forTable(DNAT_TABLE).build();
199
200 applyRules(install, rule);
201 }
202
203 private void processL3fwdTable(boolean install) {
204 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
205 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
206
207 treatment.transition(SNAT_TABLE);
208
209 FlowRule rule;
210 rule = DefaultFlowRule.builder().forDevice(deviceId)
211 .withSelector(selector.build())
212 .withTreatment(treatment.build())
213 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
214 .makePermanent().forTable(L3FWD_TABLE).build();
215
216 applyRules(install, rule);
217 }
218
219 private void processSnatTable(boolean install) {
220 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
221 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
222
223 treatment.transition(MAC_TABLE);
Bob zhoue9795fd2016-05-12 20:18:45 +0800224 treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
lishuai4fa26342015-12-03 13:01:39 +0800225 FlowRule rule;
226 rule = DefaultFlowRule.builder().forDevice(deviceId)
227 .withSelector(selector.build())
228 .withTreatment(treatment.build())
229 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
230 .makePermanent().forTable(SNAT_TABLE).build();
231
232 applyRules(install, rule);
233 }
234
lishuai4d6a0ee2015-10-19 19:05:48 +0800235 private void processMacTable(boolean install) {
236 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
237 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
238
239 treatment.drop();
240
241 FlowRule rule;
242 rule = DefaultFlowRule.builder().forDevice(deviceId)
243 .withSelector(selector.build())
244 .withTreatment(treatment.build())
245 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
246 .makePermanent().forTable(MAC_TABLE).build();
247
248 applyRules(install, rule);
249 }
250
251 private void applyRules(boolean install, FlowRule rule) {
252 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
253
254 ops = install ? ops.add(rule) : ops.remove(rule);
255 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
256 @Override
257 public void onSuccess(FlowRuleOperations ops) {
258 log.info("ONOSW provisioned " + rule.tableId() + " table");
259 }
260
261 @Override
262 public void onError(FlowRuleOperations ops) {
263 log.info("ONOSW failed to provision " + rule.tableId() + " table");
264 }
265 }));
266 }
267
samuel3b2743d2015-07-29 10:44:30 +0800268 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
269 switch (fwd.flag()) {
270 case SPECIFIC:
271 return processSpecific(fwd);
272 case VERSATILE:
273 return processVersatile(fwd);
274 default:
275 fail(fwd, ObjectiveError.UNKNOWN);
276 log.warn("Unknown forwarding flag {}", fwd.flag());
277 }
278 return Collections.emptySet();
279 }
280
281 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
282 log.debug("Processing versatile forwarding objective");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530283 TrafficSelector selector = fwd.selector();
284 TrafficTreatment tb = fwd.treatment();
285 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority())
286 .forDevice(deviceId).withSelector(selector).withTreatment(tb).makeTemporary(TIME_OUT);
287 ruleBuilder.withPriority(fwd.priority());
288 if (fwd.priority() == 100) {
289 ruleBuilder.forTable(ENCAP_OUTPUT_TABLE);
290 } else if (fwd.priority() == 200) {
291 ruleBuilder.forTable(TUN_SEND_TABLE);
292 } else {
293 ruleBuilder.forTable(CLASSIFIER_TABLE);
294 }
295
296 if (fwd.permanent()) {
297 ruleBuilder.makePermanent();
298 }
299 return Collections.singletonList(ruleBuilder.build());
samuel3b2743d2015-07-29 10:44:30 +0800300 }
301
302 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
303 log.debug("Processing specific forwarding objective");
304 TrafficSelector selector = fwd.selector();
305 TrafficTreatment tb = fwd.treatment();
306 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
307 .fromApp(fwd.appId()).withPriority(fwd.priority())
308 .forDevice(deviceId).withSelector(selector)
CNluciusa66c3972015-09-06 20:31:29 +0800309 .withTreatment(tb).makeTemporary(TIME_OUT);
310 ruleBuilder.withPriority(fwd.priority());
samuel3b2743d2015-07-29 10:44:30 +0800311 if (fwd.permanent()) {
312 ruleBuilder.makePermanent();
313 }
lishuai4fa26342015-12-03 13:01:39 +0800314 Integer transition = null;
315 Integer forTable = null;
316 // MAC table flow rules
Bob zhoue9795fd2016-05-12 20:18:45 +0800317 if (selector.getCriterion(Type.TUNNEL_ID) != null
318 && (selector.getCriterion(Type.ETH_DST) != null
319 || selector.getCriterion(Type.ETH_SRC) != null)) {
lishuai4fa26342015-12-03 13:01:39 +0800320 forTable = MAC_TABLE;
321 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
322 }
323 // CLASSIFIER table flow rules
324 if (selector.getCriterion(Type.IN_PORT) != null) {
325 forTable = CLASSIFIER_TABLE;
326 if (selector.getCriterion(Type.ETH_SRC) != null
327 && selector.getCriterion(Type.ETH_DST) != null) {
328 transition = L3FWD_TABLE;
329 } else if (selector.getCriterion(Type.ETH_SRC) != null
330 || selector.getCriterion(Type.TUNNEL_ID) != null) {
331 transition = MAC_TABLE;
332 } else if (selector.getCriterion(Type.IPV4_DST) != null) {
333 transition = DNAT_TABLE;
Bob zhoue9795fd2016-05-12 20:18:45 +0800334 } else if (selector.getCriterion(Type.ETH_TYPE) != null
335 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
336 .matchEthType(EtherType.ARP.ethType().toShort()))) {
337 transition = ARP_TABLE;
lishuai4fa26342015-12-03 13:01:39 +0800338 }
339 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
340 }
341 // ARP table flow rules
342 if (selector.getCriterion(Type.ETH_TYPE) != null
343 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
344 .matchEthType(EtherType.ARP.ethType().toShort()))) {
345 // CLASSIFIER table arp flow rules
346 if (selector.getCriterion(Type.TUNNEL_ID) == null) {
Bob zhoue9795fd2016-05-12 20:18:45 +0800347 if (selector.getCriterion(Type.ARP_OP) != null) {
348 forTable = CLASSIFIER_TABLE;
349 return reassemblyFlowRule(ruleBuilder, tb, null, forTable);
350 }
lishuai4fa26342015-12-03 13:01:39 +0800351 transition = ARP_TABLE;
352 forTable = CLASSIFIER_TABLE;
353 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
354 }
355 forTable = ARP_TABLE;
356 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
357 }
Bob zhoue9795fd2016-05-12 20:18:45 +0800358 // SNAT table flow rules
359 if (selector.getCriterion(Type.TUNNEL_ID) != null
360 && selector.getCriterion(Type.IPV4_SRC) != null) {
361 transition = MAC_TABLE;
362 forTable = SNAT_TABLE;
363 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
364 }
lishuai4fa26342015-12-03 13:01:39 +0800365 // L3FWD table flow rules
366 if (selector.getCriterion(Type.TUNNEL_ID) != null
367 && selector.getCriterion(Type.IPV4_DST) != null) {
368 transition = MAC_TABLE;
369 forTable = L3FWD_TABLE;
370 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
371 }
372 // DNAT table flow rules
373 if (selector.getCriterion(Type.IPV4_DST) != null) {
Bob zhoue9795fd2016-05-12 20:18:45 +0800374 IPCriterion ipCriterion = (IPCriterion) selector.getCriterion(Type.IPV4_DST);
375 IpPrefix ipPrefix = ipCriterion.ip();
376 // specific CLASSIFIER table flow rules for userdata
377 if (ipPrefix.address().equals(IpAddress.valueOf(USERDATA_IP))) {
378 forTable = CLASSIFIER_TABLE;
379 transition = MAC_TABLE;
380 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
381 }
lishuai4fa26342015-12-03 13:01:39 +0800382 transition = L3FWD_TABLE;
383 forTable = DNAT_TABLE;
384 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
385 }
lishuai4fa26342015-12-03 13:01:39 +0800386 return Collections.singletonList(ruleBuilder.build());
387 }
388
389 private Collection<FlowRule> reassemblyFlowRule(FlowRule.Builder ruleBuilder,
390 TrafficTreatment tb,
391 Integer transition,
392 Integer forTable) {
393 if (transition != null) {
394 TrafficTreatment.Builder newTraffic = DefaultTrafficTreatment
395 .builder();
samuel3b2743d2015-07-29 10:44:30 +0800396 tb.allInstructions().forEach(t -> newTraffic.add(t));
lishuai4fa26342015-12-03 13:01:39 +0800397 newTraffic.transition(transition);
samuel3b2743d2015-07-29 10:44:30 +0800398 ruleBuilder.withTreatment(newTraffic.build());
lishuai4fa26342015-12-03 13:01:39 +0800399 } else {
400 ruleBuilder.withTreatment(tb);
401 }
402 if (forTable != null) {
403 ruleBuilder.forTable(forTable);
samuel3b2743d2015-07-29 10:44:30 +0800404 }
405 return Collections.singletonList(ruleBuilder.build());
406 }
407
408 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800409 obj.context().ifPresent(context -> context.onError(obj, error));
samuel3b2743d2015-07-29 10:44:30 +0800410 }
411
412 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800413 obj.context().ifPresent(context -> context.onSuccess(obj));
samuel3b2743d2015-07-29 10:44:30 +0800414 }
Bob zhoue9795fd2016-05-12 20:18:45 +0800415}