blob: 74cb75625c1649faba3a2a209a690a85faa92e3f [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;
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;
lishuai4fa26342015-12-03 13:01:39 +080073 private static final int ARP_TABLE = 10;
74 private static final int DNAT_TABLE = 20;
75 private static final int L3FWD_TABLE = 30;
76 private static final int SNAT_TABLE = 40;
lishuai4d6a0ee2015-10-19 19:05:48 +080077 private static final int MAC_TABLE = 50;
78 private static final int TABLE_MISS_PRIORITY = 0;
Bob zhoue9795fd2016-05-12 20:18:45 +080079 private static final String USERDATA_IP = "169.254.169.254";
samuel3b2743d2015-07-29 10:44:30 +080080
81 @Override
82 public void init(DeviceId deviceId, PipelinerContext context) {
CNluciusa66c3972015-09-06 20:31:29 +080083 super.init(deviceId, context);
samuel3b2743d2015-07-29 10:44:30 +080084 this.serviceDirectory = context.directory();
85 this.deviceId = deviceId;
86
87 coreService = serviceDirectory.get(CoreService.class);
88 flowRuleService = serviceDirectory.get(FlowRuleService.class);
89 flowObjectiveStore = context.store();
lishuai4d6a0ee2015-10-19 19:05:48 +080090 appId = coreService
samuel3b2743d2015-07-29 10:44:30 +080091 .registerApplication("org.onosproject.driver.OpenVSwitchPipeline");
lishuai4d6a0ee2015-10-19 19:05:48 +080092 initializePipeline();
samuel3b2743d2015-07-29 10:44:30 +080093 }
94
95 @Override
96 public void filter(FilteringObjective filteringObjective) {
CNluciusa66c3972015-09-06 20:31:29 +080097 super.filter(filteringObjective);
samuel3b2743d2015-07-29 10:44:30 +080098 }
99
100 @Override
101 public void forward(ForwardingObjective fwd) {
CNluciusa66c3972015-09-06 20:31:29 +0800102 if (!VTN_APP_ID.equals(fwd.appId().name())) {
103 super.forward(fwd);
104 return;
105 }
samuel3b2743d2015-07-29 10:44:30 +0800106 Collection<FlowRule> rules;
107 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations
108 .builder();
109
110 rules = processForward(fwd);
111 switch (fwd.op()) {
112 case ADD:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800113 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800114 .forEach(flowOpsBuilder::add);
115 break;
116 case REMOVE:
Sho SHIMIZU45906042016-01-13 23:05:54 -0800117 rules.stream().filter(Objects::nonNull)
samuel3b2743d2015-07-29 10:44:30 +0800118 .forEach(flowOpsBuilder::remove);
119 break;
120 default:
121 fail(fwd, ObjectiveError.UNKNOWN);
122 log.warn("Unknown forwarding type {}", fwd.op());
123 }
124
125 flowRuleService.apply(flowOpsBuilder
126 .build(new FlowRuleOperationsContext() {
127 @Override
128 public void onSuccess(FlowRuleOperations ops) {
129 pass(fwd);
130 }
131
132 @Override
133 public void onError(FlowRuleOperations ops) {
134 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
135 }
136 }));
137 }
138
139 @Override
140 public void next(NextObjective nextObjective) {
CNluciusa66c3972015-09-06 20:31:29 +0800141 super.next(nextObjective);
samuel3b2743d2015-07-29 10:44:30 +0800142 }
143
lishuai4d6a0ee2015-10-19 19:05:48 +0800144 private void initializePipeline() {
145 processClassifierTable(true);
lishuai4fa26342015-12-03 13:01:39 +0800146 processArpTable(true);
147 processDnatTable(true);
148 processL3fwdTable(true);
149 processSnatTable(true);
lishuai4d6a0ee2015-10-19 19:05:48 +0800150 processMacTable(true);
151 }
152
153 private void processClassifierTable(boolean install) {
154 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
155 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
156
157 treatment.transition(MAC_TABLE);
158
159 FlowRule rule;
160 rule = DefaultFlowRule.builder().forDevice(deviceId)
161 .withSelector(selector.build())
162 .withTreatment(treatment.build())
163 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
164 .makePermanent().forTable(CLASSIFIER_TABLE).build();
165
166 applyRules(install, rule);
167 }
168
lishuai4fa26342015-12-03 13:01:39 +0800169 private void processArpTable(boolean install) {
170 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
171 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
172
173 treatment.transition(MAC_TABLE);
174
175 FlowRule rule;
176 rule = DefaultFlowRule.builder().forDevice(deviceId)
177 .withSelector(selector.build())
178 .withTreatment(treatment.build())
179 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
180 .makePermanent().forTable(ARP_TABLE).build();
181
182 applyRules(install, rule);
183 }
184
185 private void processDnatTable(boolean install) {
186 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
187 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
188
189 treatment.transition(MAC_TABLE);
190
191 FlowRule rule;
192 rule = DefaultFlowRule.builder().forDevice(deviceId)
193 .withSelector(selector.build())
194 .withTreatment(treatment.build())
195 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
196 .makePermanent().forTable(DNAT_TABLE).build();
197
198 applyRules(install, rule);
199 }
200
201 private void processL3fwdTable(boolean install) {
202 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
203 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
204
205 treatment.transition(SNAT_TABLE);
206
207 FlowRule rule;
208 rule = DefaultFlowRule.builder().forDevice(deviceId)
209 .withSelector(selector.build())
210 .withTreatment(treatment.build())
211 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
212 .makePermanent().forTable(L3FWD_TABLE).build();
213
214 applyRules(install, rule);
215 }
216
217 private void processSnatTable(boolean install) {
218 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
219 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
220
221 treatment.transition(MAC_TABLE);
Bob zhoue9795fd2016-05-12 20:18:45 +0800222 treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
lishuai4fa26342015-12-03 13:01:39 +0800223 FlowRule rule;
224 rule = DefaultFlowRule.builder().forDevice(deviceId)
225 .withSelector(selector.build())
226 .withTreatment(treatment.build())
227 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
228 .makePermanent().forTable(SNAT_TABLE).build();
229
230 applyRules(install, rule);
231 }
232
lishuai4d6a0ee2015-10-19 19:05:48 +0800233 private void processMacTable(boolean install) {
234 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
235 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
236
237 treatment.drop();
238
239 FlowRule rule;
240 rule = DefaultFlowRule.builder().forDevice(deviceId)
241 .withSelector(selector.build())
242 .withTreatment(treatment.build())
243 .withPriority(TABLE_MISS_PRIORITY).fromApp(appId)
244 .makePermanent().forTable(MAC_TABLE).build();
245
246 applyRules(install, rule);
247 }
248
249 private void applyRules(boolean install, FlowRule rule) {
250 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
251
252 ops = install ? ops.add(rule) : ops.remove(rule);
253 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
254 @Override
255 public void onSuccess(FlowRuleOperations ops) {
256 log.info("ONOSW provisioned " + rule.tableId() + " table");
257 }
258
259 @Override
260 public void onError(FlowRuleOperations ops) {
261 log.info("ONOSW failed to provision " + rule.tableId() + " table");
262 }
263 }));
264 }
265
samuel3b2743d2015-07-29 10:44:30 +0800266 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
267 switch (fwd.flag()) {
268 case SPECIFIC:
269 return processSpecific(fwd);
270 case VERSATILE:
271 return processVersatile(fwd);
272 default:
273 fail(fwd, ObjectiveError.UNKNOWN);
274 log.warn("Unknown forwarding flag {}", fwd.flag());
275 }
276 return Collections.emptySet();
277 }
278
279 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
280 log.debug("Processing versatile forwarding objective");
281 return Collections.emptyList();
282 }
283
284 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
285 log.debug("Processing specific forwarding objective");
286 TrafficSelector selector = fwd.selector();
287 TrafficTreatment tb = fwd.treatment();
288 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
289 .fromApp(fwd.appId()).withPriority(fwd.priority())
290 .forDevice(deviceId).withSelector(selector)
CNluciusa66c3972015-09-06 20:31:29 +0800291 .withTreatment(tb).makeTemporary(TIME_OUT);
292 ruleBuilder.withPriority(fwd.priority());
samuel3b2743d2015-07-29 10:44:30 +0800293 if (fwd.permanent()) {
294 ruleBuilder.makePermanent();
295 }
lishuai4fa26342015-12-03 13:01:39 +0800296 Integer transition = null;
297 Integer forTable = null;
298 // MAC table flow rules
Bob zhoue9795fd2016-05-12 20:18:45 +0800299 if (selector.getCriterion(Type.TUNNEL_ID) != null
300 && (selector.getCriterion(Type.ETH_DST) != null
301 || selector.getCriterion(Type.ETH_SRC) != null)) {
lishuai4fa26342015-12-03 13:01:39 +0800302 forTable = MAC_TABLE;
303 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
304 }
305 // CLASSIFIER table flow rules
306 if (selector.getCriterion(Type.IN_PORT) != null) {
307 forTable = CLASSIFIER_TABLE;
308 if (selector.getCriterion(Type.ETH_SRC) != null
309 && selector.getCriterion(Type.ETH_DST) != null) {
310 transition = L3FWD_TABLE;
311 } else if (selector.getCriterion(Type.ETH_SRC) != null
312 || selector.getCriterion(Type.TUNNEL_ID) != null) {
313 transition = MAC_TABLE;
314 } else if (selector.getCriterion(Type.IPV4_DST) != null) {
315 transition = DNAT_TABLE;
Bob zhoue9795fd2016-05-12 20:18:45 +0800316 } else if (selector.getCriterion(Type.ETH_TYPE) != null
317 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
318 .matchEthType(EtherType.ARP.ethType().toShort()))) {
319 transition = ARP_TABLE;
lishuai4fa26342015-12-03 13:01:39 +0800320 }
321 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
322 }
323 // ARP table flow rules
324 if (selector.getCriterion(Type.ETH_TYPE) != null
325 && selector.getCriterion(Type.ETH_TYPE).equals(Criteria
326 .matchEthType(EtherType.ARP.ethType().toShort()))) {
327 // CLASSIFIER table arp flow rules
328 if (selector.getCriterion(Type.TUNNEL_ID) == null) {
Bob zhoue9795fd2016-05-12 20:18:45 +0800329 if (selector.getCriterion(Type.ARP_OP) != null) {
330 forTable = CLASSIFIER_TABLE;
331 return reassemblyFlowRule(ruleBuilder, tb, null, forTable);
332 }
lishuai4fa26342015-12-03 13:01:39 +0800333 transition = ARP_TABLE;
334 forTable = CLASSIFIER_TABLE;
335 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
336 }
337 forTable = ARP_TABLE;
338 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
339 }
Bob zhoue9795fd2016-05-12 20:18:45 +0800340 // 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 }
lishuai4fa26342015-12-03 13:01:39 +0800347 // L3FWD table flow rules
348 if (selector.getCriterion(Type.TUNNEL_ID) != null
349 && selector.getCriterion(Type.IPV4_DST) != null) {
350 transition = MAC_TABLE;
351 forTable = L3FWD_TABLE;
352 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
353 }
354 // DNAT table flow rules
355 if (selector.getCriterion(Type.IPV4_DST) != null) {
Bob zhoue9795fd2016-05-12 20:18:45 +0800356 IPCriterion ipCriterion = (IPCriterion) selector.getCriterion(Type.IPV4_DST);
357 IpPrefix ipPrefix = ipCriterion.ip();
358 // specific CLASSIFIER table flow rules for userdata
359 if (ipPrefix.address().equals(IpAddress.valueOf(USERDATA_IP))) {
360 forTable = CLASSIFIER_TABLE;
361 transition = MAC_TABLE;
362 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
363 }
lishuai4fa26342015-12-03 13:01:39 +0800364 transition = L3FWD_TABLE;
365 forTable = DNAT_TABLE;
366 return reassemblyFlowRule(ruleBuilder, tb, transition, forTable);
367 }
lishuai4fa26342015-12-03 13:01:39 +0800368 return Collections.singletonList(ruleBuilder.build());
369 }
370
371 private Collection<FlowRule> reassemblyFlowRule(FlowRule.Builder ruleBuilder,
372 TrafficTreatment tb,
373 Integer transition,
374 Integer forTable) {
375 if (transition != null) {
376 TrafficTreatment.Builder newTraffic = DefaultTrafficTreatment
377 .builder();
samuel3b2743d2015-07-29 10:44:30 +0800378 tb.allInstructions().forEach(t -> newTraffic.add(t));
lishuai4fa26342015-12-03 13:01:39 +0800379 newTraffic.transition(transition);
samuel3b2743d2015-07-29 10:44:30 +0800380 ruleBuilder.withTreatment(newTraffic.build());
lishuai4fa26342015-12-03 13:01:39 +0800381 } else {
382 ruleBuilder.withTreatment(tb);
383 }
384 if (forTable != null) {
385 ruleBuilder.forTable(forTable);
samuel3b2743d2015-07-29 10:44:30 +0800386 }
387 return Collections.singletonList(ruleBuilder.build());
388 }
389
390 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800391 obj.context().ifPresent(context -> context.onError(obj, error));
samuel3b2743d2015-07-29 10:44:30 +0800392 }
393
394 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800395 obj.context().ifPresent(context -> context.onSuccess(obj));
samuel3b2743d2015-07-29 10:44:30 +0800396 }
Bob zhoue9795fd2016-05-12 20:18:45 +0800397}