blob: 955dfe78feac42e0c4fc10306b0fe95cca75e9ab [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Saurav Das558afec2015-05-31 17:12:48 -070016package org.onosproject.driver.pipeline;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
Saurav Das2857f382015-11-03 14:39:27 -080020import java.util.ArrayList;
Saurav Das8a0732e2015-11-20 15:27:53 -080021import java.util.Collection;
Saurav Das4f980082015-11-05 13:39:15 -080022import java.util.Collections;
Saurav Das8a0732e2015-11-20 15:27:53 -080023import java.util.Deque;
Saurav Das2857f382015-11-03 14:39:27 -080024import java.util.List;
Saurav Das4f980082015-11-05 13:39:15 -080025import java.util.Set;
26import java.util.concurrent.ConcurrentHashMap;
Saurav Das2857f382015-11-03 14:39:27 -080027
Charles Chan5270ed02016-01-30 23:22:37 -080028import com.google.common.collect.ImmutableList;
Saurav Das8a0732e2015-11-20 15:27:53 -080029import org.onlab.packet.Ethernet;
Saurav Das52025962016-01-28 22:30:01 -080030import org.onlab.packet.MacAddress;
Flavio Castroe10fa242016-01-15 12:43:51 -080031import org.onlab.packet.IpPrefix;
Saurav Das2857f382015-11-03 14:39:27 -080032import org.onlab.packet.VlanId;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.net.Port;
35import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080036import org.onosproject.net.behaviour.NextGroup;
Saurav Das558afec2015-05-31 17:12:48 -070037import org.onosproject.net.flow.DefaultFlowRule;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.FlowRule;
41import org.onosproject.net.flow.FlowRuleOperations;
42import org.onosproject.net.flow.FlowRuleOperationsContext;
43import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080045import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080046import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080047import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080048import org.onosproject.net.flow.criteria.EthTypeCriterion;
49import org.onosproject.net.flow.criteria.IPCriterion;
50import org.onosproject.net.flow.criteria.MplsBosCriterion;
51import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080052import org.onosproject.net.flow.criteria.PortCriterion;
53import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080054import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080055import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
56import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
57import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080058import org.onosproject.net.flowobjective.ForwardingObjective;
59import org.onosproject.net.flowobjective.ObjectiveError;
60import org.onosproject.net.group.Group;
61import org.onosproject.net.group.GroupKey;
Saurav Das558afec2015-05-31 17:12:48 -070062import org.slf4j.Logger;
63
64
65/**
Saurav Das822c4e22015-10-23 10:51:11 -070066 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
Saurav Das52025962016-01-28 22:30:01 -080067 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
68 * does not handle vlan tags and mpls labels simultaneously, which requires us
69 * to do some workarounds in the driver. This driver is meant for the use of
70 * the cpqd switch when MPLS is required. As a result this driver works only
71 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070072 */
Charles Chan361154b2016-03-24 10:23:39 -070073public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070074
75 private final Logger log = getLogger(getClass());
76
Saurav Das4ce45962015-11-24 23:21:05 -080077 /*
Saurav Das52025962016-01-28 22:30:01 -080078 * CPQD emulation does not require special untagged packet handling, unlike
79 * the real ofdpa.
80 */
81 @Override
82 protected void processFilter(FilteringObjective filt,
83 boolean install, ApplicationId applicationId) {
84 // This driver only processes filtering criteria defined with switch
85 // ports as the key
86 PortCriterion portCriterion = null;
87 EthCriterion ethCriterion = null;
88 VlanIdCriterion vidCriterion = null;
89 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
90 if (!filt.key().equals(Criteria.dummy()) &&
91 filt.key().type() == Criterion.Type.IN_PORT) {
92 portCriterion = (PortCriterion) filt.key();
93 } else {
94 log.warn("No key defined in filtering objective from app: {}. Not"
95 + "processing filtering objective", applicationId);
96 fail(filt, ObjectiveError.UNKNOWN);
97 return;
98 }
99 // convert filtering conditions for switch-intfs into flowrules
100 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
101 for (Criterion criterion : filt.conditions()) {
102 if (criterion.type() == Criterion.Type.ETH_DST) {
103 ethCriterion = (EthCriterion) criterion;
104 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
105 vidCriterion = (VlanIdCriterion) criterion;
106 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
107 ips.add((IPCriterion) criterion);
108 } else {
109 log.error("Unsupported filter {}", criterion);
110 fail(filt, ObjectiveError.UNSUPPORTED);
111 return;
112 }
113 }
114
115 VlanId assignedVlan = null;
116 // For VLAN cross-connect packets, use the configured VLAN
117 if (vidCriterion != null) {
118 if (vidCriterion.vlanId() != VlanId.NONE) {
119 assignedVlan = vidCriterion.vlanId();
120
121 // For untagged packets, assign a VLAN ID
122 } else {
123 if (filt.meta() == null) {
124 log.error("Missing metadata in filtering objective required " +
125 "for vlan assignment in dev {}", deviceId);
126 fail(filt, ObjectiveError.BADPARAMS);
127 return;
128 }
129 for (Instruction i : filt.meta().allInstructions()) {
130 if (i instanceof ModVlanIdInstruction) {
131 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
132 }
133 }
134 if (assignedVlan == null) {
135 log.error("Driver requires an assigned vlan-id to tag incoming "
136 + "untagged packets. Not processing vlan filters on "
137 + "device {}", deviceId);
138 fail(filt, ObjectiveError.BADPARAMS);
139 return;
140 }
141 }
142 }
143
144 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
145 log.debug("filtering objective missing dstMac, cannot program TMAC table");
146 } else {
147 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
148 vidCriterion, assignedVlan,
149 applicationId)) {
150 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
151 tmacRule, deviceId);
152 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
153 }
154 }
155
156 if (ethCriterion == null || vidCriterion == null) {
157 log.debug("filtering objective missing dstMac or VLAN, "
158 + "cannot program VLAN Table");
159 } else {
160 List<FlowRule> allRules = processVlanIdFilter(
161 portCriterion, vidCriterion, assignedVlan, applicationId);
162 for (FlowRule rule : allRules) {
163 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
164 rule, deviceId);
165 ops = install ? ops.add(rule) : ops.remove(rule);
166 }
167 }
168
169 for (IPCriterion ipaddr : ips) {
170 // since we ignore port information for IP rules, and the same (gateway) IP
171 // can be configured on multiple ports, we make sure that we send
172 // only a single rule to the switch.
173 if (!sentIpFilters.contains(ipaddr)) {
174 sentIpFilters.add(ipaddr);
175 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
176 ipaddr, deviceId);
177 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
178 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
179 selector.matchEthType(Ethernet.TYPE_IPV4);
180 selector.matchIPDst(ipaddr.ip());
181 treatment.setOutput(PortNumber.CONTROLLER);
182 FlowRule rule = DefaultFlowRule.builder()
183 .forDevice(deviceId)
184 .withSelector(selector.build())
185 .withTreatment(treatment.build())
186 .withPriority(HIGHEST_PRIORITY)
187 .fromApp(applicationId)
188 .makePermanent()
189 .forTable(ACL_TABLE).build();
190 ops = install ? ops.add(rule) : ops.remove(rule);
191 }
192 }
193
194 // apply filtering flow rules
195 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
196 @Override
197 public void onSuccess(FlowRuleOperations ops) {
198 log.info("Applied {} filtering rules in device {}",
199 ops.stages().get(0).size(), deviceId);
200 pass(filt);
201 }
202
203 @Override
204 public void onError(FlowRuleOperations ops) {
205 log.info("Failed to apply all filtering rules in dev {}", deviceId);
206 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
207 }
208 }));
209
210 }
211
212 /*
Saurav Das4ce45962015-11-24 23:21:05 -0800213 * Cpqd emulation does not require the non-OF standard rules for
214 * matching untagged packets.
215 *
216 * (non-Javadoc)
217 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
218 */
Saurav Das558afec2015-05-31 17:12:48 -0700219 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800220 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
221 VlanIdCriterion vidCriterion,
222 VlanId assignedVlan,
223 ApplicationId applicationId) {
224 List<FlowRule> rules = new ArrayList<FlowRule>();
225 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
226 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
227 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800228 treatment.transition(TMAC_TABLE);
229
230 VlanId storeVlan = null;
Saurav Das2857f382015-11-03 14:39:27 -0800231 if (vidCriterion.vlanId() == VlanId.NONE) {
232 // untagged packets are assigned vlans
233 treatment.pushVlan().setVlanId(assignedVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800234 storeVlan = assignedVlan;
235 } else {
236 storeVlan = vidCriterion.vlanId();
Saurav Das2857f382015-11-03 14:39:27 -0800237 }
Saurav Das2857f382015-11-03 14:39:27 -0800238
239 // ofdpa cannot match on ALL portnumber, so we need to use separate
240 // rules for each port.
241 List<PortNumber> portnums = new ArrayList<PortNumber>();
242 if (portCriterion.port() == PortNumber.ALL) {
243 for (Port port : deviceService.getPorts(deviceId)) {
244 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
245 portnums.add(port.number());
246 }
247 }
248 } else {
249 portnums.add(portCriterion.port());
250 }
Saurav Das4f980082015-11-05 13:39:15 -0800251
Saurav Das2857f382015-11-03 14:39:27 -0800252 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800253 // update storage
Charles Chan188ebf52015-12-23 00:15:11 -0800254 ofdpa2GroupHandler.port2Vlan.put(pnum, storeVlan);
255 Set<PortNumber> vlanPorts = ofdpa2GroupHandler.vlan2Port.get(storeVlan);
Saurav Das4f980082015-11-05 13:39:15 -0800256 if (vlanPorts == null) {
257 vlanPorts = Collections.newSetFromMap(
258 new ConcurrentHashMap<PortNumber, Boolean>());
259 vlanPorts.add(pnum);
Charles Chan188ebf52015-12-23 00:15:11 -0800260 ofdpa2GroupHandler.vlan2Port.put(storeVlan, vlanPorts);
Saurav Das4f980082015-11-05 13:39:15 -0800261 } else {
262 vlanPorts.add(pnum);
263 }
264 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800265 selector.matchInPort(pnum);
266 FlowRule rule = DefaultFlowRule.builder()
267 .forDevice(deviceId)
268 .withSelector(selector.build())
269 .withTreatment(treatment.build())
270 .withPriority(DEFAULT_PRIORITY)
271 .fromApp(applicationId)
272 .makePermanent()
273 .forTable(VLAN_TABLE).build();
274 rules.add(rule);
275 }
276 return rules;
277 }
278
Saurav Das4ce45962015-11-24 23:21:05 -0800279 /*
280 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
281 * Workaround requires popping off the VLAN tags in the TMAC table.
282 *
283 * (non-Javadoc)
284 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
285 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800286 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800287 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
288 EthCriterion ethCriterion,
289 VlanIdCriterion vidCriterion,
290 VlanId assignedVlan,
291 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800292 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
293 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
294 return processEthDstOnlyFilter(ethCriterion, applicationId);
295 }
296
Saurav Das4ce45962015-11-24 23:21:05 -0800297 //handling untagged packets via assigned VLAN
298 if (vidCriterion.vlanId() == VlanId.NONE) {
299 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
300 }
301 // ofdpa cannot match on ALL portnumber, so we need to use separate
302 // rules for each port.
303 List<PortNumber> portnums = new ArrayList<PortNumber>();
304 if (portCriterion.port() == PortNumber.ALL) {
305 for (Port port : deviceService.getPorts(deviceId)) {
306 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
307 portnums.add(port.number());
308 }
309 }
310 } else {
311 portnums.add(portCriterion.port());
312 }
313
314 List<FlowRule> rules = new ArrayList<FlowRule>();
315 for (PortNumber pnum : portnums) {
316 // for unicast IP packets
317 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
318 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
319 selector.matchInPort(pnum);
320 selector.matchVlanId(vidCriterion.vlanId());
321 selector.matchEthType(Ethernet.TYPE_IPV4);
322 selector.matchEthDst(ethCriterion.mac());
323 /*
324 * Note: CpqD switches do not handle MPLS-related operation properly
325 * for a packet with VLAN tag. We pop VLAN here as a workaround.
326 * Side effect: HostService learns redundant hosts with same MAC but
327 * different VLAN. No known side effect on the network reachability.
328 */
329 treatment.popVlan();
330 treatment.transition(UNICAST_ROUTING_TABLE);
331 FlowRule rule = DefaultFlowRule.builder()
332 .forDevice(deviceId)
333 .withSelector(selector.build())
334 .withTreatment(treatment.build())
335 .withPriority(DEFAULT_PRIORITY)
336 .fromApp(applicationId)
337 .makePermanent()
338 .forTable(TMAC_TABLE).build();
339 rules.add(rule);
340 //for MPLS packets
341 selector = DefaultTrafficSelector.builder();
342 treatment = DefaultTrafficTreatment.builder();
343 selector.matchInPort(pnum);
344 selector.matchVlanId(vidCriterion.vlanId());
345 selector.matchEthType(Ethernet.MPLS_UNICAST);
346 selector.matchEthDst(ethCriterion.mac());
347 // workaround here again
348 treatment.popVlan();
349 treatment.transition(MPLS_TABLE_0);
350 rule = DefaultFlowRule.builder()
351 .forDevice(deviceId)
352 .withSelector(selector.build())
353 .withTreatment(treatment.build())
354 .withPriority(DEFAULT_PRIORITY)
355 .fromApp(applicationId)
356 .makePermanent()
357 .forTable(TMAC_TABLE).build();
358 rules.add(rule);
359 }
360 return rules;
361 }
362
Charles Chan5270ed02016-01-30 23:22:37 -0800363 @Override
364 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
365 ApplicationId applicationId) {
366 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
367 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
368 selector.matchEthType(Ethernet.TYPE_IPV4);
369 selector.matchEthDst(ethCriterion.mac());
370 /*
371 * Note: CpqD switches do not handle MPLS-related operation properly
372 * for a packet with VLAN tag. We pop VLAN here as a workaround.
373 * Side effect: HostService learns redundant hosts with same MAC but
374 * different VLAN. No known side effect on the network reachability.
375 */
376 treatment.popVlan();
377 treatment.transition(UNICAST_ROUTING_TABLE);
378 FlowRule rule = DefaultFlowRule.builder()
379 .forDevice(deviceId)
380 .withSelector(selector.build())
381 .withTreatment(treatment.build())
382 .withPriority(DEFAULT_PRIORITY)
383 .fromApp(applicationId)
384 .makePermanent()
385 .forTable(TMAC_TABLE).build();
386 return ImmutableList.<FlowRule>builder().add(rule).build();
387 }
388
Saurav Das4ce45962015-11-24 23:21:05 -0800389 /*
390 * Cpqd emulation allows MPLS ecmp.
391 *
392 * (non-Javadoc)
393 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
394 */
395 @Override
396 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800397 TrafficSelector selector = fwd.selector();
398 EthTypeCriterion ethType =
399 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
400 if ((ethType == null) ||
401 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
402 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800403 log.warn("processSpecific: Unsupported forwarding objective criteria"
404 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800405 fail(fwd, ObjectiveError.UNSUPPORTED);
406 return Collections.emptySet();
407 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800408 boolean defaultRule = false;
Saurav Das8a0732e2015-11-20 15:27:53 -0800409 int forTableId = -1;
410 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800411 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
412
413 /*
414 * NOTE: The switch does not support matching 0.0.0.0/0.
415 * Split it into 0.0.0.0/1 and 128.0.0.0/1
416 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800417 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800418 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
419 if (ipv4Dst.prefixLength() > 0) {
420 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
421 .matchIPDst(ipv4Dst);
422 } else {
423 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
424 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
425 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
426 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
427 defaultRule = true;
428 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800429 forTableId = UNICAST_ROUTING_TABLE;
Saurav Das4ce45962015-11-24 23:21:05 -0800430 log.debug("processing IPv4 specific forwarding objective {} -> next:{}"
431 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800432 } else {
433 filteredSelector
434 .matchEthType(Ethernet.MPLS_UNICAST)
435 .matchMplsLabel(((MplsCriterion)
436 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
437 MplsBosCriterion bos = (MplsBosCriterion) selector
438 .getCriterion(Criterion.Type.MPLS_BOS);
439 if (bos != null) {
440 filteredSelector.matchMplsBos(bos.mplsBos());
441 }
442 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800443 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
444 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800445 }
446
447 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
448 if (fwd.treatment() != null) {
449 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan7d10b162015-12-07 18:54:45 -0800450 /*
451 * NOTE: OF-DPA does not support immediate instruction in
452 * L3 unicast and MPLS table.
453 */
454 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800455 }
456 }
457
458 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800459 NextGroup next = getGroupForNextObjective(fwd.nextId());
460 if (next != null) {
461 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
462 // we only need the top level group's key to point the flow to it
463 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
464 if (group == null) {
465 log.warn("The group left!");
466 fail(fwd, ObjectiveError.GROUPMISSING);
467 return Collections.emptySet();
468 }
469 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800470 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800471 }
472 tb.transition(ACL_TABLE);
473 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
474 .fromApp(fwd.appId())
475 .withPriority(fwd.priority())
476 .forDevice(deviceId)
477 .withSelector(filteredSelector.build())
478 .withTreatment(tb.build())
479 .forTable(forTableId);
480
481 if (fwd.permanent()) {
482 ruleBuilder.makePermanent();
483 } else {
484 ruleBuilder.makeTemporary(fwd.timeout());
485 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800486 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
487 flowRuleCollection.add(ruleBuilder.build());
488 if (defaultRule) {
489 FlowRule.Builder rule = DefaultFlowRule.builder()
490 .fromApp(fwd.appId())
491 .withPriority(fwd.priority())
492 .forDevice(deviceId)
493 .withSelector(complementarySelector.build())
494 .withTreatment(tb.build())
495 .forTable(forTableId);
496 if (fwd.permanent()) {
497 rule.makePermanent();
498 } else {
499 rule.makeTemporary(fwd.timeout());
500 }
501 flowRuleCollection.add(rule.build());
502 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
503 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800504
Flavio Castroe10fa242016-01-15 12:43:51 -0800505 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800506 }
507
Charles Chan1e492d32016-01-30 23:22:37 -0800508 @Override
509 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
510 List<FlowRule> rules = new ArrayList<>();
511
512 // Build filtered selector
513 TrafficSelector selector = fwd.selector();
514 EthCriterion ethCriterion = (EthCriterion) selector
515 .getCriterion(Criterion.Type.ETH_DST);
516 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
517 .getCriterion(Criterion.Type.VLAN_VID);
518
519 if (vlanIdCriterion == null) {
520 log.warn("Forwarding objective for bridging requires vlan. Not "
521 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
522 fail(fwd, ObjectiveError.BADPARAMS);
523 return Collections.emptySet();
524 }
525
526 TrafficSelector.Builder filteredSelectorBuilder =
527 DefaultTrafficSelector.builder();
528 // Do not match MacAddress for subnet broadcast entry
529 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
530 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
531 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
532 fwd.id(), fwd.nextId(), deviceId);
533 } else {
534 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
535 + "in dev:{} for vlan:{}",
536 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
537 }
538 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
539 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
540
541 if (fwd.treatment() != null) {
542 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
543 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
544 }
545
546 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
547 if (fwd.nextId() != null) {
548 NextGroup next = getGroupForNextObjective(fwd.nextId());
549 if (next != null) {
550 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
551 // we only need the top level group's key to point the flow to it
552 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
553 if (group != null) {
554 treatmentBuilder.deferred().group(group.id());
555 } else {
556 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
557 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
558 fail(fwd, ObjectiveError.GROUPMISSING);
559 return Collections.emptySet();
560 }
561 }
562 }
563 treatmentBuilder.immediate().transition(ACL_TABLE);
564 TrafficTreatment filteredTreatment = treatmentBuilder.build();
565
566 // Build bridging table entries
567 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
568 flowRuleBuilder.fromApp(fwd.appId())
569 .withPriority(fwd.priority())
570 .forDevice(deviceId)
571 .withSelector(filteredSelector)
572 .withTreatment(filteredTreatment)
573 .forTable(BRIDGING_TABLE);
574 if (fwd.permanent()) {
575 flowRuleBuilder.makePermanent();
576 } else {
577 flowRuleBuilder.makeTemporary(fwd.timeout());
578 }
579 rules.add(flowRuleBuilder.build());
580 return rules;
581 }
582
Saurav Das52025962016-01-28 22:30:01 -0800583 /*
584 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
585 * ACL table. Because we pop off vlan tags in TMAC table,
586 * we need to avoid matching on vlans in the ACL table.
587 */
588 @Override
589 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
590 log.info("Processing versatile forwarding objective");
591
592 EthTypeCriterion ethType =
593 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
594 if (ethType == null) {
595 log.error("Versatile forwarding objective must include ethType");
596 fail(fwd, ObjectiveError.BADPARAMS);
597 return Collections.emptySet();
598 }
599 if (fwd.nextId() == null && fwd.treatment() == null) {
600 log.error("Forwarding objective {} from {} must contain "
601 + "nextId or Treatment", fwd.selector(), fwd.appId());
602 return Collections.emptySet();
603 }
604
605 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
606 fwd.selector().criteria().forEach(criterion -> {
607 if (criterion instanceof VlanIdCriterion) {
608 // avoid matching on vlans
609 return;
610 } else {
611 sbuilder.add(criterion);
612 }
613 });
614
615 // XXX driver does not currently do type checking as per Tables 65-67 in
616 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
617 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
618 if (fwd.treatment() != null) {
619 for (Instruction ins : fwd.treatment().allInstructions()) {
620 if (ins instanceof OutputInstruction) {
621 OutputInstruction o = (OutputInstruction) ins;
622 if (o.port() == PortNumber.CONTROLLER) {
Saurav Das49831642016-02-05 13:15:20 -0800623 // emulating real ofdpa behavior by popping off internal
624 // vlan before sending to controller
625 ttBuilder.popVlan();
Saurav Das52025962016-01-28 22:30:01 -0800626 ttBuilder.add(o);
627 } else {
628 log.warn("Only allowed treatments in versatile forwarding "
629 + "objectives are punts to the controller");
630 }
631 } else {
632 log.warn("Cannot process instruction in versatile fwd {}", ins);
633 }
634 }
Charles Chan5270ed02016-01-30 23:22:37 -0800635 ttBuilder.wipeDeferred();
Saurav Das52025962016-01-28 22:30:01 -0800636 }
637 if (fwd.nextId() != null) {
638 // overide case
639 NextGroup next = getGroupForNextObjective(fwd.nextId());
640 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
641 // we only need the top level group's key to point the flow to it
642 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
643 if (group == null) {
644 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
645 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
646 fail(fwd, ObjectiveError.GROUPMISSING);
647 return Collections.emptySet();
648 }
649 ttBuilder.deferred().group(group.id());
650 }
651
652 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
653 .fromApp(fwd.appId())
654 .withPriority(fwd.priority())
655 .forDevice(deviceId)
656 .withSelector(sbuilder.build())
657 .withTreatment(ttBuilder.build())
658 .makePermanent()
659 .forTable(ACL_TABLE);
660 return Collections.singletonList(ruleBuilder.build());
661 }
662
663 /*
664 * Cpqd emulation requires table-miss-entries in forwarding tables.
665 * Real OFDPA does not require these rules as they are put in by default.
666 *
667 * (non-Javadoc)
668 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
669 */
Saurav Das2857f382015-11-03 14:39:27 -0800670 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700671 protected void initializePipeline() {
672 processPortTable();
Saurav Das2857f382015-11-03 14:39:27 -0800673 // vlan table processing not required, as default is to drop packets
674 // which can be accomplished without a table-miss-entry.
Saurav Das558afec2015-05-31 17:12:48 -0700675 processTmacTable();
676 processIpTable();
Saurav Das2857f382015-11-03 14:39:27 -0800677 processMplsTable();
Saurav Das558afec2015-05-31 17:12:48 -0700678 processBridgingTable();
Saurav Das337c7a42015-06-02 15:12:06 -0700679 processAclTable();
Saurav Das558afec2015-05-31 17:12:48 -0700680 }
681
Saurav Das558afec2015-05-31 17:12:48 -0700682 protected void processPortTable() {
683 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
684 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
685 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
686 treatment.transition(VLAN_TABLE);
687 FlowRule tmisse = DefaultFlowRule.builder()
688 .forDevice(deviceId)
689 .withSelector(selector.build())
690 .withTreatment(treatment.build())
691 .withPriority(LOWEST_PRIORITY)
692 .fromApp(driverId)
693 .makePermanent()
694 .forTable(PORT_TABLE).build();
695 ops = ops.add(tmisse);
696
697 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
698 @Override
699 public void onSuccess(FlowRuleOperations ops) {
700 log.info("Initialized port table");
701 }
702
703 @Override
704 public void onError(FlowRuleOperations ops) {
705 log.info("Failed to initialize port table");
706 }
707 }));
708 }
709
Saurav Das558afec2015-05-31 17:12:48 -0700710 protected void processTmacTable() {
711 //table miss entry
712 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
713 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
714 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
715 selector = DefaultTrafficSelector.builder();
716 treatment = DefaultTrafficTreatment.builder();
717 treatment.transition(BRIDGING_TABLE);
718 FlowRule rule = DefaultFlowRule.builder()
719 .forDevice(deviceId)
720 .withSelector(selector.build())
721 .withTreatment(treatment.build())
722 .withPriority(LOWEST_PRIORITY)
723 .fromApp(driverId)
724 .makePermanent()
725 .forTable(TMAC_TABLE).build();
726 ops = ops.add(rule);
727 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
728 @Override
729 public void onSuccess(FlowRuleOperations ops) {
730 log.info("Initialized tmac table");
731 }
732
733 @Override
734 public void onError(FlowRuleOperations ops) {
735 log.info("Failed to initialize tmac table");
736 }
737 }));
738 }
739
Saurav Das558afec2015-05-31 17:12:48 -0700740 protected void processIpTable() {
741 //table miss entry
742 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
743 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
744 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
745 selector = DefaultTrafficSelector.builder();
746 treatment = DefaultTrafficTreatment.builder();
Saurav Das4ce45962015-11-24 23:21:05 -0800747 treatment.deferred().setOutput(PortNumber.CONTROLLER);
Saurav Das558afec2015-05-31 17:12:48 -0700748 treatment.transition(ACL_TABLE);
749 FlowRule rule = DefaultFlowRule.builder()
750 .forDevice(deviceId)
751 .withSelector(selector.build())
752 .withTreatment(treatment.build())
753 .withPriority(LOWEST_PRIORITY)
754 .fromApp(driverId)
755 .makePermanent()
756 .forTable(UNICAST_ROUTING_TABLE).build();
757 ops = ops.add(rule);
758 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
759 @Override
760 public void onSuccess(FlowRuleOperations ops) {
761 log.info("Initialized IP table");
762 }
763
764 @Override
765 public void onError(FlowRuleOperations ops) {
766 log.info("Failed to initialize unicast IP table");
767 }
768 }));
769 }
770
Saurav Das2857f382015-11-03 14:39:27 -0800771 protected void processMplsTable() {
772 //table miss entry
773 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
774 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
775 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
776 selector = DefaultTrafficSelector.builder();
777 treatment = DefaultTrafficTreatment.builder();
778 treatment.transition(MPLS_TABLE_1);
779 FlowRule rule = DefaultFlowRule.builder()
780 .forDevice(deviceId)
781 .withSelector(selector.build())
782 .withTreatment(treatment.build())
783 .withPriority(LOWEST_PRIORITY)
784 .fromApp(driverId)
785 .makePermanent()
786 .forTable(MPLS_TABLE_0).build();
787 ops = ops.add(rule);
788
789 treatment.transition(ACL_TABLE);
790 rule = DefaultFlowRule.builder()
791 .forDevice(deviceId)
792 .withSelector(selector.build())
793 .withTreatment(treatment.build())
794 .withPriority(LOWEST_PRIORITY)
795 .fromApp(driverId)
796 .makePermanent()
797 .forTable(MPLS_TABLE_1).build();
798 ops = ops.add(rule);
799
800 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
801 @Override
802 public void onSuccess(FlowRuleOperations ops) {
803 log.info("Initialized MPLS tables");
804 }
805
806 @Override
807 public void onError(FlowRuleOperations ops) {
808 log.info("Failed to initialize MPLS tables");
809 }
810 }));
811 }
812
Saurav Das558afec2015-05-31 17:12:48 -0700813 private void processBridgingTable() {
814 //table miss entry
815 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
816 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
817 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
818 selector = DefaultTrafficSelector.builder();
819 treatment = DefaultTrafficTreatment.builder();
820 treatment.transition(ACL_TABLE);
821 FlowRule rule = DefaultFlowRule.builder()
822 .forDevice(deviceId)
823 .withSelector(selector.build())
824 .withTreatment(treatment.build())
825 .withPriority(LOWEST_PRIORITY)
826 .fromApp(driverId)
827 .makePermanent()
828 .forTable(BRIDGING_TABLE).build();
829 ops = ops.add(rule);
830 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
831 @Override
832 public void onSuccess(FlowRuleOperations ops) {
833 log.info("Initialized Bridging table");
834 }
835
836 @Override
837 public void onError(FlowRuleOperations ops) {
838 log.info("Failed to initialize Bridging table");
839 }
840 }));
Saurav Das337c7a42015-06-02 15:12:06 -0700841 }
Saurav Das558afec2015-05-31 17:12:48 -0700842
Saurav Dasa07f2032015-10-19 14:37:36 -0700843 protected void processAclTable() {
Saurav Das337c7a42015-06-02 15:12:06 -0700844 //table miss entry - catch all to executed action-set
845 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
846 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
847 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
848 selector = DefaultTrafficSelector.builder();
849 treatment = DefaultTrafficTreatment.builder();
850 FlowRule rule = DefaultFlowRule.builder()
851 .forDevice(deviceId)
852 .withSelector(selector.build())
853 .withTreatment(treatment.build())
854 .withPriority(LOWEST_PRIORITY)
855 .fromApp(driverId)
856 .makePermanent()
857 .forTable(ACL_TABLE).build();
858 ops = ops.add(rule);
859 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
860 @Override
861 public void onSuccess(FlowRuleOperations ops) {
862 log.info("Initialized Acl table");
863 }
864
865 @Override
866 public void onError(FlowRuleOperations ops) {
867 log.info("Failed to initialize Acl table");
868 }
869 }));
Saurav Das558afec2015-05-31 17:12:48 -0700870 }
871
872}