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