blob: d906953491cdf8bc958b2f709e63e7966d96b443 [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
pier5c817582019-04-17 17:05:08 +020061import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Pier Ventre42287df2016-11-09 14:17:26 -080062import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
Andrea Campanella84ac4df2018-04-30 11:48:55 +020063import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
64import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
65import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
66import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Pier Ventre42287df2016-11-09 14:17:26 -080067import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
68import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
69import static org.slf4j.LoggerFactory.getLogger;
70
Charles Chanf9e98652016-09-07 16:54:23 -070071/**
72 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
73 */
74public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080075
76 private final Logger log = getLogger(getClass());
77
Charles Chanf9e98652016-09-07 16:54:23 -070078 @Override
Charles Chan40132b32017-01-22 00:19:37 -080079 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070080 driverId = coreService.registerApplication(
81 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080082 }
Charles Chanf9e98652016-09-07 16:54:23 -070083
Charles Chan40132b32017-01-22 00:19:37 -080084 @Override
85 protected void initGroupHander(PipelinerContext context) {
86 groupHandler = new Ofdpa3GroupHandler();
87 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070088 }
89
90 @Override
Charles Chand1172632017-03-15 17:33:09 -070091 protected boolean requireVlanExtensions() {
92 return false;
93 }
94
95 @Override
Saurav Dasf3f75942018-01-25 09:49:01 -080096 protected boolean shouldRetry() {
97 return false;
98 }
99
100 @Override
Andrea Campanella84ac4df2018-04-30 11:48:55 +0200101 protected boolean supportsUnicastBlackHole() {
102 return true;
103 }
104
105 @Override
Pier Ventre42287df2016-11-09 14:17:26 -0800106 protected void processFilter(FilteringObjective filteringObjective,
107 boolean install,
108 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700109
110 // Check if filter is intended for pseudowire
111 boolean isPw = isPseudowire(filteringObjective);
112
113 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800114 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
115 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700116
117 VlanIdCriterion innerVlanIdCriterion = null;
118 for (Criterion criterion : filteringObjective.conditions()) {
119 if (criterion.type() == INNER_VLAN_VID) {
120 innerVlanIdCriterion = (VlanIdCriterion) criterion;
121 break;
122 }
123 }
124
Pier Ventre42287df2016-11-09 14:17:26 -0800125 VlanIdCriterion outerVlanIdCriterion = null;
126 // We extract the expected port criterion in the key.
127 portCriterion = (PortCriterion) filteringObjective.key();
128 // We extract the outer vlan id criterion.
129 for (Criterion criterion : filteringObjective.conditions()) {
130 if (criterion.type() == VLAN_VID) {
131 outerVlanIdCriterion = (VlanIdCriterion) criterion;
132 break;
133 }
134 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700135
Pier Ventre42287df2016-11-09 14:17:26 -0800136 // We extract the tunnel id.
137 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700138 VlanId egressVlan;
139
Pier Ventre42287df2016-11-09 14:17:26 -0800140 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700141 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800142 log.warn("Bad filtering objective from app: {}. Not"
143 + "processing filtering objective", applicationId);
144 fail(filteringObjective, ObjectiveError.BADPARAMS);
145 return;
146 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700147 filteringObjective.meta().allInstructions().size() == 2 &&
148 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
149 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
150
Pier Ventre42287df2016-11-09 14:17:26 -0800151 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
152 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700153
Pier Ventre42287df2016-11-09 14:17:26 -0800154 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
155 log.warn("Bad filtering objective from app: {}. Not"
156 + "processing filtering objective", applicationId);
157 fail(filteringObjective, ObjectiveError.BADPARAMS);
158 return;
159 } else {
160 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
161 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700162
163 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
164 filteringObjective.meta().allInstructions().get(1);
165
166 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
167 log.warn("Bad filtering objective from app: {}. Not"
168 + "processing filtering objective", applicationId);
169 fail(filteringObjective, ObjectiveError.BADPARAMS);
170 return;
171 } else {
172 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
173 }
Pier Ventre42287df2016-11-09 14:17:26 -0800174 } else {
175 log.warn("Bad filtering objective from app: {}. Not"
176 + "processing filtering objective", applicationId);
177 fail(filteringObjective, ObjectiveError.BADPARAMS);
178 return;
179 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700180
Pier Ventre42287df2016-11-09 14:17:26 -0800181 // Mpls tunnel ids according to the OFDPA manual have to be
182 // in the range [2^17-1, 2^16].
183 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
184 // Sanity check for the filtering objective.
185 if (portCriterion == null ||
186 outerVlanIdCriterion == null ||
187 tunnelId > MPLS_TUNNEL_ID_MAX) {
188 log.warn("Bad filtering objective from app: {}. Not"
189 + "processing filtering objective", applicationId);
190 fail(filteringObjective, ObjectiveError.BADPARAMS);
191 return;
192 }
193 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800194 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530195 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800196 portCriterion.port().toLong());
197 fail(filteringObjective, ObjectiveError.BADPARAMS);
198 return;
199 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700200
Pier Ventre42287df2016-11-09 14:17:26 -0800201 // We create the flows.
202 List<FlowRule> pwRules = processPwFilter(portCriterion,
203 innerVlanIdCriterion,
204 outerVlanIdCriterion,
205 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700206 applicationId,
207 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800208 );
209 // We tag the flow for adding or for removing.
210 for (FlowRule pwRule : pwRules) {
211 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
212 pwRule, deviceId);
213 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
214 }
215 // We push the filtering rules for the pw.
216 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
217 @Override
218 public void onSuccess(FlowRuleOperations ops) {
219 log.info("Applied {} filtering rules in device {}",
220 ops.stages().get(0).size(), deviceId);
221 pass(filteringObjective);
222 }
223
224 @Override
225 public void onError(FlowRuleOperations ops) {
226 log.info("Failed to apply all filtering rules in dev {}", deviceId);
227 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
228 }
229 }));
230
231 return;
232 }
233 // If it is not a pseudo wire flow we fall back
234 // to the OFDPA 2.0 pipeline.
235 super.processFilter(filteringObjective, install, applicationId);
236 }
237
238 /**
239 * Method to process the pw related filtering objectives.
240 *
241 * @param portCriterion the in port match
242 * @param innerVlanIdCriterion the inner vlan match
243 * @param outerVlanIdCriterion the outer vlan match
244 * @param tunnelId the tunnel id
245 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700246 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800247 * @return a list of flow rules to install
248 */
249 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700250 VlanIdCriterion innerVlanIdCriterion,
251 VlanIdCriterion outerVlanIdCriterion,
252 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700253 ApplicationId applicationId,
254 VlanId egressVlan) {
255
Pier Ventre42287df2016-11-09 14:17:26 -0800256 FlowRule vlan1FlowRule;
257 int mplsLogicalPort = ((int) portCriterion.port().toLong());
258 // We have to match on the inner vlan and outer vlan at the same time.
259 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800260
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700261 ImmutableList<FlowRule> toReturn;
262
263 // pseudowire configured with double tagged vlans
264 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
265 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
266
267 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
268
269 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
270 .matchInPort(portCriterion.port())
271 .matchVlanId(innerVlanIdCriterion.vlanId())
272 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
273 // TODO understand for the future how to manage the vlan rewrite.
274 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
275 .pushVlan()
276 .setVlanId(egressVlan)
277 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
278 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
279 .setTunnelId(tunnelId)
280 .transition(MPLS_L2_PORT_FLOW_TABLE);
281 vlan1FlowRule = DefaultFlowRule.builder()
282 .forDevice(deviceId)
283 .withSelector(vlan1Selector.build())
284 .withTreatment(vlan1Treatment.build())
285 .withPriority(DEFAULT_PRIORITY)
286 .fromApp(applicationId)
287 .makePermanent()
288 .forTable(VLAN_1_TABLE)
289 .build();
290 // Finally we create the flow rule for the vlan table.
291 FlowRule vlanFlowRule;
292 // We have to match on the outer vlan.
293 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
294 .matchInPort(portCriterion.port())
295 .matchVlanId(outerVlanIdCriterion.vlanId());
296 // TODO understand for the future how to manage the vlan rewrite.
297 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
298 .popVlan()
299 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
300 .transition(VLAN_1_TABLE);
301 vlanFlowRule = DefaultFlowRule.builder()
302 .forDevice(deviceId)
303 .withSelector(vlanSelector.build())
304 .withTreatment(vlanTreatment.build())
305 .withPriority(DEFAULT_PRIORITY)
306 .fromApp(applicationId)
307 .makePermanent()
308 .forTable(VLAN_TABLE)
309 .build();
310
311 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
312 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
313 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
314
315 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
316
317 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
318 .matchInPort(portCriterion.port())
319 .matchVlanId(innerVlanIdCriterion.vlanId());
320
321 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
322 // .pushVlan()
323 .setVlanId(egressVlan)
324 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
325 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
326 .setTunnelId(tunnelId)
327 .transition(MPLS_L2_PORT_FLOW_TABLE);
328
329 vlan1FlowRule = DefaultFlowRule.builder()
330 .forDevice(deviceId)
331 .withSelector(singleVlanSelector.build())
332 .withTreatment(singleVlanTreatment.build())
333 .withPriority(DEFAULT_PRIORITY)
334 .fromApp(applicationId)
335 .makePermanent()
336 .forTable(VLAN_TABLE)
337 .build();
338
339 return ImmutableList.of(vlan1FlowRule);
340 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
341 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
342
343 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
344 .matchInPort(portCriterion.port())
345 .matchVlanId(innerVlanIdCriterion.vlanId());
346
347 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
348 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
349 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
350 .setTunnelId(tunnelId)
351 .transition(MPLS_L2_PORT_FLOW_TABLE);
352
353 vlan1FlowRule = DefaultFlowRule.builder()
354 .forDevice(deviceId)
355 .withSelector(singleVlanSelector.build())
356 .withTreatment(singleVlanTreatment.build())
357 .withPriority(DEFAULT_PRIORITY)
358 .fromApp(applicationId)
359 .makePermanent()
360 .forTable(VLAN_TABLE)
361 .build();
362
363 return ImmutableList.of(vlan1FlowRule);
364 } else {
365 // failure...
366 return Collections.emptyList();
367 }
Pier Ventre42287df2016-11-09 14:17:26 -0800368 }
369
370 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700371 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa89b95a2018-02-14 14:14:54 -0800372 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
373 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
374 if (isNotMplsBos(fwd.selector())
375 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700376 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
377 }
Saurav Dasa89b95a2018-02-14 14:14:54 -0800378 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700379 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700380 }
Pier Ventre42287df2016-11-09 14:17:26 -0800381
382 @Override
383 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
384 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800385 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800386 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
387 .getCriterion(TUNNEL_ID);
388 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800389 return processInitPwVersatile(fwd);
390 }
391 // Looking for the fwd objective of the termination.
392 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
393 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
394 if (modTunnelIdInstruction != null && outputInstruction != null) {
395 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800396 }
397 // If it is not a pseudo wire flow we fall back
398 // to the OFDPA 2.0 pipeline.
399 return super.processVersatile(fwd);
400 }
401
Pier Ventre70d53ba2016-11-17 22:26:29 -0800402 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
403 ModTunnelIdInstruction modTunnelIdInstruction,
404 OutputInstruction outputInstruction) {
405 TrafficTreatment.Builder flowTreatment;
406 TrafficSelector.Builder flowSelector;
407 // We divide the mpls actions from the tunnel actions. We need
408 // this to order the actions in the final treatment.
409 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
410 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
411 // The match of the forwarding objective is ready to go.
412 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
413 // We verify the tunnel id and mpls port are correct.
414 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
415 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
416 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
417 MPLS_TUNNEL_ID_MAX);
418 fail(forwardingObjective, ObjectiveError.BADPARAMS);
419 return Collections.emptySet();
420 }
421 // 0x0002XXXX is NNI interface.
422 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
423 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
424 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
425 mplsLogicalPort);
426 fail(forwardingObjective, ObjectiveError.BADPARAMS);
427 return Collections.emptySet();
428 }
429 // Next id cannot be null.
430 if (forwardingObjective.nextId() == null) {
431 log.error("Pw Versatile Forwarding Objective must contain nextId ",
432 forwardingObjective.nextId());
433 fail(forwardingObjective, ObjectiveError.BADPARAMS);
434 return Collections.emptySet();
435 }
436 // We retrieve the l2 interface group and point the mpls
437 // flow to this.
438 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
439 if (next == null) {
440 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
441 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
442 return Collections.emptySet();
443 }
444 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
445 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
446 if (group == null) {
447 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
448 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
449 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
450 return Collections.emptySet();
451 }
452 // We prepare the treatment for the mpls flow table.
453 // The order of the actions has to be strictly this
454 // according to the OFDPA 2.0 specification.
455 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
456 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800457 // Even though the specification and the xml/json files
458 // specify is allowed, the switch rejects the flow. In the
459 // OFDPA 3.0 EA0 version was necessary
460 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800461 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
462 flowTreatment.setTunnelId(tunnelId);
463 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
464 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
465 flowTreatment.transition(MPLS_TYPE_TABLE);
466 flowTreatment.deferred().group(group.id());
467 // We prepare the flow rule for the mpls table.
468 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
469 .fromApp(forwardingObjective.appId())
470 .withPriority(forwardingObjective.priority())
471 .forDevice(deviceId)
472 .withSelector(flowSelector.build())
473 .withTreatment(flowTreatment.build())
474 .makePermanent()
475 .forTable(MPLS_TABLE_1);
476 return Collections.singletonList(ruleBuilder.build());
477 }
478
Pier Ventre42287df2016-11-09 14:17:26 -0800479 /**
480 * Helper method to process the pw forwarding objectives.
481 *
482 * @param forwardingObjective the fw objective to process
483 * @return a singleton list of flow rule
484 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800485 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800486 // We retrieve the matching criteria for mpls l2 port.
487 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
488 .getCriterion(TUNNEL_ID);
489 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
490 .getCriterion(IN_PORT);
491 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
492 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
493 int mplsLogicalPort;
494 long tunnelId;
495 // Mpls tunnel ids according to the OFDPA manual have to be
496 // in the range [2^17-1, 2^16].
497 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
498 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
499 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
500 MPLS_TUNNEL_ID_MAX);
501 fail(forwardingObjective, ObjectiveError.BADPARAMS);
502 return Collections.emptySet();
503 }
504 // Port has not been null.
505 if (portCriterion == null) {
506 log.error("Pw Versatile Forwarding Objective must include port");
507 fail(forwardingObjective, ObjectiveError.BADPARAMS);
508 return Collections.emptySet();
509 }
510 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800511 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800512 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
513 portCriterion.port().toLong());
514 fail(forwardingObjective, ObjectiveError.BADPARAMS);
515 return Collections.emptySet();
516 }
517 mplsLogicalPort = ((int) portCriterion.port().toLong());
518 if (forwardingObjective.nextId() == null) {
519 log.error("Pw Versatile Forwarding Objective must contain nextId ",
520 forwardingObjective.nextId());
521 fail(forwardingObjective, ObjectiveError.BADPARAMS);
522 return Collections.emptySet();
523 }
524 // We don't expect a treatment.
525 if (forwardingObjective.treatment() != null &&
526 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
527 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
528 forwardingObjective.nextId());
529 fail(forwardingObjective, ObjectiveError.BADPARAMS);
530 return Collections.emptySet();
531 }
532 // We retrieve the l2 vpn group and point the mpls
533 // l2 port to this.
534 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
535 if (next == null) {
536 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
537 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
538 return Collections.emptySet();
539 }
540 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
541 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
542 if (group == null) {
543 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
544 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
545 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
546 return Collections.emptySet();
547 }
548 // We prepare the flow rule for the mpls l2 port table.
549 selector.matchTunnelId(tunnelId);
550 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
551 // This should not be necessary but without we receive an error
552 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
553 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
554 treatment.deferred().group(group.id());
555 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
556 .fromApp(forwardingObjective.appId())
557 .withPriority(MPLS_L2_PORT_PRIORITY)
558 .forDevice(deviceId)
559 .withSelector(selector.build())
560 .withTreatment(treatment.build())
561 .makePermanent()
562 .forTable(MPLS_L2_PORT_FLOW_TABLE);
563 return Collections.singletonList(ruleBuilder.build());
564 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800565
566 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800567 * Helper method for dividing the tunnel instructions from the mpls
568 * instructions.
569 *
570 * @param treatment the treatment to analyze
571 * @param mplsTreatment the mpls treatment builder
572 */
573 private void createMplsTreatment(TrafficTreatment treatment,
574 TrafficTreatment.Builder mplsTreatment) {
575
576 for (Instruction ins : treatment.allInstructions()) {
577
578 if (ins.type() == Instruction.Type.L2MODIFICATION) {
579 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
580 switch (l2ins.subtype()) {
581 // These instructions have to go in the mpls
582 // treatment.
583 case TUNNEL_ID:
584 break;
585 case DEC_MPLS_TTL:
586 case MPLS_POP:
587 mplsTreatment.add(ins);
588 break;
589 default:
590 log.warn("Driver does not handle this type of TrafficTreatment"
591 + " instruction in nextObjectives: {} - {}",
592 ins.type(), ins);
593 break;
594 }
595 } else if (ins.type() == Instruction.Type.OUTPUT) {
596 break;
597 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
598 // We support partially the l3 instructions.
599 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
600 switch (l3ins.subtype()) {
601 case TTL_IN:
602 mplsTreatment.add(ins);
603 break;
604 default:
605 log.warn("Driver does not handle this type of TrafficTreatment"
606 + " instruction in nextObjectives: {} - {}",
607 ins.type(), ins);
608 }
609
610 } else {
611 log.warn("Driver does not handle this type of TrafficTreatment"
612 + " instruction in nextObjectives: {} - {}",
613 ins.type(), ins);
614 }
615 }
616 }
pier5c817582019-04-17 17:05:08 +0200617
Charles Chanf9e98652016-09-07 16:54:23 -0700618}