blob: dee4fff6e7a2bc4ad0642722e108a6ae9f27f5f0 [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;
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
Saurav Das95047002018-01-25 09:49:01 -080091 protected boolean shouldRetry() {
92 return false;
93 }
94
95 @Override
Pier Ventre42287df2016-11-09 14:17:26 -080096 protected void processFilter(FilteringObjective filteringObjective,
97 boolean install,
98 ApplicationId applicationId) {
99 // We are looking for inner vlan id criterion. We use this
100 // to identify the pseudo wire flows. In future we can enforce
101 // using also the tunnel id in the meta.
102 VlanIdCriterion innerVlanIdCriterion = null;
103 for (Criterion criterion : filteringObjective.conditions()) {
104 if (criterion.type() == INNER_VLAN_VID) {
105 innerVlanIdCriterion = (VlanIdCriterion) criterion;
106 break;
107 }
108 }
109 if (innerVlanIdCriterion != null) {
110 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
111 PortCriterion portCriterion;
112 VlanIdCriterion outerVlanIdCriterion = null;
113 // We extract the expected port criterion in the key.
114 portCriterion = (PortCriterion) filteringObjective.key();
115 // We extract the outer vlan id criterion.
116 for (Criterion criterion : filteringObjective.conditions()) {
117 if (criterion.type() == VLAN_VID) {
118 outerVlanIdCriterion = (VlanIdCriterion) criterion;
119 break;
120 }
121 }
122 // We extract the tunnel id.
123 long tunnelId;
124 if (filteringObjective.meta() != null &&
125 filteringObjective.meta().allInstructions().size() != 1) {
126 log.warn("Bad filtering objective from app: {}. Not"
127 + "processing filtering objective", applicationId);
128 fail(filteringObjective, ObjectiveError.BADPARAMS);
129 return;
130 } else if (filteringObjective.meta() != null &&
131 filteringObjective.meta().allInstructions().size() == 1 &&
132 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION) {
133 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
134 filteringObjective.meta().allInstructions().get(0);
135 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
136 log.warn("Bad filtering objective from app: {}. Not"
137 + "processing filtering objective", applicationId);
138 fail(filteringObjective, ObjectiveError.BADPARAMS);
139 return;
140 } else {
141 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
142 }
143 } else {
144 log.warn("Bad filtering objective from app: {}. Not"
145 + "processing filtering objective", applicationId);
146 fail(filteringObjective, ObjectiveError.BADPARAMS);
147 return;
148 }
149 // Mpls tunnel ids according to the OFDPA manual have to be
150 // in the range [2^17-1, 2^16].
151 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
152 // Sanity check for the filtering objective.
153 if (portCriterion == null ||
154 outerVlanIdCriterion == null ||
155 tunnelId > MPLS_TUNNEL_ID_MAX) {
156 log.warn("Bad filtering objective from app: {}. Not"
157 + "processing filtering objective", applicationId);
158 fail(filteringObjective, ObjectiveError.BADPARAMS);
159 return;
160 }
161 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800162 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530163 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800164 portCriterion.port().toLong());
165 fail(filteringObjective, ObjectiveError.BADPARAMS);
166 return;
167 }
168 // We create the flows.
169 List<FlowRule> pwRules = processPwFilter(portCriterion,
170 innerVlanIdCriterion,
171 outerVlanIdCriterion,
172 tunnelId,
173 applicationId
174 );
175 // We tag the flow for adding or for removing.
176 for (FlowRule pwRule : pwRules) {
177 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
178 pwRule, deviceId);
179 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
180 }
181 // We push the filtering rules for the pw.
182 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
183 @Override
184 public void onSuccess(FlowRuleOperations ops) {
185 log.info("Applied {} filtering rules in device {}",
186 ops.stages().get(0).size(), deviceId);
187 pass(filteringObjective);
188 }
189
190 @Override
191 public void onError(FlowRuleOperations ops) {
192 log.info("Failed to apply all filtering rules in dev {}", deviceId);
193 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
194 }
195 }));
196
197 return;
198 }
199 // If it is not a pseudo wire flow we fall back
200 // to the OFDPA 2.0 pipeline.
201 super.processFilter(filteringObjective, install, applicationId);
202 }
203
204 /**
205 * Method to process the pw related filtering objectives.
206 *
207 * @param portCriterion the in port match
208 * @param innerVlanIdCriterion the inner vlan match
209 * @param outerVlanIdCriterion the outer vlan match
210 * @param tunnelId the tunnel id
211 * @param applicationId the application id
212 * @return a list of flow rules to install
213 */
214 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700215 VlanIdCriterion innerVlanIdCriterion,
216 VlanIdCriterion outerVlanIdCriterion,
217 long tunnelId,
218 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800219 // As first we create the flow rule for the vlan 1 table.
220 FlowRule vlan1FlowRule;
221 int mplsLogicalPort = ((int) portCriterion.port().toLong());
222 // We have to match on the inner vlan and outer vlan at the same time.
223 // Ofdpa supports this through the OVID meta-data type.
224 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
225 .matchInPort(portCriterion.port())
Charles Chand1172632017-03-15 17:33:09 -0700226 .matchVlanId(innerVlanIdCriterion.vlanId())
Pier Ventre42287df2016-11-09 14:17:26 -0800227 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
228 // TODO understand for the future how to manage the vlan rewrite.
229 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
230 .pushVlan()
231 .setVlanId(outerVlanIdCriterion.vlanId())
232 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
233 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
234 .setTunnelId(tunnelId)
235 .transition(MPLS_L2_PORT_FLOW_TABLE);
236 vlan1FlowRule = DefaultFlowRule.builder()
237 .forDevice(deviceId)
238 .withSelector(vlan1Selector.build())
239 .withTreatment(vlan1Treatment.build())
240 .withPriority(DEFAULT_PRIORITY)
241 .fromApp(applicationId)
242 .makePermanent()
243 .forTable(VLAN_1_TABLE)
244 .build();
245 // Finally we create the flow rule for the vlan table.
246 FlowRule vlanFlowRule;
247 // We have to match on the outer vlan.
248 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
249 .matchInPort(portCriterion.port())
Charles Chand1172632017-03-15 17:33:09 -0700250 .matchVlanId(outerVlanIdCriterion.vlanId());
Pier Ventre42287df2016-11-09 14:17:26 -0800251 // TODO understand for the future how to manage the vlan rewrite.
252 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
253 .popVlan()
254 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
255 .transition(VLAN_1_TABLE);
256 vlanFlowRule = DefaultFlowRule.builder()
257 .forDevice(deviceId)
258 .withSelector(vlanSelector.build())
259 .withTreatment(vlanTreatment.build())
260 .withPriority(DEFAULT_PRIORITY)
261 .fromApp(applicationId)
262 .makePermanent()
263 .forTable(VLAN_TABLE)
264 .build();
265
266 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
267 }
268
269 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700270 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Pier Ventre140a8942016-11-02 07:26:38 -0700271 if (isNotMplsBos(fwd.selector())) {
272 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
273 }
274 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700275 }
Pier Ventre42287df2016-11-09 14:17:26 -0800276
277 @Override
278 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
279 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800280 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800281 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
282 .getCriterion(TUNNEL_ID);
283 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800284 return processInitPwVersatile(fwd);
285 }
286 // Looking for the fwd objective of the termination.
287 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
288 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
289 if (modTunnelIdInstruction != null && outputInstruction != null) {
290 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800291 }
292 // If it is not a pseudo wire flow we fall back
293 // to the OFDPA 2.0 pipeline.
294 return super.processVersatile(fwd);
295 }
296
Pier Ventre70d53ba2016-11-17 22:26:29 -0800297 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
298 ModTunnelIdInstruction modTunnelIdInstruction,
299 OutputInstruction outputInstruction) {
300 TrafficTreatment.Builder flowTreatment;
301 TrafficSelector.Builder flowSelector;
302 // We divide the mpls actions from the tunnel actions. We need
303 // this to order the actions in the final treatment.
304 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
305 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
306 // The match of the forwarding objective is ready to go.
307 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
308 // We verify the tunnel id and mpls port are correct.
309 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
310 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
311 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
312 MPLS_TUNNEL_ID_MAX);
313 fail(forwardingObjective, ObjectiveError.BADPARAMS);
314 return Collections.emptySet();
315 }
316 // 0x0002XXXX is NNI interface.
317 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
318 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
319 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
320 mplsLogicalPort);
321 fail(forwardingObjective, ObjectiveError.BADPARAMS);
322 return Collections.emptySet();
323 }
324 // Next id cannot be null.
325 if (forwardingObjective.nextId() == null) {
326 log.error("Pw Versatile Forwarding Objective must contain nextId ",
327 forwardingObjective.nextId());
328 fail(forwardingObjective, ObjectiveError.BADPARAMS);
329 return Collections.emptySet();
330 }
331 // We retrieve the l2 interface group and point the mpls
332 // flow to this.
333 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
334 if (next == null) {
335 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
336 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
337 return Collections.emptySet();
338 }
339 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
340 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
341 if (group == null) {
342 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
343 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
344 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
345 return Collections.emptySet();
346 }
347 // We prepare the treatment for the mpls flow table.
348 // The order of the actions has to be strictly this
349 // according to the OFDPA 2.0 specification.
350 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
351 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800352 // Even though the specification and the xml/json files
353 // specify is allowed, the switch rejects the flow. In the
354 // OFDPA 3.0 EA0 version was necessary
355 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800356 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
357 flowTreatment.setTunnelId(tunnelId);
358 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
359 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
360 flowTreatment.transition(MPLS_TYPE_TABLE);
361 flowTreatment.deferred().group(group.id());
362 // We prepare the flow rule for the mpls table.
363 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
364 .fromApp(forwardingObjective.appId())
365 .withPriority(forwardingObjective.priority())
366 .forDevice(deviceId)
367 .withSelector(flowSelector.build())
368 .withTreatment(flowTreatment.build())
369 .makePermanent()
370 .forTable(MPLS_TABLE_1);
371 return Collections.singletonList(ruleBuilder.build());
372 }
373
Pier Ventre42287df2016-11-09 14:17:26 -0800374 /**
375 * Helper method to process the pw forwarding objectives.
376 *
377 * @param forwardingObjective the fw objective to process
378 * @return a singleton list of flow rule
379 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800380 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800381 // We retrieve the matching criteria for mpls l2 port.
382 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
383 .getCriterion(TUNNEL_ID);
384 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
385 .getCriterion(IN_PORT);
386 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
387 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
388 int mplsLogicalPort;
389 long tunnelId;
390 // Mpls tunnel ids according to the OFDPA manual have to be
391 // in the range [2^17-1, 2^16].
392 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
393 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
394 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
395 MPLS_TUNNEL_ID_MAX);
396 fail(forwardingObjective, ObjectiveError.BADPARAMS);
397 return Collections.emptySet();
398 }
399 // Port has not been null.
400 if (portCriterion == null) {
401 log.error("Pw Versatile Forwarding Objective must include port");
402 fail(forwardingObjective, ObjectiveError.BADPARAMS);
403 return Collections.emptySet();
404 }
405 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800406 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800407 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
408 portCriterion.port().toLong());
409 fail(forwardingObjective, ObjectiveError.BADPARAMS);
410 return Collections.emptySet();
411 }
412 mplsLogicalPort = ((int) portCriterion.port().toLong());
413 if (forwardingObjective.nextId() == null) {
414 log.error("Pw Versatile Forwarding Objective must contain nextId ",
415 forwardingObjective.nextId());
416 fail(forwardingObjective, ObjectiveError.BADPARAMS);
417 return Collections.emptySet();
418 }
419 // We don't expect a treatment.
420 if (forwardingObjective.treatment() != null &&
421 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
422 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
423 forwardingObjective.nextId());
424 fail(forwardingObjective, ObjectiveError.BADPARAMS);
425 return Collections.emptySet();
426 }
427 // We retrieve the l2 vpn group and point the mpls
428 // l2 port to this.
429 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
430 if (next == null) {
431 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
432 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
433 return Collections.emptySet();
434 }
435 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
436 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
437 if (group == null) {
438 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
439 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
440 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
441 return Collections.emptySet();
442 }
443 // We prepare the flow rule for the mpls l2 port table.
444 selector.matchTunnelId(tunnelId);
445 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
446 // This should not be necessary but without we receive an error
447 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
448 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
449 treatment.deferred().group(group.id());
450 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
451 .fromApp(forwardingObjective.appId())
452 .withPriority(MPLS_L2_PORT_PRIORITY)
453 .forDevice(deviceId)
454 .withSelector(selector.build())
455 .withTreatment(treatment.build())
456 .makePermanent()
457 .forTable(MPLS_L2_PORT_FLOW_TABLE);
458 return Collections.singletonList(ruleBuilder.build());
459 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800460
461 /**
462 * Utility function to get the mod tunnel id instruction
463 * if present.
464 *
465 * @param treatment the treatment to analyze
466 * @return the mod tunnel id instruction if present,
467 * otherwise null
468 */
469 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800470 if (treatment == null) {
471 return null;
472 }
473
Pier Ventre70d53ba2016-11-17 22:26:29 -0800474 L2ModificationInstruction l2ModificationInstruction;
475 for (Instruction instruction : treatment.allInstructions()) {
476 if (instruction.type() == L2MODIFICATION) {
477 l2ModificationInstruction = (L2ModificationInstruction) instruction;
478 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
479 return (ModTunnelIdInstruction) l2ModificationInstruction;
480 }
481 }
482 }
483 return null;
484 }
485
486 /**
487 * Utility function to get the output instruction
488 * if present.
489 *
490 * @param treatment the treatment to analyze
491 * @return the output instruction if present,
492 * otherwise null
493 */
494 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800495 if (treatment == null) {
496 return null;
497 }
498
Pier Ventre70d53ba2016-11-17 22:26:29 -0800499 for (Instruction instruction : treatment.allInstructions()) {
500 if (instruction.type() == Instruction.Type.OUTPUT) {
501 return (OutputInstruction) instruction;
502 }
503 }
504 return null;
505 }
506
507 /**
508 * Helper method for dividing the tunnel instructions from the mpls
509 * instructions.
510 *
511 * @param treatment the treatment to analyze
512 * @param mplsTreatment the mpls treatment builder
513 */
514 private void createMplsTreatment(TrafficTreatment treatment,
515 TrafficTreatment.Builder mplsTreatment) {
516
517 for (Instruction ins : treatment.allInstructions()) {
518
519 if (ins.type() == Instruction.Type.L2MODIFICATION) {
520 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
521 switch (l2ins.subtype()) {
522 // These instructions have to go in the mpls
523 // treatment.
524 case TUNNEL_ID:
525 break;
526 case DEC_MPLS_TTL:
527 case MPLS_POP:
528 mplsTreatment.add(ins);
529 break;
530 default:
531 log.warn("Driver does not handle this type of TrafficTreatment"
532 + " instruction in nextObjectives: {} - {}",
533 ins.type(), ins);
534 break;
535 }
536 } else if (ins.type() == Instruction.Type.OUTPUT) {
537 break;
538 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
539 // We support partially the l3 instructions.
540 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
541 switch (l3ins.subtype()) {
542 case TTL_IN:
543 mplsTreatment.add(ins);
544 break;
545 default:
546 log.warn("Driver does not handle this type of TrafficTreatment"
547 + " instruction in nextObjectives: {} - {}",
548 ins.type(), ins);
549 }
550
551 } else {
552 log.warn("Driver does not handle this type of TrafficTreatment"
553 + " instruction in nextObjectives: {} - {}",
554 ins.type(), ins);
555 }
556 }
557 }
Charles Chanf9e98652016-09-07 16:54:23 -0700558}