blob: 1cce7140434e865af0a7365fb28e6c2928209d2a [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
17package org.onosproject.driver.pipeline;
18
Pier Ventre42287df2016-11-09 14:17:26 -080019import com.google.common.collect.ImmutableList;
Charles Chanf9e98652016-09-07 16:54:23 -070020import org.onlab.packet.VlanId;
21import 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;
30import org.onosproject.driver.extensions.OfdpaMatchVlanVid;
31import org.onosproject.net.behaviour.NextGroup;
Charles Chanf9e98652016-09-07 16:54:23 -070032import org.onosproject.net.behaviour.PipelinerContext;
Pier Ventre42287df2016-11-09 14:17:26 -080033import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070036import org.onosproject.net.flow.FlowRule;
Pier Ventre42287df2016-11-09 14:17:26 -080037import org.onosproject.net.flow.FlowRuleOperations;
38import org.onosproject.net.flow.FlowRuleOperationsContext;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.flow.criteria.Criterion;
Charles Chanf9e98652016-09-07 16:54:23 -070042import org.onosproject.net.flow.criteria.PortCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080043import org.onosproject.net.flow.criteria.TunnelIdCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070044import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre70d53ba2016-11-17 22:26:29 -080045import org.onosproject.net.flow.instructions.Instruction;
46import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080047import org.onosproject.net.flow.instructions.L2ModificationInstruction;
48import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Pier Ventre70d53ba2016-11-17 22:26:29 -080049import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080050import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chanf9e98652016-09-07 16:54:23 -070051import org.onosproject.net.flowobjective.ForwardingObjective;
Pier Ventre42287df2016-11-09 14:17:26 -080052import org.onosproject.net.flowobjective.ObjectiveError;
53import org.onosproject.net.group.Group;
54import org.onosproject.net.group.GroupKey;
55import org.slf4j.Logger;
Charles Chanf9e98652016-09-07 16:54:23 -070056
57import java.util.Collection;
Pier Ventre42287df2016-11-09 14:17:26 -080058import java.util.Collections;
59import java.util.Deque;
Charles Chanf9e98652016-09-07 16:54:23 -070060import java.util.List;
61
Pier Ventre42287df2016-11-09 14:17:26 -080062import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
63import static org.onosproject.net.flow.criteria.Criterion.Type.*;
64import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
65import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
66import static org.slf4j.LoggerFactory.getLogger;
67
Charles Chanf9e98652016-09-07 16:54:23 -070068/**
69 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
70 */
71public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080072
73 private final Logger log = getLogger(getClass());
74
Charles Chanf9e98652016-09-07 16:54:23 -070075 @Override
Charles Chan40132b32017-01-22 00:19:37 -080076 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070077 driverId = coreService.registerApplication(
78 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080079 }
Charles Chanf9e98652016-09-07 16:54:23 -070080
Charles Chan40132b32017-01-22 00:19:37 -080081 @Override
82 protected void initGroupHander(PipelinerContext context) {
83 groupHandler = new Ofdpa3GroupHandler();
84 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070085 }
86
87 @Override
Pier Ventre42287df2016-11-09 14:17:26 -080088 protected void processFilter(FilteringObjective filteringObjective,
89 boolean install,
90 ApplicationId applicationId) {
91 // We are looking for inner vlan id criterion. We use this
92 // to identify the pseudo wire flows. In future we can enforce
93 // using also the tunnel id in the meta.
94 VlanIdCriterion innerVlanIdCriterion = null;
95 for (Criterion criterion : filteringObjective.conditions()) {
96 if (criterion.type() == INNER_VLAN_VID) {
97 innerVlanIdCriterion = (VlanIdCriterion) criterion;
98 break;
99 }
100 }
101 if (innerVlanIdCriterion != null) {
102 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
103 PortCriterion portCriterion;
104 VlanIdCriterion outerVlanIdCriterion = null;
105 // We extract the expected port criterion in the key.
106 portCriterion = (PortCriterion) filteringObjective.key();
107 // We extract the outer vlan id criterion.
108 for (Criterion criterion : filteringObjective.conditions()) {
109 if (criterion.type() == VLAN_VID) {
110 outerVlanIdCriterion = (VlanIdCriterion) criterion;
111 break;
112 }
113 }
114 // We extract the tunnel id.
115 long tunnelId;
116 if (filteringObjective.meta() != null &&
117 filteringObjective.meta().allInstructions().size() != 1) {
118 log.warn("Bad filtering objective from app: {}. Not"
119 + "processing filtering objective", applicationId);
120 fail(filteringObjective, ObjectiveError.BADPARAMS);
121 return;
122 } else if (filteringObjective.meta() != null &&
123 filteringObjective.meta().allInstructions().size() == 1 &&
124 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION) {
125 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
126 filteringObjective.meta().allInstructions().get(0);
127 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
128 log.warn("Bad filtering objective from app: {}. Not"
129 + "processing filtering objective", applicationId);
130 fail(filteringObjective, ObjectiveError.BADPARAMS);
131 return;
132 } else {
133 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
134 }
135 } else {
136 log.warn("Bad filtering objective from app: {}. Not"
137 + "processing filtering objective", applicationId);
138 fail(filteringObjective, ObjectiveError.BADPARAMS);
139 return;
140 }
141 // Mpls tunnel ids according to the OFDPA manual have to be
142 // in the range [2^17-1, 2^16].
143 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
144 // Sanity check for the filtering objective.
145 if (portCriterion == null ||
146 outerVlanIdCriterion == null ||
147 tunnelId > MPLS_TUNNEL_ID_MAX) {
148 log.warn("Bad filtering objective from app: {}. Not"
149 + "processing filtering objective", applicationId);
150 fail(filteringObjective, ObjectiveError.BADPARAMS);
151 return;
152 }
153 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800154 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800155 log.error("Filering Objective invalid logical port {}",
156 portCriterion.port().toLong());
157 fail(filteringObjective, ObjectiveError.BADPARAMS);
158 return;
159 }
160 // We create the flows.
161 List<FlowRule> pwRules = processPwFilter(portCriterion,
162 innerVlanIdCriterion,
163 outerVlanIdCriterion,
164 tunnelId,
165 applicationId
166 );
167 // We tag the flow for adding or for removing.
168 for (FlowRule pwRule : pwRules) {
169 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
170 pwRule, deviceId);
171 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
172 }
173 // We push the filtering rules for the pw.
174 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
175 @Override
176 public void onSuccess(FlowRuleOperations ops) {
177 log.info("Applied {} filtering rules in device {}",
178 ops.stages().get(0).size(), deviceId);
179 pass(filteringObjective);
180 }
181
182 @Override
183 public void onError(FlowRuleOperations ops) {
184 log.info("Failed to apply all filtering rules in dev {}", deviceId);
185 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
186 }
187 }));
188
189 return;
190 }
191 // If it is not a pseudo wire flow we fall back
192 // to the OFDPA 2.0 pipeline.
193 super.processFilter(filteringObjective, install, applicationId);
194 }
195
196 /**
197 * Method to process the pw related filtering objectives.
198 *
199 * @param portCriterion the in port match
200 * @param innerVlanIdCriterion the inner vlan match
201 * @param outerVlanIdCriterion the outer vlan match
202 * @param tunnelId the tunnel id
203 * @param applicationId the application id
204 * @return a list of flow rules to install
205 */
206 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
207 VlanIdCriterion innerVlanIdCriterion,
208 VlanIdCriterion outerVlanIdCriterion,
209 long tunnelId,
210 ApplicationId applicationId) {
211 // As first we create the flow rule for the vlan 1 table.
212 FlowRule vlan1FlowRule;
213 int mplsLogicalPort = ((int) portCriterion.port().toLong());
214 // We have to match on the inner vlan and outer vlan at the same time.
215 // Ofdpa supports this through the OVID meta-data type.
216 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
217 .matchInPort(portCriterion.port())
218 .extension(new OfdpaMatchVlanVid(innerVlanIdCriterion.vlanId()), deviceId)
219 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
220 // TODO understand for the future how to manage the vlan rewrite.
221 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
222 .pushVlan()
223 .setVlanId(outerVlanIdCriterion.vlanId())
224 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
225 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
226 .setTunnelId(tunnelId)
227 .transition(MPLS_L2_PORT_FLOW_TABLE);
228 vlan1FlowRule = DefaultFlowRule.builder()
229 .forDevice(deviceId)
230 .withSelector(vlan1Selector.build())
231 .withTreatment(vlan1Treatment.build())
232 .withPriority(DEFAULT_PRIORITY)
233 .fromApp(applicationId)
234 .makePermanent()
235 .forTable(VLAN_1_TABLE)
236 .build();
237 // Finally we create the flow rule for the vlan table.
238 FlowRule vlanFlowRule;
239 // We have to match on the outer vlan.
240 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
241 .matchInPort(portCriterion.port())
242 .extension(new OfdpaMatchVlanVid(outerVlanIdCriterion.vlanId()), deviceId);
243 // TODO understand for the future how to manage the vlan rewrite.
244 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
245 .popVlan()
246 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
247 .transition(VLAN_1_TABLE);
248 vlanFlowRule = DefaultFlowRule.builder()
249 .forDevice(deviceId)
250 .withSelector(vlanSelector.build())
251 .withTreatment(vlanTreatment.build())
252 .withPriority(DEFAULT_PRIORITY)
253 .fromApp(applicationId)
254 .makePermanent()
255 .forTable(VLAN_TABLE)
256 .build();
257
258 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
259 }
260
261 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700262 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
263 VlanIdCriterion vidCriterion,
264 VlanId assignedVlan,
265 ApplicationId applicationId) {
266 return processVlanIdFilterInternal(portCriterion, vidCriterion, assignedVlan,
267 applicationId, false);
268 }
269
270 @Override
271 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Pier Ventre140a8942016-11-02 07:26:38 -0700272 if (isNotMplsBos(fwd.selector())) {
273 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
274 }
275 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700276 }
Pier Ventre42287df2016-11-09 14:17:26 -0800277
278 @Override
279 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
280 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800281 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800282 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
283 .getCriterion(TUNNEL_ID);
284 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800285 return processInitPwVersatile(fwd);
286 }
287 // Looking for the fwd objective of the termination.
288 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
289 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
290 if (modTunnelIdInstruction != null && outputInstruction != null) {
291 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800292 }
293 // If it is not a pseudo wire flow we fall back
294 // to the OFDPA 2.0 pipeline.
295 return super.processVersatile(fwd);
296 }
297
Pier Ventre70d53ba2016-11-17 22:26:29 -0800298 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
299 ModTunnelIdInstruction modTunnelIdInstruction,
300 OutputInstruction outputInstruction) {
301 TrafficTreatment.Builder flowTreatment;
302 TrafficSelector.Builder flowSelector;
303 // We divide the mpls actions from the tunnel actions. We need
304 // this to order the actions in the final treatment.
305 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
306 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
307 // The match of the forwarding objective is ready to go.
308 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
309 // We verify the tunnel id and mpls port are correct.
310 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
311 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
312 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
313 MPLS_TUNNEL_ID_MAX);
314 fail(forwardingObjective, ObjectiveError.BADPARAMS);
315 return Collections.emptySet();
316 }
317 // 0x0002XXXX is NNI interface.
318 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
319 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
320 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
321 mplsLogicalPort);
322 fail(forwardingObjective, ObjectiveError.BADPARAMS);
323 return Collections.emptySet();
324 }
325 // Next id cannot be null.
326 if (forwardingObjective.nextId() == null) {
327 log.error("Pw Versatile Forwarding Objective must contain nextId ",
328 forwardingObjective.nextId());
329 fail(forwardingObjective, ObjectiveError.BADPARAMS);
330 return Collections.emptySet();
331 }
332 // We retrieve the l2 interface group and point the mpls
333 // flow to this.
334 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
335 if (next == null) {
336 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
337 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
338 return Collections.emptySet();
339 }
340 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
341 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
342 if (group == null) {
343 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
344 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
345 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
346 return Collections.emptySet();
347 }
348 // We prepare the treatment for the mpls flow table.
349 // The order of the actions has to be strictly this
350 // according to the OFDPA 2.0 specification.
351 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
352 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800353 // Even though the specification and the xml/json files
354 // specify is allowed, the switch rejects the flow. In the
355 // OFDPA 3.0 EA0 version was necessary
356 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800357 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
358 flowTreatment.setTunnelId(tunnelId);
359 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
360 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
361 flowTreatment.transition(MPLS_TYPE_TABLE);
362 flowTreatment.deferred().group(group.id());
363 // We prepare the flow rule for the mpls table.
364 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
365 .fromApp(forwardingObjective.appId())
366 .withPriority(forwardingObjective.priority())
367 .forDevice(deviceId)
368 .withSelector(flowSelector.build())
369 .withTreatment(flowTreatment.build())
370 .makePermanent()
371 .forTable(MPLS_TABLE_1);
372 return Collections.singletonList(ruleBuilder.build());
373 }
374
Pier Ventre42287df2016-11-09 14:17:26 -0800375 /**
376 * Helper method to process the pw forwarding objectives.
377 *
378 * @param forwardingObjective the fw objective to process
379 * @return a singleton list of flow rule
380 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800381 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800382 // We retrieve the matching criteria for mpls l2 port.
383 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
384 .getCriterion(TUNNEL_ID);
385 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
386 .getCriterion(IN_PORT);
387 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
388 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
389 int mplsLogicalPort;
390 long tunnelId;
391 // Mpls tunnel ids according to the OFDPA manual have to be
392 // in the range [2^17-1, 2^16].
393 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
394 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
395 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
396 MPLS_TUNNEL_ID_MAX);
397 fail(forwardingObjective, ObjectiveError.BADPARAMS);
398 return Collections.emptySet();
399 }
400 // Port has not been null.
401 if (portCriterion == null) {
402 log.error("Pw Versatile Forwarding Objective must include port");
403 fail(forwardingObjective, ObjectiveError.BADPARAMS);
404 return Collections.emptySet();
405 }
406 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800407 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800408 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
409 portCriterion.port().toLong());
410 fail(forwardingObjective, ObjectiveError.BADPARAMS);
411 return Collections.emptySet();
412 }
413 mplsLogicalPort = ((int) portCriterion.port().toLong());
414 if (forwardingObjective.nextId() == null) {
415 log.error("Pw Versatile Forwarding Objective must contain nextId ",
416 forwardingObjective.nextId());
417 fail(forwardingObjective, ObjectiveError.BADPARAMS);
418 return Collections.emptySet();
419 }
420 // We don't expect a treatment.
421 if (forwardingObjective.treatment() != null &&
422 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
423 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
424 forwardingObjective.nextId());
425 fail(forwardingObjective, ObjectiveError.BADPARAMS);
426 return Collections.emptySet();
427 }
428 // We retrieve the l2 vpn group and point the mpls
429 // l2 port to this.
430 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
431 if (next == null) {
432 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
433 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
434 return Collections.emptySet();
435 }
436 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
437 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
438 if (group == null) {
439 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
440 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
441 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
442 return Collections.emptySet();
443 }
444 // We prepare the flow rule for the mpls l2 port table.
445 selector.matchTunnelId(tunnelId);
446 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
447 // This should not be necessary but without we receive an error
448 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
449 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
450 treatment.deferred().group(group.id());
451 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
452 .fromApp(forwardingObjective.appId())
453 .withPriority(MPLS_L2_PORT_PRIORITY)
454 .forDevice(deviceId)
455 .withSelector(selector.build())
456 .withTreatment(treatment.build())
457 .makePermanent()
458 .forTable(MPLS_L2_PORT_FLOW_TABLE);
459 return Collections.singletonList(ruleBuilder.build());
460 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800461
462 /**
463 * Utility function to get the mod tunnel id instruction
464 * if present.
465 *
466 * @param treatment the treatment to analyze
467 * @return the mod tunnel id instruction if present,
468 * otherwise null
469 */
470 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800471 if (treatment == null) {
472 return null;
473 }
474
Pier Ventre70d53ba2016-11-17 22:26:29 -0800475 L2ModificationInstruction l2ModificationInstruction;
476 for (Instruction instruction : treatment.allInstructions()) {
477 if (instruction.type() == L2MODIFICATION) {
478 l2ModificationInstruction = (L2ModificationInstruction) instruction;
479 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
480 return (ModTunnelIdInstruction) l2ModificationInstruction;
481 }
482 }
483 }
484 return null;
485 }
486
487 /**
488 * Utility function to get the output instruction
489 * if present.
490 *
491 * @param treatment the treatment to analyze
492 * @return the output instruction if present,
493 * otherwise null
494 */
495 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
496 for (Instruction instruction : treatment.allInstructions()) {
497 if (instruction.type() == Instruction.Type.OUTPUT) {
498 return (OutputInstruction) instruction;
499 }
500 }
501 return null;
502 }
503
504 /**
505 * Helper method for dividing the tunnel instructions from the mpls
506 * instructions.
507 *
508 * @param treatment the treatment to analyze
509 * @param mplsTreatment the mpls treatment builder
510 */
511 private void createMplsTreatment(TrafficTreatment treatment,
512 TrafficTreatment.Builder mplsTreatment) {
513
514 for (Instruction ins : treatment.allInstructions()) {
515
516 if (ins.type() == Instruction.Type.L2MODIFICATION) {
517 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
518 switch (l2ins.subtype()) {
519 // These instructions have to go in the mpls
520 // treatment.
521 case TUNNEL_ID:
522 break;
523 case DEC_MPLS_TTL:
524 case MPLS_POP:
525 mplsTreatment.add(ins);
526 break;
527 default:
528 log.warn("Driver does not handle this type of TrafficTreatment"
529 + " instruction in nextObjectives: {} - {}",
530 ins.type(), ins);
531 break;
532 }
533 } else if (ins.type() == Instruction.Type.OUTPUT) {
534 break;
535 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
536 // We support partially the l3 instructions.
537 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
538 switch (l3ins.subtype()) {
539 case TTL_IN:
540 mplsTreatment.add(ins);
541 break;
542 default:
543 log.warn("Driver does not handle this type of TrafficTreatment"
544 + " instruction in nextObjectives: {} - {}",
545 ins.type(), ins);
546 }
547
548 } else {
549 log.warn("Driver does not handle this type of TrafficTreatment"
550 + " instruction in nextObjectives: {} - {}",
551 ins.type(), ins);
552 }
553 }
554 }
Charles Chanf9e98652016-09-07 16:54:23 -0700555}