blob: ff2d7209f55066fb72702daf88b7a3ca8ddbacfb [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
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070019import com.google.common.collect.ImmutableSet;
Saurav Das8a0732e2015-11-20 15:27:53 -080020import org.onlab.packet.Ethernet;
Flavio Castroe10fa242016-01-15 12:43:51 -080021import org.onlab.packet.IpPrefix;
Jonathan Hart855179c2016-04-26 07:40:04 -070022import org.onlab.packet.MacAddress;
Saurav Das2857f382015-11-03 14:39:27 -080023import org.onlab.packet.VlanId;
24import org.onosproject.core.ApplicationId;
Charles Chan425854b2016-04-11 15:32:12 -070025import org.onosproject.core.CoreService;
26import org.onosproject.net.DeviceId;
Saurav Das2857f382015-11-03 14:39:27 -080027import org.onosproject.net.Port;
28import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080029import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070030import org.onosproject.net.behaviour.PipelinerContext;
31import org.onosproject.net.device.DeviceService;
Saurav Das558afec2015-05-31 17:12:48 -070032import org.onosproject.net.flow.DefaultFlowRule;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleOperations;
37import org.onosproject.net.flow.FlowRuleOperationsContext;
Charles Chan425854b2016-04-11 15:32:12 -070038import org.onosproject.net.flow.FlowRuleService;
Saurav Das558afec2015-05-31 17:12:48 -070039import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080041import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080042import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080043import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080044import org.onosproject.net.flow.criteria.EthTypeCriterion;
45import org.onosproject.net.flow.criteria.IPCriterion;
46import org.onosproject.net.flow.criteria.MplsBosCriterion;
47import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080048import org.onosproject.net.flow.criteria.PortCriterion;
49import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080050import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080051import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
52import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
53import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080054import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.ObjectiveError;
56import org.onosproject.net.group.Group;
57import org.onosproject.net.group.GroupKey;
Charles Chan425854b2016-04-11 15:32:12 -070058import org.onosproject.net.group.GroupService;
Charles Chanf57a8252016-06-29 19:12:37 -070059import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070060import org.slf4j.Logger;
61
Jonathan Hart855179c2016-04-26 07:40:04 -070062import java.util.ArrayList;
63import java.util.Collection;
64import java.util.Collections;
65import java.util.Deque;
66import java.util.List;
67
68import static org.slf4j.LoggerFactory.getLogger;
69
Saurav Das558afec2015-05-31 17:12:48 -070070
71/**
Saurav Das822c4e22015-10-23 10:51:11 -070072 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das52025962016-01-28 22:30:01 -080073 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
74 * does not handle vlan tags and mpls labels simultaneously, which requires us
75 * to do some workarounds in the driver. This driver is meant for the use of
76 * the cpqd switch when MPLS is required. As a result this driver works only
77 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070078 */
Charles Chan361154b2016-03-24 10:23:39 -070079public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070080
81 private final Logger log = getLogger(getClass());
82
Charles Chan425854b2016-04-11 15:32:12 -070083 @Override
84 public void init(DeviceId deviceId, PipelinerContext context) {
85 this.deviceId = deviceId;
86
87 // Initialize OFDPA group handler
88 groupHandler = new CpqdOfdpa2GroupHandler();
89 groupHandler.init(deviceId, context);
90
91 serviceDirectory = context.directory();
92 coreService = serviceDirectory.get(CoreService.class);
93 flowRuleService = serviceDirectory.get(FlowRuleService.class);
94 groupService = serviceDirectory.get(GroupService.class);
95 flowObjectiveStore = context.store();
96 deviceService = serviceDirectory.get(DeviceService.class);
97
98 driverId = coreService.registerApplication(
99 "org.onosproject.driver.CpqdOfdpa2Pipeline");
100
101 initializePipeline();
102 }
103
Saurav Das4ce45962015-11-24 23:21:05 -0800104 /*
Saurav Das52025962016-01-28 22:30:01 -0800105 * CPQD emulation does not require special untagged packet handling, unlike
106 * the real ofdpa.
107 */
108 @Override
109 protected void processFilter(FilteringObjective filt,
110 boolean install, ApplicationId applicationId) {
111 // This driver only processes filtering criteria defined with switch
112 // ports as the key
113 PortCriterion portCriterion = null;
114 EthCriterion ethCriterion = null;
115 VlanIdCriterion vidCriterion = null;
116 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
117 if (!filt.key().equals(Criteria.dummy()) &&
118 filt.key().type() == Criterion.Type.IN_PORT) {
119 portCriterion = (PortCriterion) filt.key();
120 } else {
121 log.warn("No key defined in filtering objective from app: {}. Not"
122 + "processing filtering objective", applicationId);
123 fail(filt, ObjectiveError.UNKNOWN);
124 return;
125 }
126 // convert filtering conditions for switch-intfs into flowrules
127 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
128 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700129 if (criterion.type() == Criterion.Type.ETH_DST ||
130 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das52025962016-01-28 22:30:01 -0800131 ethCriterion = (EthCriterion) criterion;
132 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
133 vidCriterion = (VlanIdCriterion) criterion;
134 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
135 ips.add((IPCriterion) criterion);
136 } else {
137 log.error("Unsupported filter {}", criterion);
138 fail(filt, ObjectiveError.UNSUPPORTED);
139 return;
140 }
141 }
142
143 VlanId assignedVlan = null;
144 // For VLAN cross-connect packets, use the configured VLAN
145 if (vidCriterion != null) {
146 if (vidCriterion.vlanId() != VlanId.NONE) {
147 assignedVlan = vidCriterion.vlanId();
148
149 // For untagged packets, assign a VLAN ID
150 } else {
151 if (filt.meta() == null) {
152 log.error("Missing metadata in filtering objective required " +
153 "for vlan assignment in dev {}", deviceId);
154 fail(filt, ObjectiveError.BADPARAMS);
155 return;
156 }
157 for (Instruction i : filt.meta().allInstructions()) {
158 if (i instanceof ModVlanIdInstruction) {
159 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
160 }
161 }
162 if (assignedVlan == null) {
163 log.error("Driver requires an assigned vlan-id to tag incoming "
164 + "untagged packets. Not processing vlan filters on "
165 + "device {}", deviceId);
166 fail(filt, ObjectiveError.BADPARAMS);
167 return;
168 }
169 }
170 }
171
172 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
173 log.debug("filtering objective missing dstMac, cannot program TMAC table");
174 } else {
175 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
176 vidCriterion, assignedVlan,
177 applicationId)) {
178 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
179 tmacRule, deviceId);
180 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
181 }
182 }
183
184 if (ethCriterion == null || vidCriterion == null) {
185 log.debug("filtering objective missing dstMac or VLAN, "
186 + "cannot program VLAN Table");
187 } else {
188 List<FlowRule> allRules = processVlanIdFilter(
189 portCriterion, vidCriterion, assignedVlan, applicationId);
190 for (FlowRule rule : allRules) {
191 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
192 rule, deviceId);
193 ops = install ? ops.add(rule) : ops.remove(rule);
194 }
195 }
196
197 for (IPCriterion ipaddr : ips) {
198 // since we ignore port information for IP rules, and the same (gateway) IP
199 // can be configured on multiple ports, we make sure that we send
200 // only a single rule to the switch.
201 if (!sentIpFilters.contains(ipaddr)) {
202 sentIpFilters.add(ipaddr);
203 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
204 ipaddr, deviceId);
205 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
206 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
207 selector.matchEthType(Ethernet.TYPE_IPV4);
208 selector.matchIPDst(ipaddr.ip());
209 treatment.setOutput(PortNumber.CONTROLLER);
210 FlowRule rule = DefaultFlowRule.builder()
211 .forDevice(deviceId)
212 .withSelector(selector.build())
213 .withTreatment(treatment.build())
214 .withPriority(HIGHEST_PRIORITY)
215 .fromApp(applicationId)
216 .makePermanent()
217 .forTable(ACL_TABLE).build();
218 ops = install ? ops.add(rule) : ops.remove(rule);
219 }
220 }
221
222 // apply filtering flow rules
223 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
224 @Override
225 public void onSuccess(FlowRuleOperations ops) {
226 log.info("Applied {} filtering rules in device {}",
227 ops.stages().get(0).size(), deviceId);
228 pass(filt);
229 }
230
231 @Override
232 public void onError(FlowRuleOperations ops) {
233 log.info("Failed to apply all filtering rules in dev {}", deviceId);
234 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
235 }
236 }));
237
238 }
239
240 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700241 * Cpqd emulation does not require the non OF-standard rules for
242 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800243 *
244 * (non-Javadoc)
245 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
246 */
Saurav Das558afec2015-05-31 17:12:48 -0700247 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800248 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
249 VlanIdCriterion vidCriterion,
250 VlanId assignedVlan,
251 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700252 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800253 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
254 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
255 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800256 treatment.transition(TMAC_TABLE);
257
Saurav Das2857f382015-11-03 14:39:27 -0800258 if (vidCriterion.vlanId() == VlanId.NONE) {
259 // untagged packets are assigned vlans
260 treatment.pushVlan().setVlanId(assignedVlan);
Charles Chan79769232016-07-05 16:34:39 -0700261
262 // Emulating OFDPA behavior by popping off internal assigned VLAN
263 // before sending to controller
264 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
265 .matchEthType(Ethernet.TYPE_ARP)
266 .matchVlanId(assignedVlan);
267 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
268 .popVlan()
269 .punt();
270 FlowRule internalVlan = DefaultFlowRule.builder()
271 .forDevice(deviceId)
272 .withSelector(sbuilder.build())
273 .withTreatment(tbuilder.build())
274 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
275 .fromApp(applicationId)
276 .makePermanent()
277 .forTable(ACL_TABLE).build();
278 rules.add(internalVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800279 }
Saurav Das2857f382015-11-03 14:39:27 -0800280
281 // ofdpa cannot match on ALL portnumber, so we need to use separate
282 // rules for each port.
283 List<PortNumber> portnums = new ArrayList<PortNumber>();
284 if (portCriterion.port() == PortNumber.ALL) {
285 for (Port port : deviceService.getPorts(deviceId)) {
286 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
287 portnums.add(port.number());
288 }
289 }
290 } else {
291 portnums.add(portCriterion.port());
292 }
Saurav Das4f980082015-11-05 13:39:15 -0800293
Saurav Das2857f382015-11-03 14:39:27 -0800294 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800295 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800296 selector.matchInPort(pnum);
297 FlowRule rule = DefaultFlowRule.builder()
298 .forDevice(deviceId)
299 .withSelector(selector.build())
300 .withTreatment(treatment.build())
301 .withPriority(DEFAULT_PRIORITY)
302 .fromApp(applicationId)
303 .makePermanent()
304 .forTable(VLAN_TABLE).build();
305 rules.add(rule);
306 }
Charles Chanf57a8252016-06-29 19:12:37 -0700307
Saurav Das2857f382015-11-03 14:39:27 -0800308 return rules;
309 }
310
Saurav Das4ce45962015-11-24 23:21:05 -0800311 /*
312 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
313 * Workaround requires popping off the VLAN tags in the TMAC table.
314 *
315 * (non-Javadoc)
316 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
317 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800318 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800319 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
320 EthCriterion ethCriterion,
321 VlanIdCriterion vidCriterion,
322 VlanId assignedVlan,
323 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800324 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
325 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
326 return processEthDstOnlyFilter(ethCriterion, applicationId);
327 }
328
Charles Chan5b9df8d2016-03-28 22:21:40 -0700329 // Multicast MAC
330 if (ethCriterion.mask() != null) {
331 return processMcastEthDstFilter(ethCriterion, applicationId);
332 }
333
Saurav Das4ce45962015-11-24 23:21:05 -0800334 //handling untagged packets via assigned VLAN
335 if (vidCriterion.vlanId() == VlanId.NONE) {
336 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
337 }
338 // ofdpa cannot match on ALL portnumber, so we need to use separate
339 // rules for each port.
340 List<PortNumber> portnums = new ArrayList<PortNumber>();
341 if (portCriterion.port() == PortNumber.ALL) {
342 for (Port port : deviceService.getPorts(deviceId)) {
343 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
344 portnums.add(port.number());
345 }
346 }
347 } else {
348 portnums.add(portCriterion.port());
349 }
350
351 List<FlowRule> rules = new ArrayList<FlowRule>();
352 for (PortNumber pnum : portnums) {
353 // for unicast IP packets
354 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
355 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
356 selector.matchInPort(pnum);
357 selector.matchVlanId(vidCriterion.vlanId());
358 selector.matchEthType(Ethernet.TYPE_IPV4);
359 selector.matchEthDst(ethCriterion.mac());
360 /*
361 * Note: CpqD switches do not handle MPLS-related operation properly
362 * for a packet with VLAN tag. We pop VLAN here as a workaround.
363 * Side effect: HostService learns redundant hosts with same MAC but
364 * different VLAN. No known side effect on the network reachability.
365 */
366 treatment.popVlan();
367 treatment.transition(UNICAST_ROUTING_TABLE);
368 FlowRule rule = DefaultFlowRule.builder()
369 .forDevice(deviceId)
370 .withSelector(selector.build())
371 .withTreatment(treatment.build())
372 .withPriority(DEFAULT_PRIORITY)
373 .fromApp(applicationId)
374 .makePermanent()
375 .forTable(TMAC_TABLE).build();
376 rules.add(rule);
377 //for MPLS packets
378 selector = DefaultTrafficSelector.builder();
379 treatment = DefaultTrafficTreatment.builder();
380 selector.matchInPort(pnum);
381 selector.matchVlanId(vidCriterion.vlanId());
382 selector.matchEthType(Ethernet.MPLS_UNICAST);
383 selector.matchEthDst(ethCriterion.mac());
384 // workaround here again
385 treatment.popVlan();
386 treatment.transition(MPLS_TABLE_0);
387 rule = DefaultFlowRule.builder()
388 .forDevice(deviceId)
389 .withSelector(selector.build())
390 .withTreatment(treatment.build())
391 .withPriority(DEFAULT_PRIORITY)
392 .fromApp(applicationId)
393 .makePermanent()
394 .forTable(TMAC_TABLE).build();
395 rules.add(rule);
396 }
397 return rules;
398 }
399
Charles Chan5270ed02016-01-30 23:22:37 -0800400 @Override
401 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
402 ApplicationId applicationId) {
403 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
404 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
405 selector.matchEthType(Ethernet.TYPE_IPV4);
406 selector.matchEthDst(ethCriterion.mac());
407 /*
408 * Note: CpqD switches do not handle MPLS-related operation properly
409 * for a packet with VLAN tag. We pop VLAN here as a workaround.
410 * Side effect: HostService learns redundant hosts with same MAC but
411 * different VLAN. No known side effect on the network reachability.
412 */
413 treatment.popVlan();
414 treatment.transition(UNICAST_ROUTING_TABLE);
415 FlowRule rule = DefaultFlowRule.builder()
416 .forDevice(deviceId)
417 .withSelector(selector.build())
418 .withTreatment(treatment.build())
419 .withPriority(DEFAULT_PRIORITY)
420 .fromApp(applicationId)
421 .makePermanent()
422 .forTable(TMAC_TABLE).build();
423 return ImmutableList.<FlowRule>builder().add(rule).build();
424 }
425
Saurav Das4ce45962015-11-24 23:21:05 -0800426 /*
427 * Cpqd emulation allows MPLS ecmp.
428 *
429 * (non-Javadoc)
430 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
431 */
432 @Override
433 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800434 TrafficSelector selector = fwd.selector();
435 EthTypeCriterion ethType =
436 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
437 if ((ethType == null) ||
438 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
439 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800440 log.warn("processSpecific: Unsupported forwarding objective criteria"
441 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800442 fail(fwd, ObjectiveError.UNSUPPORTED);
443 return Collections.emptySet();
444 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800445 boolean defaultRule = false;
Saurav Das8a0732e2015-11-20 15:27:53 -0800446 int forTableId = -1;
447 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800448 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
449
Saurav Das8a0732e2015-11-20 15:27:53 -0800450 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800451 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700452 if (ipv4Dst.isMulticast()) {
453 if (ipv4Dst.prefixLength() != 32) {
454 log.warn("Multicast specific forwarding objective can only be /32");
455 fail(fwd, ObjectiveError.BADPARAMS);
456 return ImmutableSet.of();
457 }
458 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
459 if (assignedVlan == null) {
460 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
461 fail(fwd, ObjectiveError.BADPARAMS);
462 return ImmutableSet.of();
463 }
464 filteredSelector.matchVlanId(assignedVlan);
465 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
466 forTableId = MULTICAST_ROUTING_TABLE;
467 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
468 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800469 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700470 if (ipv4Dst.prefixLength() == 0) {
471 // The entire IPV4_DST field is wildcarded intentionally
472 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700473 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700474 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700475 }
476 forTableId = UNICAST_ROUTING_TABLE;
477 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
478 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800479 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800480 } else {
481 filteredSelector
482 .matchEthType(Ethernet.MPLS_UNICAST)
483 .matchMplsLabel(((MplsCriterion)
484 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
485 MplsBosCriterion bos = (MplsBosCriterion) selector
486 .getCriterion(Criterion.Type.MPLS_BOS);
487 if (bos != null) {
488 filteredSelector.matchMplsBos(bos.mplsBos());
489 }
490 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800491 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
492 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800493 }
494
495 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
496 if (fwd.treatment() != null) {
497 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800498 /*
499 * NOTE: OF-DPA does not support immediate instruction in
500 * L3 unicast and MPLS table.
501 */
502 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800503 }
504 }
505
506 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800507 NextGroup next = getGroupForNextObjective(fwd.nextId());
508 if (next != null) {
509 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
510 // we only need the top level group's key to point the flow to it
511 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
512 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700513 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
514 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800515 fail(fwd, ObjectiveError.GROUPMISSING);
516 return Collections.emptySet();
517 }
518 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800519 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800520 }
521 tb.transition(ACL_TABLE);
522 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
523 .fromApp(fwd.appId())
524 .withPriority(fwd.priority())
525 .forDevice(deviceId)
526 .withSelector(filteredSelector.build())
527 .withTreatment(tb.build())
528 .forTable(forTableId);
529
530 if (fwd.permanent()) {
531 ruleBuilder.makePermanent();
532 } else {
533 ruleBuilder.makeTemporary(fwd.timeout());
534 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800535 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
536 flowRuleCollection.add(ruleBuilder.build());
537 if (defaultRule) {
538 FlowRule.Builder rule = DefaultFlowRule.builder()
539 .fromApp(fwd.appId())
540 .withPriority(fwd.priority())
541 .forDevice(deviceId)
542 .withSelector(complementarySelector.build())
543 .withTreatment(tb.build())
544 .forTable(forTableId);
545 if (fwd.permanent()) {
546 rule.makePermanent();
547 } else {
548 rule.makeTemporary(fwd.timeout());
549 }
550 flowRuleCollection.add(rule.build());
551 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
552 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800553 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800554 }
555
Charles Chan1e492d32016-01-30 23:22:37 -0800556 @Override
557 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
558 List<FlowRule> rules = new ArrayList<>();
559
560 // Build filtered selector
561 TrafficSelector selector = fwd.selector();
562 EthCriterion ethCriterion = (EthCriterion) selector
563 .getCriterion(Criterion.Type.ETH_DST);
564 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
565 .getCriterion(Criterion.Type.VLAN_VID);
566
567 if (vlanIdCriterion == null) {
568 log.warn("Forwarding objective for bridging requires vlan. Not "
569 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
570 fail(fwd, ObjectiveError.BADPARAMS);
571 return Collections.emptySet();
572 }
573
574 TrafficSelector.Builder filteredSelectorBuilder =
575 DefaultTrafficSelector.builder();
576 // Do not match MacAddress for subnet broadcast entry
577 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
578 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
579 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
580 fwd.id(), fwd.nextId(), deviceId);
581 } else {
582 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
583 + "in dev:{} for vlan:{}",
584 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
585 }
586 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
587 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
588
589 if (fwd.treatment() != null) {
590 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
591 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
592 }
593
594 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
595 if (fwd.nextId() != null) {
596 NextGroup next = getGroupForNextObjective(fwd.nextId());
597 if (next != null) {
598 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
599 // we only need the top level group's key to point the flow to it
600 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
601 if (group != null) {
602 treatmentBuilder.deferred().group(group.id());
603 } else {
604 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
605 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
606 fail(fwd, ObjectiveError.GROUPMISSING);
607 return Collections.emptySet();
608 }
609 }
610 }
611 treatmentBuilder.immediate().transition(ACL_TABLE);
612 TrafficTreatment filteredTreatment = treatmentBuilder.build();
613
614 // Build bridging table entries
615 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
616 flowRuleBuilder.fromApp(fwd.appId())
617 .withPriority(fwd.priority())
618 .forDevice(deviceId)
619 .withSelector(filteredSelector)
620 .withTreatment(filteredTreatment)
621 .forTable(BRIDGING_TABLE);
622 if (fwd.permanent()) {
623 flowRuleBuilder.makePermanent();
624 } else {
625 flowRuleBuilder.makeTemporary(fwd.timeout());
626 }
627 rules.add(flowRuleBuilder.build());
628 return rules;
629 }
630
Saurav Das52025962016-01-28 22:30:01 -0800631 /*
632 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
633 * ACL table. Because we pop off vlan tags in TMAC table,
634 * we need to avoid matching on vlans in the ACL table.
635 */
636 @Override
637 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
638 log.info("Processing versatile forwarding objective");
639
640 EthTypeCriterion ethType =
641 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
642 if (ethType == null) {
643 log.error("Versatile forwarding objective must include ethType");
644 fail(fwd, ObjectiveError.BADPARAMS);
645 return Collections.emptySet();
646 }
647 if (fwd.nextId() == null && fwd.treatment() == null) {
648 log.error("Forwarding objective {} from {} must contain "
649 + "nextId or Treatment", fwd.selector(), fwd.appId());
650 return Collections.emptySet();
651 }
652
653 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
654 fwd.selector().criteria().forEach(criterion -> {
655 if (criterion instanceof VlanIdCriterion) {
656 // avoid matching on vlans
657 return;
658 } else {
659 sbuilder.add(criterion);
660 }
661 });
662
663 // XXX driver does not currently do type checking as per Tables 65-67 in
664 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
665 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
666 if (fwd.treatment() != null) {
667 for (Instruction ins : fwd.treatment().allInstructions()) {
668 if (ins instanceof OutputInstruction) {
669 OutputInstruction o = (OutputInstruction) ins;
670 if (o.port() == PortNumber.CONTROLLER) {
671 ttBuilder.add(o);
672 } else {
673 log.warn("Only allowed treatments in versatile forwarding "
674 + "objectives are punts to the controller");
675 }
676 } else {
677 log.warn("Cannot process instruction in versatile fwd {}", ins);
678 }
679 }
680 }
681 if (fwd.nextId() != null) {
682 // overide case
683 NextGroup next = getGroupForNextObjective(fwd.nextId());
684 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
685 // we only need the top level group's key to point the flow to it
686 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
687 if (group == null) {
688 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
689 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
690 fail(fwd, ObjectiveError.GROUPMISSING);
691 return Collections.emptySet();
692 }
693 ttBuilder.deferred().group(group.id());
694 }
695
696 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
697 .fromApp(fwd.appId())
698 .withPriority(fwd.priority())
699 .forDevice(deviceId)
700 .withSelector(sbuilder.build())
701 .withTreatment(ttBuilder.build())
702 .makePermanent()
703 .forTable(ACL_TABLE);
704 return Collections.singletonList(ruleBuilder.build());
705 }
706
707 /*
708 * Cpqd emulation requires table-miss-entries in forwarding tables.
709 * Real OFDPA does not require these rules as they are put in by default.
710 *
711 * (non-Javadoc)
712 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
713 */
Saurav Das2857f382015-11-03 14:39:27 -0800714 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700715 protected void initializePipeline() {
716 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800717 // vlan table processing not required, as default is to drop packets
718 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700719 processTmacTable();
720 processIpTable();
Jonathan Hart855179c2016-04-26 07:40:04 -0700721 processMulticastIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800722 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700723 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700724 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700725 }
726
Saurav Das558afec2015-05-31 17:12:48 -0700727 protected void processPortTable() {
728 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
729 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
730 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
731 treatment.transition(VLAN_TABLE);
732 FlowRule tmisse = DefaultFlowRule.builder()
733 .forDevice(deviceId)
734 .withSelector(selector.build())
735 .withTreatment(treatment.build())
736 .withPriority(LOWEST_PRIORITY)
737 .fromApp(driverId)
738 .makePermanent()
739 .forTable(PORT_TABLE).build();
740 ops = ops.add(tmisse);
741
742 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
743 @Override
744 public void onSuccess(FlowRuleOperations ops) {
745 log.info("Initialized port table");
746 }
747
748 @Override
749 public void onError(FlowRuleOperations ops) {
750 log.info("Failed to initialize port table");
751 }
752 }));
753 }
754
Saurav Das558afec2015-05-31 17:12:48 -0700755 protected void processTmacTable() {
756 //table miss entry
757 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
758 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
759 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Saurav Das558afec2015-05-31 17:12:48 -0700760 treatment.transition(BRIDGING_TABLE);
761 FlowRule rule = DefaultFlowRule.builder()
762 .forDevice(deviceId)
763 .withSelector(selector.build())
764 .withTreatment(treatment.build())
765 .withPriority(LOWEST_PRIORITY)
766 .fromApp(driverId)
767 .makePermanent()
768 .forTable(TMAC_TABLE).build();
769 ops = ops.add(rule);
770 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
771 @Override
772 public void onSuccess(FlowRuleOperations ops) {
773 log.info("Initialized tmac table");
774 }
775
776 @Override
777 public void onError(FlowRuleOperations ops) {
778 log.info("Failed to initialize tmac table");
779 }
780 }));
781 }
782
Saurav Das558afec2015-05-31 17:12:48 -0700783 protected void processIpTable() {
784 //table miss entry
785 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
786 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
787 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Saurav Das558afec2015-05-31 17:12:48 -0700788 treatment.transition(ACL_TABLE);
789 FlowRule rule = DefaultFlowRule.builder()
790 .forDevice(deviceId)
791 .withSelector(selector.build())
792 .withTreatment(treatment.build())
793 .withPriority(LOWEST_PRIORITY)
794 .fromApp(driverId)
795 .makePermanent()
796 .forTable(UNICAST_ROUTING_TABLE).build();
797 ops = ops.add(rule);
798 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
799 @Override
800 public void onSuccess(FlowRuleOperations ops) {
801 log.info("Initialized IP table");
802 }
803
804 @Override
805 public void onError(FlowRuleOperations ops) {
806 log.info("Failed to initialize unicast IP table");
807 }
808 }));
809 }
810
Jonathan Hart855179c2016-04-26 07:40:04 -0700811 protected void processMulticastIpTable() {
812 //table miss entry
813 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
814 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
815 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
816 treatment.transition(ACL_TABLE);
817 FlowRule rule = DefaultFlowRule.builder()
818 .forDevice(deviceId)
819 .withSelector(selector.build())
820 .withTreatment(treatment.build())
821 .withPriority(LOWEST_PRIORITY)
822 .fromApp(driverId)
823 .makePermanent()
824 .forTable(MULTICAST_ROUTING_TABLE).build();
825 ops = ops.add(rule);
826 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
827 @Override
828 public void onSuccess(FlowRuleOperations ops) {
829 log.info("Initialized multicast IP table");
830 }
831
832 @Override
833 public void onError(FlowRuleOperations ops) {
834 log.info("Failed to initialize multicast IP table");
835 }
836 }));
837 }
838
Saurav Das2857f382015-11-03 14:39:27 -0800839 protected void processMplsTable() {
840 //table miss entry
841 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
842 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
843 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
844 selector = DefaultTrafficSelector.builder();
845 treatment = DefaultTrafficTreatment.builder();
846 treatment.transition(MPLS_TABLE_1);
847 FlowRule rule = DefaultFlowRule.builder()
848 .forDevice(deviceId)
849 .withSelector(selector.build())
850 .withTreatment(treatment.build())
851 .withPriority(LOWEST_PRIORITY)
852 .fromApp(driverId)
853 .makePermanent()
854 .forTable(MPLS_TABLE_0).build();
855 ops = ops.add(rule);
856
857 treatment.transition(ACL_TABLE);
858 rule = DefaultFlowRule.builder()
859 .forDevice(deviceId)
860 .withSelector(selector.build())
861 .withTreatment(treatment.build())
862 .withPriority(LOWEST_PRIORITY)
863 .fromApp(driverId)
864 .makePermanent()
865 .forTable(MPLS_TABLE_1).build();
866 ops = ops.add(rule);
867
868 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
869 @Override
870 public void onSuccess(FlowRuleOperations ops) {
871 log.info("Initialized MPLS tables");
872 }
873
874 @Override
875 public void onError(FlowRuleOperations ops) {
876 log.info("Failed to initialize MPLS tables");
877 }
878 }));
879 }
880
Saurav Das558afec2015-05-31 17:12:48 -0700881 private void processBridgingTable() {
882 //table miss entry
883 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
884 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
885 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Saurav Das558afec2015-05-31 17:12:48 -0700886 treatment.transition(ACL_TABLE);
887 FlowRule rule = DefaultFlowRule.builder()
888 .forDevice(deviceId)
889 .withSelector(selector.build())
890 .withTreatment(treatment.build())
891 .withPriority(LOWEST_PRIORITY)
892 .fromApp(driverId)
893 .makePermanent()
894 .forTable(BRIDGING_TABLE).build();
895 ops = ops.add(rule);
896 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
897 @Override
898 public void onSuccess(FlowRuleOperations ops) {
899 log.info("Initialized Bridging table");
900 }
901
902 @Override
903 public void onError(FlowRuleOperations ops) {
904 log.info("Failed to initialize Bridging table");
905 }
906 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700907 }
Saurav Das558afec2015-05-31 17:12:48 -0700908
Saurav Dasa07f2032015-10-19 14:37:36 -0700909 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700910 //table miss entry - catch all to executed action-set
911 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
912 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
913 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Saurav Das337c7a42015-06-02 15:12:06 -0700914 FlowRule rule = DefaultFlowRule.builder()
915 .forDevice(deviceId)
916 .withSelector(selector.build())
917 .withTreatment(treatment.build())
918 .withPriority(LOWEST_PRIORITY)
919 .fromApp(driverId)
920 .makePermanent()
921 .forTable(ACL_TABLE).build();
922 ops = ops.add(rule);
923 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
924 @Override
925 public void onSuccess(FlowRuleOperations ops) {
926 log.info("Initialized Acl table");
927 }
928
929 @Override
930 public void onError(FlowRuleOperations ops) {
931 log.info("Failed to initialize Acl table");
932 }
933 }));
Saurav Das558afec2015-05-31 17:12:48 -0700934 }
935
936}