blob: 6bcebd722359565d77e61043420b647acf74e4bd [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Thomas Vachuska58de4162015-09-10 16:15:33 -07003 *
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;
Charles Chan425854b2016-04-11 15:32:12 -070035import org.onosproject.core.CoreService;
36import org.onosproject.net.DeviceId;
Saurav Das2857f382015-11-03 14:39:27 -080037import org.onosproject.net.Port;
38import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080039import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070040import org.onosproject.net.behaviour.PipelinerContext;
41import org.onosproject.net.device.DeviceService;
Saurav Das558afec2015-05-31 17:12:48 -070042import org.onosproject.net.flow.DefaultFlowRule;
43import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.FlowRule;
46import org.onosproject.net.flow.FlowRuleOperations;
47import org.onosproject.net.flow.FlowRuleOperationsContext;
Charles Chan425854b2016-04-11 15:32:12 -070048import org.onosproject.net.flow.FlowRuleService;
Saurav Das558afec2015-05-31 17:12:48 -070049import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080051import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080052import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080053import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080054import org.onosproject.net.flow.criteria.EthTypeCriterion;
55import org.onosproject.net.flow.criteria.IPCriterion;
56import org.onosproject.net.flow.criteria.MplsBosCriterion;
57import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080058import org.onosproject.net.flow.criteria.PortCriterion;
59import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080060import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080061import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
62import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
63import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080064import org.onosproject.net.flowobjective.ForwardingObjective;
65import org.onosproject.net.flowobjective.ObjectiveError;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupKey;
Charles Chan425854b2016-04-11 15:32:12 -070068import org.onosproject.net.group.GroupService;
Saurav Das558afec2015-05-31 17:12:48 -070069import org.slf4j.Logger;
70
71
72/**
Saurav Das822c4e22015-10-23 10:51:11 -070073 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das52025962016-01-28 22:30:01 -080074 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
75 * does not handle vlan tags and mpls labels simultaneously, which requires us
76 * to do some workarounds in the driver. This driver is meant for the use of
77 * the cpqd switch when MPLS is required. As a result this driver works only
78 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070079 */
Charles Chan361154b2016-03-24 10:23:39 -070080public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070081
82 private final Logger log = getLogger(getClass());
83
Charles Chan425854b2016-04-11 15:32:12 -070084 @Override
85 public void init(DeviceId deviceId, PipelinerContext context) {
86 this.deviceId = deviceId;
87
88 // Initialize OFDPA group handler
89 groupHandler = new CpqdOfdpa2GroupHandler();
90 groupHandler.init(deviceId, context);
91
92 serviceDirectory = context.directory();
93 coreService = serviceDirectory.get(CoreService.class);
94 flowRuleService = serviceDirectory.get(FlowRuleService.class);
95 groupService = serviceDirectory.get(GroupService.class);
96 flowObjectiveStore = context.store();
97 deviceService = serviceDirectory.get(DeviceService.class);
98
99 driverId = coreService.registerApplication(
100 "org.onosproject.driver.CpqdOfdpa2Pipeline");
101
102 initializePipeline();
103 }
104
Saurav Das4ce45962015-11-24 23:21:05 -0800105 /*
Saurav Das52025962016-01-28 22:30:01 -0800106 * CPQD emulation does not require special untagged packet handling, unlike
107 * the real ofdpa.
108 */
109 @Override
110 protected void processFilter(FilteringObjective filt,
111 boolean install, ApplicationId applicationId) {
112 // This driver only processes filtering criteria defined with switch
113 // ports as the key
114 PortCriterion portCriterion = null;
115 EthCriterion ethCriterion = null;
116 VlanIdCriterion vidCriterion = null;
117 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
118 if (!filt.key().equals(Criteria.dummy()) &&
119 filt.key().type() == Criterion.Type.IN_PORT) {
120 portCriterion = (PortCriterion) filt.key();
121 } else {
122 log.warn("No key defined in filtering objective from app: {}. Not"
123 + "processing filtering objective", applicationId);
124 fail(filt, ObjectiveError.UNKNOWN);
125 return;
126 }
127 // convert filtering conditions for switch-intfs into flowrules
128 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
129 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700130 if (criterion.type() == Criterion.Type.ETH_DST ||
131 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das52025962016-01-28 22:30:01 -0800132 ethCriterion = (EthCriterion) criterion;
133 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
134 vidCriterion = (VlanIdCriterion) criterion;
135 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
136 ips.add((IPCriterion) criterion);
137 } else {
138 log.error("Unsupported filter {}", criterion);
139 fail(filt, ObjectiveError.UNSUPPORTED);
140 return;
141 }
142 }
143
144 VlanId assignedVlan = null;
145 // For VLAN cross-connect packets, use the configured VLAN
146 if (vidCriterion != null) {
147 if (vidCriterion.vlanId() != VlanId.NONE) {
148 assignedVlan = vidCriterion.vlanId();
149
150 // For untagged packets, assign a VLAN ID
151 } else {
152 if (filt.meta() == null) {
153 log.error("Missing metadata in filtering objective required " +
154 "for vlan assignment in dev {}", deviceId);
155 fail(filt, ObjectiveError.BADPARAMS);
156 return;
157 }
158 for (Instruction i : filt.meta().allInstructions()) {
159 if (i instanceof ModVlanIdInstruction) {
160 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
161 }
162 }
163 if (assignedVlan == null) {
164 log.error("Driver requires an assigned vlan-id to tag incoming "
165 + "untagged packets. Not processing vlan filters on "
166 + "device {}", deviceId);
167 fail(filt, ObjectiveError.BADPARAMS);
168 return;
169 }
170 }
171 }
172
173 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
174 log.debug("filtering objective missing dstMac, cannot program TMAC table");
175 } else {
176 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
177 vidCriterion, assignedVlan,
178 applicationId)) {
179 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
180 tmacRule, deviceId);
181 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
182 }
183 }
184
185 if (ethCriterion == null || vidCriterion == null) {
186 log.debug("filtering objective missing dstMac or VLAN, "
187 + "cannot program VLAN Table");
188 } else {
189 List<FlowRule> allRules = processVlanIdFilter(
190 portCriterion, vidCriterion, assignedVlan, applicationId);
191 for (FlowRule rule : allRules) {
192 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
193 rule, deviceId);
194 ops = install ? ops.add(rule) : ops.remove(rule);
195 }
196 }
197
198 for (IPCriterion ipaddr : ips) {
199 // since we ignore port information for IP rules, and the same (gateway) IP
200 // can be configured on multiple ports, we make sure that we send
201 // only a single rule to the switch.
202 if (!sentIpFilters.contains(ipaddr)) {
203 sentIpFilters.add(ipaddr);
204 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
205 ipaddr, deviceId);
206 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
207 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
208 selector.matchEthType(Ethernet.TYPE_IPV4);
209 selector.matchIPDst(ipaddr.ip());
210 treatment.setOutput(PortNumber.CONTROLLER);
211 FlowRule rule = DefaultFlowRule.builder()
212 .forDevice(deviceId)
213 .withSelector(selector.build())
214 .withTreatment(treatment.build())
215 .withPriority(HIGHEST_PRIORITY)
216 .fromApp(applicationId)
217 .makePermanent()
218 .forTable(ACL_TABLE).build();
219 ops = install ? ops.add(rule) : ops.remove(rule);
220 }
221 }
222
223 // apply filtering flow rules
224 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
225 @Override
226 public void onSuccess(FlowRuleOperations ops) {
227 log.info("Applied {} filtering rules in device {}",
228 ops.stages().get(0).size(), deviceId);
229 pass(filt);
230 }
231
232 @Override
233 public void onError(FlowRuleOperations ops) {
234 log.info("Failed to apply all filtering rules in dev {}", deviceId);
235 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
236 }
237 }));
238
239 }
240
241 /*
Saurav Das4ce45962015-11-24 23:21:05 -0800242 * Cpqd emulation does not require the non-OF standard rules for
243 * matching untagged packets.
244 *
245 * (non-Javadoc)
246 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
247 */
Saurav Das558afec2015-05-31 17:12:48 -0700248 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800249 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
250 VlanIdCriterion vidCriterion,
251 VlanId assignedVlan,
252 ApplicationId applicationId) {
253 List<FlowRule> rules = new ArrayList<FlowRule>();
254 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
255 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
256 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800257 treatment.transition(TMAC_TABLE);
258
259 VlanId storeVlan = null;
Saurav Das2857f382015-11-03 14:39:27 -0800260 if (vidCriterion.vlanId() == VlanId.NONE) {
261 // untagged packets are assigned vlans
262 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800263 storeVlan = assignedVlan;
264 } else {
265 storeVlan = vidCriterion.vlanId();
Saurav Das2857f382015-11-03 14:39:27 -0800266 }
Saurav Das2857f382015-11-03 14:39:27 -0800267
268 // ofdpa cannot match on ALL portnumber, so we need to use separate
269 // rules for each port.
270 List<PortNumber> portnums = new ArrayList<PortNumber>();
271 if (portCriterion.port() == PortNumber.ALL) {
272 for (Port port : deviceService.getPorts(deviceId)) {
273 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
274 portnums.add(port.number());
275 }
276 }
277 } else {
278 portnums.add(portCriterion.port());
279 }
Saurav Das4f980082015-11-05 13:39:15 -0800280
Saurav Das2857f382015-11-03 14:39:27 -0800281 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800282 // update storage
Charles Chan425854b2016-04-11 15:32:12 -0700283 groupHandler.port2Vlan.put(pnum, storeVlan);
284 Set<PortNumber> vlanPorts = groupHandler.vlan2Port.get(storeVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800285 if (vlanPorts == null) {
286 vlanPorts = Collections.newSetFromMap(
287 new ConcurrentHashMap<PortNumber, Boolean>());
288 vlanPorts.add(pnum);
Charles Chan425854b2016-04-11 15:32:12 -0700289 groupHandler.vlan2Port.put(storeVlan, vlanPorts);
Saurav Das4f980082015-11-05 13:39:15 -0800290 } else {
291 vlanPorts.add(pnum);
292 }
293 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800294 selector.matchInPort(pnum);
295 FlowRule rule = DefaultFlowRule.builder()
296 .forDevice(deviceId)
297 .withSelector(selector.build())
298 .withTreatment(treatment.build())
299 .withPriority(DEFAULT_PRIORITY)
300 .fromApp(applicationId)
301 .makePermanent()
302 .forTable(VLAN_TABLE).build();
303 rules.add(rule);
304 }
305 return rules;
306 }
307
Saurav Das4ce45962015-11-24 23:21:05 -0800308 /*
309 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
310 * Workaround requires popping off the VLAN tags in the TMAC table.
311 *
312 * (non-Javadoc)
313 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
314 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800315 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800316 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
317 EthCriterion ethCriterion,
318 VlanIdCriterion vidCriterion,
319 VlanId assignedVlan,
320 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800321 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
322 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
323 return processEthDstOnlyFilter(ethCriterion, applicationId);
324 }
325
Charles Chan5b9df8d2016-03-28 22:21:40 -0700326 // Multicast MAC
327 if (ethCriterion.mask() != null) {
328 return processMcastEthDstFilter(ethCriterion, applicationId);
329 }
330
Saurav Das4ce45962015-11-24 23:21:05 -0800331 //handling untagged packets via assigned VLAN
332 if (vidCriterion.vlanId() == VlanId.NONE) {
333 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
334 }
335 // ofdpa cannot match on ALL portnumber, so we need to use separate
336 // rules for each port.
337 List<PortNumber> portnums = new ArrayList<PortNumber>();
338 if (portCriterion.port() == PortNumber.ALL) {
339 for (Port port : deviceService.getPorts(deviceId)) {
340 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
341 portnums.add(port.number());
342 }
343 }
344 } else {
345 portnums.add(portCriterion.port());
346 }
347
348 List<FlowRule> rules = new ArrayList<FlowRule>();
349 for (PortNumber pnum : portnums) {
350 // for unicast IP packets
351 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
352 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
353 selector.matchInPort(pnum);
354 selector.matchVlanId(vidCriterion.vlanId());
355 selector.matchEthType(Ethernet.TYPE_IPV4);
356 selector.matchEthDst(ethCriterion.mac());
357 /*
358 * Note: CpqD switches do not handle MPLS-related operation properly
359 * for a packet with VLAN tag. We pop VLAN here as a workaround.
360 * Side effect: HostService learns redundant hosts with same MAC but
361 * different VLAN. No known side effect on the network reachability.
362 */
363 treatment.popVlan();
364 treatment.transition(UNICAST_ROUTING_TABLE);
365 FlowRule rule = DefaultFlowRule.builder()
366 .forDevice(deviceId)
367 .withSelector(selector.build())
368 .withTreatment(treatment.build())
369 .withPriority(DEFAULT_PRIORITY)
370 .fromApp(applicationId)
371 .makePermanent()
372 .forTable(TMAC_TABLE).build();
373 rules.add(rule);
374 //for MPLS packets
375 selector = DefaultTrafficSelector.builder();
376 treatment = DefaultTrafficTreatment.builder();
377 selector.matchInPort(pnum);
378 selector.matchVlanId(vidCriterion.vlanId());
379 selector.matchEthType(Ethernet.MPLS_UNICAST);
380 selector.matchEthDst(ethCriterion.mac());
381 // workaround here again
382 treatment.popVlan();
383 treatment.transition(MPLS_TABLE_0);
384 rule = DefaultFlowRule.builder()
385 .forDevice(deviceId)
386 .withSelector(selector.build())
387 .withTreatment(treatment.build())
388 .withPriority(DEFAULT_PRIORITY)
389 .fromApp(applicationId)
390 .makePermanent()
391 .forTable(TMAC_TABLE).build();
392 rules.add(rule);
393 }
394 return rules;
395 }
396
Charles Chan5270ed02016-01-30 23:22:37 -0800397 @Override
398 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
399 ApplicationId applicationId) {
400 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
401 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
402 selector.matchEthType(Ethernet.TYPE_IPV4);
403 selector.matchEthDst(ethCriterion.mac());
404 /*
405 * Note: CpqD switches do not handle MPLS-related operation properly
406 * for a packet with VLAN tag. We pop VLAN here as a workaround.
407 * Side effect: HostService learns redundant hosts with same MAC but
408 * different VLAN. No known side effect on the network reachability.
409 */
410 treatment.popVlan();
411 treatment.transition(UNICAST_ROUTING_TABLE);
412 FlowRule rule = DefaultFlowRule.builder()
413 .forDevice(deviceId)
414 .withSelector(selector.build())
415 .withTreatment(treatment.build())
416 .withPriority(DEFAULT_PRIORITY)
417 .fromApp(applicationId)
418 .makePermanent()
419 .forTable(TMAC_TABLE).build();
420 return ImmutableList.<FlowRule>builder().add(rule).build();
421 }
422
Saurav Das4ce45962015-11-24 23:21:05 -0800423 /*
424 * Cpqd emulation allows MPLS ecmp.
425 *
426 * (non-Javadoc)
427 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
428 */
429 @Override
430 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800431 TrafficSelector selector = fwd.selector();
432 EthTypeCriterion ethType =
433 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
434 if ((ethType == null) ||
435 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
436 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800437 log.warn("processSpecific: Unsupported forwarding objective criteria"
438 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800439 fail(fwd, ObjectiveError.UNSUPPORTED);
440 return Collections.emptySet();
441 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800442 boolean defaultRule = false;
Saurav Das8a0732e2015-11-20 15:27:53 -0800443 int forTableId = -1;
444 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800445 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
446
447 /*
448 * NOTE: The switch does not support matching 0.0.0.0/0.
449 * Split it into 0.0.0.0/1 and 128.0.0.0/1
450 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800451 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800452 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700453 if (ipv4Dst.isMulticast()) {
454 if (ipv4Dst.prefixLength() != 32) {
455 log.warn("Multicast specific forwarding objective can only be /32");
456 fail(fwd, ObjectiveError.BADPARAMS);
457 return ImmutableSet.of();
458 }
459 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
460 if (assignedVlan == null) {
461 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
462 fail(fwd, ObjectiveError.BADPARAMS);
463 return ImmutableSet.of();
464 }
465 filteredSelector.matchVlanId(assignedVlan);
466 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
467 forTableId = MULTICAST_ROUTING_TABLE;
468 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
469 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800470 } else {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700471 if (ipv4Dst.prefixLength() > 0) {
472 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
473 } else {
474 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
475 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
476 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
477 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
478 defaultRule = true;
479 }
480 forTableId = UNICAST_ROUTING_TABLE;
481 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
482 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800483 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800484 } else {
485 filteredSelector
486 .matchEthType(Ethernet.MPLS_UNICAST)
487 .matchMplsLabel(((MplsCriterion)
488 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
489 MplsBosCriterion bos = (MplsBosCriterion) selector
490 .getCriterion(Criterion.Type.MPLS_BOS);
491 if (bos != null) {
492 filteredSelector.matchMplsBos(bos.mplsBos());
493 }
494 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800495 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
496 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800497 }
498
499 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
500 if (fwd.treatment() != null) {
501 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800502 /*
503 * NOTE: OF-DPA does not support immediate instruction in
504 * L3 unicast and MPLS table.
505 */
506 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800507 }
508 }
509
510 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800511 NextGroup next = getGroupForNextObjective(fwd.nextId());
512 if (next != null) {
513 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
514 // we only need the top level group's key to point the flow to it
515 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
516 if (group == null) {
517 log.warn("The group left!");
518 fail(fwd, ObjectiveError.GROUPMISSING);
519 return Collections.emptySet();
520 }
521 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800522 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800523 }
524 tb.transition(ACL_TABLE);
525 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
526 .fromApp(fwd.appId())
527 .withPriority(fwd.priority())
528 .forDevice(deviceId)
529 .withSelector(filteredSelector.build())
530 .withTreatment(tb.build())
531 .forTable(forTableId);
532
533 if (fwd.permanent()) {
534 ruleBuilder.makePermanent();
535 } else {
536 ruleBuilder.makeTemporary(fwd.timeout());
537 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800538 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
539 flowRuleCollection.add(ruleBuilder.build());
540 if (defaultRule) {
541 FlowRule.Builder rule = DefaultFlowRule.builder()
542 .fromApp(fwd.appId())
543 .withPriority(fwd.priority())
544 .forDevice(deviceId)
545 .withSelector(complementarySelector.build())
546 .withTreatment(tb.build())
547 .forTable(forTableId);
548 if (fwd.permanent()) {
549 rule.makePermanent();
550 } else {
551 rule.makeTemporary(fwd.timeout());
552 }
553 flowRuleCollection.add(rule.build());
554 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
555 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800556
Flavio Castroe10fa242016-01-15 12:43:51 -0800557 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800558 }
559
Charles Chan1e492d32016-01-30 23:22:37 -0800560 @Override
561 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
562 List<FlowRule> rules = new ArrayList<>();
563
564 // Build filtered selector
565 TrafficSelector selector = fwd.selector();
566 EthCriterion ethCriterion = (EthCriterion) selector
567 .getCriterion(Criterion.Type.ETH_DST);
568 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
569 .getCriterion(Criterion.Type.VLAN_VID);
570
571 if (vlanIdCriterion == null) {
572 log.warn("Forwarding objective for bridging requires vlan. Not "
573 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
574 fail(fwd, ObjectiveError.BADPARAMS);
575 return Collections.emptySet();
576 }
577
578 TrafficSelector.Builder filteredSelectorBuilder =
579 DefaultTrafficSelector.builder();
580 // Do not match MacAddress for subnet broadcast entry
581 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
582 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
583 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
584 fwd.id(), fwd.nextId(), deviceId);
585 } else {
586 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
587 + "in dev:{} for vlan:{}",
588 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
589 }
590 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
591 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
592
593 if (fwd.treatment() != null) {
594 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
595 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
596 }
597
598 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
599 if (fwd.nextId() != null) {
600 NextGroup next = getGroupForNextObjective(fwd.nextId());
601 if (next != null) {
602 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
603 // we only need the top level group's key to point the flow to it
604 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
605 if (group != null) {
606 treatmentBuilder.deferred().group(group.id());
607 } else {
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 }
614 }
615 treatmentBuilder.immediate().transition(ACL_TABLE);
616 TrafficTreatment filteredTreatment = treatmentBuilder.build();
617
618 // Build bridging table entries
619 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
620 flowRuleBuilder.fromApp(fwd.appId())
621 .withPriority(fwd.priority())
622 .forDevice(deviceId)
623 .withSelector(filteredSelector)
624 .withTreatment(filteredTreatment)
625 .forTable(BRIDGING_TABLE);
626 if (fwd.permanent()) {
627 flowRuleBuilder.makePermanent();
628 } else {
629 flowRuleBuilder.makeTemporary(fwd.timeout());
630 }
631 rules.add(flowRuleBuilder.build());
632 return rules;
633 }
634
Saurav Das52025962016-01-28 22:30:01 -0800635 /*
636 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
637 * ACL table. Because we pop off vlan tags in TMAC table,
638 * we need to avoid matching on vlans in the ACL table.
639 */
640 @Override
641 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
642 log.info("Processing versatile forwarding objective");
643
644 EthTypeCriterion ethType =
645 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
646 if (ethType == null) {
647 log.error("Versatile forwarding objective must include ethType");
648 fail(fwd, ObjectiveError.BADPARAMS);
649 return Collections.emptySet();
650 }
651 if (fwd.nextId() == null && fwd.treatment() == null) {
652 log.error("Forwarding objective {} from {} must contain "
653 + "nextId or Treatment", fwd.selector(), fwd.appId());
654 return Collections.emptySet();
655 }
656
657 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
658 fwd.selector().criteria().forEach(criterion -> {
659 if (criterion instanceof VlanIdCriterion) {
660 // avoid matching on vlans
661 return;
662 } else {
663 sbuilder.add(criterion);
664 }
665 });
666
667 // XXX driver does not currently do type checking as per Tables 65-67 in
668 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
669 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
670 if (fwd.treatment() != null) {
671 for (Instruction ins : fwd.treatment().allInstructions()) {
672 if (ins instanceof OutputInstruction) {
673 OutputInstruction o = (OutputInstruction) ins;
674 if (o.port() == PortNumber.CONTROLLER) {
Saurav Das49831642016-02-05 13:15:20 -0800675 // emulating real ofdpa behavior by popping off internal
676 // vlan before sending to controller
677 ttBuilder.popVlan();
Saurav Das52025962016-01-28 22:30:01 -0800678 ttBuilder.add(o);
679 } else {
680 log.warn("Only allowed treatments in versatile forwarding "
681 + "objectives are punts to the controller");
682 }
683 } else {
684 log.warn("Cannot process instruction in versatile fwd {}", ins);
685 }
686 }
Charles Chan5270ed02016-01-30 23:22:37 -0800687 ttBuilder.wipeDeferred();
Saurav Das52025962016-01-28 22:30:01 -0800688 }
689 if (fwd.nextId() != null) {
690 // overide case
691 NextGroup next = getGroupForNextObjective(fwd.nextId());
692 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
693 // we only need the top level group's key to point the flow to it
694 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
695 if (group == null) {
696 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
697 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
698 fail(fwd, ObjectiveError.GROUPMISSING);
699 return Collections.emptySet();
700 }
701 ttBuilder.deferred().group(group.id());
702 }
703
704 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
705 .fromApp(fwd.appId())
706 .withPriority(fwd.priority())
707 .forDevice(deviceId)
708 .withSelector(sbuilder.build())
709 .withTreatment(ttBuilder.build())
710 .makePermanent()
711 .forTable(ACL_TABLE);
712 return Collections.singletonList(ruleBuilder.build());
713 }
714
715 /*
716 * Cpqd emulation requires table-miss-entries in forwarding tables.
717 * Real OFDPA does not require these rules as they are put in by default.
718 *
719 * (non-Javadoc)
720 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
721 */
Saurav Das2857f382015-11-03 14:39:27 -0800722 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700723 protected void initializePipeline() {
724 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800725 // vlan table processing not required, as default is to drop packets
726 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700727 processTmacTable();
728 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800729 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700730 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700731 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700732 }
733
Saurav Das558afec2015-05-31 17:12:48 -0700734 protected void processPortTable() {
735 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
736 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
737 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
738 treatment.transition(VLAN_TABLE);
739 FlowRule tmisse = DefaultFlowRule.builder()
740 .forDevice(deviceId)
741 .withSelector(selector.build())
742 .withTreatment(treatment.build())
743 .withPriority(LOWEST_PRIORITY)
744 .fromApp(driverId)
745 .makePermanent()
746 .forTable(PORT_TABLE).build();
747 ops = ops.add(tmisse);
748
749 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
750 @Override
751 public void onSuccess(FlowRuleOperations ops) {
752 log.info("Initialized port table");
753 }
754
755 @Override
756 public void onError(FlowRuleOperations ops) {
757 log.info("Failed to initialize port table");
758 }
759 }));
760 }
761
Saurav Das558afec2015-05-31 17:12:48 -0700762 protected void processTmacTable() {
763 //table miss entry
764 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
765 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
766 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
767 selector = DefaultTrafficSelector.builder();
768 treatment = DefaultTrafficTreatment.builder();
769 treatment.transition(BRIDGING_TABLE);
770 FlowRule rule = DefaultFlowRule.builder()
771 .forDevice(deviceId)
772 .withSelector(selector.build())
773 .withTreatment(treatment.build())
774 .withPriority(LOWEST_PRIORITY)
775 .fromApp(driverId)
776 .makePermanent()
777 .forTable(TMAC_TABLE).build();
778 ops = ops.add(rule);
779 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
780 @Override
781 public void onSuccess(FlowRuleOperations ops) {
782 log.info("Initialized tmac table");
783 }
784
785 @Override
786 public void onError(FlowRuleOperations ops) {
787 log.info("Failed to initialize tmac table");
788 }
789 }));
790 }
791
Saurav Das558afec2015-05-31 17:12:48 -0700792 protected void processIpTable() {
793 //table miss entry
794 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
795 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
796 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
797 selector = DefaultTrafficSelector.builder();
798 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800799 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700800 treatment.transition(ACL_TABLE);
801 FlowRule rule = DefaultFlowRule.builder()
802 .forDevice(deviceId)
803 .withSelector(selector.build())
804 .withTreatment(treatment.build())
805 .withPriority(LOWEST_PRIORITY)
806 .fromApp(driverId)
807 .makePermanent()
808 .forTable(UNICAST_ROUTING_TABLE).build();
809 ops = ops.add(rule);
810 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
811 @Override
812 public void onSuccess(FlowRuleOperations ops) {
813 log.info("Initialized IP table");
814 }
815
816 @Override
817 public void onError(FlowRuleOperations ops) {
818 log.info("Failed to initialize unicast IP table");
819 }
820 }));
821 }
822
Saurav Das2857f382015-11-03 14:39:27 -0800823 protected void processMplsTable() {
824 //table miss entry
825 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
826 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
827 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
828 selector = DefaultTrafficSelector.builder();
829 treatment = DefaultTrafficTreatment.builder();
830 treatment.transition(MPLS_TABLE_1);
831 FlowRule rule = DefaultFlowRule.builder()
832 .forDevice(deviceId)
833 .withSelector(selector.build())
834 .withTreatment(treatment.build())
835 .withPriority(LOWEST_PRIORITY)
836 .fromApp(driverId)
837 .makePermanent()
838 .forTable(MPLS_TABLE_0).build();
839 ops = ops.add(rule);
840
841 treatment.transition(ACL_TABLE);
842 rule = DefaultFlowRule.builder()
843 .forDevice(deviceId)
844 .withSelector(selector.build())
845 .withTreatment(treatment.build())
846 .withPriority(LOWEST_PRIORITY)
847 .fromApp(driverId)
848 .makePermanent()
849 .forTable(MPLS_TABLE_1).build();
850 ops = ops.add(rule);
851
852 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
853 @Override
854 public void onSuccess(FlowRuleOperations ops) {
855 log.info("Initialized MPLS tables");
856 }
857
858 @Override
859 public void onError(FlowRuleOperations ops) {
860 log.info("Failed to initialize MPLS tables");
861 }
862 }));
863 }
864
Saurav Das558afec2015-05-31 17:12:48 -0700865 private void processBridgingTable() {
866 //table miss entry
867 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
868 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
869 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
870 selector = DefaultTrafficSelector.builder();
871 treatment = DefaultTrafficTreatment.builder();
872 treatment.transition(ACL_TABLE);
873 FlowRule rule = DefaultFlowRule.builder()
874 .forDevice(deviceId)
875 .withSelector(selector.build())
876 .withTreatment(treatment.build())
877 .withPriority(LOWEST_PRIORITY)
878 .fromApp(driverId)
879 .makePermanent()
880 .forTable(BRIDGING_TABLE).build();
881 ops = ops.add(rule);
882 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
883 @Override
884 public void onSuccess(FlowRuleOperations ops) {
885 log.info("Initialized Bridging table");
886 }
887
888 @Override
889 public void onError(FlowRuleOperations ops) {
890 log.info("Failed to initialize Bridging table");
891 }
892 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700893 }
Saurav Das558afec2015-05-31 17:12:48 -0700894
Saurav Dasa07f2032015-10-19 14:37:36 -0700895 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700896 //table miss entry - catch all to executed action-set
897 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
898 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
899 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
900 selector = DefaultTrafficSelector.builder();
901 treatment = DefaultTrafficTreatment.builder();
902 FlowRule rule = DefaultFlowRule.builder()
903 .forDevice(deviceId)
904 .withSelector(selector.build())
905 .withTreatment(treatment.build())
906 .withPriority(LOWEST_PRIORITY)
907 .fromApp(driverId)
908 .makePermanent()
909 .forTable(ACL_TABLE).build();
910 ops = ops.add(rule);
911 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
912 @Override
913 public void onSuccess(FlowRuleOperations ops) {
914 log.info("Initialized Acl table");
915 }
916
917 @Override
918 public void onError(FlowRuleOperations ops) {
919 log.info("Failed to initialize Acl table");
920 }
921 }));
Saurav Das558afec2015-05-31 17:12:48 -0700922 }
923
924}