blob: 57e0c4b6f647b449d4ada891b28be3f815d6186e [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
Charles Chan5270ed02016-01-30 23:22:37 -080028import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070029import com.google.common.collect.ImmutableSet;
Saurav Das8a0732e2015-11-20 15:27:53 -080030import org.onlab.packet.Ethernet;
Saurav Das52025962016-01-28 22:30:01 -080031import org.onlab.packet.MacAddress;
Flavio Castroe10fa242016-01-15 12:43:51 -080032import org.onlab.packet.IpPrefix;
Saurav Das2857f382015-11-03 14:39:27 -080033import org.onlab.packet.VlanId;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.net.Port;
36import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080037import org.onosproject.net.behaviour.NextGroup;
Saurav Das558afec2015-05-31 17:12:48 -070038import org.onosproject.net.flow.DefaultFlowRule;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.FlowRule;
42import org.onosproject.net.flow.FlowRuleOperations;
43import org.onosproject.net.flow.FlowRuleOperationsContext;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080046import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080047import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080048import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080049import org.onosproject.net.flow.criteria.EthTypeCriterion;
50import org.onosproject.net.flow.criteria.IPCriterion;
51import org.onosproject.net.flow.criteria.MplsBosCriterion;
52import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080053import org.onosproject.net.flow.criteria.PortCriterion;
54import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080055import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080056import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
57import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
58import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080059import org.onosproject.net.flowobjective.ForwardingObjective;
60import org.onosproject.net.flowobjective.ObjectiveError;
61import org.onosproject.net.group.Group;
62import org.onosproject.net.group.GroupKey;
Saurav Das558afec2015-05-31 17:12:48 -070063import org.slf4j.Logger;
64
65
66/**
Saurav Das822c4e22015-10-23 10:51:11 -070067 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das52025962016-01-28 22:30:01 -080068 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
69 * does not handle vlan tags and mpls labels simultaneously, which requires us
70 * to do some workarounds in the driver. This driver is meant for the use of
71 * the cpqd switch when MPLS is required. As a result this driver works only
72 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070073 */
Charles Chan361154b2016-03-24 10:23:39 -070074public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070075
76 private final Logger log = getLogger(getClass());
77
Saurav Das4ce45962015-11-24 23:21:05 -080078 /*
Saurav Das52025962016-01-28 22:30:01 -080079 * CPQD emulation does not require special untagged packet handling, unlike
80 * the real ofdpa.
81 */
82 @Override
83 protected void processFilter(FilteringObjective filt,
84 boolean install, ApplicationId applicationId) {
85 // This driver only processes filtering criteria defined with switch
86 // ports as the key
87 PortCriterion portCriterion = null;
88 EthCriterion ethCriterion = null;
89 VlanIdCriterion vidCriterion = null;
90 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
91 if (!filt.key().equals(Criteria.dummy()) &&
92 filt.key().type() == Criterion.Type.IN_PORT) {
93 portCriterion = (PortCriterion) filt.key();
94 } else {
95 log.warn("No key defined in filtering objective from app: {}. Not"
96 + "processing filtering objective", applicationId);
97 fail(filt, ObjectiveError.UNKNOWN);
98 return;
99 }
100 // convert filtering conditions for switch-intfs into flowrules
101 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
102 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700103 if (criterion.type() == Criterion.Type.ETH_DST ||
104 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das52025962016-01-28 22:30:01 -0800105 ethCriterion = (EthCriterion) criterion;
106 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
107 vidCriterion = (VlanIdCriterion) criterion;
108 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
109 ips.add((IPCriterion) criterion);
110 } else {
111 log.error("Unsupported filter {}", criterion);
112 fail(filt, ObjectiveError.UNSUPPORTED);
113 return;
114 }
115 }
116
117 VlanId assignedVlan = null;
118 // For VLAN cross-connect packets, use the configured VLAN
119 if (vidCriterion != null) {
120 if (vidCriterion.vlanId() != VlanId.NONE) {
121 assignedVlan = vidCriterion.vlanId();
122
123 // For untagged packets, assign a VLAN ID
124 } else {
125 if (filt.meta() == null) {
126 log.error("Missing metadata in filtering objective required " +
127 "for vlan assignment in dev {}", deviceId);
128 fail(filt, ObjectiveError.BADPARAMS);
129 return;
130 }
131 for (Instruction i : filt.meta().allInstructions()) {
132 if (i instanceof ModVlanIdInstruction) {
133 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
134 }
135 }
136 if (assignedVlan == null) {
137 log.error("Driver requires an assigned vlan-id to tag incoming "
138 + "untagged packets. Not processing vlan filters on "
139 + "device {}", deviceId);
140 fail(filt, ObjectiveError.BADPARAMS);
141 return;
142 }
143 }
144 }
145
146 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
147 log.debug("filtering objective missing dstMac, cannot program TMAC table");
148 } else {
149 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
150 vidCriterion, assignedVlan,
151 applicationId)) {
152 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
153 tmacRule, deviceId);
154 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
155 }
156 }
157
158 if (ethCriterion == null || vidCriterion == null) {
159 log.debug("filtering objective missing dstMac or VLAN, "
160 + "cannot program VLAN Table");
161 } else {
162 List<FlowRule> allRules = processVlanIdFilter(
163 portCriterion, vidCriterion, assignedVlan, applicationId);
164 for (FlowRule rule : allRules) {
165 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
166 rule, deviceId);
167 ops = install ? ops.add(rule) : ops.remove(rule);
168 }
169 }
170
171 for (IPCriterion ipaddr : ips) {
172 // since we ignore port information for IP rules, and the same (gateway) IP
173 // can be configured on multiple ports, we make sure that we send
174 // only a single rule to the switch.
175 if (!sentIpFilters.contains(ipaddr)) {
176 sentIpFilters.add(ipaddr);
177 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
178 ipaddr, deviceId);
179 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
180 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
181 selector.matchEthType(Ethernet.TYPE_IPV4);
182 selector.matchIPDst(ipaddr.ip());
183 treatment.setOutput(PortNumber.CONTROLLER);
184 FlowRule rule = DefaultFlowRule.builder()
185 .forDevice(deviceId)
186 .withSelector(selector.build())
187 .withTreatment(treatment.build())
188 .withPriority(HIGHEST_PRIORITY)
189 .fromApp(applicationId)
190 .makePermanent()
191 .forTable(ACL_TABLE).build();
192 ops = install ? ops.add(rule) : ops.remove(rule);
193 }
194 }
195
196 // apply filtering flow rules
197 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
198 @Override
199 public void onSuccess(FlowRuleOperations ops) {
200 log.info("Applied {} filtering rules in device {}",
201 ops.stages().get(0).size(), deviceId);
202 pass(filt);
203 }
204
205 @Override
206 public void onError(FlowRuleOperations ops) {
207 log.info("Failed to apply all filtering rules in dev {}", deviceId);
208 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
209 }
210 }));
211
212 }
213
214 /*
Saurav Das4ce45962015-11-24 23:21:05 -0800215 * Cpqd emulation does not require the non-OF standard rules for
216 * matching untagged packets.
217 *
218 * (non-Javadoc)
219 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
220 */
Saurav Das558afec2015-05-31 17:12:48 -0700221 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800222 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
223 VlanIdCriterion vidCriterion,
224 VlanId assignedVlan,
225 ApplicationId applicationId) {
226 List<FlowRule> rules = new ArrayList<FlowRule>();
227 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
228 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
229 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800230 treatment.transition(TMAC_TABLE);
231
232 VlanId storeVlan = null;
Saurav Das2857f382015-11-03 14:39:27 -0800233 if (vidCriterion.vlanId() == VlanId.NONE) {
234 // untagged packets are assigned vlans
235 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800236 storeVlan = assignedVlan;
237 } else {
238 storeVlan = vidCriterion.vlanId();
Saurav Das2857f382015-11-03 14:39:27 -0800239 }
Saurav Das2857f382015-11-03 14:39:27 -0800240
241 // ofdpa cannot match on ALL portnumber, so we need to use separate
242 // rules for each port.
243 List<PortNumber> portnums = new ArrayList<PortNumber>();
244 if (portCriterion.port() == PortNumber.ALL) {
245 for (Port port : deviceService.getPorts(deviceId)) {
246 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
247 portnums.add(port.number());
248 }
249 }
250 } else {
251 portnums.add(portCriterion.port());
252 }
Saurav Das4f980082015-11-05 13:39:15 -0800253
Saurav Das2857f382015-11-03 14:39:27 -0800254 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800255 // update storage
Charles Chan188ebf52015-12-23 00:15:11 -0800256 ofdpa2GroupHandler.port2Vlan.put(pnum, storeVlan);
257 Set<PortNumber> vlanPorts = ofdpa2GroupHandler.vlan2Port.get(storeVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800258 if (vlanPorts == null) {
259 vlanPorts = Collections.newSetFromMap(
260 new ConcurrentHashMap<PortNumber, Boolean>());
261 vlanPorts.add(pnum);
Charles Chan188ebf52015-12-23 00:15:11 -0800262 ofdpa2GroupHandler.vlan2Port.put(storeVlan, vlanPorts);
Saurav Das4f980082015-11-05 13:39:15 -0800263 } else {
264 vlanPorts.add(pnum);
265 }
266 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800267 selector.matchInPort(pnum);
268 FlowRule rule = DefaultFlowRule.builder()
269 .forDevice(deviceId)
270 .withSelector(selector.build())
271 .withTreatment(treatment.build())
272 .withPriority(DEFAULT_PRIORITY)
273 .fromApp(applicationId)
274 .makePermanent()
275 .forTable(VLAN_TABLE).build();
276 rules.add(rule);
277 }
278 return rules;
279 }
280
Saurav Das4ce45962015-11-24 23:21:05 -0800281 /*
282 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
283 * Workaround requires popping off the VLAN tags in the TMAC table.
284 *
285 * (non-Javadoc)
286 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
287 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800288 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800289 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
290 EthCriterion ethCriterion,
291 VlanIdCriterion vidCriterion,
292 VlanId assignedVlan,
293 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800294 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
295 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
296 return processEthDstOnlyFilter(ethCriterion, applicationId);
297 }
298
Charles Chan5b9df8d2016-03-28 22:21:40 -0700299 // Multicast MAC
300 if (ethCriterion.mask() != null) {
301 return processMcastEthDstFilter(ethCriterion, applicationId);
302 }
303
Saurav Das4ce45962015-11-24 23:21:05 -0800304 //handling untagged packets via assigned VLAN
305 if (vidCriterion.vlanId() == VlanId.NONE) {
306 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
307 }
308 // ofdpa cannot match on ALL portnumber, so we need to use separate
309 // rules for each port.
310 List<PortNumber> portnums = new ArrayList<PortNumber>();
311 if (portCriterion.port() == PortNumber.ALL) {
312 for (Port port : deviceService.getPorts(deviceId)) {
313 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
314 portnums.add(port.number());
315 }
316 }
317 } else {
318 portnums.add(portCriterion.port());
319 }
320
321 List<FlowRule> rules = new ArrayList<FlowRule>();
322 for (PortNumber pnum : portnums) {
323 // for unicast IP packets
324 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
325 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
326 selector.matchInPort(pnum);
327 selector.matchVlanId(vidCriterion.vlanId());
328 selector.matchEthType(Ethernet.TYPE_IPV4);
329 selector.matchEthDst(ethCriterion.mac());
330 /*
331 * Note: CpqD switches do not handle MPLS-related operation properly
332 * for a packet with VLAN tag. We pop VLAN here as a workaround.
333 * Side effect: HostService learns redundant hosts with same MAC but
334 * different VLAN. No known side effect on the network reachability.
335 */
336 treatment.popVlan();
337 treatment.transition(UNICAST_ROUTING_TABLE);
338 FlowRule rule = DefaultFlowRule.builder()
339 .forDevice(deviceId)
340 .withSelector(selector.build())
341 .withTreatment(treatment.build())
342 .withPriority(DEFAULT_PRIORITY)
343 .fromApp(applicationId)
344 .makePermanent()
345 .forTable(TMAC_TABLE).build();
346 rules.add(rule);
347 //for MPLS packets
348 selector = DefaultTrafficSelector.builder();
349 treatment = DefaultTrafficTreatment.builder();
350 selector.matchInPort(pnum);
351 selector.matchVlanId(vidCriterion.vlanId());
352 selector.matchEthType(Ethernet.MPLS_UNICAST);
353 selector.matchEthDst(ethCriterion.mac());
354 // workaround here again
355 treatment.popVlan();
356 treatment.transition(MPLS_TABLE_0);
357 rule = DefaultFlowRule.builder()
358 .forDevice(deviceId)
359 .withSelector(selector.build())
360 .withTreatment(treatment.build())
361 .withPriority(DEFAULT_PRIORITY)
362 .fromApp(applicationId)
363 .makePermanent()
364 .forTable(TMAC_TABLE).build();
365 rules.add(rule);
366 }
367 return rules;
368 }
369
Charles Chan5270ed02016-01-30 23:22:37 -0800370 @Override
371 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
372 ApplicationId applicationId) {
373 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
374 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
375 selector.matchEthType(Ethernet.TYPE_IPV4);
376 selector.matchEthDst(ethCriterion.mac());
377 /*
378 * Note: CpqD switches do not handle MPLS-related operation properly
379 * for a packet with VLAN tag. We pop VLAN here as a workaround.
380 * Side effect: HostService learns redundant hosts with same MAC but
381 * different VLAN. No known side effect on the network reachability.
382 */
383 treatment.popVlan();
384 treatment.transition(UNICAST_ROUTING_TABLE);
385 FlowRule rule = DefaultFlowRule.builder()
386 .forDevice(deviceId)
387 .withSelector(selector.build())
388 .withTreatment(treatment.build())
389 .withPriority(DEFAULT_PRIORITY)
390 .fromApp(applicationId)
391 .makePermanent()
392 .forTable(TMAC_TABLE).build();
393 return ImmutableList.<FlowRule>builder().add(rule).build();
394 }
395
Saurav Das4ce45962015-11-24 23:21:05 -0800396 /*
397 * Cpqd emulation allows MPLS ecmp.
398 *
399 * (non-Javadoc)
400 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
401 */
402 @Override
403 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800404 TrafficSelector selector = fwd.selector();
405 EthTypeCriterion ethType =
406 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
407 if ((ethType == null) ||
408 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
409 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800410 log.warn("processSpecific: Unsupported forwarding objective criteria"
411 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800412 fail(fwd, ObjectiveError.UNSUPPORTED);
413 return Collections.emptySet();
414 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800415 boolean defaultRule = false;
Saurav Das8a0732e2015-11-20 15:27:53 -0800416 int forTableId = -1;
417 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800418 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
419
420 /*
421 * NOTE: The switch does not support matching 0.0.0.0/0.
422 * Split it into 0.0.0.0/1 and 128.0.0.0/1
423 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800424 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800425 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700426 if (ipv4Dst.isMulticast()) {
427 if (ipv4Dst.prefixLength() != 32) {
428 log.warn("Multicast specific forwarding objective can only be /32");
429 fail(fwd, ObjectiveError.BADPARAMS);
430 return ImmutableSet.of();
431 }
432 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
433 if (assignedVlan == null) {
434 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
435 fail(fwd, ObjectiveError.BADPARAMS);
436 return ImmutableSet.of();
437 }
438 filteredSelector.matchVlanId(assignedVlan);
439 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
440 forTableId = MULTICAST_ROUTING_TABLE;
441 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
442 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800443 } else {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700444 if (ipv4Dst.prefixLength() > 0) {
445 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
446 } else {
447 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
448 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
449 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
450 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
451 defaultRule = true;
452 }
453 forTableId = UNICAST_ROUTING_TABLE;
454 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
455 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800456 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800457 } else {
458 filteredSelector
459 .matchEthType(Ethernet.MPLS_UNICAST)
460 .matchMplsLabel(((MplsCriterion)
461 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
462 MplsBosCriterion bos = (MplsBosCriterion) selector
463 .getCriterion(Criterion.Type.MPLS_BOS);
464 if (bos != null) {
465 filteredSelector.matchMplsBos(bos.mplsBos());
466 }
467 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800468 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
469 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800470 }
471
472 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
473 if (fwd.treatment() != null) {
474 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800475 /*
476 * NOTE: OF-DPA does not support immediate instruction in
477 * L3 unicast and MPLS table.
478 */
479 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800480 }
481 }
482
483 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800484 NextGroup next = getGroupForNextObjective(fwd.nextId());
485 if (next != null) {
486 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
487 // we only need the top level group's key to point the flow to it
488 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
489 if (group == null) {
490 log.warn("The group left!");
491 fail(fwd, ObjectiveError.GROUPMISSING);
492 return Collections.emptySet();
493 }
494 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800495 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800496 }
497 tb.transition(ACL_TABLE);
498 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
499 .fromApp(fwd.appId())
500 .withPriority(fwd.priority())
501 .forDevice(deviceId)
502 .withSelector(filteredSelector.build())
503 .withTreatment(tb.build())
504 .forTable(forTableId);
505
506 if (fwd.permanent()) {
507 ruleBuilder.makePermanent();
508 } else {
509 ruleBuilder.makeTemporary(fwd.timeout());
510 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800511 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
512 flowRuleCollection.add(ruleBuilder.build());
513 if (defaultRule) {
514 FlowRule.Builder rule = DefaultFlowRule.builder()
515 .fromApp(fwd.appId())
516 .withPriority(fwd.priority())
517 .forDevice(deviceId)
518 .withSelector(complementarySelector.build())
519 .withTreatment(tb.build())
520 .forTable(forTableId);
521 if (fwd.permanent()) {
522 rule.makePermanent();
523 } else {
524 rule.makeTemporary(fwd.timeout());
525 }
526 flowRuleCollection.add(rule.build());
527 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
528 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800529
Flavio Castroe10fa242016-01-15 12:43:51 -0800530 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800531 }
532
Charles Chan1e492d32016-01-30 23:22:37 -0800533 @Override
534 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
535 List<FlowRule> rules = new ArrayList<>();
536
537 // Build filtered selector
538 TrafficSelector selector = fwd.selector();
539 EthCriterion ethCriterion = (EthCriterion) selector
540 .getCriterion(Criterion.Type.ETH_DST);
541 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
542 .getCriterion(Criterion.Type.VLAN_VID);
543
544 if (vlanIdCriterion == null) {
545 log.warn("Forwarding objective for bridging requires vlan. Not "
546 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
547 fail(fwd, ObjectiveError.BADPARAMS);
548 return Collections.emptySet();
549 }
550
551 TrafficSelector.Builder filteredSelectorBuilder =
552 DefaultTrafficSelector.builder();
553 // Do not match MacAddress for subnet broadcast entry
554 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
555 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
556 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
557 fwd.id(), fwd.nextId(), deviceId);
558 } else {
559 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
560 + "in dev:{} for vlan:{}",
561 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
562 }
563 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
564 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
565
566 if (fwd.treatment() != null) {
567 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
568 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
569 }
570
571 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
572 if (fwd.nextId() != null) {
573 NextGroup next = getGroupForNextObjective(fwd.nextId());
574 if (next != null) {
575 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
576 // we only need the top level group's key to point the flow to it
577 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
578 if (group != null) {
579 treatmentBuilder.deferred().group(group.id());
580 } else {
581 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
582 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
583 fail(fwd, ObjectiveError.GROUPMISSING);
584 return Collections.emptySet();
585 }
586 }
587 }
588 treatmentBuilder.immediate().transition(ACL_TABLE);
589 TrafficTreatment filteredTreatment = treatmentBuilder.build();
590
591 // Build bridging table entries
592 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
593 flowRuleBuilder.fromApp(fwd.appId())
594 .withPriority(fwd.priority())
595 .forDevice(deviceId)
596 .withSelector(filteredSelector)
597 .withTreatment(filteredTreatment)
598 .forTable(BRIDGING_TABLE);
599 if (fwd.permanent()) {
600 flowRuleBuilder.makePermanent();
601 } else {
602 flowRuleBuilder.makeTemporary(fwd.timeout());
603 }
604 rules.add(flowRuleBuilder.build());
605 return rules;
606 }
607
Saurav Das52025962016-01-28 22:30:01 -0800608 /*
609 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
610 * ACL table. Because we pop off vlan tags in TMAC table,
611 * we need to avoid matching on vlans in the ACL table.
612 */
613 @Override
614 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
615 log.info("Processing versatile forwarding objective");
616
617 EthTypeCriterion ethType =
618 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
619 if (ethType == null) {
620 log.error("Versatile forwarding objective must include ethType");
621 fail(fwd, ObjectiveError.BADPARAMS);
622 return Collections.emptySet();
623 }
624 if (fwd.nextId() == null && fwd.treatment() == null) {
625 log.error("Forwarding objective {} from {} must contain "
626 + "nextId or Treatment", fwd.selector(), fwd.appId());
627 return Collections.emptySet();
628 }
629
630 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
631 fwd.selector().criteria().forEach(criterion -> {
632 if (criterion instanceof VlanIdCriterion) {
633 // avoid matching on vlans
634 return;
635 } else {
636 sbuilder.add(criterion);
637 }
638 });
639
640 // XXX driver does not currently do type checking as per Tables 65-67 in
641 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
642 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
643 if (fwd.treatment() != null) {
644 for (Instruction ins : fwd.treatment().allInstructions()) {
645 if (ins instanceof OutputInstruction) {
646 OutputInstruction o = (OutputInstruction) ins;
647 if (o.port() == PortNumber.CONTROLLER) {
Saurav Das49831642016-02-05 13:15:20 -0800648 // emulating real ofdpa behavior by popping off internal
649 // vlan before sending to controller
650 ttBuilder.popVlan();
Saurav Das52025962016-01-28 22:30:01 -0800651 ttBuilder.add(o);
652 } else {
653 log.warn("Only allowed treatments in versatile forwarding "
654 + "objectives are punts to the controller");
655 }
656 } else {
657 log.warn("Cannot process instruction in versatile fwd {}", ins);
658 }
659 }
Charles Chan5270ed02016-01-30 23:22:37 -0800660 ttBuilder.wipeDeferred();
Saurav Das52025962016-01-28 22:30:01 -0800661 }
662 if (fwd.nextId() != null) {
663 // overide case
664 NextGroup next = getGroupForNextObjective(fwd.nextId());
665 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
666 // we only need the top level group's key to point the flow to it
667 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
668 if (group == null) {
669 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
670 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
671 fail(fwd, ObjectiveError.GROUPMISSING);
672 return Collections.emptySet();
673 }
674 ttBuilder.deferred().group(group.id());
675 }
676
677 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
678 .fromApp(fwd.appId())
679 .withPriority(fwd.priority())
680 .forDevice(deviceId)
681 .withSelector(sbuilder.build())
682 .withTreatment(ttBuilder.build())
683 .makePermanent()
684 .forTable(ACL_TABLE);
685 return Collections.singletonList(ruleBuilder.build());
686 }
687
688 /*
689 * Cpqd emulation requires table-miss-entries in forwarding tables.
690 * Real OFDPA does not require these rules as they are put in by default.
691 *
692 * (non-Javadoc)
693 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
694 */
Saurav Das2857f382015-11-03 14:39:27 -0800695 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700696 protected void initializePipeline() {
697 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800698 // vlan table processing not required, as default is to drop packets
699 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700700 processTmacTable();
701 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800702 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700703 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700704 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700705 }
706
Saurav Das558afec2015-05-31 17:12:48 -0700707 protected void processPortTable() {
708 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
709 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
710 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
711 treatment.transition(VLAN_TABLE);
712 FlowRule tmisse = DefaultFlowRule.builder()
713 .forDevice(deviceId)
714 .withSelector(selector.build())
715 .withTreatment(treatment.build())
716 .withPriority(LOWEST_PRIORITY)
717 .fromApp(driverId)
718 .makePermanent()
719 .forTable(PORT_TABLE).build();
720 ops = ops.add(tmisse);
721
722 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
723 @Override
724 public void onSuccess(FlowRuleOperations ops) {
725 log.info("Initialized port table");
726 }
727
728 @Override
729 public void onError(FlowRuleOperations ops) {
730 log.info("Failed to initialize port table");
731 }
732 }));
733 }
734
Saurav Das558afec2015-05-31 17:12:48 -0700735 protected void processTmacTable() {
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(BRIDGING_TABLE);
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(TMAC_TABLE).build();
751 ops = ops.add(rule);
752 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
753 @Override
754 public void onSuccess(FlowRuleOperations ops) {
755 log.info("Initialized tmac table");
756 }
757
758 @Override
759 public void onError(FlowRuleOperations ops) {
760 log.info("Failed to initialize tmac table");
761 }
762 }));
763 }
764
Saurav Das558afec2015-05-31 17:12:48 -0700765 protected void processIpTable() {
766 //table miss entry
767 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
768 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
769 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
770 selector = DefaultTrafficSelector.builder();
771 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800772 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700773 treatment.transition(ACL_TABLE);
774 FlowRule rule = DefaultFlowRule.builder()
775 .forDevice(deviceId)
776 .withSelector(selector.build())
777 .withTreatment(treatment.build())
778 .withPriority(LOWEST_PRIORITY)
779 .fromApp(driverId)
780 .makePermanent()
781 .forTable(UNICAST_ROUTING_TABLE).build();
782 ops = ops.add(rule);
783 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
784 @Override
785 public void onSuccess(FlowRuleOperations ops) {
786 log.info("Initialized IP table");
787 }
788
789 @Override
790 public void onError(FlowRuleOperations ops) {
791 log.info("Failed to initialize unicast IP table");
792 }
793 }));
794 }
795
Saurav Das2857f382015-11-03 14:39:27 -0800796 protected void processMplsTable() {
797 //table miss entry
798 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
799 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
800 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
801 selector = DefaultTrafficSelector.builder();
802 treatment = DefaultTrafficTreatment.builder();
803 treatment.transition(MPLS_TABLE_1);
804 FlowRule rule = DefaultFlowRule.builder()
805 .forDevice(deviceId)
806 .withSelector(selector.build())
807 .withTreatment(treatment.build())
808 .withPriority(LOWEST_PRIORITY)
809 .fromApp(driverId)
810 .makePermanent()
811 .forTable(MPLS_TABLE_0).build();
812 ops = ops.add(rule);
813
814 treatment.transition(ACL_TABLE);
815 rule = DefaultFlowRule.builder()
816 .forDevice(deviceId)
817 .withSelector(selector.build())
818 .withTreatment(treatment.build())
819 .withPriority(LOWEST_PRIORITY)
820 .fromApp(driverId)
821 .makePermanent()
822 .forTable(MPLS_TABLE_1).build();
823 ops = ops.add(rule);
824
825 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
826 @Override
827 public void onSuccess(FlowRuleOperations ops) {
828 log.info("Initialized MPLS tables");
829 }
830
831 @Override
832 public void onError(FlowRuleOperations ops) {
833 log.info("Failed to initialize MPLS tables");
834 }
835 }));
836 }
837
Saurav Das558afec2015-05-31 17:12:48 -0700838 private void processBridgingTable() {
839 //table miss entry
840 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
841 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
842 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
843 selector = DefaultTrafficSelector.builder();
844 treatment = DefaultTrafficTreatment.builder();
845 treatment.transition(ACL_TABLE);
846 FlowRule rule = DefaultFlowRule.builder()
847 .forDevice(deviceId)
848 .withSelector(selector.build())
849 .withTreatment(treatment.build())
850 .withPriority(LOWEST_PRIORITY)
851 .fromApp(driverId)
852 .makePermanent()
853 .forTable(BRIDGING_TABLE).build();
854 ops = ops.add(rule);
855 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
856 @Override
857 public void onSuccess(FlowRuleOperations ops) {
858 log.info("Initialized Bridging table");
859 }
860
861 @Override
862 public void onError(FlowRuleOperations ops) {
863 log.info("Failed to initialize Bridging table");
864 }
865 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700866 }
Saurav Das558afec2015-05-31 17:12:48 -0700867
Saurav Dasa07f2032015-10-19 14:37:36 -0700868 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700869 //table miss entry - catch all to executed action-set
870 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
871 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
872 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
873 selector = DefaultTrafficSelector.builder();
874 treatment = DefaultTrafficTreatment.builder();
875 FlowRule rule = DefaultFlowRule.builder()
876 .forDevice(deviceId)
877 .withSelector(selector.build())
878 .withTreatment(treatment.build())
879 .withPriority(LOWEST_PRIORITY)
880 .fromApp(driverId)
881 .makePermanent()
882 .forTable(ACL_TABLE).build();
883 ops = ops.add(rule);
884 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
885 @Override
886 public void onSuccess(FlowRuleOperations ops) {
887 log.info("Initialized Acl table");
888 }
889
890 @Override
891 public void onError(FlowRuleOperations ops) {
892 log.info("Failed to initialize Acl table");
893 }
894 }));
Saurav Das558afec2015-05-31 17:12:48 -0700895 }
896
897}