blob: 02522cf106df78efb64e98a0275fee31f138655f [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
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 */
Saurav Das558afec2015-05-31 17:12:48 -070016package org.onosproject.driver.pipeline;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
Saurav Das2857f382015-11-03 14:39:27 -080020import java.util.ArrayList;
Saurav Das8a0732e2015-11-20 15:27:53 -080021import java.util.Collection;
Saurav Das4f980082015-11-05 13:39:15 -080022import java.util.Collections;
Saurav Das8a0732e2015-11-20 15:27:53 -080023import java.util.Deque;
Saurav Das2857f382015-11-03 14:39:27 -080024import java.util.List;
Saurav Das4f980082015-11-05 13:39:15 -080025import java.util.Set;
26import java.util.concurrent.ConcurrentHashMap;
Saurav Das2857f382015-11-03 14:39:27 -080027
Saurav Das8a0732e2015-11-20 15:27:53 -080028import org.onlab.packet.Ethernet;
Saurav Das2857f382015-11-03 14:39:27 -080029import org.onlab.packet.VlanId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.net.Port;
32import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080033import org.onosproject.net.behaviour.NextGroup;
Saurav Das558afec2015-05-31 17:12:48 -070034import org.onosproject.net.flow.DefaultFlowRule;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.FlowRule;
38import org.onosproject.net.flow.FlowRuleOperations;
39import org.onosproject.net.flow.FlowRuleOperationsContext;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080042import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080043import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080044import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080045import org.onosproject.net.flow.criteria.EthTypeCriterion;
46import org.onosproject.net.flow.criteria.IPCriterion;
47import org.onosproject.net.flow.criteria.MplsBosCriterion;
48import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080049import org.onosproject.net.flow.criteria.PortCriterion;
50import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080051import org.onosproject.net.flow.instructions.Instruction;
52import org.onosproject.net.flowobjective.ForwardingObjective;
53import org.onosproject.net.flowobjective.ObjectiveError;
54import org.onosproject.net.group.Group;
55import org.onosproject.net.group.GroupKey;
Saurav Das558afec2015-05-31 17:12:48 -070056import org.slf4j.Logger;
57
58
59/**
Saurav Das822c4e22015-10-23 10:51:11 -070060 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das558afec2015-05-31 17:12:48 -070061 * The software switch is the CPqD OF 1.3 switch.
62 */
Saurav Das822c4e22015-10-23 10:51:11 -070063public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070064
65 private final Logger log = getLogger(getClass());
66
Saurav Das4ce45962015-11-24 23:21:05 -080067 /*
68 * Cpqd emulation does not require the non-OF standard rules for
69 * matching untagged packets.
70 *
71 * (non-Javadoc)
72 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
73 */
74
Saurav Das558afec2015-05-31 17:12:48 -070075 @Override
Saurav Das2857f382015-11-03 14:39:27 -080076 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
77 VlanIdCriterion vidCriterion,
78 VlanId assignedVlan,
79 ApplicationId applicationId) {
80 List<FlowRule> rules = new ArrayList<FlowRule>();
81 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
82 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
83 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -080084 treatment.transition(TMAC_TABLE);
85
86 VlanId storeVlan = null;
Saurav Das2857f382015-11-03 14:39:27 -080087 if (vidCriterion.vlanId() == VlanId.NONE) {
88 // untagged packets are assigned vlans
89 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das4f980082015-11-05 13:39:15 -080090 storeVlan = assignedVlan;
91 } else {
92 storeVlan = vidCriterion.vlanId();
Saurav Das2857f382015-11-03 14:39:27 -080093 }
Saurav Das2857f382015-11-03 14:39:27 -080094
95 // ofdpa cannot match on ALL portnumber, so we need to use separate
96 // rules for each port.
97 List<PortNumber> portnums = new ArrayList<PortNumber>();
98 if (portCriterion.port() == PortNumber.ALL) {
99 for (Port port : deviceService.getPorts(deviceId)) {
100 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
101 portnums.add(port.number());
102 }
103 }
104 } else {
105 portnums.add(portCriterion.port());
106 }
Saurav Das4f980082015-11-05 13:39:15 -0800107
Saurav Das2857f382015-11-03 14:39:27 -0800108 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800109 // update storage
110 port2Vlan.put(pnum, storeVlan);
111 Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan);
112 if (vlanPorts == null) {
113 vlanPorts = Collections.newSetFromMap(
114 new ConcurrentHashMap<PortNumber, Boolean>());
115 vlanPorts.add(pnum);
116 vlan2Port.put(storeVlan, vlanPorts);
117 } else {
118 vlanPorts.add(pnum);
119 }
120 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800121 selector.matchInPort(pnum);
122 FlowRule rule = DefaultFlowRule.builder()
123 .forDevice(deviceId)
124 .withSelector(selector.build())
125 .withTreatment(treatment.build())
126 .withPriority(DEFAULT_PRIORITY)
127 .fromApp(applicationId)
128 .makePermanent()
129 .forTable(VLAN_TABLE).build();
130 rules.add(rule);
131 }
132 return rules;
133 }
134
Saurav Das4ce45962015-11-24 23:21:05 -0800135 /*
136 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
137 * Workaround requires popping off the VLAN tags in the TMAC table.
138 *
139 * (non-Javadoc)
140 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
141 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800142 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800143 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
144 EthCriterion ethCriterion,
145 VlanIdCriterion vidCriterion,
146 VlanId assignedVlan,
147 ApplicationId applicationId) {
148 //handling untagged packets via assigned VLAN
149 if (vidCriterion.vlanId() == VlanId.NONE) {
150 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
151 }
152 // ofdpa cannot match on ALL portnumber, so we need to use separate
153 // rules for each port.
154 List<PortNumber> portnums = new ArrayList<PortNumber>();
155 if (portCriterion.port() == PortNumber.ALL) {
156 for (Port port : deviceService.getPorts(deviceId)) {
157 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
158 portnums.add(port.number());
159 }
160 }
161 } else {
162 portnums.add(portCriterion.port());
163 }
164
165 List<FlowRule> rules = new ArrayList<FlowRule>();
166 for (PortNumber pnum : portnums) {
167 // for unicast IP packets
168 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
169 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
170 selector.matchInPort(pnum);
171 selector.matchVlanId(vidCriterion.vlanId());
172 selector.matchEthType(Ethernet.TYPE_IPV4);
173 selector.matchEthDst(ethCriterion.mac());
174 /*
175 * Note: CpqD switches do not handle MPLS-related operation properly
176 * for a packet with VLAN tag. We pop VLAN here as a workaround.
177 * Side effect: HostService learns redundant hosts with same MAC but
178 * different VLAN. No known side effect on the network reachability.
179 */
180 treatment.popVlan();
181 treatment.transition(UNICAST_ROUTING_TABLE);
182 FlowRule rule = DefaultFlowRule.builder()
183 .forDevice(deviceId)
184 .withSelector(selector.build())
185 .withTreatment(treatment.build())
186 .withPriority(DEFAULT_PRIORITY)
187 .fromApp(applicationId)
188 .makePermanent()
189 .forTable(TMAC_TABLE).build();
190 rules.add(rule);
191 //for MPLS packets
192 selector = DefaultTrafficSelector.builder();
193 treatment = DefaultTrafficTreatment.builder();
194 selector.matchInPort(pnum);
195 selector.matchVlanId(vidCriterion.vlanId());
196 selector.matchEthType(Ethernet.MPLS_UNICAST);
197 selector.matchEthDst(ethCriterion.mac());
198 // workaround here again
199 treatment.popVlan();
200 treatment.transition(MPLS_TABLE_0);
201 rule = DefaultFlowRule.builder()
202 .forDevice(deviceId)
203 .withSelector(selector.build())
204 .withTreatment(treatment.build())
205 .withPriority(DEFAULT_PRIORITY)
206 .fromApp(applicationId)
207 .makePermanent()
208 .forTable(TMAC_TABLE).build();
209 rules.add(rule);
210 }
211 return rules;
212 }
213
214 /*
215 * Cpqd emulation allows MPLS ecmp.
216 *
217 * (non-Javadoc)
218 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
219 */
220 @Override
221 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800222 TrafficSelector selector = fwd.selector();
223 EthTypeCriterion ethType =
224 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
225 if ((ethType == null) ||
226 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
227 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800228 log.warn("processSpecific: Unsupported forwarding objective criteria"
229 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800230 fail(fwd, ObjectiveError.UNSUPPORTED);
231 return Collections.emptySet();
232 }
233
234 int forTableId = -1;
235 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
236 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
237 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
238 .matchIPDst(((IPCriterion)
239 selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
240 forTableId = UNICAST_ROUTING_TABLE;
Saurav Das4ce45962015-11-24 23:21:05 -0800241 log.debug("processing IPv4 specific forwarding objective {} -> next:{}"
242 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800243 } else {
244 filteredSelector
245 .matchEthType(Ethernet.MPLS_UNICAST)
246 .matchMplsLabel(((MplsCriterion)
247 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
248 MplsBosCriterion bos = (MplsBosCriterion) selector
249 .getCriterion(Criterion.Type.MPLS_BOS);
250 if (bos != null) {
251 filteredSelector.matchMplsBos(bos.mplsBos());
252 }
253 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800254 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
255 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800256 }
257
258 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
259 if (fwd.treatment() != null) {
260 for (Instruction i : fwd.treatment().allInstructions()) {
261 tb.add(i);
262 }
263 }
264
265 if (fwd.nextId() != null) {
266 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
267 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
268 // we only need the top level group's key to point the flow to it
269 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
270 if (group == null) {
271 log.warn("The group left!");
272 fail(fwd, ObjectiveError.GROUPMISSING);
273 return Collections.emptySet();
274 }
275 tb.deferred().group(group.id());
276 }
277 tb.transition(ACL_TABLE);
278 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
279 .fromApp(fwd.appId())
280 .withPriority(fwd.priority())
281 .forDevice(deviceId)
282 .withSelector(filteredSelector.build())
283 .withTreatment(tb.build())
284 .forTable(forTableId);
285
286 if (fwd.permanent()) {
287 ruleBuilder.makePermanent();
288 } else {
289 ruleBuilder.makeTemporary(fwd.timeout());
290 }
291
292 return Collections.singletonList(ruleBuilder.build());
293 }
294
Saurav Das2857f382015-11-03 14:39:27 -0800295 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700296 protected void initializePipeline() {
297 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800298 // vlan table processing not required, as default is to drop packets
299 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700300 processTmacTable();
301 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800302 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700303 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700304 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700305 }
306
Saurav Das558afec2015-05-31 17:12:48 -0700307 protected void processPortTable() {
308 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
309 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
310 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
311 treatment.transition(VLAN_TABLE);
312 FlowRule tmisse = DefaultFlowRule.builder()
313 .forDevice(deviceId)
314 .withSelector(selector.build())
315 .withTreatment(treatment.build())
316 .withPriority(LOWEST_PRIORITY)
317 .fromApp(driverId)
318 .makePermanent()
319 .forTable(PORT_TABLE).build();
320 ops = ops.add(tmisse);
321
322 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
323 @Override
324 public void onSuccess(FlowRuleOperations ops) {
325 log.info("Initialized port table");
326 }
327
328 @Override
329 public void onError(FlowRuleOperations ops) {
330 log.info("Failed to initialize port table");
331 }
332 }));
333 }
334
Saurav Das558afec2015-05-31 17:12:48 -0700335 protected void processTmacTable() {
336 //table miss entry
337 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
338 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
339 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
340 selector = DefaultTrafficSelector.builder();
341 treatment = DefaultTrafficTreatment.builder();
342 treatment.transition(BRIDGING_TABLE);
343 FlowRule rule = DefaultFlowRule.builder()
344 .forDevice(deviceId)
345 .withSelector(selector.build())
346 .withTreatment(treatment.build())
347 .withPriority(LOWEST_PRIORITY)
348 .fromApp(driverId)
349 .makePermanent()
350 .forTable(TMAC_TABLE).build();
351 ops = ops.add(rule);
352 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
353 @Override
354 public void onSuccess(FlowRuleOperations ops) {
355 log.info("Initialized tmac table");
356 }
357
358 @Override
359 public void onError(FlowRuleOperations ops) {
360 log.info("Failed to initialize tmac table");
361 }
362 }));
363 }
364
Saurav Das558afec2015-05-31 17:12:48 -0700365 protected void processIpTable() {
366 //table miss entry
367 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
368 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
369 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
370 selector = DefaultTrafficSelector.builder();
371 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800372 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700373 treatment.transition(ACL_TABLE);
374 FlowRule rule = DefaultFlowRule.builder()
375 .forDevice(deviceId)
376 .withSelector(selector.build())
377 .withTreatment(treatment.build())
378 .withPriority(LOWEST_PRIORITY)
379 .fromApp(driverId)
380 .makePermanent()
381 .forTable(UNICAST_ROUTING_TABLE).build();
382 ops = ops.add(rule);
383 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
384 @Override
385 public void onSuccess(FlowRuleOperations ops) {
386 log.info("Initialized IP table");
387 }
388
389 @Override
390 public void onError(FlowRuleOperations ops) {
391 log.info("Failed to initialize unicast IP table");
392 }
393 }));
394 }
395
Saurav Das2857f382015-11-03 14:39:27 -0800396 protected void processMplsTable() {
397 //table miss entry
398 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
399 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
400 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
401 selector = DefaultTrafficSelector.builder();
402 treatment = DefaultTrafficTreatment.builder();
403 treatment.transition(MPLS_TABLE_1);
404 FlowRule rule = DefaultFlowRule.builder()
405 .forDevice(deviceId)
406 .withSelector(selector.build())
407 .withTreatment(treatment.build())
408 .withPriority(LOWEST_PRIORITY)
409 .fromApp(driverId)
410 .makePermanent()
411 .forTable(MPLS_TABLE_0).build();
412 ops = ops.add(rule);
413
414 treatment.transition(ACL_TABLE);
415 rule = DefaultFlowRule.builder()
416 .forDevice(deviceId)
417 .withSelector(selector.build())
418 .withTreatment(treatment.build())
419 .withPriority(LOWEST_PRIORITY)
420 .fromApp(driverId)
421 .makePermanent()
422 .forTable(MPLS_TABLE_1).build();
423 ops = ops.add(rule);
424
425 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
426 @Override
427 public void onSuccess(FlowRuleOperations ops) {
428 log.info("Initialized MPLS tables");
429 }
430
431 @Override
432 public void onError(FlowRuleOperations ops) {
433 log.info("Failed to initialize MPLS tables");
434 }
435 }));
436 }
437
Saurav Das558afec2015-05-31 17:12:48 -0700438 private void processBridgingTable() {
439 //table miss entry
440 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
441 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
442 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
443 selector = DefaultTrafficSelector.builder();
444 treatment = DefaultTrafficTreatment.builder();
445 treatment.transition(ACL_TABLE);
446 FlowRule rule = DefaultFlowRule.builder()
447 .forDevice(deviceId)
448 .withSelector(selector.build())
449 .withTreatment(treatment.build())
450 .withPriority(LOWEST_PRIORITY)
451 .fromApp(driverId)
452 .makePermanent()
453 .forTable(BRIDGING_TABLE).build();
454 ops = ops.add(rule);
455 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
456 @Override
457 public void onSuccess(FlowRuleOperations ops) {
458 log.info("Initialized Bridging table");
459 }
460
461 @Override
462 public void onError(FlowRuleOperations ops) {
463 log.info("Failed to initialize Bridging table");
464 }
465 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700466 }
Saurav Das558afec2015-05-31 17:12:48 -0700467
Saurav Dasa07f2032015-10-19 14:37:36 -0700468 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700469 //table miss entry - catch all to executed action-set
470 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
471 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
472 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
473 selector = DefaultTrafficSelector.builder();
474 treatment = DefaultTrafficTreatment.builder();
475 FlowRule rule = DefaultFlowRule.builder()
476 .forDevice(deviceId)
477 .withSelector(selector.build())
478 .withTreatment(treatment.build())
479 .withPriority(LOWEST_PRIORITY)
480 .fromApp(driverId)
481 .makePermanent()
482 .forTable(ACL_TABLE).build();
483 ops = ops.add(rule);
484 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
485 @Override
486 public void onSuccess(FlowRuleOperations ops) {
487 log.info("Initialized Acl table");
488 }
489
490 @Override
491 public void onError(FlowRuleOperations ops) {
492 log.info("Failed to initialize Acl table");
493 }
494 }));
Saurav Das558afec2015-05-31 17:12:48 -0700495 }
496
497}