blob: b111e87a42e55668bb541ff66fdc487cdcd2a09b [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 Das4ce45962015-11-24 23:21:05 -0800241 * Cpqd emulation does not require the non-OF standard rules for
242 * matching untagged packets.
243 *
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
450 /*
451 * NOTE: The switch does not support matching 0.0.0.0/0.
452 * Split it into 0.0.0.0/1 and 128.0.0.0/1
453 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800454 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800455 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700456 if (ipv4Dst.isMulticast()) {
457 if (ipv4Dst.prefixLength() != 32) {
458 log.warn("Multicast specific forwarding objective can only be /32");
459 fail(fwd, ObjectiveError.BADPARAMS);
460 return ImmutableSet.of();
461 }
462 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
463 if (assignedVlan == null) {
464 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
465 fail(fwd, ObjectiveError.BADPARAMS);
466 return ImmutableSet.of();
467 }
468 filteredSelector.matchVlanId(assignedVlan);
469 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
470 forTableId = MULTICAST_ROUTING_TABLE;
471 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
472 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800473 } else {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700474 if (ipv4Dst.prefixLength() > 0) {
475 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
476 } else {
477 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
478 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
479 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
480 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
481 defaultRule = true;
482 }
483 forTableId = UNICAST_ROUTING_TABLE;
484 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
485 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800486 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800487 } else {
488 filteredSelector
489 .matchEthType(Ethernet.MPLS_UNICAST)
490 .matchMplsLabel(((MplsCriterion)
491 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
492 MplsBosCriterion bos = (MplsBosCriterion) selector
493 .getCriterion(Criterion.Type.MPLS_BOS);
494 if (bos != null) {
495 filteredSelector.matchMplsBos(bos.mplsBos());
496 }
497 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800498 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
499 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800500 }
501
502 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
503 if (fwd.treatment() != null) {
504 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800505 /*
506 * NOTE: OF-DPA does not support immediate instruction in
507 * L3 unicast and MPLS table.
508 */
509 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800510 }
511 }
512
513 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800514 NextGroup next = getGroupForNextObjective(fwd.nextId());
515 if (next != null) {
516 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
517 // we only need the top level group's key to point the flow to it
518 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
519 if (group == null) {
520 log.warn("The group left!");
521 fail(fwd, ObjectiveError.GROUPMISSING);
522 return Collections.emptySet();
523 }
524 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800525 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800526 }
527 tb.transition(ACL_TABLE);
528 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
529 .fromApp(fwd.appId())
530 .withPriority(fwd.priority())
531 .forDevice(deviceId)
532 .withSelector(filteredSelector.build())
533 .withTreatment(tb.build())
534 .forTable(forTableId);
535
536 if (fwd.permanent()) {
537 ruleBuilder.makePermanent();
538 } else {
539 ruleBuilder.makeTemporary(fwd.timeout());
540 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800541 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
542 flowRuleCollection.add(ruleBuilder.build());
543 if (defaultRule) {
544 FlowRule.Builder rule = DefaultFlowRule.builder()
545 .fromApp(fwd.appId())
546 .withPriority(fwd.priority())
547 .forDevice(deviceId)
548 .withSelector(complementarySelector.build())
549 .withTreatment(tb.build())
550 .forTable(forTableId);
551 if (fwd.permanent()) {
552 rule.makePermanent();
553 } else {
554 rule.makeTemporary(fwd.timeout());
555 }
556 flowRuleCollection.add(rule.build());
557 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
558 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800559
Flavio Castroe10fa242016-01-15 12:43:51 -0800560 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800561 }
562
Charles Chan1e492d32016-01-30 23:22:37 -0800563 @Override
564 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
565 List<FlowRule> rules = new ArrayList<>();
566
567 // Build filtered selector
568 TrafficSelector selector = fwd.selector();
569 EthCriterion ethCriterion = (EthCriterion) selector
570 .getCriterion(Criterion.Type.ETH_DST);
571 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
572 .getCriterion(Criterion.Type.VLAN_VID);
573
574 if (vlanIdCriterion == null) {
575 log.warn("Forwarding objective for bridging requires vlan. Not "
576 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
577 fail(fwd, ObjectiveError.BADPARAMS);
578 return Collections.emptySet();
579 }
580
581 TrafficSelector.Builder filteredSelectorBuilder =
582 DefaultTrafficSelector.builder();
583 // Do not match MacAddress for subnet broadcast entry
584 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
585 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
586 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
587 fwd.id(), fwd.nextId(), deviceId);
588 } else {
589 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
590 + "in dev:{} for vlan:{}",
591 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
592 }
593 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
594 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
595
596 if (fwd.treatment() != null) {
597 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
598 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
599 }
600
601 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
602 if (fwd.nextId() != null) {
603 NextGroup next = getGroupForNextObjective(fwd.nextId());
604 if (next != null) {
605 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
606 // we only need the top level group's key to point the flow to it
607 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
608 if (group != null) {
609 treatmentBuilder.deferred().group(group.id());
610 } else {
611 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
612 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
613 fail(fwd, ObjectiveError.GROUPMISSING);
614 return Collections.emptySet();
615 }
616 }
617 }
618 treatmentBuilder.immediate().transition(ACL_TABLE);
619 TrafficTreatment filteredTreatment = treatmentBuilder.build();
620
621 // Build bridging table entries
622 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
623 flowRuleBuilder.fromApp(fwd.appId())
624 .withPriority(fwd.priority())
625 .forDevice(deviceId)
626 .withSelector(filteredSelector)
627 .withTreatment(filteredTreatment)
628 .forTable(BRIDGING_TABLE);
629 if (fwd.permanent()) {
630 flowRuleBuilder.makePermanent();
631 } else {
632 flowRuleBuilder.makeTemporary(fwd.timeout());
633 }
634 rules.add(flowRuleBuilder.build());
635 return rules;
636 }
637
Saurav Das52025962016-01-28 22:30:01 -0800638 /*
639 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
640 * ACL table. Because we pop off vlan tags in TMAC table,
641 * we need to avoid matching on vlans in the ACL table.
642 */
643 @Override
644 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
645 log.info("Processing versatile forwarding objective");
646
647 EthTypeCriterion ethType =
648 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
649 if (ethType == null) {
650 log.error("Versatile forwarding objective must include ethType");
651 fail(fwd, ObjectiveError.BADPARAMS);
652 return Collections.emptySet();
653 }
654 if (fwd.nextId() == null && fwd.treatment() == null) {
655 log.error("Forwarding objective {} from {} must contain "
656 + "nextId or Treatment", fwd.selector(), fwd.appId());
657 return Collections.emptySet();
658 }
659
660 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
661 fwd.selector().criteria().forEach(criterion -> {
662 if (criterion instanceof VlanIdCriterion) {
663 // avoid matching on vlans
664 return;
665 } else {
666 sbuilder.add(criterion);
667 }
668 });
669
670 // XXX driver does not currently do type checking as per Tables 65-67 in
671 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
672 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
673 if (fwd.treatment() != null) {
674 for (Instruction ins : fwd.treatment().allInstructions()) {
675 if (ins instanceof OutputInstruction) {
676 OutputInstruction o = (OutputInstruction) ins;
677 if (o.port() == PortNumber.CONTROLLER) {
678 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 }
687 }
688 if (fwd.nextId() != null) {
689 // overide case
690 NextGroup next = getGroupForNextObjective(fwd.nextId());
691 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
692 // we only need the top level group's key to point the flow to it
693 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
694 if (group == null) {
695 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
696 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
697 fail(fwd, ObjectiveError.GROUPMISSING);
698 return Collections.emptySet();
699 }
700 ttBuilder.deferred().group(group.id());
701 }
702
703 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
704 .fromApp(fwd.appId())
705 .withPriority(fwd.priority())
706 .forDevice(deviceId)
707 .withSelector(sbuilder.build())
708 .withTreatment(ttBuilder.build())
709 .makePermanent()
710 .forTable(ACL_TABLE);
711 return Collections.singletonList(ruleBuilder.build());
712 }
713
714 /*
715 * Cpqd emulation requires table-miss-entries in forwarding tables.
716 * Real OFDPA does not require these rules as they are put in by default.
717 *
718 * (non-Javadoc)
719 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
720 */
Saurav Das2857f382015-11-03 14:39:27 -0800721 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700722 protected void initializePipeline() {
723 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800724 // vlan table processing not required, as default is to drop packets
725 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700726 processTmacTable();
727 processIpTable();
Jonathan Hart855179c2016-04-26 07:40:04 -0700728 processMulticastIpTable();
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();
Saurav Das558afec2015-05-31 17:12:48 -0700797 treatment.transition(ACL_TABLE);
798 FlowRule rule = DefaultFlowRule.builder()
799 .forDevice(deviceId)
800 .withSelector(selector.build())
801 .withTreatment(treatment.build())
802 .withPriority(LOWEST_PRIORITY)
803 .fromApp(driverId)
804 .makePermanent()
805 .forTable(UNICAST_ROUTING_TABLE).build();
806 ops = ops.add(rule);
807 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
808 @Override
809 public void onSuccess(FlowRuleOperations ops) {
810 log.info("Initialized IP table");
811 }
812
813 @Override
814 public void onError(FlowRuleOperations ops) {
815 log.info("Failed to initialize unicast IP table");
816 }
817 }));
818 }
819
Jonathan Hart855179c2016-04-26 07:40:04 -0700820 protected void processMulticastIpTable() {
821 //table miss entry
822 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
823 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
824 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
825 treatment.transition(ACL_TABLE);
826 FlowRule rule = DefaultFlowRule.builder()
827 .forDevice(deviceId)
828 .withSelector(selector.build())
829 .withTreatment(treatment.build())
830 .withPriority(LOWEST_PRIORITY)
831 .fromApp(driverId)
832 .makePermanent()
833 .forTable(MULTICAST_ROUTING_TABLE).build();
834 ops = ops.add(rule);
835 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
836 @Override
837 public void onSuccess(FlowRuleOperations ops) {
838 log.info("Initialized multicast IP table");
839 }
840
841 @Override
842 public void onError(FlowRuleOperations ops) {
843 log.info("Failed to initialize multicast IP table");
844 }
845 }));
846 }
847
Saurav Das2857f382015-11-03 14:39:27 -0800848 protected void processMplsTable() {
849 //table miss entry
850 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
851 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
852 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
853 selector = DefaultTrafficSelector.builder();
854 treatment = DefaultTrafficTreatment.builder();
855 treatment.transition(MPLS_TABLE_1);
856 FlowRule rule = DefaultFlowRule.builder()
857 .forDevice(deviceId)
858 .withSelector(selector.build())
859 .withTreatment(treatment.build())
860 .withPriority(LOWEST_PRIORITY)
861 .fromApp(driverId)
862 .makePermanent()
863 .forTable(MPLS_TABLE_0).build();
864 ops = ops.add(rule);
865
866 treatment.transition(ACL_TABLE);
867 rule = DefaultFlowRule.builder()
868 .forDevice(deviceId)
869 .withSelector(selector.build())
870 .withTreatment(treatment.build())
871 .withPriority(LOWEST_PRIORITY)
872 .fromApp(driverId)
873 .makePermanent()
874 .forTable(MPLS_TABLE_1).build();
875 ops = ops.add(rule);
876
877 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
878 @Override
879 public void onSuccess(FlowRuleOperations ops) {
880 log.info("Initialized MPLS tables");
881 }
882
883 @Override
884 public void onError(FlowRuleOperations ops) {
885 log.info("Failed to initialize MPLS tables");
886 }
887 }));
888 }
889
Saurav Das558afec2015-05-31 17:12:48 -0700890 private void processBridgingTable() {
891 //table miss entry
892 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
893 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
894 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
895 selector = DefaultTrafficSelector.builder();
896 treatment = DefaultTrafficTreatment.builder();
897 treatment.transition(ACL_TABLE);
898 FlowRule rule = DefaultFlowRule.builder()
899 .forDevice(deviceId)
900 .withSelector(selector.build())
901 .withTreatment(treatment.build())
902 .withPriority(LOWEST_PRIORITY)
903 .fromApp(driverId)
904 .makePermanent()
905 .forTable(BRIDGING_TABLE).build();
906 ops = ops.add(rule);
907 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
908 @Override
909 public void onSuccess(FlowRuleOperations ops) {
910 log.info("Initialized Bridging table");
911 }
912
913 @Override
914 public void onError(FlowRuleOperations ops) {
915 log.info("Failed to initialize Bridging table");
916 }
917 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700918 }
Saurav Das558afec2015-05-31 17:12:48 -0700919
Saurav Dasa07f2032015-10-19 14:37:36 -0700920 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700921 //table miss entry - catch all to executed action-set
922 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
923 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
924 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
925 selector = DefaultTrafficSelector.builder();
926 treatment = DefaultTrafficTreatment.builder();
927 FlowRule rule = DefaultFlowRule.builder()
928 .forDevice(deviceId)
929 .withSelector(selector.build())
930 .withTreatment(treatment.build())
931 .withPriority(LOWEST_PRIORITY)
932 .fromApp(driverId)
933 .makePermanent()
934 .forTable(ACL_TABLE).build();
935 ops = ops.add(rule);
936 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
937 @Override
938 public void onSuccess(FlowRuleOperations ops) {
939 log.info("Initialized Acl table");
940 }
941
942 @Override
943 public void onError(FlowRuleOperations ops) {
944 log.info("Failed to initialize Acl table");
945 }
946 }));
Saurav Das558afec2015-05-31 17:12:48 -0700947 }
948
949}