blob: 82aa55eb63168484a577997af155bc959454f585 [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()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800261 /*
262 * NOTE: OF-DPA does not support immediate instruction in
263 * L3 unicast and MPLS table.
264 */
265 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800266 }
267 }
268
269 if (fwd.nextId() != null) {
270 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
271 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
272 // we only need the top level group's key to point the flow to it
273 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
274 if (group == null) {
275 log.warn("The group left!");
276 fail(fwd, ObjectiveError.GROUPMISSING);
277 return Collections.emptySet();
278 }
279 tb.deferred().group(group.id());
280 }
281 tb.transition(ACL_TABLE);
282 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
283 .fromApp(fwd.appId())
284 .withPriority(fwd.priority())
285 .forDevice(deviceId)
286 .withSelector(filteredSelector.build())
287 .withTreatment(tb.build())
288 .forTable(forTableId);
289
290 if (fwd.permanent()) {
291 ruleBuilder.makePermanent();
292 } else {
293 ruleBuilder.makeTemporary(fwd.timeout());
294 }
295
296 return Collections.singletonList(ruleBuilder.build());
297 }
298
Saurav Das2857f382015-11-03 14:39:27 -0800299 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700300 protected void initializePipeline() {
301 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800302 // vlan table processing not required, as default is to drop packets
303 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700304 processTmacTable();
305 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800306 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700307 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700308 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700309 }
310
Saurav Das558afec2015-05-31 17:12:48 -0700311 protected void processPortTable() {
312 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
313 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
314 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
315 treatment.transition(VLAN_TABLE);
316 FlowRule tmisse = DefaultFlowRule.builder()
317 .forDevice(deviceId)
318 .withSelector(selector.build())
319 .withTreatment(treatment.build())
320 .withPriority(LOWEST_PRIORITY)
321 .fromApp(driverId)
322 .makePermanent()
323 .forTable(PORT_TABLE).build();
324 ops = ops.add(tmisse);
325
326 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
327 @Override
328 public void onSuccess(FlowRuleOperations ops) {
329 log.info("Initialized port table");
330 }
331
332 @Override
333 public void onError(FlowRuleOperations ops) {
334 log.info("Failed to initialize port table");
335 }
336 }));
337 }
338
Saurav Das558afec2015-05-31 17:12:48 -0700339 protected void processTmacTable() {
340 //table miss entry
341 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
342 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
343 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
344 selector = DefaultTrafficSelector.builder();
345 treatment = DefaultTrafficTreatment.builder();
346 treatment.transition(BRIDGING_TABLE);
347 FlowRule rule = DefaultFlowRule.builder()
348 .forDevice(deviceId)
349 .withSelector(selector.build())
350 .withTreatment(treatment.build())
351 .withPriority(LOWEST_PRIORITY)
352 .fromApp(driverId)
353 .makePermanent()
354 .forTable(TMAC_TABLE).build();
355 ops = ops.add(rule);
356 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
357 @Override
358 public void onSuccess(FlowRuleOperations ops) {
359 log.info("Initialized tmac table");
360 }
361
362 @Override
363 public void onError(FlowRuleOperations ops) {
364 log.info("Failed to initialize tmac table");
365 }
366 }));
367 }
368
Saurav Das558afec2015-05-31 17:12:48 -0700369 protected void processIpTable() {
370 //table miss entry
371 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
372 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
373 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
374 selector = DefaultTrafficSelector.builder();
375 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800376 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700377 treatment.transition(ACL_TABLE);
378 FlowRule rule = DefaultFlowRule.builder()
379 .forDevice(deviceId)
380 .withSelector(selector.build())
381 .withTreatment(treatment.build())
382 .withPriority(LOWEST_PRIORITY)
383 .fromApp(driverId)
384 .makePermanent()
385 .forTable(UNICAST_ROUTING_TABLE).build();
386 ops = ops.add(rule);
387 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
388 @Override
389 public void onSuccess(FlowRuleOperations ops) {
390 log.info("Initialized IP table");
391 }
392
393 @Override
394 public void onError(FlowRuleOperations ops) {
395 log.info("Failed to initialize unicast IP table");
396 }
397 }));
398 }
399
Saurav Das2857f382015-11-03 14:39:27 -0800400 protected void processMplsTable() {
401 //table miss entry
402 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
403 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
404 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
405 selector = DefaultTrafficSelector.builder();
406 treatment = DefaultTrafficTreatment.builder();
407 treatment.transition(MPLS_TABLE_1);
408 FlowRule rule = DefaultFlowRule.builder()
409 .forDevice(deviceId)
410 .withSelector(selector.build())
411 .withTreatment(treatment.build())
412 .withPriority(LOWEST_PRIORITY)
413 .fromApp(driverId)
414 .makePermanent()
415 .forTable(MPLS_TABLE_0).build();
416 ops = ops.add(rule);
417
418 treatment.transition(ACL_TABLE);
419 rule = DefaultFlowRule.builder()
420 .forDevice(deviceId)
421 .withSelector(selector.build())
422 .withTreatment(treatment.build())
423 .withPriority(LOWEST_PRIORITY)
424 .fromApp(driverId)
425 .makePermanent()
426 .forTable(MPLS_TABLE_1).build();
427 ops = ops.add(rule);
428
429 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
430 @Override
431 public void onSuccess(FlowRuleOperations ops) {
432 log.info("Initialized MPLS tables");
433 }
434
435 @Override
436 public void onError(FlowRuleOperations ops) {
437 log.info("Failed to initialize MPLS tables");
438 }
439 }));
440 }
441
Saurav Das558afec2015-05-31 17:12:48 -0700442 private void processBridgingTable() {
443 //table miss entry
444 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
445 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
446 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
447 selector = DefaultTrafficSelector.builder();
448 treatment = DefaultTrafficTreatment.builder();
449 treatment.transition(ACL_TABLE);
450 FlowRule rule = DefaultFlowRule.builder()
451 .forDevice(deviceId)
452 .withSelector(selector.build())
453 .withTreatment(treatment.build())
454 .withPriority(LOWEST_PRIORITY)
455 .fromApp(driverId)
456 .makePermanent()
457 .forTable(BRIDGING_TABLE).build();
458 ops = ops.add(rule);
459 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
460 @Override
461 public void onSuccess(FlowRuleOperations ops) {
462 log.info("Initialized Bridging table");
463 }
464
465 @Override
466 public void onError(FlowRuleOperations ops) {
467 log.info("Failed to initialize Bridging table");
468 }
469 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700470 }
Saurav Das558afec2015-05-31 17:12:48 -0700471
Saurav Dasa07f2032015-10-19 14:37:36 -0700472 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700473 //table miss entry - catch all to executed action-set
474 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
475 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
476 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
477 selector = DefaultTrafficSelector.builder();
478 treatment = DefaultTrafficTreatment.builder();
479 FlowRule rule = DefaultFlowRule.builder()
480 .forDevice(deviceId)
481 .withSelector(selector.build())
482 .withTreatment(treatment.build())
483 .withPriority(LOWEST_PRIORITY)
484 .fromApp(driverId)
485 .makePermanent()
486 .forTable(ACL_TABLE).build();
487 ops = ops.add(rule);
488 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
489 @Override
490 public void onSuccess(FlowRuleOperations ops) {
491 log.info("Initialized Acl table");
492 }
493
494 @Override
495 public void onError(FlowRuleOperations ops) {
496 log.info("Failed to initialize Acl table");
497 }
498 }));
Saurav Das558afec2015-05-31 17:12:48 -0700499 }
500
501}