blob: 703e41310842280dd06a361330df926541b26be6 [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 Das52025962016-01-28 22:30:01 -080029import org.onlab.packet.MacAddress;
Saurav Das2857f382015-11-03 14:39:27 -080030import org.onlab.packet.VlanId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080034import org.onosproject.net.behaviour.NextGroup;
Saurav Das558afec2015-05-31 17:12:48 -070035import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import 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.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080043import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080044import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080045import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080046import org.onosproject.net.flow.criteria.EthTypeCriterion;
47import org.onosproject.net.flow.criteria.IPCriterion;
48import org.onosproject.net.flow.criteria.MplsBosCriterion;
49import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080050import org.onosproject.net.flow.criteria.PortCriterion;
51import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080052import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080053import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
54import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
55import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080056import org.onosproject.net.flowobjective.ForwardingObjective;
57import org.onosproject.net.flowobjective.ObjectiveError;
58import org.onosproject.net.group.Group;
59import org.onosproject.net.group.GroupKey;
Saurav Das558afec2015-05-31 17:12:48 -070060import org.slf4j.Logger;
61
62
63/**
Saurav Das822c4e22015-10-23 10:51:11 -070064 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das52025962016-01-28 22:30:01 -080065 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
66 * does not handle vlan tags and mpls labels simultaneously, which requires us
67 * to do some workarounds in the driver. This driver is meant for the use of
68 * the cpqd switch when MPLS is required. As a result this driver works only
69 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070070 */
Saurav Das822c4e22015-10-23 10:51:11 -070071public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070072
73 private final Logger log = getLogger(getClass());
74
Saurav Das4ce45962015-11-24 23:21:05 -080075 /*
Saurav Das52025962016-01-28 22:30:01 -080076 * CPQD emulation does not require special untagged packet handling, unlike
77 * the real ofdpa.
78 */
79 @Override
80 protected void processFilter(FilteringObjective filt,
81 boolean install, ApplicationId applicationId) {
82 // This driver only processes filtering criteria defined with switch
83 // ports as the key
84 PortCriterion portCriterion = null;
85 EthCriterion ethCriterion = null;
86 VlanIdCriterion vidCriterion = null;
87 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
88 if (!filt.key().equals(Criteria.dummy()) &&
89 filt.key().type() == Criterion.Type.IN_PORT) {
90 portCriterion = (PortCriterion) filt.key();
91 } else {
92 log.warn("No key defined in filtering objective from app: {}. Not"
93 + "processing filtering objective", applicationId);
94 fail(filt, ObjectiveError.UNKNOWN);
95 return;
96 }
97 // convert filtering conditions for switch-intfs into flowrules
98 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
99 for (Criterion criterion : filt.conditions()) {
100 if (criterion.type() == Criterion.Type.ETH_DST) {
101 ethCriterion = (EthCriterion) criterion;
102 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
103 vidCriterion = (VlanIdCriterion) criterion;
104 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
105 ips.add((IPCriterion) criterion);
106 } else {
107 log.error("Unsupported filter {}", criterion);
108 fail(filt, ObjectiveError.UNSUPPORTED);
109 return;
110 }
111 }
112
113 VlanId assignedVlan = null;
114 // For VLAN cross-connect packets, use the configured VLAN
115 if (vidCriterion != null) {
116 if (vidCriterion.vlanId() != VlanId.NONE) {
117 assignedVlan = vidCriterion.vlanId();
118
119 // For untagged packets, assign a VLAN ID
120 } else {
121 if (filt.meta() == null) {
122 log.error("Missing metadata in filtering objective required " +
123 "for vlan assignment in dev {}", deviceId);
124 fail(filt, ObjectiveError.BADPARAMS);
125 return;
126 }
127 for (Instruction i : filt.meta().allInstructions()) {
128 if (i instanceof ModVlanIdInstruction) {
129 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
130 }
131 }
132 if (assignedVlan == null) {
133 log.error("Driver requires an assigned vlan-id to tag incoming "
134 + "untagged packets. Not processing vlan filters on "
135 + "device {}", deviceId);
136 fail(filt, ObjectiveError.BADPARAMS);
137 return;
138 }
139 }
140 }
141
142 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
143 log.debug("filtering objective missing dstMac, cannot program TMAC table");
144 } else {
145 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
146 vidCriterion, assignedVlan,
147 applicationId)) {
148 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
149 tmacRule, deviceId);
150 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
151 }
152 }
153
154 if (ethCriterion == null || vidCriterion == null) {
155 log.debug("filtering objective missing dstMac or VLAN, "
156 + "cannot program VLAN Table");
157 } else {
158 List<FlowRule> allRules = processVlanIdFilter(
159 portCriterion, vidCriterion, assignedVlan, applicationId);
160 for (FlowRule rule : allRules) {
161 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
162 rule, deviceId);
163 ops = install ? ops.add(rule) : ops.remove(rule);
164 }
165 }
166
167 for (IPCriterion ipaddr : ips) {
168 // since we ignore port information for IP rules, and the same (gateway) IP
169 // can be configured on multiple ports, we make sure that we send
170 // only a single rule to the switch.
171 if (!sentIpFilters.contains(ipaddr)) {
172 sentIpFilters.add(ipaddr);
173 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
174 ipaddr, deviceId);
175 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
176 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
177 selector.matchEthType(Ethernet.TYPE_IPV4);
178 selector.matchIPDst(ipaddr.ip());
179 treatment.setOutput(PortNumber.CONTROLLER);
180 FlowRule rule = DefaultFlowRule.builder()
181 .forDevice(deviceId)
182 .withSelector(selector.build())
183 .withTreatment(treatment.build())
184 .withPriority(HIGHEST_PRIORITY)
185 .fromApp(applicationId)
186 .makePermanent()
187 .forTable(ACL_TABLE).build();
188 ops = install ? ops.add(rule) : ops.remove(rule);
189 }
190 }
191
192 // apply filtering flow rules
193 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
194 @Override
195 public void onSuccess(FlowRuleOperations ops) {
196 log.info("Applied {} filtering rules in device {}",
197 ops.stages().get(0).size(), deviceId);
198 pass(filt);
199 }
200
201 @Override
202 public void onError(FlowRuleOperations ops) {
203 log.info("Failed to apply all filtering rules in dev {}", deviceId);
204 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
205 }
206 }));
207
208 }
209
210 /*
Saurav Das4ce45962015-11-24 23:21:05 -0800211 * Cpqd emulation does not require the non-OF standard rules for
212 * matching untagged packets.
213 *
214 * (non-Javadoc)
215 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
216 */
Saurav Das558afec2015-05-31 17:12:48 -0700217 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800218 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
219 VlanIdCriterion vidCriterion,
220 VlanId assignedVlan,
221 ApplicationId applicationId) {
222 List<FlowRule> rules = new ArrayList<FlowRule>();
223 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
224 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
225 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800226 treatment.transition(TMAC_TABLE);
227
228 VlanId storeVlan = null;
Saurav Das2857f382015-11-03 14:39:27 -0800229 if (vidCriterion.vlanId() == VlanId.NONE) {
230 // untagged packets are assigned vlans
231 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800232 storeVlan = assignedVlan;
233 } else {
234 storeVlan = vidCriterion.vlanId();
Saurav Das2857f382015-11-03 14:39:27 -0800235 }
Saurav Das2857f382015-11-03 14:39:27 -0800236
237 // ofdpa cannot match on ALL portnumber, so we need to use separate
238 // rules for each port.
239 List<PortNumber> portnums = new ArrayList<PortNumber>();
240 if (portCriterion.port() == PortNumber.ALL) {
241 for (Port port : deviceService.getPorts(deviceId)) {
242 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
243 portnums.add(port.number());
244 }
245 }
246 } else {
247 portnums.add(portCriterion.port());
248 }
Saurav Das4f980082015-11-05 13:39:15 -0800249
Saurav Das2857f382015-11-03 14:39:27 -0800250 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800251 // update storage
Charles Chan188ebf52015-12-23 00:15:11 -0800252 ofdpa2GroupHandler.port2Vlan.put(pnum, storeVlan);
253 Set<PortNumber> vlanPorts = ofdpa2GroupHandler.vlan2Port.get(storeVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800254 if (vlanPorts == null) {
255 vlanPorts = Collections.newSetFromMap(
256 new ConcurrentHashMap<PortNumber, Boolean>());
257 vlanPorts.add(pnum);
Charles Chan188ebf52015-12-23 00:15:11 -0800258 ofdpa2GroupHandler.vlan2Port.put(storeVlan, vlanPorts);
Saurav Das4f980082015-11-05 13:39:15 -0800259 } else {
260 vlanPorts.add(pnum);
261 }
262 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800263 selector.matchInPort(pnum);
264 FlowRule rule = DefaultFlowRule.builder()
265 .forDevice(deviceId)
266 .withSelector(selector.build())
267 .withTreatment(treatment.build())
268 .withPriority(DEFAULT_PRIORITY)
269 .fromApp(applicationId)
270 .makePermanent()
271 .forTable(VLAN_TABLE).build();
272 rules.add(rule);
273 }
274 return rules;
275 }
276
Saurav Das4ce45962015-11-24 23:21:05 -0800277 /*
278 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
279 * Workaround requires popping off the VLAN tags in the TMAC table.
280 *
281 * (non-Javadoc)
282 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
283 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800284 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800285 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
286 EthCriterion ethCriterion,
287 VlanIdCriterion vidCriterion,
288 VlanId assignedVlan,
289 ApplicationId applicationId) {
290 //handling untagged packets via assigned VLAN
291 if (vidCriterion.vlanId() == VlanId.NONE) {
292 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
293 }
294 // ofdpa cannot match on ALL portnumber, so we need to use separate
295 // rules for each port.
296 List<PortNumber> portnums = new ArrayList<PortNumber>();
297 if (portCriterion.port() == PortNumber.ALL) {
298 for (Port port : deviceService.getPorts(deviceId)) {
299 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
300 portnums.add(port.number());
301 }
302 }
303 } else {
304 portnums.add(portCriterion.port());
305 }
306
307 List<FlowRule> rules = new ArrayList<FlowRule>();
308 for (PortNumber pnum : portnums) {
309 // for unicast IP packets
310 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
311 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
312 selector.matchInPort(pnum);
313 selector.matchVlanId(vidCriterion.vlanId());
314 selector.matchEthType(Ethernet.TYPE_IPV4);
315 selector.matchEthDst(ethCriterion.mac());
316 /*
317 * Note: CpqD switches do not handle MPLS-related operation properly
318 * for a packet with VLAN tag. We pop VLAN here as a workaround.
319 * Side effect: HostService learns redundant hosts with same MAC but
320 * different VLAN. No known side effect on the network reachability.
321 */
322 treatment.popVlan();
323 treatment.transition(UNICAST_ROUTING_TABLE);
324 FlowRule rule = DefaultFlowRule.builder()
325 .forDevice(deviceId)
326 .withSelector(selector.build())
327 .withTreatment(treatment.build())
328 .withPriority(DEFAULT_PRIORITY)
329 .fromApp(applicationId)
330 .makePermanent()
331 .forTable(TMAC_TABLE).build();
332 rules.add(rule);
333 //for MPLS packets
334 selector = DefaultTrafficSelector.builder();
335 treatment = DefaultTrafficTreatment.builder();
336 selector.matchInPort(pnum);
337 selector.matchVlanId(vidCriterion.vlanId());
338 selector.matchEthType(Ethernet.MPLS_UNICAST);
339 selector.matchEthDst(ethCriterion.mac());
340 // workaround here again
341 treatment.popVlan();
342 treatment.transition(MPLS_TABLE_0);
343 rule = DefaultFlowRule.builder()
344 .forDevice(deviceId)
345 .withSelector(selector.build())
346 .withTreatment(treatment.build())
347 .withPriority(DEFAULT_PRIORITY)
348 .fromApp(applicationId)
349 .makePermanent()
350 .forTable(TMAC_TABLE).build();
351 rules.add(rule);
352 }
353 return rules;
354 }
355
356 /*
357 * Cpqd emulation allows MPLS ecmp.
358 *
359 * (non-Javadoc)
360 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
361 */
362 @Override
363 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800364 TrafficSelector selector = fwd.selector();
365 EthTypeCriterion ethType =
366 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
367 if ((ethType == null) ||
368 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
369 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800370 log.warn("processSpecific: Unsupported forwarding objective criteria"
371 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800372 fail(fwd, ObjectiveError.UNSUPPORTED);
373 return Collections.emptySet();
374 }
375
376 int forTableId = -1;
377 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
378 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
379 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
380 .matchIPDst(((IPCriterion)
381 selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
382 forTableId = UNICAST_ROUTING_TABLE;
Saurav Das4ce45962015-11-24 23:21:05 -0800383 log.debug("processing IPv4 specific forwarding objective {} -> next:{}"
384 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800385 } else {
386 filteredSelector
387 .matchEthType(Ethernet.MPLS_UNICAST)
388 .matchMplsLabel(((MplsCriterion)
389 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
390 MplsBosCriterion bos = (MplsBosCriterion) selector
391 .getCriterion(Criterion.Type.MPLS_BOS);
392 if (bos != null) {
393 filteredSelector.matchMplsBos(bos.mplsBos());
394 }
395 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800396 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
397 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800398 }
399
400 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
401 if (fwd.treatment() != null) {
402 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800403 /*
404 * NOTE: OF-DPA does not support immediate instruction in
405 * L3 unicast and MPLS table.
406 */
407 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800408 }
409 }
410
411 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800412 NextGroup next = getGroupForNextObjective(fwd.nextId());
413 if (next != null) {
414 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
415 // we only need the top level group's key to point the flow to it
416 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
417 if (group == null) {
418 log.warn("The group left!");
419 fail(fwd, ObjectiveError.GROUPMISSING);
420 return Collections.emptySet();
421 }
422 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800423 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800424 }
425 tb.transition(ACL_TABLE);
426 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
427 .fromApp(fwd.appId())
428 .withPriority(fwd.priority())
429 .forDevice(deviceId)
430 .withSelector(filteredSelector.build())
431 .withTreatment(tb.build())
432 .forTable(forTableId);
433
434 if (fwd.permanent()) {
435 ruleBuilder.makePermanent();
436 } else {
437 ruleBuilder.makeTemporary(fwd.timeout());
438 }
439
440 return Collections.singletonList(ruleBuilder.build());
441 }
442
Charles Chan1e492d32016-01-30 23:22:37 -0800443 @Override
444 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
445 List<FlowRule> rules = new ArrayList<>();
446
447 // Build filtered selector
448 TrafficSelector selector = fwd.selector();
449 EthCriterion ethCriterion = (EthCriterion) selector
450 .getCriterion(Criterion.Type.ETH_DST);
451 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
452 .getCriterion(Criterion.Type.VLAN_VID);
453
454 if (vlanIdCriterion == null) {
455 log.warn("Forwarding objective for bridging requires vlan. Not "
456 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
457 fail(fwd, ObjectiveError.BADPARAMS);
458 return Collections.emptySet();
459 }
460
461 TrafficSelector.Builder filteredSelectorBuilder =
462 DefaultTrafficSelector.builder();
463 // Do not match MacAddress for subnet broadcast entry
464 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
465 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
466 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
467 fwd.id(), fwd.nextId(), deviceId);
468 } else {
469 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
470 + "in dev:{} for vlan:{}",
471 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
472 }
473 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
474 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
475
476 if (fwd.treatment() != null) {
477 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
478 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
479 }
480
481 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
482 if (fwd.nextId() != null) {
483 NextGroup next = getGroupForNextObjective(fwd.nextId());
484 if (next != null) {
485 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
486 // we only need the top level group's key to point the flow to it
487 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
488 if (group != null) {
489 treatmentBuilder.deferred().group(group.id());
490 } else {
491 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
492 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
493 fail(fwd, ObjectiveError.GROUPMISSING);
494 return Collections.emptySet();
495 }
496 }
497 }
498 treatmentBuilder.immediate().transition(ACL_TABLE);
499 TrafficTreatment filteredTreatment = treatmentBuilder.build();
500
501 // Build bridging table entries
502 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
503 flowRuleBuilder.fromApp(fwd.appId())
504 .withPriority(fwd.priority())
505 .forDevice(deviceId)
506 .withSelector(filteredSelector)
507 .withTreatment(filteredTreatment)
508 .forTable(BRIDGING_TABLE);
509 if (fwd.permanent()) {
510 flowRuleBuilder.makePermanent();
511 } else {
512 flowRuleBuilder.makeTemporary(fwd.timeout());
513 }
514 rules.add(flowRuleBuilder.build());
515 return rules;
516 }
517
Saurav Das52025962016-01-28 22:30:01 -0800518 /*
519 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
520 * ACL table. Because we pop off vlan tags in TMAC table,
521 * we need to avoid matching on vlans in the ACL table.
522 */
523 @Override
524 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
525 log.info("Processing versatile forwarding objective");
526
527 EthTypeCriterion ethType =
528 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
529 if (ethType == null) {
530 log.error("Versatile forwarding objective must include ethType");
531 fail(fwd, ObjectiveError.BADPARAMS);
532 return Collections.emptySet();
533 }
534 if (fwd.nextId() == null && fwd.treatment() == null) {
535 log.error("Forwarding objective {} from {} must contain "
536 + "nextId or Treatment", fwd.selector(), fwd.appId());
537 return Collections.emptySet();
538 }
539
540 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
541 fwd.selector().criteria().forEach(criterion -> {
542 if (criterion instanceof VlanIdCriterion) {
543 // avoid matching on vlans
544 return;
545 } else {
546 sbuilder.add(criterion);
547 }
548 });
549
550 // XXX driver does not currently do type checking as per Tables 65-67 in
551 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
552 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
553 if (fwd.treatment() != null) {
554 for (Instruction ins : fwd.treatment().allInstructions()) {
555 if (ins instanceof OutputInstruction) {
556 OutputInstruction o = (OutputInstruction) ins;
557 if (o.port() == PortNumber.CONTROLLER) {
558 ttBuilder.add(o);
559 } else {
560 log.warn("Only allowed treatments in versatile forwarding "
561 + "objectives are punts to the controller");
562 }
563 } else {
564 log.warn("Cannot process instruction in versatile fwd {}", ins);
565 }
566 }
567 }
568 if (fwd.nextId() != null) {
569 // overide case
570 NextGroup next = getGroupForNextObjective(fwd.nextId());
571 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
572 // we only need the top level group's key to point the flow to it
573 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
574 if (group == null) {
575 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
576 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
577 fail(fwd, ObjectiveError.GROUPMISSING);
578 return Collections.emptySet();
579 }
580 ttBuilder.deferred().group(group.id());
581 }
582
583 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
584 .fromApp(fwd.appId())
585 .withPriority(fwd.priority())
586 .forDevice(deviceId)
587 .withSelector(sbuilder.build())
588 .withTreatment(ttBuilder.build())
589 .makePermanent()
590 .forTable(ACL_TABLE);
591 return Collections.singletonList(ruleBuilder.build());
592 }
593
594 /*
595 * Cpqd emulation requires table-miss-entries in forwarding tables.
596 * Real OFDPA does not require these rules as they are put in by default.
597 *
598 * (non-Javadoc)
599 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
600 */
Saurav Das2857f382015-11-03 14:39:27 -0800601 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700602 protected void initializePipeline() {
603 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800604 // vlan table processing not required, as default is to drop packets
605 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700606 processTmacTable();
607 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800608 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700609 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700610 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700611 }
612
Saurav Das558afec2015-05-31 17:12:48 -0700613 protected void processPortTable() {
614 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
615 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
616 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
617 treatment.transition(VLAN_TABLE);
618 FlowRule tmisse = DefaultFlowRule.builder()
619 .forDevice(deviceId)
620 .withSelector(selector.build())
621 .withTreatment(treatment.build())
622 .withPriority(LOWEST_PRIORITY)
623 .fromApp(driverId)
624 .makePermanent()
625 .forTable(PORT_TABLE).build();
626 ops = ops.add(tmisse);
627
628 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
629 @Override
630 public void onSuccess(FlowRuleOperations ops) {
631 log.info("Initialized port table");
632 }
633
634 @Override
635 public void onError(FlowRuleOperations ops) {
636 log.info("Failed to initialize port table");
637 }
638 }));
639 }
640
Saurav Das558afec2015-05-31 17:12:48 -0700641 protected void processTmacTable() {
642 //table miss entry
643 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
644 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
645 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
646 selector = DefaultTrafficSelector.builder();
647 treatment = DefaultTrafficTreatment.builder();
648 treatment.transition(BRIDGING_TABLE);
649 FlowRule rule = DefaultFlowRule.builder()
650 .forDevice(deviceId)
651 .withSelector(selector.build())
652 .withTreatment(treatment.build())
653 .withPriority(LOWEST_PRIORITY)
654 .fromApp(driverId)
655 .makePermanent()
656 .forTable(TMAC_TABLE).build();
657 ops = ops.add(rule);
658 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
659 @Override
660 public void onSuccess(FlowRuleOperations ops) {
661 log.info("Initialized tmac table");
662 }
663
664 @Override
665 public void onError(FlowRuleOperations ops) {
666 log.info("Failed to initialize tmac table");
667 }
668 }));
669 }
670
Saurav Das558afec2015-05-31 17:12:48 -0700671 protected void processIpTable() {
672 //table miss entry
673 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
674 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
675 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
676 selector = DefaultTrafficSelector.builder();
677 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800678 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700679 treatment.transition(ACL_TABLE);
680 FlowRule rule = DefaultFlowRule.builder()
681 .forDevice(deviceId)
682 .withSelector(selector.build())
683 .withTreatment(treatment.build())
684 .withPriority(LOWEST_PRIORITY)
685 .fromApp(driverId)
686 .makePermanent()
687 .forTable(UNICAST_ROUTING_TABLE).build();
688 ops = ops.add(rule);
689 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
690 @Override
691 public void onSuccess(FlowRuleOperations ops) {
692 log.info("Initialized IP table");
693 }
694
695 @Override
696 public void onError(FlowRuleOperations ops) {
697 log.info("Failed to initialize unicast IP table");
698 }
699 }));
700 }
701
Saurav Das2857f382015-11-03 14:39:27 -0800702 protected void processMplsTable() {
703 //table miss entry
704 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
705 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
706 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
707 selector = DefaultTrafficSelector.builder();
708 treatment = DefaultTrafficTreatment.builder();
709 treatment.transition(MPLS_TABLE_1);
710 FlowRule rule = DefaultFlowRule.builder()
711 .forDevice(deviceId)
712 .withSelector(selector.build())
713 .withTreatment(treatment.build())
714 .withPriority(LOWEST_PRIORITY)
715 .fromApp(driverId)
716 .makePermanent()
717 .forTable(MPLS_TABLE_0).build();
718 ops = ops.add(rule);
719
720 treatment.transition(ACL_TABLE);
721 rule = DefaultFlowRule.builder()
722 .forDevice(deviceId)
723 .withSelector(selector.build())
724 .withTreatment(treatment.build())
725 .withPriority(LOWEST_PRIORITY)
726 .fromApp(driverId)
727 .makePermanent()
728 .forTable(MPLS_TABLE_1).build();
729 ops = ops.add(rule);
730
731 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
732 @Override
733 public void onSuccess(FlowRuleOperations ops) {
734 log.info("Initialized MPLS tables");
735 }
736
737 @Override
738 public void onError(FlowRuleOperations ops) {
739 log.info("Failed to initialize MPLS tables");
740 }
741 }));
742 }
743
Saurav Das558afec2015-05-31 17:12:48 -0700744 private void processBridgingTable() {
745 //table miss entry
746 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
747 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
748 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
749 selector = DefaultTrafficSelector.builder();
750 treatment = DefaultTrafficTreatment.builder();
751 treatment.transition(ACL_TABLE);
752 FlowRule rule = DefaultFlowRule.builder()
753 .forDevice(deviceId)
754 .withSelector(selector.build())
755 .withTreatment(treatment.build())
756 .withPriority(LOWEST_PRIORITY)
757 .fromApp(driverId)
758 .makePermanent()
759 .forTable(BRIDGING_TABLE).build();
760 ops = ops.add(rule);
761 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
762 @Override
763 public void onSuccess(FlowRuleOperations ops) {
764 log.info("Initialized Bridging table");
765 }
766
767 @Override
768 public void onError(FlowRuleOperations ops) {
769 log.info("Failed to initialize Bridging table");
770 }
771 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700772 }
Saurav Das558afec2015-05-31 17:12:48 -0700773
Saurav Dasa07f2032015-10-19 14:37:36 -0700774 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700775 //table miss entry - catch all to executed action-set
776 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
777 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
778 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
779 selector = DefaultTrafficSelector.builder();
780 treatment = DefaultTrafficTreatment.builder();
781 FlowRule rule = DefaultFlowRule.builder()
782 .forDevice(deviceId)
783 .withSelector(selector.build())
784 .withTreatment(treatment.build())
785 .withPriority(LOWEST_PRIORITY)
786 .fromApp(driverId)
787 .makePermanent()
788 .forTable(ACL_TABLE).build();
789 ops = ops.add(rule);
790 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
791 @Override
792 public void onSuccess(FlowRuleOperations ops) {
793 log.info("Initialized Acl table");
794 }
795
796 @Override
797 public void onError(FlowRuleOperations ops) {
798 log.info("Failed to initialize Acl table");
799 }
800 }));
Saurav Das558afec2015-05-31 17:12:48 -0700801 }
802
803}