blob: 7377a20647419c74315154fb68abab1b096f36f2 [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;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070020import org.onlab.packet.MacAddress;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -070021import org.onlab.packet.VlanId;
Charles Chanf9e98652016-09-07 16:54:23 -070022import org.onosproject.core.ApplicationId;
Pier Ventre42287df2016-11-09 14:17:26 -080023import org.onosproject.driver.extensions.Ofdpa3MatchMplsL2Port;
24import org.onosproject.driver.extensions.Ofdpa3MatchOvid;
Pier Ventre70d53ba2016-11-17 22:26:29 -080025import org.onosproject.driver.extensions.Ofdpa3PopCw;
26import org.onosproject.driver.extensions.Ofdpa3PopL2Header;
Pier Ventre42287df2016-11-09 14:17:26 -080027import org.onosproject.driver.extensions.Ofdpa3SetMplsL2Port;
28import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
29import org.onosproject.driver.extensions.Ofdpa3SetOvid;
30import org.onosproject.driver.extensions.Ofdpa3SetQosIndex;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070031import org.onosproject.driver.extensions.OfdpaMatchVlanVid;
32import org.onosproject.net.PortNumber;
Pier Ventre42287df2016-11-09 14:17:26 -080033import org.onosproject.net.behaviour.NextGroup;
Charles Chanf9e98652016-09-07 16:54:23 -070034import org.onosproject.net.behaviour.PipelinerContext;
Pier Ventre42287df2016-11-09 14:17:26 -080035import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070038import org.onosproject.net.flow.FlowRule;
Pier Ventre42287df2016-11-09 14:17:26 -080039import org.onosproject.net.flow.FlowRuleOperations;
40import org.onosproject.net.flow.FlowRuleOperationsContext;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070043import org.onosproject.net.flow.criteria.Criteria;
Pier Ventre42287df2016-11-09 14:17:26 -080044import org.onosproject.net.flow.criteria.Criterion;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070045import org.onosproject.net.flow.criteria.EthCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070046import org.onosproject.net.flow.criteria.PortCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080047import org.onosproject.net.flow.criteria.TunnelIdCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070048import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre70d53ba2016-11-17 22:26:29 -080049import org.onosproject.net.flow.instructions.Instruction;
50import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080051import org.onosproject.net.flow.instructions.L2ModificationInstruction;
52import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Pier Ventre70d53ba2016-11-17 22:26:29 -080053import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080054import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chanf9e98652016-09-07 16:54:23 -070055import org.onosproject.net.flowobjective.ForwardingObjective;
Pier Ventre42287df2016-11-09 14:17:26 -080056import org.onosproject.net.flowobjective.ObjectiveError;
57import org.onosproject.net.group.Group;
58import org.onosproject.net.group.GroupKey;
59import org.slf4j.Logger;
Charles Chanf9e98652016-09-07 16:54:23 -070060
61import java.util.Collection;
Pier Ventre42287df2016-11-09 14:17:26 -080062import java.util.Collections;
63import java.util.Deque;
Charles Chanf9e98652016-09-07 16:54:23 -070064import java.util.List;
65
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070066import static org.onlab.packet.MacAddress.NONE;
Pier Ventre42287df2016-11-09 14:17:26 -080067import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
68import static org.onosproject.net.flow.criteria.Criterion.Type.*;
69import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
70import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
71import static org.slf4j.LoggerFactory.getLogger;
72
Charles Chanf9e98652016-09-07 16:54:23 -070073/**
74 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
75 */
76public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080077
78 private final Logger log = getLogger(getClass());
79
Charles Chanf9e98652016-09-07 16:54:23 -070080 @Override
Charles Chan40132b32017-01-22 00:19:37 -080081 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070082 driverId = coreService.registerApplication(
83 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080084 }
Charles Chanf9e98652016-09-07 16:54:23 -070085
Charles Chan40132b32017-01-22 00:19:37 -080086 @Override
87 protected void initGroupHander(PipelinerContext context) {
88 groupHandler = new Ofdpa3GroupHandler();
89 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070090 }
91
92 @Override
Charles Chand1172632017-03-15 17:33:09 -070093 protected boolean requireVlanExtensions() {
94 return false;
95 }
96
97 @Override
Saurav Dasc568c342018-01-25 09:49:01 -080098 protected boolean shouldRetry() {
99 return false;
100 }
101
102 @Override
Pier Ventre42287df2016-11-09 14:17:26 -0800103 protected void processFilter(FilteringObjective filteringObjective,
104 boolean install,
105 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700106
107 // Check if filter is intended for pseudowire
108 boolean isPw = isPseudowire(filteringObjective);
109
110 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800111 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
112 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700113
114 VlanIdCriterion innerVlanIdCriterion = null;
115 for (Criterion criterion : filteringObjective.conditions()) {
116 if (criterion.type() == INNER_VLAN_VID) {
117 innerVlanIdCriterion = (VlanIdCriterion) criterion;
118 break;
119 }
120 }
121
Pier Ventre42287df2016-11-09 14:17:26 -0800122 VlanIdCriterion outerVlanIdCriterion = null;
123 // We extract the expected port criterion in the key.
124 portCriterion = (PortCriterion) filteringObjective.key();
125 // We extract the outer vlan id criterion.
126 for (Criterion criterion : filteringObjective.conditions()) {
127 if (criterion.type() == VLAN_VID) {
128 outerVlanIdCriterion = (VlanIdCriterion) criterion;
129 break;
130 }
131 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700132
Pier Ventre42287df2016-11-09 14:17:26 -0800133 // We extract the tunnel id.
134 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700135 VlanId egressVlan;
136
Pier Ventre42287df2016-11-09 14:17:26 -0800137 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700138 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800139 log.warn("Bad filtering objective from app: {}. Not"
140 + "processing filtering objective", applicationId);
141 fail(filteringObjective, ObjectiveError.BADPARAMS);
142 return;
143 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700144 filteringObjective.meta().allInstructions().size() == 2 &&
145 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
146 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
147
Pier Ventre42287df2016-11-09 14:17:26 -0800148 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
149 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700150
Pier Ventre42287df2016-11-09 14:17:26 -0800151 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
152 log.warn("Bad filtering objective from app: {}. Not"
153 + "processing filtering objective", applicationId);
154 fail(filteringObjective, ObjectiveError.BADPARAMS);
155 return;
156 } else {
157 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
158 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700159
160 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
161 filteringObjective.meta().allInstructions().get(1);
162
163 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
164 log.warn("Bad filtering objective from app: {}. Not"
165 + "processing filtering objective", applicationId);
166 fail(filteringObjective, ObjectiveError.BADPARAMS);
167 return;
168 } else {
169 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
170 }
Pier Ventre42287df2016-11-09 14:17:26 -0800171 } else {
172 log.warn("Bad filtering objective from app: {}. Not"
173 + "processing filtering objective", applicationId);
174 fail(filteringObjective, ObjectiveError.BADPARAMS);
175 return;
176 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700177
Pier Ventre42287df2016-11-09 14:17:26 -0800178 // Mpls tunnel ids according to the OFDPA manual have to be
179 // in the range [2^17-1, 2^16].
180 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
181 // Sanity check for the filtering objective.
182 if (portCriterion == null ||
183 outerVlanIdCriterion == null ||
184 tunnelId > MPLS_TUNNEL_ID_MAX) {
185 log.warn("Bad filtering objective from app: {}. Not"
186 + "processing filtering objective", applicationId);
187 fail(filteringObjective, ObjectiveError.BADPARAMS);
188 return;
189 }
190 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800191 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530192 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800193 portCriterion.port().toLong());
194 fail(filteringObjective, ObjectiveError.BADPARAMS);
195 return;
196 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700197
Pier Ventre42287df2016-11-09 14:17:26 -0800198 // We create the flows.
199 List<FlowRule> pwRules = processPwFilter(portCriterion,
200 innerVlanIdCriterion,
201 outerVlanIdCriterion,
202 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700203 applicationId,
204 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800205 );
206 // We tag the flow for adding or for removing.
207 for (FlowRule pwRule : pwRules) {
208 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
209 pwRule, deviceId);
210 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
211 }
212 // We push the filtering rules for the pw.
213 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
214 @Override
215 public void onSuccess(FlowRuleOperations ops) {
216 log.info("Applied {} filtering rules in device {}",
217 ops.stages().get(0).size(), deviceId);
218 pass(filteringObjective);
219 }
220
221 @Override
222 public void onError(FlowRuleOperations ops) {
223 log.info("Failed to apply all filtering rules in dev {}", deviceId);
224 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
225 }
226 }));
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700227 } else if (isDoubleTagged(filteringObjective)) {
228 processDoubleTaggedFilter(filteringObjective, install, applicationId);
229 } else {
230 // If it is not a pseudo wire flow or double-tagged filter, we fall back
231 // to the OFDPA 2.0 pipeline.
232 super.processFilter(filteringObjective, install, applicationId);
233 }
234 }
Pier Ventre42287df2016-11-09 14:17:26 -0800235
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700236 /**
237 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
238 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
239 *
240 * @param filteringObjective the filtering objective
241 * @param install true to add, false to remove
242 * @param applicationId for application programming this filter
243 */
244 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
245 boolean install,
246 ApplicationId applicationId) {
247 PortCriterion portCriterion = null;
248 EthCriterion ethCriterion = null;
249 VlanIdCriterion innervidCriterion = null;
250 VlanIdCriterion outerVidCriterion = null;
251 boolean popVlan = false;
252 TrafficTreatment meta = filteringObjective.meta();
253 if (!filteringObjective.key().equals(Criteria.dummy()) &&
254 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
255 portCriterion = (PortCriterion) filteringObjective.key();
256 }
257 if (portCriterion == null) {
258 log.warn("No IN_PORT defined in filtering objective from app: {}" +
259 "Failed to program VLAN tables.", applicationId);
260 return;
261 } else {
262 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
263 portCriterion.port());
264 }
265
266 // meta should have only one instruction, popVlan.
267 if (meta != null && meta.allInstructions().size() == 1) {
268 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
269 if (l2Inst.subtype().equals(L2SubType.VLAN_POP)) {
270 popVlan = true;
271 } else {
272 log.warn("Filtering objective can have only VLAN_POP instruction.");
273 return;
274 }
275 } else {
276 log.warn("Filtering objective should have one instruction.");
Pier Ventre42287df2016-11-09 14:17:26 -0800277 return;
278 }
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700279
280 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
281 for (Criterion criterion : filteringObjective.conditions()) {
282 switch (criterion.type()) {
283 case ETH_DST:
284 case ETH_DST_MASKED:
285 ethCriterion = (EthCriterion) criterion;
286 break;
287 case VLAN_VID:
288 if (innervidCriterion == null) {
289 innervidCriterion = (VlanIdCriterion) criterion;
290 } else {
291 outerVidCriterion = innervidCriterion;
292 innervidCriterion = (VlanIdCriterion) criterion;
293 }
294 break;
295 default:
296 log.warn("Unsupported filter {}", criterion);
297 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
298 return;
299 }
300 }
301
302 if (innervidCriterion == null || outerVidCriterion == null) {
303 log.warn("filtering objective should have two vidCriterion.");
304 return;
305 }
306
307 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
308 // NOTE: it is possible that a filtering objective only has vidCriterion
309 log.warn("filtering objective missing dstMac, cannot program TMAC table");
310 return;
311 } else {
312 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
313 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
314 innervidCriterion.vlanId(), unicastMac,
315 applicationId);
316 for (List<FlowRule> flowRules : allStages) {
317 log.trace("Starting a new flow rule stage for TMAC table flow");
318 ops.newStage();
319
320 for (FlowRule flowRule : flowRules) {
321 log.trace("{} flow rules in TMAC table: {} for dev: {}",
322 (install) ? "adding" : "removing", flowRules, deviceId);
323 if (install) {
324 ops = ops.add(flowRule);
325 } else {
326 // NOTE: Only remove TMAC flow when there is no more enabled port within the
327 // same VLAN on this device if TMAC doesn't support matching on in_port.
328 if (matchInPortTmacTable()
329 || (filteringObjective.meta() != null
330 && filteringObjective.meta().clearedDeferred())) {
331 ops = ops.remove(flowRule);
332 } else {
333 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
334 }
335 }
336 }
337 }
338 }
339
340 List<FlowRule> rules;
341 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
342 outerVidCriterion, popVlan, applicationId);
343 for (FlowRule flowRule : rules) {
344 log.trace("{} flow rule in VLAN table: {} for dev: {}",
345 (install) ? "adding" : "removing", flowRule, deviceId);
346 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
347 }
348
349 // apply filtering flow rules
350 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
351 @Override
352 public void onSuccess(FlowRuleOperations ops) {
353 log.debug("Applied {} filtering rules in device {}",
354 ops.stages().get(0).size(), deviceId);
355 pass(filteringObjective);
356 }
357
358 @Override
359 public void onError(FlowRuleOperations ops) {
360 log.info("Failed to apply all filtering rules in dev {}", deviceId);
361 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
362 }
363 }));
364
365 }
366 /**
367 * Internal implementation of processDoubleVlanIdFilter.
368 *
369 * @param portCriterion port on device for which this filter is programmed
370 * @param innerVidCriterion inner vlan
371 * @param outerVidCriterion outer vlan
372 * @param popVlan true if outer vlan header needs to be removed
373 * @param applicationId for application programming this filter
374 * @return flow rules for port-vlan filters
375 */
376 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
377 VlanIdCriterion innerVidCriterion,
378 VlanIdCriterion outerVidCriterion,
379 boolean popVlan,
380 ApplicationId applicationId) {
381 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
382 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
383 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
384 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
385
386 VlanId outerVlanId = outerVidCriterion.vlanId();
387 VlanId innerVlanId = innerVidCriterion.vlanId();
388 PortNumber portNumber = portCriterion.port();
389 // Check arguments
390 if (PortNumber.ALL.equals(portNumber)
391 || outerVlanId.equals(VlanId.NONE)
392 || innerVlanId.equals(VlanId.NONE)) {
393 log.warn("Incomplete Filtering Objective. " +
394 "VLAN Table cannot be programmed for {}", deviceId);
395 return ImmutableList.of();
396 } else {
397 outerSelector.matchInPort(portNumber);
398 innerSelector.matchInPort(portNumber);
399 outerTreatment.transition(VLAN_1_TABLE);
400 innerTreatment.transition(TMAC_TABLE);
401
402 if (requireVlanExtensions()) {
403 OfdpaMatchVlanVid ofdpaOuterMatchVlanVid = new OfdpaMatchVlanVid(outerVlanId);
404 outerSelector.extension(ofdpaOuterMatchVlanVid, deviceId);
405 OfdpaMatchVlanVid ofdpaInnerMatchVlanVid = new OfdpaMatchVlanVid(innerVlanId);
406 innerSelector.extension(ofdpaInnerMatchVlanVid, deviceId);
407 } else {
408 outerSelector.matchVlanId(outerVlanId);
409 innerSelector.matchVlanId(innerVlanId);
410 }
411
412 innerSelector.extension(new Ofdpa3MatchOvid(outerVlanId), deviceId);
413 outerTreatment.extension(new Ofdpa3SetOvid(outerVlanId), deviceId);
414 if (popVlan) {
415 outerTreatment.popVlan();
416 }
417 }
418 FlowRule outerRule = DefaultFlowRule.builder()
419 .forDevice(deviceId)
420 .withSelector(outerSelector.build())
421 .withTreatment(outerTreatment.build())
422 .withPriority(DEFAULT_PRIORITY)
423 .fromApp(applicationId)
424 .makePermanent()
425 .forTable(VLAN_TABLE)
426 .build();
427 FlowRule innerRule = DefaultFlowRule.builder()
428 .forDevice(deviceId)
429 .withSelector(innerSelector.build())
430 .withTreatment(innerTreatment.build())
431 .withPriority(DEFAULT_PRIORITY)
432 .fromApp(applicationId)
433 .makePermanent()
434 .forTable(VLAN_1_TABLE)
435 .build();
436
437 return ImmutableList.of(outerRule, innerRule);
438 }
439
440 /**
441 * Determines if the filtering objective will be used for double-tagged packets.
442 *
443 * @param fob Filtering objective
444 * @return True if the objective was created for double-tagged packets, false otherwise.
445 */
446 private boolean isDoubleTagged(FilteringObjective fob) {
447 return fob.meta() != null &&
448 fob.meta().allInstructions().stream().anyMatch(inst -> inst.type() == L2MODIFICATION
449 && ((L2ModificationInstruction) inst).subtype() == L2SubType.VLAN_POP) &&
450 fob.conditions().stream().filter(criterion -> criterion.type() == VLAN_VID).count() == 2;
Pier Ventre42287df2016-11-09 14:17:26 -0800451 }
452
453 /**
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700454 * Determines if the filtering objective will be used for a pseudowire.
455 *
456 * @param filteringObjective
457 * @return True if objective was created for a pseudowire, false otherwise.
458 */
459 private boolean isPseudowire(FilteringObjective filteringObjective) {
460
461
462 if (filteringObjective.meta() != null) {
463
464 TrafficTreatment treatment = filteringObjective.meta();
465 for (Instruction instr : treatment.immediate()) {
466 if (instr.type().equals(Instruction.Type.L2MODIFICATION)) {
467
468 L2ModificationInstruction l2Instr = (L2ModificationInstruction) instr;
469 if (l2Instr.subtype().equals(L2SubType.TUNNEL_ID)) {
470 return true;
471 }
472 }
473 }
474 }
475
476 return false;
477 }
478
479 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800480 * Method to process the pw related filtering objectives.
481 *
482 * @param portCriterion the in port match
483 * @param innerVlanIdCriterion the inner vlan match
484 * @param outerVlanIdCriterion the outer vlan match
485 * @param tunnelId the tunnel id
486 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700487 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800488 * @return a list of flow rules to install
489 */
490 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700491 VlanIdCriterion innerVlanIdCriterion,
492 VlanIdCriterion outerVlanIdCriterion,
493 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700494 ApplicationId applicationId,
495 VlanId egressVlan) {
496
Pier Ventre42287df2016-11-09 14:17:26 -0800497 FlowRule vlan1FlowRule;
498 int mplsLogicalPort = ((int) portCriterion.port().toLong());
499 // We have to match on the inner vlan and outer vlan at the same time.
500 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800501
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700502 ImmutableList<FlowRule> toReturn;
503
504 // pseudowire configured with double tagged vlans
505 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
506 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
507
508 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
509
510 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
511 .matchInPort(portCriterion.port())
512 .matchVlanId(innerVlanIdCriterion.vlanId())
513 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
514 // TODO understand for the future how to manage the vlan rewrite.
515 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
516 .pushVlan()
517 .setVlanId(egressVlan)
518 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
519 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
520 .setTunnelId(tunnelId)
521 .transition(MPLS_L2_PORT_FLOW_TABLE);
522 vlan1FlowRule = DefaultFlowRule.builder()
523 .forDevice(deviceId)
524 .withSelector(vlan1Selector.build())
525 .withTreatment(vlan1Treatment.build())
526 .withPriority(DEFAULT_PRIORITY)
527 .fromApp(applicationId)
528 .makePermanent()
529 .forTable(VLAN_1_TABLE)
530 .build();
531 // Finally we create the flow rule for the vlan table.
532 FlowRule vlanFlowRule;
533 // We have to match on the outer vlan.
534 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
535 .matchInPort(portCriterion.port())
536 .matchVlanId(outerVlanIdCriterion.vlanId());
537 // TODO understand for the future how to manage the vlan rewrite.
538 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
539 .popVlan()
540 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
541 .transition(VLAN_1_TABLE);
542 vlanFlowRule = DefaultFlowRule.builder()
543 .forDevice(deviceId)
544 .withSelector(vlanSelector.build())
545 .withTreatment(vlanTreatment.build())
546 .withPriority(DEFAULT_PRIORITY)
547 .fromApp(applicationId)
548 .makePermanent()
549 .forTable(VLAN_TABLE)
550 .build();
551
552 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
553 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
554 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
555
556 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
557
558 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
559 .matchInPort(portCriterion.port())
560 .matchVlanId(innerVlanIdCriterion.vlanId());
561
562 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
563 // .pushVlan()
564 .setVlanId(egressVlan)
565 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
566 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
567 .setTunnelId(tunnelId)
568 .transition(MPLS_L2_PORT_FLOW_TABLE);
569
570 vlan1FlowRule = DefaultFlowRule.builder()
571 .forDevice(deviceId)
572 .withSelector(singleVlanSelector.build())
573 .withTreatment(singleVlanTreatment.build())
574 .withPriority(DEFAULT_PRIORITY)
575 .fromApp(applicationId)
576 .makePermanent()
577 .forTable(VLAN_TABLE)
578 .build();
579
580 return ImmutableList.of(vlan1FlowRule);
581 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
582 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
583
584 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
585 .matchInPort(portCriterion.port())
586 .matchVlanId(innerVlanIdCriterion.vlanId());
587
588 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
589 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
590 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
591 .setTunnelId(tunnelId)
592 .transition(MPLS_L2_PORT_FLOW_TABLE);
593
594 vlan1FlowRule = DefaultFlowRule.builder()
595 .forDevice(deviceId)
596 .withSelector(singleVlanSelector.build())
597 .withTreatment(singleVlanTreatment.build())
598 .withPriority(DEFAULT_PRIORITY)
599 .fromApp(applicationId)
600 .makePermanent()
601 .forTable(VLAN_TABLE)
602 .build();
603
604 return ImmutableList.of(vlan1FlowRule);
605 } else {
606 // failure...
607 return Collections.emptyList();
608 }
Pier Ventre42287df2016-11-09 14:17:26 -0800609 }
610
611 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700612 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa4020382018-02-14 14:14:54 -0800613 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
614 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
615 if (isNotMplsBos(fwd.selector())
616 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700617 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
618 }
Saurav Dasa4020382018-02-14 14:14:54 -0800619 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700620 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700621 }
Pier Ventre42287df2016-11-09 14:17:26 -0800622
623 @Override
624 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
625 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800626 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800627 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
628 .getCriterion(TUNNEL_ID);
629 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800630 return processInitPwVersatile(fwd);
631 }
632 // Looking for the fwd objective of the termination.
633 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
634 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
635 if (modTunnelIdInstruction != null && outputInstruction != null) {
636 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800637 }
638 // If it is not a pseudo wire flow we fall back
639 // to the OFDPA 2.0 pipeline.
640 return super.processVersatile(fwd);
641 }
642
Pier Ventre70d53ba2016-11-17 22:26:29 -0800643 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
644 ModTunnelIdInstruction modTunnelIdInstruction,
645 OutputInstruction outputInstruction) {
646 TrafficTreatment.Builder flowTreatment;
647 TrafficSelector.Builder flowSelector;
648 // We divide the mpls actions from the tunnel actions. We need
649 // this to order the actions in the final treatment.
650 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
651 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
652 // The match of the forwarding objective is ready to go.
653 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
654 // We verify the tunnel id and mpls port are correct.
655 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
656 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
657 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
658 MPLS_TUNNEL_ID_MAX);
659 fail(forwardingObjective, ObjectiveError.BADPARAMS);
660 return Collections.emptySet();
661 }
662 // 0x0002XXXX is NNI interface.
663 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
664 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
665 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
666 mplsLogicalPort);
667 fail(forwardingObjective, ObjectiveError.BADPARAMS);
668 return Collections.emptySet();
669 }
670 // Next id cannot be null.
671 if (forwardingObjective.nextId() == null) {
672 log.error("Pw Versatile Forwarding Objective must contain nextId ",
673 forwardingObjective.nextId());
674 fail(forwardingObjective, ObjectiveError.BADPARAMS);
675 return Collections.emptySet();
676 }
677 // We retrieve the l2 interface group and point the mpls
678 // flow to this.
679 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
680 if (next == null) {
681 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
682 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
683 return Collections.emptySet();
684 }
685 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
686 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
687 if (group == null) {
688 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
689 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
690 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
691 return Collections.emptySet();
692 }
693 // We prepare the treatment for the mpls flow table.
694 // The order of the actions has to be strictly this
695 // according to the OFDPA 2.0 specification.
696 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
697 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800698 // Even though the specification and the xml/json files
699 // specify is allowed, the switch rejects the flow. In the
700 // OFDPA 3.0 EA0 version was necessary
701 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800702 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
703 flowTreatment.setTunnelId(tunnelId);
704 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
705 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
706 flowTreatment.transition(MPLS_TYPE_TABLE);
707 flowTreatment.deferred().group(group.id());
708 // We prepare the flow rule for the mpls table.
709 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
710 .fromApp(forwardingObjective.appId())
711 .withPriority(forwardingObjective.priority())
712 .forDevice(deviceId)
713 .withSelector(flowSelector.build())
714 .withTreatment(flowTreatment.build())
715 .makePermanent()
716 .forTable(MPLS_TABLE_1);
717 return Collections.singletonList(ruleBuilder.build());
718 }
719
Pier Ventre42287df2016-11-09 14:17:26 -0800720 /**
721 * Helper method to process the pw forwarding objectives.
722 *
723 * @param forwardingObjective the fw objective to process
724 * @return a singleton list of flow rule
725 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800726 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800727 // We retrieve the matching criteria for mpls l2 port.
728 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
729 .getCriterion(TUNNEL_ID);
730 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
731 .getCriterion(IN_PORT);
732 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
733 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
734 int mplsLogicalPort;
735 long tunnelId;
736 // Mpls tunnel ids according to the OFDPA manual have to be
737 // in the range [2^17-1, 2^16].
738 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
739 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
740 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
741 MPLS_TUNNEL_ID_MAX);
742 fail(forwardingObjective, ObjectiveError.BADPARAMS);
743 return Collections.emptySet();
744 }
745 // Port has not been null.
746 if (portCriterion == null) {
747 log.error("Pw Versatile Forwarding Objective must include port");
748 fail(forwardingObjective, ObjectiveError.BADPARAMS);
749 return Collections.emptySet();
750 }
751 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800752 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800753 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
754 portCriterion.port().toLong());
755 fail(forwardingObjective, ObjectiveError.BADPARAMS);
756 return Collections.emptySet();
757 }
758 mplsLogicalPort = ((int) portCriterion.port().toLong());
759 if (forwardingObjective.nextId() == null) {
760 log.error("Pw Versatile Forwarding Objective must contain nextId ",
761 forwardingObjective.nextId());
762 fail(forwardingObjective, ObjectiveError.BADPARAMS);
763 return Collections.emptySet();
764 }
765 // We don't expect a treatment.
766 if (forwardingObjective.treatment() != null &&
767 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
768 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
769 forwardingObjective.nextId());
770 fail(forwardingObjective, ObjectiveError.BADPARAMS);
771 return Collections.emptySet();
772 }
773 // We retrieve the l2 vpn group and point the mpls
774 // l2 port to this.
775 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
776 if (next == null) {
777 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
778 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
779 return Collections.emptySet();
780 }
781 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
782 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
783 if (group == null) {
784 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
785 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
786 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
787 return Collections.emptySet();
788 }
789 // We prepare the flow rule for the mpls l2 port table.
790 selector.matchTunnelId(tunnelId);
791 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
792 // This should not be necessary but without we receive an error
793 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
794 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
795 treatment.deferred().group(group.id());
796 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
797 .fromApp(forwardingObjective.appId())
798 .withPriority(MPLS_L2_PORT_PRIORITY)
799 .forDevice(deviceId)
800 .withSelector(selector.build())
801 .withTreatment(treatment.build())
802 .makePermanent()
803 .forTable(MPLS_L2_PORT_FLOW_TABLE);
804 return Collections.singletonList(ruleBuilder.build());
805 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800806
807 /**
808 * Utility function to get the mod tunnel id instruction
809 * if present.
810 *
811 * @param treatment the treatment to analyze
812 * @return the mod tunnel id instruction if present,
813 * otherwise null
814 */
815 private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
Charles Chan3bb11702017-02-16 14:58:58 -0800816 if (treatment == null) {
817 return null;
818 }
819
Pier Ventre70d53ba2016-11-17 22:26:29 -0800820 L2ModificationInstruction l2ModificationInstruction;
821 for (Instruction instruction : treatment.allInstructions()) {
822 if (instruction.type() == L2MODIFICATION) {
823 l2ModificationInstruction = (L2ModificationInstruction) instruction;
824 if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
825 return (ModTunnelIdInstruction) l2ModificationInstruction;
826 }
827 }
828 }
829 return null;
830 }
831
832 /**
833 * Utility function to get the output instruction
834 * if present.
835 *
836 * @param treatment the treatment to analyze
837 * @return the output instruction if present,
838 * otherwise null
839 */
840 private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
Saurav Das018605f2017-02-18 14:05:44 -0800841 if (treatment == null) {
842 return null;
843 }
844
Pier Ventre70d53ba2016-11-17 22:26:29 -0800845 for (Instruction instruction : treatment.allInstructions()) {
846 if (instruction.type() == Instruction.Type.OUTPUT) {
847 return (OutputInstruction) instruction;
848 }
849 }
850 return null;
851 }
852
853 /**
854 * Helper method for dividing the tunnel instructions from the mpls
855 * instructions.
856 *
857 * @param treatment the treatment to analyze
858 * @param mplsTreatment the mpls treatment builder
859 */
860 private void createMplsTreatment(TrafficTreatment treatment,
861 TrafficTreatment.Builder mplsTreatment) {
862
863 for (Instruction ins : treatment.allInstructions()) {
864
865 if (ins.type() == Instruction.Type.L2MODIFICATION) {
866 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
867 switch (l2ins.subtype()) {
868 // These instructions have to go in the mpls
869 // treatment.
870 case TUNNEL_ID:
871 break;
872 case DEC_MPLS_TTL:
873 case MPLS_POP:
874 mplsTreatment.add(ins);
875 break;
876 default:
877 log.warn("Driver does not handle this type of TrafficTreatment"
878 + " instruction in nextObjectives: {} - {}",
879 ins.type(), ins);
880 break;
881 }
882 } else if (ins.type() == Instruction.Type.OUTPUT) {
883 break;
884 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
885 // We support partially the l3 instructions.
886 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
887 switch (l3ins.subtype()) {
888 case TTL_IN:
889 mplsTreatment.add(ins);
890 break;
891 default:
892 log.warn("Driver does not handle this type of TrafficTreatment"
893 + " instruction in nextObjectives: {} - {}",
894 ins.type(), ins);
895 }
896
897 } else {
898 log.warn("Driver does not handle this type of TrafficTreatment"
899 + " instruction in nextObjectives: {} - {}",
900 ins.type(), ins);
901 }
902 }
903 }
Charles Chanf9e98652016-09-07 16:54:23 -0700904}