blob: c0418b73611b5abee6739a5d4c56df6710d88654 [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;
Andrea Campanella84ac4df2018-04-30 11:48:55 +020062import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
63import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
64import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
65import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Pier Ventre42287df2016-11-09 14:17:26 -080066import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
67import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
68import static org.slf4j.LoggerFactory.getLogger;
69
Charles Chanf9e98652016-09-07 16:54:23 -070070/**
71 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
72 */
73public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080074
75 private final Logger log = getLogger(getClass());
76
Charles Chanf9e98652016-09-07 16:54:23 -070077 @Override
Charles Chan40132b32017-01-22 00:19:37 -080078 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070079 driverId = coreService.registerApplication(
80 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080081 }
Charles Chanf9e98652016-09-07 16:54:23 -070082
Charles Chan40132b32017-01-22 00:19:37 -080083 @Override
84 protected void initGroupHander(PipelinerContext context) {
85 groupHandler = new Ofdpa3GroupHandler();
86 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070087 }
88
89 @Override
Charles Chand1172632017-03-15 17:33:09 -070090 protected boolean requireVlanExtensions() {
91 return false;
92 }
93
94 @Override
Saurav Dasf3f75942018-01-25 09:49:01 -080095 protected boolean shouldRetry() {
96 return false;
97 }
98
99 @Override
Andrea Campanella84ac4df2018-04-30 11:48:55 +0200100 protected boolean supportsUnicastBlackHole() {
101 return true;
102 }
103
104 @Override
Pier Ventre42287df2016-11-09 14:17:26 -0800105 protected void processFilter(FilteringObjective filteringObjective,
106 boolean install,
107 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700108
109 // Check if filter is intended for pseudowire
110 boolean isPw = isPseudowire(filteringObjective);
111
112 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800113 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
114 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700115
116 VlanIdCriterion innerVlanIdCriterion = null;
117 for (Criterion criterion : filteringObjective.conditions()) {
118 if (criterion.type() == INNER_VLAN_VID) {
119 innerVlanIdCriterion = (VlanIdCriterion) criterion;
120 break;
121 }
122 }
123
Pier Ventre42287df2016-11-09 14:17:26 -0800124 VlanIdCriterion outerVlanIdCriterion = null;
125 // We extract the expected port criterion in the key.
126 portCriterion = (PortCriterion) filteringObjective.key();
127 // We extract the outer vlan id criterion.
128 for (Criterion criterion : filteringObjective.conditions()) {
129 if (criterion.type() == VLAN_VID) {
130 outerVlanIdCriterion = (VlanIdCriterion) criterion;
131 break;
132 }
133 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700134
Pier Ventre42287df2016-11-09 14:17:26 -0800135 // We extract the tunnel id.
136 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700137 VlanId egressVlan;
138
Pier Ventre42287df2016-11-09 14:17:26 -0800139 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700140 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800141 log.warn("Bad filtering objective from app: {}. Not"
142 + "processing filtering objective", applicationId);
143 fail(filteringObjective, ObjectiveError.BADPARAMS);
144 return;
145 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700146 filteringObjective.meta().allInstructions().size() == 2 &&
147 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
148 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
149
Pier Ventre42287df2016-11-09 14:17:26 -0800150 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
151 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700152
Pier Ventre42287df2016-11-09 14:17:26 -0800153 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
154 log.warn("Bad filtering objective from app: {}. Not"
155 + "processing filtering objective", applicationId);
156 fail(filteringObjective, ObjectiveError.BADPARAMS);
157 return;
158 } else {
159 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
160 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700161
162 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
163 filteringObjective.meta().allInstructions().get(1);
164
165 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
166 log.warn("Bad filtering objective from app: {}. Not"
167 + "processing filtering objective", applicationId);
168 fail(filteringObjective, ObjectiveError.BADPARAMS);
169 return;
170 } else {
171 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
172 }
Pier Ventre42287df2016-11-09 14:17:26 -0800173 } else {
174 log.warn("Bad filtering objective from app: {}. Not"
175 + "processing filtering objective", applicationId);
176 fail(filteringObjective, ObjectiveError.BADPARAMS);
177 return;
178 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700179
Pier Ventre42287df2016-11-09 14:17:26 -0800180 // Mpls tunnel ids according to the OFDPA manual have to be
181 // in the range [2^17-1, 2^16].
182 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
183 // Sanity check for the filtering objective.
184 if (portCriterion == null ||
185 outerVlanIdCriterion == null ||
186 tunnelId > MPLS_TUNNEL_ID_MAX) {
187 log.warn("Bad filtering objective from app: {}. Not"
188 + "processing filtering objective", applicationId);
189 fail(filteringObjective, ObjectiveError.BADPARAMS);
190 return;
191 }
192 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800193 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530194 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800195 portCriterion.port().toLong());
196 fail(filteringObjective, ObjectiveError.BADPARAMS);
197 return;
198 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700199
Pier Ventre42287df2016-11-09 14:17:26 -0800200 // We create the flows.
201 List<FlowRule> pwRules = processPwFilter(portCriterion,
202 innerVlanIdCriterion,
203 outerVlanIdCriterion,
204 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700205 applicationId,
206 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800207 );
208 // We tag the flow for adding or for removing.
209 for (FlowRule pwRule : pwRules) {
210 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
211 pwRule, deviceId);
212 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
213 }
214 // We push the filtering rules for the pw.
215 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
216 @Override
217 public void onSuccess(FlowRuleOperations ops) {
218 log.info("Applied {} filtering rules in device {}",
219 ops.stages().get(0).size(), deviceId);
220 pass(filteringObjective);
221 }
222
223 @Override
224 public void onError(FlowRuleOperations ops) {
225 log.info("Failed to apply all filtering rules in dev {}", deviceId);
226 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
227 }
228 }));
229
230 return;
231 }
232 // If it is not a pseudo wire flow we fall back
233 // to the OFDPA 2.0 pipeline.
234 super.processFilter(filteringObjective, install, applicationId);
235 }
236
237 /**
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700238 * Determines if the filtering objective will be used for a pseudowire.
239 *
240 * @param filteringObjective
241 * @return True if objective was created for a pseudowire, false otherwise.
242 */
243 private boolean isPseudowire(FilteringObjective filteringObjective) {
244
245
246 if (filteringObjective.meta() != null) {
247
248 TrafficTreatment treatment = filteringObjective.meta();
249 for (Instruction instr : treatment.immediate()) {
250 if (instr.type().equals(Instruction.Type.L2MODIFICATION)) {
251
252 L2ModificationInstruction l2Instr = (L2ModificationInstruction) instr;
253 if (l2Instr.subtype().equals(L2SubType.TUNNEL_ID)) {
254 return true;
255 }
256 }
257 }
258 }
259
260 return false;
261 }
262
263 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800264 * Method to process the pw related filtering objectives.
265 *
266 * @param portCriterion the in port match
267 * @param innerVlanIdCriterion the inner vlan match
268 * @param outerVlanIdCriterion the outer vlan match
269 * @param tunnelId the tunnel id
270 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700271 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800272 * @return a list of flow rules to install
273 */
274 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700275 VlanIdCriterion innerVlanIdCriterion,
276 VlanIdCriterion outerVlanIdCriterion,
277 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700278 ApplicationId applicationId,
279 VlanId egressVlan) {
280
Pier Ventre42287df2016-11-09 14:17:26 -0800281 FlowRule vlan1FlowRule;
282 int mplsLogicalPort = ((int) portCriterion.port().toLong());
283 // We have to match on the inner vlan and outer vlan at the same time.
284 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800285
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700286 ImmutableList<FlowRule> toReturn;
287
288 // pseudowire configured with double tagged vlans
289 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
290 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
291
292 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
293
294 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
295 .matchInPort(portCriterion.port())
296 .matchVlanId(innerVlanIdCriterion.vlanId())
297 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
298 // TODO understand for the future how to manage the vlan rewrite.
299 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
300 .pushVlan()
301 .setVlanId(egressVlan)
302 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
303 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
304 .setTunnelId(tunnelId)
305 .transition(MPLS_L2_PORT_FLOW_TABLE);
306 vlan1FlowRule = DefaultFlowRule.builder()
307 .forDevice(deviceId)
308 .withSelector(vlan1Selector.build())
309 .withTreatment(vlan1Treatment.build())
310 .withPriority(DEFAULT_PRIORITY)
311 .fromApp(applicationId)
312 .makePermanent()
313 .forTable(VLAN_1_TABLE)
314 .build();
315 // Finally we create the flow rule for the vlan table.
316 FlowRule vlanFlowRule;
317 // We have to match on the outer vlan.
318 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
319 .matchInPort(portCriterion.port())
320 .matchVlanId(outerVlanIdCriterion.vlanId());
321 // TODO understand for the future how to manage the vlan rewrite.
322 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
323 .popVlan()
324 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
325 .transition(VLAN_1_TABLE);
326 vlanFlowRule = DefaultFlowRule.builder()
327 .forDevice(deviceId)
328 .withSelector(vlanSelector.build())
329 .withTreatment(vlanTreatment.build())
330 .withPriority(DEFAULT_PRIORITY)
331 .fromApp(applicationId)
332 .makePermanent()
333 .forTable(VLAN_TABLE)
334 .build();
335
336 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
337 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
338 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
339
340 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
341
342 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
343 .matchInPort(portCriterion.port())
344 .matchVlanId(innerVlanIdCriterion.vlanId());
345
346 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
347 // .pushVlan()
348 .setVlanId(egressVlan)
349 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
350 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
351 .setTunnelId(tunnelId)
352 .transition(MPLS_L2_PORT_FLOW_TABLE);
353
354 vlan1FlowRule = DefaultFlowRule.builder()
355 .forDevice(deviceId)
356 .withSelector(singleVlanSelector.build())
357 .withTreatment(singleVlanTreatment.build())
358 .withPriority(DEFAULT_PRIORITY)
359 .fromApp(applicationId)
360 .makePermanent()
361 .forTable(VLAN_TABLE)
362 .build();
363
364 return ImmutableList.of(vlan1FlowRule);
365 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
366 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
367
368 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
369 .matchInPort(portCriterion.port())
370 .matchVlanId(innerVlanIdCriterion.vlanId());
371
372 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
373 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
374 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
375 .setTunnelId(tunnelId)
376 .transition(MPLS_L2_PORT_FLOW_TABLE);
377
378 vlan1FlowRule = DefaultFlowRule.builder()
379 .forDevice(deviceId)
380 .withSelector(singleVlanSelector.build())
381 .withTreatment(singleVlanTreatment.build())
382 .withPriority(DEFAULT_PRIORITY)
383 .fromApp(applicationId)
384 .makePermanent()
385 .forTable(VLAN_TABLE)
386 .build();
387
388 return ImmutableList.of(vlan1FlowRule);
389 } else {
390 // failure...
391 return Collections.emptyList();
392 }
Pier Ventre42287df2016-11-09 14:17:26 -0800393 }
394
395 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700396 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa89b95a2018-02-14 14:14:54 -0800397 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
398 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
399 if (isNotMplsBos(fwd.selector())
400 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700401 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
402 }
Saurav Dasa89b95a2018-02-14 14:14:54 -0800403 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700404 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700405 }
Pier Ventre42287df2016-11-09 14:17:26 -0800406
407 @Override
408 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
409 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800410 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800411 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
412 .getCriterion(TUNNEL_ID);
413 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800414 return processInitPwVersatile(fwd);
415 }
416 // Looking for the fwd objective of the termination.
417 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
418 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
419 if (modTunnelIdInstruction != null && outputInstruction != null) {
420 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800421 }
422 // If it is not a pseudo wire flow we fall back
423 // to the OFDPA 2.0 pipeline.
424 return super.processVersatile(fwd);
425 }
426
Pier Ventre70d53ba2016-11-17 22:26:29 -0800427 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
428 ModTunnelIdInstruction modTunnelIdInstruction,
429 OutputInstruction outputInstruction) {
430 TrafficTreatment.Builder flowTreatment;
431 TrafficSelector.Builder flowSelector;
432 // We divide the mpls actions from the tunnel actions. We need
433 // this to order the actions in the final treatment.
434 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
435 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
436 // The match of the forwarding objective is ready to go.
437 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
438 // We verify the tunnel id and mpls port are correct.
439 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
440 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
441 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
442 MPLS_TUNNEL_ID_MAX);
443 fail(forwardingObjective, ObjectiveError.BADPARAMS);
444 return Collections.emptySet();
445 }
446 // 0x0002XXXX is NNI interface.
447 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
448 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
449 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
450 mplsLogicalPort);
451 fail(forwardingObjective, ObjectiveError.BADPARAMS);
452 return Collections.emptySet();
453 }
454 // Next id cannot be null.
455 if (forwardingObjective.nextId() == null) {
456 log.error("Pw Versatile Forwarding Objective must contain nextId ",
457 forwardingObjective.nextId());
458 fail(forwardingObjective, ObjectiveError.BADPARAMS);
459 return Collections.emptySet();
460 }
461 // We retrieve the l2 interface group and point the mpls
462 // flow to this.
463 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
464 if (next == null) {
465 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
466 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
467 return Collections.emptySet();
468 }
469 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
470 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
471 if (group == null) {
472 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
473 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
474 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
475 return Collections.emptySet();
476 }
477 // We prepare the treatment for the mpls flow table.
478 // The order of the actions has to be strictly this
479 // according to the OFDPA 2.0 specification.
480 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
481 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800482 // Even though the specification and the xml/json files
483 // specify is allowed, the switch rejects the flow. In the
484 // OFDPA 3.0 EA0 version was necessary
485 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800486 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
487 flowTreatment.setTunnelId(tunnelId);
488 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
489 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
490 flowTreatment.transition(MPLS_TYPE_TABLE);
491 flowTreatment.deferred().group(group.id());
492 // We prepare the flow rule for the mpls table.
493 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
494 .fromApp(forwardingObjective.appId())
495 .withPriority(forwardingObjective.priority())
496 .forDevice(deviceId)
497 .withSelector(flowSelector.build())
498 .withTreatment(flowTreatment.build())
499 .makePermanent()
500 .forTable(MPLS_TABLE_1);
501 return Collections.singletonList(ruleBuilder.build());
502 }
503
Pier Ventre42287df2016-11-09 14:17:26 -0800504 /**
505 * Helper method to process the pw forwarding objectives.
506 *
507 * @param forwardingObjective the fw objective to process
508 * @return a singleton list of flow rule
509 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800510 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800511 // We retrieve the matching criteria for mpls l2 port.
512 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
513 .getCriterion(TUNNEL_ID);
514 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
515 .getCriterion(IN_PORT);
516 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
517 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
518 int mplsLogicalPort;
519 long tunnelId;
520 // Mpls tunnel ids according to the OFDPA manual have to be
521 // in the range [2^17-1, 2^16].
522 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
523 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
524 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
525 MPLS_TUNNEL_ID_MAX);
526 fail(forwardingObjective, ObjectiveError.BADPARAMS);
527 return Collections.emptySet();
528 }
529 // Port has not been null.
530 if (portCriterion == null) {
531 log.error("Pw Versatile Forwarding Objective must include port");
532 fail(forwardingObjective, ObjectiveError.BADPARAMS);
533 return Collections.emptySet();
534 }
535 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800536 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800537 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
538 portCriterion.port().toLong());
539 fail(forwardingObjective, ObjectiveError.BADPARAMS);
540 return Collections.emptySet();
541 }
542 mplsLogicalPort = ((int) portCriterion.port().toLong());
543 if (forwardingObjective.nextId() == null) {
544 log.error("Pw Versatile Forwarding Objective must contain nextId ",
545 forwardingObjective.nextId());
546 fail(forwardingObjective, ObjectiveError.BADPARAMS);
547 return Collections.emptySet();
548 }
549 // We don't expect a treatment.
550 if (forwardingObjective.treatment() != null &&
551 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
552 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
553 forwardingObjective.nextId());
554 fail(forwardingObjective, ObjectiveError.BADPARAMS);
555 return Collections.emptySet();
556 }
557 // We retrieve the l2 vpn group and point the mpls
558 // l2 port to this.
559 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
560 if (next == null) {
561 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
562 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
563 return Collections.emptySet();
564 }
565 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
566 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
567 if (group == null) {
568 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
569 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
570 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
571 return Collections.emptySet();
572 }
573 // We prepare the flow rule for the mpls l2 port table.
574 selector.matchTunnelId(tunnelId);
575 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
576 // This should not be necessary but without we receive an error
577 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
578 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
579 treatment.deferred().group(group.id());
580 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
581 .fromApp(forwardingObjective.appId())
582 .withPriority(MPLS_L2_PORT_PRIORITY)
583 .forDevice(deviceId)
584 .withSelector(selector.build())
585 .withTreatment(treatment.build())
586 .makePermanent()
587 .forTable(MPLS_L2_PORT_FLOW_TABLE);
588 return Collections.singletonList(ruleBuilder.build());
589 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800590
591 /**
592 * Utility function to get the mod tunnel id instruction
593 * if present.
594 *
595 * @param treatment the treatment to analyze
596 * @return the mod tunnel id instruction if present,
597 * otherwise null
598 */
599 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800600 if (treatment == null) {
601 return null;
602 }
603
Pier Ventre70d53ba2016-11-17 22:26:29 -0800604 L2ModificationInstruction l2ModificationInstruction;
605 for (Instruction instruction : treatment.allInstructions()) {
606 if (instruction.type() == L2MODIFICATION) {
607 l2ModificationInstruction = (L2ModificationInstruction) instruction;
608 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
609 return (ModTunnelIdInstruction) l2ModificationInstruction;
610 }
611 }
612 }
613 return null;
614 }
615
616 /**
617 * Utility function to get the output instruction
618 * if present.
619 *
620 * @param treatment the treatment to analyze
621 * @return the output instruction if present,
622 * otherwise null
623 */
624 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800625 if (treatment == null) {
626 return null;
627 }
628
Pier Ventre70d53ba2016-11-17 22:26:29 -0800629 for (Instruction instruction : treatment.allInstructions()) {
630 if (instruction.type() == Instruction.Type.OUTPUT) {
631 return (OutputInstruction) instruction;
632 }
633 }
634 return null;
635 }
636
637 /**
638 * Helper method for dividing the tunnel instructions from the mpls
639 * instructions.
640 *
641 * @param treatment the treatment to analyze
642 * @param mplsTreatment the mpls treatment builder
643 */
644 private void createMplsTreatment(TrafficTreatment treatment,
645 TrafficTreatment.Builder mplsTreatment) {
646
647 for (Instruction ins : treatment.allInstructions()) {
648
649 if (ins.type() == Instruction.Type.L2MODIFICATION) {
650 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
651 switch (l2ins.subtype()) {
652 // These instructions have to go in the mpls
653 // treatment.
654 case TUNNEL_ID:
655 break;
656 case DEC_MPLS_TTL:
657 case MPLS_POP:
658 mplsTreatment.add(ins);
659 break;
660 default:
661 log.warn("Driver does not handle this type of TrafficTreatment"
662 + " instruction in nextObjectives: {} - {}",
663 ins.type(), ins);
664 break;
665 }
666 } else if (ins.type() == Instruction.Type.OUTPUT) {
667 break;
668 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
669 // We support partially the l3 instructions.
670 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
671 switch (l3ins.subtype()) {
672 case TTL_IN:
673 mplsTreatment.add(ins);
674 break;
675 default:
676 log.warn("Driver does not handle this type of TrafficTreatment"
677 + " instruction in nextObjectives: {} - {}",
678 ins.type(), ins);
679 }
680
681 } else {
682 log.warn("Driver does not handle this type of TrafficTreatment"
683 + " instruction in nextObjectives: {} - {}",
684 ins.type(), ins);
685 }
686 }
687 }
Charles Chanf9e98652016-09-07 16:54:23 -0700688}