blob: 4ce533c8ccc8398ccb64b64e3e2b3aa0534c1c09 [file] [log] [blame]
Charles Chanf9e98652016-09-07 16:54:23 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
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;
Charles Chanf9e98652016-09-07 16:54:23 -070020import org.onosproject.core.ApplicationId;
Pier Ventre42287df2016-11-09 14:17:26 -080021import org.onosproject.driver.extensions.Ofdpa3MatchMplsL2Port;
22import org.onosproject.driver.extensions.Ofdpa3MatchOvid;
Pier Ventre70d53ba2016-11-17 22:26:29 -080023import org.onosproject.driver.extensions.Ofdpa3PopCw;
24import org.onosproject.driver.extensions.Ofdpa3PopL2Header;
Pier Ventre42287df2016-11-09 14:17:26 -080025import org.onosproject.driver.extensions.Ofdpa3SetMplsL2Port;
26import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
27import org.onosproject.driver.extensions.Ofdpa3SetOvid;
28import org.onosproject.driver.extensions.Ofdpa3SetQosIndex;
Pier Ventre42287df2016-11-09 14:17:26 -080029import org.onosproject.net.behaviour.NextGroup;
Charles Chanf9e98652016-09-07 16:54:23 -070030import org.onosproject.net.behaviour.PipelinerContext;
Pier Ventre42287df2016-11-09 14:17:26 -080031import org.onosproject.net.flow.DefaultFlowRule;
32import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070034import org.onosproject.net.flow.FlowRule;
Pier Ventre42287df2016-11-09 14:17:26 -080035import org.onosproject.net.flow.FlowRuleOperations;
36import org.onosproject.net.flow.FlowRuleOperationsContext;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.flow.criteria.Criterion;
Charles Chanf9e98652016-09-07 16:54:23 -070040import org.onosproject.net.flow.criteria.PortCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080041import org.onosproject.net.flow.criteria.TunnelIdCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070042import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre70d53ba2016-11-17 22:26:29 -080043import org.onosproject.net.flow.instructions.Instruction;
44import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080045import org.onosproject.net.flow.instructions.L2ModificationInstruction;
46import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Pier Ventre70d53ba2016-11-17 22:26:29 -080047import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080048import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chanf9e98652016-09-07 16:54:23 -070049import org.onosproject.net.flowobjective.ForwardingObjective;
Pier Ventre42287df2016-11-09 14:17:26 -080050import org.onosproject.net.flowobjective.ObjectiveError;
51import org.onosproject.net.group.Group;
52import org.onosproject.net.group.GroupKey;
53import org.slf4j.Logger;
Charles Chanf9e98652016-09-07 16:54:23 -070054
55import java.util.Collection;
Pier Ventre42287df2016-11-09 14:17:26 -080056import java.util.Collections;
57import java.util.Deque;
Charles Chanf9e98652016-09-07 16:54:23 -070058import java.util.List;
59
Pier Ventre42287df2016-11-09 14:17:26 -080060import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
61import static org.onosproject.net.flow.criteria.Criterion.Type.*;
62import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
63import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
64import static org.slf4j.LoggerFactory.getLogger;
65
Charles Chanf9e98652016-09-07 16:54:23 -070066/**
67 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
68 */
69public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080070
71 private final Logger log = getLogger(getClass());
72
Charles Chanf9e98652016-09-07 16:54:23 -070073 @Override
Charles Chan40132b32017-01-22 00:19:37 -080074 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070075 driverId = coreService.registerApplication(
76 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080077 }
Charles Chanf9e98652016-09-07 16:54:23 -070078
Charles Chan40132b32017-01-22 00:19:37 -080079 @Override
80 protected void initGroupHander(PipelinerContext context) {
81 groupHandler = new Ofdpa3GroupHandler();
82 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070083 }
84
85 @Override
Charles Chand1172632017-03-15 17:33:09 -070086 protected boolean requireVlanExtensions() {
87 return false;
88 }
89
90 @Override
Pier Ventre42287df2016-11-09 14:17:26 -080091 protected void processFilter(FilteringObjective filteringObjective,
92 boolean install,
93 ApplicationId applicationId) {
94 // We are looking for inner vlan id criterion. We use this
95 // to identify the pseudo wire flows. In future we can enforce
96 // using also the tunnel id in the meta.
97 VlanIdCriterion innerVlanIdCriterion = null;
98 for (Criterion criterion : filteringObjective.conditions()) {
99 if (criterion.type() == INNER_VLAN_VID) {
100 innerVlanIdCriterion = (VlanIdCriterion) criterion;
101 break;
102 }
103 }
104 if (innerVlanIdCriterion != null) {
105 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
106 PortCriterion portCriterion;
107 VlanIdCriterion outerVlanIdCriterion = null;
108 // We extract the expected port criterion in the key.
109 portCriterion = (PortCriterion) filteringObjective.key();
110 // We extract the outer vlan id criterion.
111 for (Criterion criterion : filteringObjective.conditions()) {
112 if (criterion.type() == VLAN_VID) {
113 outerVlanIdCriterion = (VlanIdCriterion) criterion;
114 break;
115 }
116 }
117 // We extract the tunnel id.
118 long tunnelId;
119 if (filteringObjective.meta() != null &&
120 filteringObjective.meta().allInstructions().size() != 1) {
121 log.warn("Bad filtering objective from app: {}. Not"
122 + "processing filtering objective", applicationId);
123 fail(filteringObjective, ObjectiveError.BADPARAMS);
124 return;
125 } else if (filteringObjective.meta() != null &&
126 filteringObjective.meta().allInstructions().size() == 1 &&
127 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION) {
128 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
129 filteringObjective.meta().allInstructions().get(0);
130 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
131 log.warn("Bad filtering objective from app: {}. Not"
132 + "processing filtering objective", applicationId);
133 fail(filteringObjective, ObjectiveError.BADPARAMS);
134 return;
135 } else {
136 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
137 }
138 } else {
139 log.warn("Bad filtering objective from app: {}. Not"
140 + "processing filtering objective", applicationId);
141 fail(filteringObjective, ObjectiveError.BADPARAMS);
142 return;
143 }
144 // Mpls tunnel ids according to the OFDPA manual have to be
145 // in the range [2^17-1, 2^16].
146 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
147 // Sanity check for the filtering objective.
148 if (portCriterion == null ||
149 outerVlanIdCriterion == null ||
150 tunnelId > MPLS_TUNNEL_ID_MAX) {
151 log.warn("Bad filtering objective from app: {}. Not"
152 + "processing filtering objective", applicationId);
153 fail(filteringObjective, ObjectiveError.BADPARAMS);
154 return;
155 }
156 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800157 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800158 log.error("Filering Objective invalid logical port {}",
159 portCriterion.port().toLong());
160 fail(filteringObjective, ObjectiveError.BADPARAMS);
161 return;
162 }
163 // We create the flows.
164 List<FlowRule> pwRules = processPwFilter(portCriterion,
165 innerVlanIdCriterion,
166 outerVlanIdCriterion,
167 tunnelId,
168 applicationId
169 );
170 // We tag the flow for adding or for removing.
171 for (FlowRule pwRule : pwRules) {
172 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
173 pwRule, deviceId);
174 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
175 }
176 // We push the filtering rules for the pw.
177 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
178 @Override
179 public void onSuccess(FlowRuleOperations ops) {
180 log.info("Applied {} filtering rules in device {}",
181 ops.stages().get(0).size(), deviceId);
182 pass(filteringObjective);
183 }
184
185 @Override
186 public void onError(FlowRuleOperations ops) {
187 log.info("Failed to apply all filtering rules in dev {}", deviceId);
188 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
189 }
190 }));
191
192 return;
193 }
194 // If it is not a pseudo wire flow we fall back
195 // to the OFDPA 2.0 pipeline.
196 super.processFilter(filteringObjective, install, applicationId);
197 }
198
199 /**
200 * Method to process the pw related filtering objectives.
201 *
202 * @param portCriterion the in port match
203 * @param innerVlanIdCriterion the inner vlan match
204 * @param outerVlanIdCriterion the outer vlan match
205 * @param tunnelId the tunnel id
206 * @param applicationId the application id
207 * @return a list of flow rules to install
208 */
209 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700210 VlanIdCriterion innerVlanIdCriterion,
211 VlanIdCriterion outerVlanIdCriterion,
212 long tunnelId,
213 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800214 // As first we create the flow rule for the vlan 1 table.
215 FlowRule vlan1FlowRule;
216 int mplsLogicalPort = ((int) portCriterion.port().toLong());
217 // We have to match on the inner vlan and outer vlan at the same time.
218 // Ofdpa supports this through the OVID meta-data type.
219 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
220 .matchInPort(portCriterion.port())
Charles Chand1172632017-03-15 17:33:09 -0700221 .matchVlanId(innerVlanIdCriterion.vlanId())
Pier Ventre42287df2016-11-09 14:17:26 -0800222 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
223 // TODO understand for the future how to manage the vlan rewrite.
224 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
225 .pushVlan()
226 .setVlanId(outerVlanIdCriterion.vlanId())
227 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
228 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
229 .setTunnelId(tunnelId)
230 .transition(MPLS_L2_PORT_FLOW_TABLE);
231 vlan1FlowRule = DefaultFlowRule.builder()
232 .forDevice(deviceId)
233 .withSelector(vlan1Selector.build())
234 .withTreatment(vlan1Treatment.build())
235 .withPriority(DEFAULT_PRIORITY)
236 .fromApp(applicationId)
237 .makePermanent()
238 .forTable(VLAN_1_TABLE)
239 .build();
240 // Finally we create the flow rule for the vlan table.
241 FlowRule vlanFlowRule;
242 // We have to match on the outer vlan.
243 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
244 .matchInPort(portCriterion.port())
Charles Chand1172632017-03-15 17:33:09 -0700245 .matchVlanId(outerVlanIdCriterion.vlanId());
Pier Ventre42287df2016-11-09 14:17:26 -0800246 // TODO understand for the future how to manage the vlan rewrite.
247 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
248 .popVlan()
249 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
250 .transition(VLAN_1_TABLE);
251 vlanFlowRule = DefaultFlowRule.builder()
252 .forDevice(deviceId)
253 .withSelector(vlanSelector.build())
254 .withTreatment(vlanTreatment.build())
255 .withPriority(DEFAULT_PRIORITY)
256 .fromApp(applicationId)
257 .makePermanent()
258 .forTable(VLAN_TABLE)
259 .build();
260
261 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
262 }
263
264 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700265 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Pier Ventre140a8942016-11-02 07:26:38 -0700266 if (isNotMplsBos(fwd.selector())) {
267 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
268 }
269 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700270 }
Pier Ventre42287df2016-11-09 14:17:26 -0800271
272 @Override
273 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
274 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800275 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800276 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
277 .getCriterion(TUNNEL_ID);
278 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800279 return processInitPwVersatile(fwd);
280 }
281 // Looking for the fwd objective of the termination.
282 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
283 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
284 if (modTunnelIdInstruction != null && outputInstruction != null) {
285 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800286 }
287 // If it is not a pseudo wire flow we fall back
288 // to the OFDPA 2.0 pipeline.
289 return super.processVersatile(fwd);
290 }
291
Pier Ventre70d53ba2016-11-17 22:26:29 -0800292 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
293 ModTunnelIdInstruction modTunnelIdInstruction,
294 OutputInstruction outputInstruction) {
295 TrafficTreatment.Builder flowTreatment;
296 TrafficSelector.Builder flowSelector;
297 // We divide the mpls actions from the tunnel actions. We need
298 // this to order the actions in the final treatment.
299 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
300 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
301 // The match of the forwarding objective is ready to go.
302 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
303 // We verify the tunnel id and mpls port are correct.
304 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
305 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
306 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
307 MPLS_TUNNEL_ID_MAX);
308 fail(forwardingObjective, ObjectiveError.BADPARAMS);
309 return Collections.emptySet();
310 }
311 // 0x0002XXXX is NNI interface.
312 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
313 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
314 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
315 mplsLogicalPort);
316 fail(forwardingObjective, ObjectiveError.BADPARAMS);
317 return Collections.emptySet();
318 }
319 // Next id cannot be null.
320 if (forwardingObjective.nextId() == null) {
321 log.error("Pw Versatile Forwarding Objective must contain nextId ",
322 forwardingObjective.nextId());
323 fail(forwardingObjective, ObjectiveError.BADPARAMS);
324 return Collections.emptySet();
325 }
326 // We retrieve the l2 interface group and point the mpls
327 // flow to this.
328 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
329 if (next == null) {
330 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
331 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
332 return Collections.emptySet();
333 }
334 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
335 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
336 if (group == null) {
337 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
338 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
339 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
340 return Collections.emptySet();
341 }
342 // We prepare the treatment for the mpls flow table.
343 // The order of the actions has to be strictly this
344 // according to the OFDPA 2.0 specification.
345 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
346 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800347 // Even though the specification and the xml/json files
348 // specify is allowed, the switch rejects the flow. In the
349 // OFDPA 3.0 EA0 version was necessary
350 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800351 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
352 flowTreatment.setTunnelId(tunnelId);
353 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
354 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
355 flowTreatment.transition(MPLS_TYPE_TABLE);
356 flowTreatment.deferred().group(group.id());
357 // We prepare the flow rule for the mpls table.
358 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
359 .fromApp(forwardingObjective.appId())
360 .withPriority(forwardingObjective.priority())
361 .forDevice(deviceId)
362 .withSelector(flowSelector.build())
363 .withTreatment(flowTreatment.build())
364 .makePermanent()
365 .forTable(MPLS_TABLE_1);
366 return Collections.singletonList(ruleBuilder.build());
367 }
368
Pier Ventre42287df2016-11-09 14:17:26 -0800369 /**
370 * Helper method to process the pw forwarding objectives.
371 *
372 * @param forwardingObjective the fw objective to process
373 * @return a singleton list of flow rule
374 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800375 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800376 // We retrieve the matching criteria for mpls l2 port.
377 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
378 .getCriterion(TUNNEL_ID);
379 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
380 .getCriterion(IN_PORT);
381 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
382 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
383 int mplsLogicalPort;
384 long tunnelId;
385 // Mpls tunnel ids according to the OFDPA manual have to be
386 // in the range [2^17-1, 2^16].
387 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
388 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
389 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
390 MPLS_TUNNEL_ID_MAX);
391 fail(forwardingObjective, ObjectiveError.BADPARAMS);
392 return Collections.emptySet();
393 }
394 // Port has not been null.
395 if (portCriterion == null) {
396 log.error("Pw Versatile Forwarding Objective must include port");
397 fail(forwardingObjective, ObjectiveError.BADPARAMS);
398 return Collections.emptySet();
399 }
400 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800401 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800402 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
403 portCriterion.port().toLong());
404 fail(forwardingObjective, ObjectiveError.BADPARAMS);
405 return Collections.emptySet();
406 }
407 mplsLogicalPort = ((int) portCriterion.port().toLong());
408 if (forwardingObjective.nextId() == null) {
409 log.error("Pw Versatile Forwarding Objective must contain nextId ",
410 forwardingObjective.nextId());
411 fail(forwardingObjective, ObjectiveError.BADPARAMS);
412 return Collections.emptySet();
413 }
414 // We don't expect a treatment.
415 if (forwardingObjective.treatment() != null &&
416 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
417 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
418 forwardingObjective.nextId());
419 fail(forwardingObjective, ObjectiveError.BADPARAMS);
420 return Collections.emptySet();
421 }
422 // We retrieve the l2 vpn group and point the mpls
423 // l2 port to this.
424 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
425 if (next == null) {
426 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
427 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
428 return Collections.emptySet();
429 }
430 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
431 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
432 if (group == null) {
433 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
434 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
435 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
436 return Collections.emptySet();
437 }
438 // We prepare the flow rule for the mpls l2 port table.
439 selector.matchTunnelId(tunnelId);
440 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
441 // This should not be necessary but without we receive an error
442 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
443 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
444 treatment.deferred().group(group.id());
445 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
446 .fromApp(forwardingObjective.appId())
447 .withPriority(MPLS_L2_PORT_PRIORITY)
448 .forDevice(deviceId)
449 .withSelector(selector.build())
450 .withTreatment(treatment.build())
451 .makePermanent()
452 .forTable(MPLS_L2_PORT_FLOW_TABLE);
453 return Collections.singletonList(ruleBuilder.build());
454 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800455
456 /**
457 * Utility function to get the mod tunnel id instruction
458 * if present.
459 *
460 * @param treatment the treatment to analyze
461 * @return the mod tunnel id instruction if present,
462 * otherwise null
463 */
464 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800465 if (treatment == null) {
466 return null;
467 }
468
Pier Ventre70d53ba2016-11-17 22:26:29 -0800469 L2ModificationInstruction l2ModificationInstruction;
470 for (Instruction instruction : treatment.allInstructions()) {
471 if (instruction.type() == L2MODIFICATION) {
472 l2ModificationInstruction = (L2ModificationInstruction) instruction;
473 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
474 return (ModTunnelIdInstruction) l2ModificationInstruction;
475 }
476 }
477 }
478 return null;
479 }
480
481 /**
482 * Utility function to get the output instruction
483 * if present.
484 *
485 * @param treatment the treatment to analyze
486 * @return the output instruction if present,
487 * otherwise null
488 */
489 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800490 if (treatment == null) {
491 return null;
492 }
493
Pier Ventre70d53ba2016-11-17 22:26:29 -0800494 for (Instruction instruction : treatment.allInstructions()) {
495 if (instruction.type() == Instruction.Type.OUTPUT) {
496 return (OutputInstruction) instruction;
497 }
498 }
499 return null;
500 }
501
502 /**
503 * Helper method for dividing the tunnel instructions from the mpls
504 * instructions.
505 *
506 * @param treatment the treatment to analyze
507 * @param mplsTreatment the mpls treatment builder
508 */
509 private void createMplsTreatment(TrafficTreatment treatment,
510 TrafficTreatment.Builder mplsTreatment) {
511
512 for (Instruction ins : treatment.allInstructions()) {
513
514 if (ins.type() == Instruction.Type.L2MODIFICATION) {
515 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
516 switch (l2ins.subtype()) {
517 // These instructions have to go in the mpls
518 // treatment.
519 case TUNNEL_ID:
520 break;
521 case DEC_MPLS_TTL:
522 case MPLS_POP:
523 mplsTreatment.add(ins);
524 break;
525 default:
526 log.warn("Driver does not handle this type of TrafficTreatment"
527 + " instruction in nextObjectives: {} - {}",
528 ins.type(), ins);
529 break;
530 }
531 } else if (ins.type() == Instruction.Type.OUTPUT) {
532 break;
533 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
534 // We support partially the l3 instructions.
535 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
536 switch (l3ins.subtype()) {
537 case TTL_IN:
538 mplsTreatment.add(ins);
539 break;
540 default:
541 log.warn("Driver does not handle this type of TrafficTreatment"
542 + " instruction in nextObjectives: {} - {}",
543 ins.type(), ins);
544 }
545
546 } else {
547 log.warn("Driver does not handle this type of TrafficTreatment"
548 + " instruction in nextObjectives: {} - {}",
549 ins.type(), ins);
550 }
551 }
552 }
Charles Chanf9e98652016-09-07 16:54:23 -0700553}