blob: cbd6fb76ddc406b5f4699c71d1b8a40d57c888ff [file] [log] [blame]
Charles Chanf9e98652016-09-07 16:54:23 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Charles Chanf9e98652016-09-07 16:54:23 -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 */
16
Yi Tsengef19de12017-04-24 11:33:05 -070017package org.onosproject.driver.pipeline.ofdpa;
Charles Chanf9e98652016-09-07 16:54:23 -070018
Pier Ventre42287df2016-11-09 14:17:26 -080019import com.google.common.collect.ImmutableList;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -070020import org.onlab.packet.VlanId;
Charles Chanf9e98652016-09-07 16:54:23 -070021import org.onosproject.core.ApplicationId;
Pier Ventre42287df2016-11-09 14:17:26 -080022import org.onosproject.driver.extensions.Ofdpa3MatchMplsL2Port;
23import org.onosproject.driver.extensions.Ofdpa3MatchOvid;
Pier Ventre70d53ba2016-11-17 22:26:29 -080024import org.onosproject.driver.extensions.Ofdpa3PopCw;
25import org.onosproject.driver.extensions.Ofdpa3PopL2Header;
Pier Ventre42287df2016-11-09 14:17:26 -080026import org.onosproject.driver.extensions.Ofdpa3SetMplsL2Port;
27import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
28import org.onosproject.driver.extensions.Ofdpa3SetOvid;
29import org.onosproject.driver.extensions.Ofdpa3SetQosIndex;
Pier Ventre42287df2016-11-09 14:17:26 -080030import org.onosproject.net.behaviour.NextGroup;
Charles Chanf9e98652016-09-07 16:54:23 -070031import org.onosproject.net.behaviour.PipelinerContext;
Pier Ventre42287df2016-11-09 14:17:26 -080032import org.onosproject.net.flow.DefaultFlowRule;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070035import org.onosproject.net.flow.FlowRule;
Pier Ventre42287df2016-11-09 14:17:26 -080036import org.onosproject.net.flow.FlowRuleOperations;
37import org.onosproject.net.flow.FlowRuleOperationsContext;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.flow.criteria.Criterion;
Charles Chanf9e98652016-09-07 16:54:23 -070041import org.onosproject.net.flow.criteria.PortCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080042import org.onosproject.net.flow.criteria.TunnelIdCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070043import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre70d53ba2016-11-17 22:26:29 -080044import org.onosproject.net.flow.instructions.Instruction;
45import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080046import org.onosproject.net.flow.instructions.L2ModificationInstruction;
47import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Pier Ventre70d53ba2016-11-17 22:26:29 -080048import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080049import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chanf9e98652016-09-07 16:54:23 -070050import org.onosproject.net.flowobjective.ForwardingObjective;
Pier Ventre42287df2016-11-09 14:17:26 -080051import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.group.Group;
53import org.onosproject.net.group.GroupKey;
54import org.slf4j.Logger;
Charles Chanf9e98652016-09-07 16:54:23 -070055
56import java.util.Collection;
Pier Ventre42287df2016-11-09 14:17:26 -080057import java.util.Collections;
58import java.util.Deque;
Charles Chanf9e98652016-09-07 16:54:23 -070059import java.util.List;
60
Pier Ventre42287df2016-11-09 14:17:26 -080061import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
62import static org.onosproject.net.flow.criteria.Criterion.Type.*;
63import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
64import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
65import static org.slf4j.LoggerFactory.getLogger;
66
Charles Chanf9e98652016-09-07 16:54:23 -070067/**
68 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
69 */
70public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080071
72 private final Logger log = getLogger(getClass());
73
Charles Chanf9e98652016-09-07 16:54:23 -070074 @Override
Charles Chan40132b32017-01-22 00:19:37 -080075 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070076 driverId = coreService.registerApplication(
77 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080078 }
Charles Chanf9e98652016-09-07 16:54:23 -070079
Charles Chan40132b32017-01-22 00:19:37 -080080 @Override
81 protected void initGroupHander(PipelinerContext context) {
82 groupHandler = new Ofdpa3GroupHandler();
83 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070084 }
85
86 @Override
Charles Chand1172632017-03-15 17:33:09 -070087 protected boolean requireVlanExtensions() {
88 return false;
89 }
90
91 @Override
Pier Ventre42287df2016-11-09 14:17:26 -080092 protected void processFilter(FilteringObjective filteringObjective,
93 boolean install,
94 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -070095
96 // Check if filter is intended for pseudowire
97 boolean isPw = isPseudowire(filteringObjective);
98
99 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800100 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
101 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700102
103 VlanIdCriterion innerVlanIdCriterion = null;
104 for (Criterion criterion : filteringObjective.conditions()) {
105 if (criterion.type() == INNER_VLAN_VID) {
106 innerVlanIdCriterion = (VlanIdCriterion) criterion;
107 break;
108 }
109 }
110
Pier Ventre42287df2016-11-09 14:17:26 -0800111 VlanIdCriterion outerVlanIdCriterion = null;
112 // We extract the expected port criterion in the key.
113 portCriterion = (PortCriterion) filteringObjective.key();
114 // We extract the outer vlan id criterion.
115 for (Criterion criterion : filteringObjective.conditions()) {
116 if (criterion.type() == VLAN_VID) {
117 outerVlanIdCriterion = (VlanIdCriterion) criterion;
118 break;
119 }
120 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700121
Pier Ventre42287df2016-11-09 14:17:26 -0800122 // We extract the tunnel id.
123 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700124 VlanId egressVlan;
125
Pier Ventre42287df2016-11-09 14:17:26 -0800126 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700127 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800128 log.warn("Bad filtering objective from app: {}. Not"
129 + "processing filtering objective", applicationId);
130 fail(filteringObjective, ObjectiveError.BADPARAMS);
131 return;
132 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700133 filteringObjective.meta().allInstructions().size() == 2 &&
134 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
135 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
136
Pier Ventre42287df2016-11-09 14:17:26 -0800137 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
138 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700139
Pier Ventre42287df2016-11-09 14:17:26 -0800140 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
141 log.warn("Bad filtering objective from app: {}. Not"
142 + "processing filtering objective", applicationId);
143 fail(filteringObjective, ObjectiveError.BADPARAMS);
144 return;
145 } else {
146 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
147 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700148
149 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
150 filteringObjective.meta().allInstructions().get(1);
151
152 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
153 log.warn("Bad filtering objective from app: {}. Not"
154 + "processing filtering objective", applicationId);
155 fail(filteringObjective, ObjectiveError.BADPARAMS);
156 return;
157 } else {
158 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
159 }
Pier Ventre42287df2016-11-09 14:17:26 -0800160 } else {
161 log.warn("Bad filtering objective from app: {}. Not"
162 + "processing filtering objective", applicationId);
163 fail(filteringObjective, ObjectiveError.BADPARAMS);
164 return;
165 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700166
Pier Ventre42287df2016-11-09 14:17:26 -0800167 // Mpls tunnel ids according to the OFDPA manual have to be
168 // in the range [2^17-1, 2^16].
169 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
170 // Sanity check for the filtering objective.
171 if (portCriterion == null ||
172 outerVlanIdCriterion == null ||
173 tunnelId > MPLS_TUNNEL_ID_MAX) {
174 log.warn("Bad filtering objective from app: {}. Not"
175 + "processing filtering objective", applicationId);
176 fail(filteringObjective, ObjectiveError.BADPARAMS);
177 return;
178 }
179 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800180 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530181 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800182 portCriterion.port().toLong());
183 fail(filteringObjective, ObjectiveError.BADPARAMS);
184 return;
185 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700186
Pier Ventre42287df2016-11-09 14:17:26 -0800187 // We create the flows.
188 List<FlowRule> pwRules = processPwFilter(portCriterion,
189 innerVlanIdCriterion,
190 outerVlanIdCriterion,
191 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700192 applicationId,
193 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800194 );
195 // We tag the flow for adding or for removing.
196 for (FlowRule pwRule : pwRules) {
197 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
198 pwRule, deviceId);
199 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
200 }
201 // We push the filtering rules for the pw.
202 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
203 @Override
204 public void onSuccess(FlowRuleOperations ops) {
205 log.info("Applied {} filtering rules in device {}",
206 ops.stages().get(0).size(), deviceId);
207 pass(filteringObjective);
208 }
209
210 @Override
211 public void onError(FlowRuleOperations ops) {
212 log.info("Failed to apply all filtering rules in dev {}", deviceId);
213 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
214 }
215 }));
216
217 return;
218 }
219 // If it is not a pseudo wire flow we fall back
220 // to the OFDPA 2.0 pipeline.
221 super.processFilter(filteringObjective, install, applicationId);
222 }
223
224 /**
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700225 * Determines if the filtering objective will be used for a pseudowire.
226 *
227 * @param filteringObjective
228 * @return True if objective was created for a pseudowire, false otherwise.
229 */
230 private boolean isPseudowire(FilteringObjective filteringObjective) {
231
232
233 if (filteringObjective.meta() != null) {
234
235 TrafficTreatment treatment = filteringObjective.meta();
236 for (Instruction instr : treatment.immediate()) {
237 if (instr.type().equals(Instruction.Type.L2MODIFICATION)) {
238
239 L2ModificationInstruction l2Instr = (L2ModificationInstruction) instr;
240 if (l2Instr.subtype().equals(L2SubType.TUNNEL_ID)) {
241 return true;
242 }
243 }
244 }
245 }
246
247 return false;
248 }
249
250 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800251 * Method to process the pw related filtering objectives.
252 *
253 * @param portCriterion the in port match
254 * @param innerVlanIdCriterion the inner vlan match
255 * @param outerVlanIdCriterion the outer vlan match
256 * @param tunnelId the tunnel id
257 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700258 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800259 * @return a list of flow rules to install
260 */
261 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700262 VlanIdCriterion innerVlanIdCriterion,
263 VlanIdCriterion outerVlanIdCriterion,
264 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700265 ApplicationId applicationId,
266 VlanId egressVlan) {
267
Pier Ventre42287df2016-11-09 14:17:26 -0800268 FlowRule vlan1FlowRule;
269 int mplsLogicalPort = ((int) portCriterion.port().toLong());
270 // We have to match on the inner vlan and outer vlan at the same time.
271 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800272
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700273 ImmutableList<FlowRule> toReturn;
274
275 // pseudowire configured with double tagged vlans
276 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
277 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
278
279 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
280
281 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
282 .matchInPort(portCriterion.port())
283 .matchVlanId(innerVlanIdCriterion.vlanId())
284 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
285 // TODO understand for the future how to manage the vlan rewrite.
286 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
287 .pushVlan()
288 .setVlanId(egressVlan)
289 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
290 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
291 .setTunnelId(tunnelId)
292 .transition(MPLS_L2_PORT_FLOW_TABLE);
293 vlan1FlowRule = DefaultFlowRule.builder()
294 .forDevice(deviceId)
295 .withSelector(vlan1Selector.build())
296 .withTreatment(vlan1Treatment.build())
297 .withPriority(DEFAULT_PRIORITY)
298 .fromApp(applicationId)
299 .makePermanent()
300 .forTable(VLAN_1_TABLE)
301 .build();
302 // Finally we create the flow rule for the vlan table.
303 FlowRule vlanFlowRule;
304 // We have to match on the outer vlan.
305 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
306 .matchInPort(portCriterion.port())
307 .matchVlanId(outerVlanIdCriterion.vlanId());
308 // TODO understand for the future how to manage the vlan rewrite.
309 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
310 .popVlan()
311 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
312 .transition(VLAN_1_TABLE);
313 vlanFlowRule = DefaultFlowRule.builder()
314 .forDevice(deviceId)
315 .withSelector(vlanSelector.build())
316 .withTreatment(vlanTreatment.build())
317 .withPriority(DEFAULT_PRIORITY)
318 .fromApp(applicationId)
319 .makePermanent()
320 .forTable(VLAN_TABLE)
321 .build();
322
323 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
324 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
325 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
326
327 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
328
329 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
330 .matchInPort(portCriterion.port())
331 .matchVlanId(innerVlanIdCriterion.vlanId());
332
333 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
334 // .pushVlan()
335 .setVlanId(egressVlan)
336 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
337 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
338 .setTunnelId(tunnelId)
339 .transition(MPLS_L2_PORT_FLOW_TABLE);
340
341 vlan1FlowRule = DefaultFlowRule.builder()
342 .forDevice(deviceId)
343 .withSelector(singleVlanSelector.build())
344 .withTreatment(singleVlanTreatment.build())
345 .withPriority(DEFAULT_PRIORITY)
346 .fromApp(applicationId)
347 .makePermanent()
348 .forTable(VLAN_TABLE)
349 .build();
350
351 return ImmutableList.of(vlan1FlowRule);
352 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
353 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
354
355 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
356 .matchInPort(portCriterion.port())
357 .matchVlanId(innerVlanIdCriterion.vlanId());
358
359 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
360 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
361 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
362 .setTunnelId(tunnelId)
363 .transition(MPLS_L2_PORT_FLOW_TABLE);
364
365 vlan1FlowRule = DefaultFlowRule.builder()
366 .forDevice(deviceId)
367 .withSelector(singleVlanSelector.build())
368 .withTreatment(singleVlanTreatment.build())
369 .withPriority(DEFAULT_PRIORITY)
370 .fromApp(applicationId)
371 .makePermanent()
372 .forTable(VLAN_TABLE)
373 .build();
374
375 return ImmutableList.of(vlan1FlowRule);
376 } else {
377 // failure...
378 return Collections.emptyList();
379 }
Pier Ventre42287df2016-11-09 14:17:26 -0800380 }
381
382 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700383 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Pier Ventre140a8942016-11-02 07:26:38 -0700384 if (isNotMplsBos(fwd.selector())) {
385 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
386 }
387 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700388 }
Pier Ventre42287df2016-11-09 14:17:26 -0800389
390 @Override
391 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
392 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800393 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800394 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
395 .getCriterion(TUNNEL_ID);
396 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800397 return processInitPwVersatile(fwd);
398 }
399 // Looking for the fwd objective of the termination.
400 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
401 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
402 if (modTunnelIdInstruction != null && outputInstruction != null) {
403 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800404 }
405 // If it is not a pseudo wire flow we fall back
406 // to the OFDPA 2.0 pipeline.
407 return super.processVersatile(fwd);
408 }
409
Pier Ventre70d53ba2016-11-17 22:26:29 -0800410 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
411 ModTunnelIdInstruction modTunnelIdInstruction,
412 OutputInstruction outputInstruction) {
413 TrafficTreatment.Builder flowTreatment;
414 TrafficSelector.Builder flowSelector;
415 // We divide the mpls actions from the tunnel actions. We need
416 // this to order the actions in the final treatment.
417 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
418 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
419 // The match of the forwarding objective is ready to go.
420 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
421 // We verify the tunnel id and mpls port are correct.
422 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
423 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
424 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
425 MPLS_TUNNEL_ID_MAX);
426 fail(forwardingObjective, ObjectiveError.BADPARAMS);
427 return Collections.emptySet();
428 }
429 // 0x0002XXXX is NNI interface.
430 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
431 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
432 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
433 mplsLogicalPort);
434 fail(forwardingObjective, ObjectiveError.BADPARAMS);
435 return Collections.emptySet();
436 }
437 // Next id cannot be null.
438 if (forwardingObjective.nextId() == null) {
439 log.error("Pw Versatile Forwarding Objective must contain nextId ",
440 forwardingObjective.nextId());
441 fail(forwardingObjective, ObjectiveError.BADPARAMS);
442 return Collections.emptySet();
443 }
444 // We retrieve the l2 interface group and point the mpls
445 // flow to this.
446 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
447 if (next == null) {
448 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
449 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
450 return Collections.emptySet();
451 }
452 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
453 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
454 if (group == null) {
455 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
456 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
457 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
458 return Collections.emptySet();
459 }
460 // We prepare the treatment for the mpls flow table.
461 // The order of the actions has to be strictly this
462 // according to the OFDPA 2.0 specification.
463 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
464 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800465 // Even though the specification and the xml/json files
466 // specify is allowed, the switch rejects the flow. In the
467 // OFDPA 3.0 EA0 version was necessary
468 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800469 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
470 flowTreatment.setTunnelId(tunnelId);
471 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
472 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
473 flowTreatment.transition(MPLS_TYPE_TABLE);
474 flowTreatment.deferred().group(group.id());
475 // We prepare the flow rule for the mpls table.
476 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
477 .fromApp(forwardingObjective.appId())
478 .withPriority(forwardingObjective.priority())
479 .forDevice(deviceId)
480 .withSelector(flowSelector.build())
481 .withTreatment(flowTreatment.build())
482 .makePermanent()
483 .forTable(MPLS_TABLE_1);
484 return Collections.singletonList(ruleBuilder.build());
485 }
486
Pier Ventre42287df2016-11-09 14:17:26 -0800487 /**
488 * Helper method to process the pw forwarding objectives.
489 *
490 * @param forwardingObjective the fw objective to process
491 * @return a singleton list of flow rule
492 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800493 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800494 // We retrieve the matching criteria for mpls l2 port.
495 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
496 .getCriterion(TUNNEL_ID);
497 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
498 .getCriterion(IN_PORT);
499 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
500 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
501 int mplsLogicalPort;
502 long tunnelId;
503 // Mpls tunnel ids according to the OFDPA manual have to be
504 // in the range [2^17-1, 2^16].
505 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
506 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
507 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
508 MPLS_TUNNEL_ID_MAX);
509 fail(forwardingObjective, ObjectiveError.BADPARAMS);
510 return Collections.emptySet();
511 }
512 // Port has not been null.
513 if (portCriterion == null) {
514 log.error("Pw Versatile Forwarding Objective must include port");
515 fail(forwardingObjective, ObjectiveError.BADPARAMS);
516 return Collections.emptySet();
517 }
518 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800519 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800520 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
521 portCriterion.port().toLong());
522 fail(forwardingObjective, ObjectiveError.BADPARAMS);
523 return Collections.emptySet();
524 }
525 mplsLogicalPort = ((int) portCriterion.port().toLong());
526 if (forwardingObjective.nextId() == null) {
527 log.error("Pw Versatile Forwarding Objective must contain nextId ",
528 forwardingObjective.nextId());
529 fail(forwardingObjective, ObjectiveError.BADPARAMS);
530 return Collections.emptySet();
531 }
532 // We don't expect a treatment.
533 if (forwardingObjective.treatment() != null &&
534 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
535 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
536 forwardingObjective.nextId());
537 fail(forwardingObjective, ObjectiveError.BADPARAMS);
538 return Collections.emptySet();
539 }
540 // We retrieve the l2 vpn group and point the mpls
541 // l2 port to this.
542 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
543 if (next == null) {
544 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
545 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
546 return Collections.emptySet();
547 }
548 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
549 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
550 if (group == null) {
551 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
552 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
553 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
554 return Collections.emptySet();
555 }
556 // We prepare the flow rule for the mpls l2 port table.
557 selector.matchTunnelId(tunnelId);
558 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
559 // This should not be necessary but without we receive an error
560 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
561 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
562 treatment.deferred().group(group.id());
563 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
564 .fromApp(forwardingObjective.appId())
565 .withPriority(MPLS_L2_PORT_PRIORITY)
566 .forDevice(deviceId)
567 .withSelector(selector.build())
568 .withTreatment(treatment.build())
569 .makePermanent()
570 .forTable(MPLS_L2_PORT_FLOW_TABLE);
571 return Collections.singletonList(ruleBuilder.build());
572 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800573
574 /**
575 * Utility function to get the mod tunnel id instruction
576 * if present.
577 *
578 * @param treatment the treatment to analyze
579 * @return the mod tunnel id instruction if present,
580 * otherwise null
581 */
582 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800583 if (treatment == null) {
584 return null;
585 }
586
Pier Ventre70d53ba2016-11-17 22:26:29 -0800587 L2ModificationInstruction l2ModificationInstruction;
588 for (Instruction instruction : treatment.allInstructions()) {
589 if (instruction.type() == L2MODIFICATION) {
590 l2ModificationInstruction = (L2ModificationInstruction) instruction;
591 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
592 return (ModTunnelIdInstruction) l2ModificationInstruction;
593 }
594 }
595 }
596 return null;
597 }
598
599 /**
600 * Utility function to get the output instruction
601 * if present.
602 *
603 * @param treatment the treatment to analyze
604 * @return the output instruction if present,
605 * otherwise null
606 */
607 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800608 if (treatment == null) {
609 return null;
610 }
611
Pier Ventre70d53ba2016-11-17 22:26:29 -0800612 for (Instruction instruction : treatment.allInstructions()) {
613 if (instruction.type() == Instruction.Type.OUTPUT) {
614 return (OutputInstruction) instruction;
615 }
616 }
617 return null;
618 }
619
620 /**
621 * Helper method for dividing the tunnel instructions from the mpls
622 * instructions.
623 *
624 * @param treatment the treatment to analyze
625 * @param mplsTreatment the mpls treatment builder
626 */
627 private void createMplsTreatment(TrafficTreatment treatment,
628 TrafficTreatment.Builder mplsTreatment) {
629
630 for (Instruction ins : treatment.allInstructions()) {
631
632 if (ins.type() == Instruction.Type.L2MODIFICATION) {
633 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
634 switch (l2ins.subtype()) {
635 // These instructions have to go in the mpls
636 // treatment.
637 case TUNNEL_ID:
638 break;
639 case DEC_MPLS_TTL:
640 case MPLS_POP:
641 mplsTreatment.add(ins);
642 break;
643 default:
644 log.warn("Driver does not handle this type of TrafficTreatment"
645 + " instruction in nextObjectives: {} - {}",
646 ins.type(), ins);
647 break;
648 }
649 } else if (ins.type() == Instruction.Type.OUTPUT) {
650 break;
651 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
652 // We support partially the l3 instructions.
653 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
654 switch (l3ins.subtype()) {
655 case TTL_IN:
656 mplsTreatment.add(ins);
657 break;
658 default:
659 log.warn("Driver does not handle this type of TrafficTreatment"
660 + " instruction in nextObjectives: {} - {}",
661 ins.type(), ins);
662 }
663
664 } else {
665 log.warn("Driver does not handle this type of TrafficTreatment"
666 + " instruction in nextObjectives: {} - {}",
667 ins.type(), ins);
668 }
669 }
670 }
Charles Chanf9e98652016-09-07 16:54:23 -0700671}