blob: 7ea79bd39ec7a133a7b1927b9c6584f0e7bf6c0e [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
Saurav Dasc568c342018-01-25 09:49:01 -080092 protected boolean shouldRetry() {
93 return false;
94 }
95
96 @Override
Pier Ventre42287df2016-11-09 14:17:26 -080097 protected void processFilter(FilteringObjective filteringObjective,
98 boolean install,
99 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700100
101 // Check if filter is intended for pseudowire
102 boolean isPw = isPseudowire(filteringObjective);
103
104 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800105 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
106 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700107
108 VlanIdCriterion innerVlanIdCriterion = null;
109 for (Criterion criterion : filteringObjective.conditions()) {
110 if (criterion.type() == INNER_VLAN_VID) {
111 innerVlanIdCriterion = (VlanIdCriterion) criterion;
112 break;
113 }
114 }
115
Pier Ventre42287df2016-11-09 14:17:26 -0800116 VlanIdCriterion outerVlanIdCriterion = null;
117 // We extract the expected port criterion in the key.
118 portCriterion = (PortCriterion) filteringObjective.key();
119 // We extract the outer vlan id criterion.
120 for (Criterion criterion : filteringObjective.conditions()) {
121 if (criterion.type() == VLAN_VID) {
122 outerVlanIdCriterion = (VlanIdCriterion) criterion;
123 break;
124 }
125 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700126
Pier Ventre42287df2016-11-09 14:17:26 -0800127 // We extract the tunnel id.
128 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700129 VlanId egressVlan;
130
Pier Ventre42287df2016-11-09 14:17:26 -0800131 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700132 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800133 log.warn("Bad filtering objective from app: {}. Not"
134 + "processing filtering objective", applicationId);
135 fail(filteringObjective, ObjectiveError.BADPARAMS);
136 return;
137 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700138 filteringObjective.meta().allInstructions().size() == 2 &&
139 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
140 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
141
Pier Ventre42287df2016-11-09 14:17:26 -0800142 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
143 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700144
Pier Ventre42287df2016-11-09 14:17:26 -0800145 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
146 log.warn("Bad filtering objective from app: {}. Not"
147 + "processing filtering objective", applicationId);
148 fail(filteringObjective, ObjectiveError.BADPARAMS);
149 return;
150 } else {
151 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
152 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700153
154 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
155 filteringObjective.meta().allInstructions().get(1);
156
157 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
158 log.warn("Bad filtering objective from app: {}. Not"
159 + "processing filtering objective", applicationId);
160 fail(filteringObjective, ObjectiveError.BADPARAMS);
161 return;
162 } else {
163 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
164 }
Pier Ventre42287df2016-11-09 14:17:26 -0800165 } else {
166 log.warn("Bad filtering objective from app: {}. Not"
167 + "processing filtering objective", applicationId);
168 fail(filteringObjective, ObjectiveError.BADPARAMS);
169 return;
170 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700171
Pier Ventre42287df2016-11-09 14:17:26 -0800172 // Mpls tunnel ids according to the OFDPA manual have to be
173 // in the range [2^17-1, 2^16].
174 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
175 // Sanity check for the filtering objective.
176 if (portCriterion == null ||
177 outerVlanIdCriterion == null ||
178 tunnelId > MPLS_TUNNEL_ID_MAX) {
179 log.warn("Bad filtering objective from app: {}. Not"
180 + "processing filtering objective", applicationId);
181 fail(filteringObjective, ObjectiveError.BADPARAMS);
182 return;
183 }
184 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800185 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530186 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800187 portCriterion.port().toLong());
188 fail(filteringObjective, ObjectiveError.BADPARAMS);
189 return;
190 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700191
Pier Ventre42287df2016-11-09 14:17:26 -0800192 // We create the flows.
193 List<FlowRule> pwRules = processPwFilter(portCriterion,
194 innerVlanIdCriterion,
195 outerVlanIdCriterion,
196 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700197 applicationId,
198 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800199 );
200 // We tag the flow for adding or for removing.
201 for (FlowRule pwRule : pwRules) {
202 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
203 pwRule, deviceId);
204 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
205 }
206 // We push the filtering rules for the pw.
207 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
208 @Override
209 public void onSuccess(FlowRuleOperations ops) {
210 log.info("Applied {} filtering rules in device {}",
211 ops.stages().get(0).size(), deviceId);
212 pass(filteringObjective);
213 }
214
215 @Override
216 public void onError(FlowRuleOperations ops) {
217 log.info("Failed to apply all filtering rules in dev {}", deviceId);
218 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
219 }
220 }));
221
222 return;
223 }
224 // If it is not a pseudo wire flow we fall back
225 // to the OFDPA 2.0 pipeline.
226 super.processFilter(filteringObjective, install, applicationId);
227 }
228
229 /**
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700230 * Determines if the filtering objective will be used for a pseudowire.
231 *
232 * @param filteringObjective
233 * @return True if objective was created for a pseudowire, false otherwise.
234 */
235 private boolean isPseudowire(FilteringObjective filteringObjective) {
236
237
238 if (filteringObjective.meta() != null) {
239
240 TrafficTreatment treatment = filteringObjective.meta();
241 for (Instruction instr : treatment.immediate()) {
242 if (instr.type().equals(Instruction.Type.L2MODIFICATION)) {
243
244 L2ModificationInstruction l2Instr = (L2ModificationInstruction) instr;
245 if (l2Instr.subtype().equals(L2SubType.TUNNEL_ID)) {
246 return true;
247 }
248 }
249 }
250 }
251
252 return false;
253 }
254
255 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800256 * Method to process the pw related filtering objectives.
257 *
258 * @param portCriterion the in port match
259 * @param innerVlanIdCriterion the inner vlan match
260 * @param outerVlanIdCriterion the outer vlan match
261 * @param tunnelId the tunnel id
262 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700263 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800264 * @return a list of flow rules to install
265 */
266 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700267 VlanIdCriterion innerVlanIdCriterion,
268 VlanIdCriterion outerVlanIdCriterion,
269 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700270 ApplicationId applicationId,
271 VlanId egressVlan) {
272
Pier Ventre42287df2016-11-09 14:17:26 -0800273 FlowRule vlan1FlowRule;
274 int mplsLogicalPort = ((int) portCriterion.port().toLong());
275 // We have to match on the inner vlan and outer vlan at the same time.
276 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800277
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700278 ImmutableList<FlowRule> toReturn;
279
280 // pseudowire configured with double tagged vlans
281 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
282 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
283
284 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
285
286 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
287 .matchInPort(portCriterion.port())
288 .matchVlanId(innerVlanIdCriterion.vlanId())
289 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
290 // TODO understand for the future how to manage the vlan rewrite.
291 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
292 .pushVlan()
293 .setVlanId(egressVlan)
294 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
295 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
296 .setTunnelId(tunnelId)
297 .transition(MPLS_L2_PORT_FLOW_TABLE);
298 vlan1FlowRule = DefaultFlowRule.builder()
299 .forDevice(deviceId)
300 .withSelector(vlan1Selector.build())
301 .withTreatment(vlan1Treatment.build())
302 .withPriority(DEFAULT_PRIORITY)
303 .fromApp(applicationId)
304 .makePermanent()
305 .forTable(VLAN_1_TABLE)
306 .build();
307 // Finally we create the flow rule for the vlan table.
308 FlowRule vlanFlowRule;
309 // We have to match on the outer vlan.
310 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
311 .matchInPort(portCriterion.port())
312 .matchVlanId(outerVlanIdCriterion.vlanId());
313 // TODO understand for the future how to manage the vlan rewrite.
314 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
315 .popVlan()
316 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
317 .transition(VLAN_1_TABLE);
318 vlanFlowRule = DefaultFlowRule.builder()
319 .forDevice(deviceId)
320 .withSelector(vlanSelector.build())
321 .withTreatment(vlanTreatment.build())
322 .withPriority(DEFAULT_PRIORITY)
323 .fromApp(applicationId)
324 .makePermanent()
325 .forTable(VLAN_TABLE)
326 .build();
327
328 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
329 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
330 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
331
332 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
333
334 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
335 .matchInPort(portCriterion.port())
336 .matchVlanId(innerVlanIdCriterion.vlanId());
337
338 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
339 // .pushVlan()
340 .setVlanId(egressVlan)
341 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
342 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
343 .setTunnelId(tunnelId)
344 .transition(MPLS_L2_PORT_FLOW_TABLE);
345
346 vlan1FlowRule = DefaultFlowRule.builder()
347 .forDevice(deviceId)
348 .withSelector(singleVlanSelector.build())
349 .withTreatment(singleVlanTreatment.build())
350 .withPriority(DEFAULT_PRIORITY)
351 .fromApp(applicationId)
352 .makePermanent()
353 .forTable(VLAN_TABLE)
354 .build();
355
356 return ImmutableList.of(vlan1FlowRule);
357 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
358 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
359
360 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
361 .matchInPort(portCriterion.port())
362 .matchVlanId(innerVlanIdCriterion.vlanId());
363
364 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
365 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
366 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
367 .setTunnelId(tunnelId)
368 .transition(MPLS_L2_PORT_FLOW_TABLE);
369
370 vlan1FlowRule = DefaultFlowRule.builder()
371 .forDevice(deviceId)
372 .withSelector(singleVlanSelector.build())
373 .withTreatment(singleVlanTreatment.build())
374 .withPriority(DEFAULT_PRIORITY)
375 .fromApp(applicationId)
376 .makePermanent()
377 .forTable(VLAN_TABLE)
378 .build();
379
380 return ImmutableList.of(vlan1FlowRule);
381 } else {
382 // failure...
383 return Collections.emptyList();
384 }
Pier Ventre42287df2016-11-09 14:17:26 -0800385 }
386
387 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700388 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa4020382018-02-14 14:14:54 -0800389 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
390 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
391 if (isNotMplsBos(fwd.selector())
392 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700393 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
394 }
Saurav Dasa4020382018-02-14 14:14:54 -0800395 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700396 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700397 }
Pier Ventre42287df2016-11-09 14:17:26 -0800398
399 @Override
400 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
401 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800402 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800403 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
404 .getCriterion(TUNNEL_ID);
405 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800406 return processInitPwVersatile(fwd);
407 }
408 // Looking for the fwd objective of the termination.
409 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
410 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
411 if (modTunnelIdInstruction != null && outputInstruction != null) {
412 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800413 }
414 // If it is not a pseudo wire flow we fall back
415 // to the OFDPA 2.0 pipeline.
416 return super.processVersatile(fwd);
417 }
418
Pier Ventre70d53ba2016-11-17 22:26:29 -0800419 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
420 ModTunnelIdInstruction modTunnelIdInstruction,
421 OutputInstruction outputInstruction) {
422 TrafficTreatment.Builder flowTreatment;
423 TrafficSelector.Builder flowSelector;
424 // We divide the mpls actions from the tunnel actions. We need
425 // this to order the actions in the final treatment.
426 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
427 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
428 // The match of the forwarding objective is ready to go.
429 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
430 // We verify the tunnel id and mpls port are correct.
431 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
432 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
433 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
434 MPLS_TUNNEL_ID_MAX);
435 fail(forwardingObjective, ObjectiveError.BADPARAMS);
436 return Collections.emptySet();
437 }
438 // 0x0002XXXX is NNI interface.
439 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
440 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
441 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
442 mplsLogicalPort);
443 fail(forwardingObjective, ObjectiveError.BADPARAMS);
444 return Collections.emptySet();
445 }
446 // Next id cannot be null.
447 if (forwardingObjective.nextId() == null) {
448 log.error("Pw Versatile Forwarding Objective must contain nextId ",
449 forwardingObjective.nextId());
450 fail(forwardingObjective, ObjectiveError.BADPARAMS);
451 return Collections.emptySet();
452 }
453 // We retrieve the l2 interface group and point the mpls
454 // flow to this.
455 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
456 if (next == null) {
457 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
458 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
459 return Collections.emptySet();
460 }
461 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
462 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
463 if (group == null) {
464 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
465 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
466 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
467 return Collections.emptySet();
468 }
469 // We prepare the treatment for the mpls flow table.
470 // The order of the actions has to be strictly this
471 // according to the OFDPA 2.0 specification.
472 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
473 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800474 // Even though the specification and the xml/json files
475 // specify is allowed, the switch rejects the flow. In the
476 // OFDPA 3.0 EA0 version was necessary
477 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800478 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
479 flowTreatment.setTunnelId(tunnelId);
480 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
481 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
482 flowTreatment.transition(MPLS_TYPE_TABLE);
483 flowTreatment.deferred().group(group.id());
484 // We prepare the flow rule for the mpls table.
485 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
486 .fromApp(forwardingObjective.appId())
487 .withPriority(forwardingObjective.priority())
488 .forDevice(deviceId)
489 .withSelector(flowSelector.build())
490 .withTreatment(flowTreatment.build())
491 .makePermanent()
492 .forTable(MPLS_TABLE_1);
493 return Collections.singletonList(ruleBuilder.build());
494 }
495
Pier Ventre42287df2016-11-09 14:17:26 -0800496 /**
497 * Helper method to process the pw forwarding objectives.
498 *
499 * @param forwardingObjective the fw objective to process
500 * @return a singleton list of flow rule
501 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800502 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800503 // We retrieve the matching criteria for mpls l2 port.
504 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
505 .getCriterion(TUNNEL_ID);
506 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
507 .getCriterion(IN_PORT);
508 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
509 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
510 int mplsLogicalPort;
511 long tunnelId;
512 // Mpls tunnel ids according to the OFDPA manual have to be
513 // in the range [2^17-1, 2^16].
514 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
515 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
516 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
517 MPLS_TUNNEL_ID_MAX);
518 fail(forwardingObjective, ObjectiveError.BADPARAMS);
519 return Collections.emptySet();
520 }
521 // Port has not been null.
522 if (portCriterion == null) {
523 log.error("Pw Versatile Forwarding Objective must include port");
524 fail(forwardingObjective, ObjectiveError.BADPARAMS);
525 return Collections.emptySet();
526 }
527 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800528 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800529 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
530 portCriterion.port().toLong());
531 fail(forwardingObjective, ObjectiveError.BADPARAMS);
532 return Collections.emptySet();
533 }
534 mplsLogicalPort = ((int) portCriterion.port().toLong());
535 if (forwardingObjective.nextId() == null) {
536 log.error("Pw Versatile Forwarding Objective must contain nextId ",
537 forwardingObjective.nextId());
538 fail(forwardingObjective, ObjectiveError.BADPARAMS);
539 return Collections.emptySet();
540 }
541 // We don't expect a treatment.
542 if (forwardingObjective.treatment() != null &&
543 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
544 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
545 forwardingObjective.nextId());
546 fail(forwardingObjective, ObjectiveError.BADPARAMS);
547 return Collections.emptySet();
548 }
549 // We retrieve the l2 vpn group and point the mpls
550 // l2 port to this.
551 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
552 if (next == null) {
553 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
554 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
555 return Collections.emptySet();
556 }
557 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
558 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
559 if (group == null) {
560 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
561 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
562 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
563 return Collections.emptySet();
564 }
565 // We prepare the flow rule for the mpls l2 port table.
566 selector.matchTunnelId(tunnelId);
567 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
568 // This should not be necessary but without we receive an error
569 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
570 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
571 treatment.deferred().group(group.id());
572 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
573 .fromApp(forwardingObjective.appId())
574 .withPriority(MPLS_L2_PORT_PRIORITY)
575 .forDevice(deviceId)
576 .withSelector(selector.build())
577 .withTreatment(treatment.build())
578 .makePermanent()
579 .forTable(MPLS_L2_PORT_FLOW_TABLE);
580 return Collections.singletonList(ruleBuilder.build());
581 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800582
583 /**
584 * Utility function to get the mod tunnel id instruction
585 * if present.
586 *
587 * @param treatment the treatment to analyze
588 * @return the mod tunnel id instruction if present,
589 * otherwise null
590 */
591 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800592 if (treatment == null) {
593 return null;
594 }
595
Pier Ventre70d53ba2016-11-17 22:26:29 -0800596 L2ModificationInstruction l2ModificationInstruction;
597 for (Instruction instruction : treatment.allInstructions()) {
598 if (instruction.type() == L2MODIFICATION) {
599 l2ModificationInstruction = (L2ModificationInstruction) instruction;
600 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
601 return (ModTunnelIdInstruction) l2ModificationInstruction;
602 }
603 }
604 }
605 return null;
606 }
607
608 /**
609 * Utility function to get the output instruction
610 * if present.
611 *
612 * @param treatment the treatment to analyze
613 * @return the output instruction if present,
614 * otherwise null
615 */
616 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800617 if (treatment == null) {
618 return null;
619 }
620
Pier Ventre70d53ba2016-11-17 22:26:29 -0800621 for (Instruction instruction : treatment.allInstructions()) {
622 if (instruction.type() == Instruction.Type.OUTPUT) {
623 return (OutputInstruction) instruction;
624 }
625 }
626 return null;
627 }
628
629 /**
630 * Helper method for dividing the tunnel instructions from the mpls
631 * instructions.
632 *
633 * @param treatment the treatment to analyze
634 * @param mplsTreatment the mpls treatment builder
635 */
636 private void createMplsTreatment(TrafficTreatment treatment,
637 TrafficTreatment.Builder mplsTreatment) {
638
639 for (Instruction ins : treatment.allInstructions()) {
640
641 if (ins.type() == Instruction.Type.L2MODIFICATION) {
642 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
643 switch (l2ins.subtype()) {
644 // These instructions have to go in the mpls
645 // treatment.
646 case TUNNEL_ID:
647 break;
648 case DEC_MPLS_TTL:
649 case MPLS_POP:
650 mplsTreatment.add(ins);
651 break;
652 default:
653 log.warn("Driver does not handle this type of TrafficTreatment"
654 + " instruction in nextObjectives: {} - {}",
655 ins.type(), ins);
656 break;
657 }
658 } else if (ins.type() == Instruction.Type.OUTPUT) {
659 break;
660 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
661 // We support partially the l3 instructions.
662 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
663 switch (l3ins.subtype()) {
664 case TTL_IN:
665 mplsTreatment.add(ins);
666 break;
667 default:
668 log.warn("Driver does not handle this type of TrafficTreatment"
669 + " instruction in nextObjectives: {} - {}",
670 ins.type(), ins);
671 }
672
673 } else {
674 log.warn("Driver does not handle this type of TrafficTreatment"
675 + " instruction in nextObjectives: {} - {}",
676 ins.type(), ins);
677 }
678 }
679 }
Charles Chanf9e98652016-09-07 16:54:23 -0700680}