blob: dbf1280f772b82b789d31b3a6ef8e3aff3aabb3b [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;
pier9469f3e2019-04-17 17:05:08 +020067import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Pier Ventre42287df2016-11-09 14:17:26 -080068import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
Andrea Campanellad980c6d2018-04-30 11:48:55 +020069import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
70import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
71import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
72import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Pier Ventre42287df2016-11-09 14:17:26 -080073import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
74import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
75import static org.slf4j.LoggerFactory.getLogger;
76
Charles Chanf9e98652016-09-07 16:54:23 -070077/**
78 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
79 */
80public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080081
82 private final Logger log = getLogger(getClass());
83
Charles Chanf9e98652016-09-07 16:54:23 -070084 @Override
Charles Chan40132b32017-01-22 00:19:37 -080085 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070086 driverId = coreService.registerApplication(
87 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080088 }
Charles Chanf9e98652016-09-07 16:54:23 -070089
Charles Chan40132b32017-01-22 00:19:37 -080090 @Override
91 protected void initGroupHander(PipelinerContext context) {
92 groupHandler = new Ofdpa3GroupHandler();
93 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070094 }
95
96 @Override
Charles Chand1172632017-03-15 17:33:09 -070097 protected boolean requireVlanExtensions() {
98 return false;
99 }
100
101 @Override
Saurav Dasc568c342018-01-25 09:49:01 -0800102 protected boolean shouldRetry() {
103 return false;
104 }
105
106 @Override
Andrea Campanellad980c6d2018-04-30 11:48:55 +0200107 protected boolean supportsUnicastBlackHole() {
108 return true;
109 }
110
111 @Override
Pier Ventre42287df2016-11-09 14:17:26 -0800112 protected void processFilter(FilteringObjective filteringObjective,
113 boolean install,
114 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700115
116 // Check if filter is intended for pseudowire
117 boolean isPw = isPseudowire(filteringObjective);
118
119 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800120 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
121 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700122
123 VlanIdCriterion innerVlanIdCriterion = null;
124 for (Criterion criterion : filteringObjective.conditions()) {
125 if (criterion.type() == INNER_VLAN_VID) {
126 innerVlanIdCriterion = (VlanIdCriterion) criterion;
127 break;
128 }
129 }
130
Pier Ventre42287df2016-11-09 14:17:26 -0800131 VlanIdCriterion outerVlanIdCriterion = null;
132 // We extract the expected port criterion in the key.
133 portCriterion = (PortCriterion) filteringObjective.key();
134 // We extract the outer vlan id criterion.
135 for (Criterion criterion : filteringObjective.conditions()) {
136 if (criterion.type() == VLAN_VID) {
137 outerVlanIdCriterion = (VlanIdCriterion) criterion;
138 break;
139 }
140 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700141
Pier Ventre42287df2016-11-09 14:17:26 -0800142 // We extract the tunnel id.
143 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700144 VlanId egressVlan;
145
Pier Ventre42287df2016-11-09 14:17:26 -0800146 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700147 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800148 log.warn("Bad filtering objective from app: {}. Not"
149 + "processing filtering objective", applicationId);
150 fail(filteringObjective, ObjectiveError.BADPARAMS);
151 return;
152 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700153 filteringObjective.meta().allInstructions().size() == 2 &&
154 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
155 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
156
Pier Ventre42287df2016-11-09 14:17:26 -0800157 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
158 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700159
Pier Ventre42287df2016-11-09 14:17:26 -0800160 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
161 log.warn("Bad filtering objective from app: {}. Not"
162 + "processing filtering objective", applicationId);
163 fail(filteringObjective, ObjectiveError.BADPARAMS);
164 return;
165 } else {
166 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
167 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700168
169 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
170 filteringObjective.meta().allInstructions().get(1);
171
172 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
173 log.warn("Bad filtering objective from app: {}. Not"
174 + "processing filtering objective", applicationId);
175 fail(filteringObjective, ObjectiveError.BADPARAMS);
176 return;
177 } else {
178 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
179 }
Pier Ventre42287df2016-11-09 14:17:26 -0800180 } else {
181 log.warn("Bad filtering objective from app: {}. Not"
182 + "processing filtering objective", applicationId);
183 fail(filteringObjective, ObjectiveError.BADPARAMS);
184 return;
185 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700186
Pier Ventre42287df2016-11-09 14:17:26 -0800187 // Mpls tunnel ids according to the OFDPA manual have to be
188 // in the range [2^17-1, 2^16].
189 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
190 // Sanity check for the filtering objective.
191 if (portCriterion == null ||
192 outerVlanIdCriterion == null ||
193 tunnelId > MPLS_TUNNEL_ID_MAX) {
194 log.warn("Bad filtering objective from app: {}. Not"
195 + "processing filtering objective", applicationId);
196 fail(filteringObjective, ObjectiveError.BADPARAMS);
197 return;
198 }
199 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800200 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530201 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800202 portCriterion.port().toLong());
203 fail(filteringObjective, ObjectiveError.BADPARAMS);
204 return;
205 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700206
Pier Ventre42287df2016-11-09 14:17:26 -0800207 // We create the flows.
208 List<FlowRule> pwRules = processPwFilter(portCriterion,
209 innerVlanIdCriterion,
210 outerVlanIdCriterion,
211 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700212 applicationId,
213 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800214 );
215 // We tag the flow for adding or for removing.
216 for (FlowRule pwRule : pwRules) {
217 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
218 pwRule, deviceId);
219 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
220 }
221 // We push the filtering rules for the pw.
222 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
223 @Override
224 public void onSuccess(FlowRuleOperations ops) {
225 log.info("Applied {} filtering rules in device {}",
226 ops.stages().get(0).size(), deviceId);
227 pass(filteringObjective);
228 }
229
230 @Override
231 public void onError(FlowRuleOperations ops) {
232 log.info("Failed to apply all filtering rules in dev {}", deviceId);
233 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
234 }
235 }));
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700236 } else if (isDoubleTagged(filteringObjective)) {
237 processDoubleTaggedFilter(filteringObjective, install, applicationId);
238 } else {
239 // If it is not a pseudo wire flow or double-tagged filter, we fall back
240 // to the OFDPA 2.0 pipeline.
241 super.processFilter(filteringObjective, install, applicationId);
242 }
243 }
Pier Ventre42287df2016-11-09 14:17:26 -0800244
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700245 /**
246 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
247 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
248 *
249 * @param filteringObjective the filtering objective
250 * @param install true to add, false to remove
251 * @param applicationId for application programming this filter
252 */
253 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
254 boolean install,
255 ApplicationId applicationId) {
256 PortCriterion portCriterion = null;
257 EthCriterion ethCriterion = null;
258 VlanIdCriterion innervidCriterion = null;
259 VlanIdCriterion outerVidCriterion = null;
260 boolean popVlan = false;
261 TrafficTreatment meta = filteringObjective.meta();
262 if (!filteringObjective.key().equals(Criteria.dummy()) &&
263 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
264 portCriterion = (PortCriterion) filteringObjective.key();
265 }
266 if (portCriterion == null) {
267 log.warn("No IN_PORT defined in filtering objective from app: {}" +
268 "Failed to program VLAN tables.", applicationId);
269 return;
270 } else {
271 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
272 portCriterion.port());
273 }
274
275 // meta should have only one instruction, popVlan.
276 if (meta != null && meta.allInstructions().size() == 1) {
277 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
278 if (l2Inst.subtype().equals(L2SubType.VLAN_POP)) {
279 popVlan = true;
280 } else {
281 log.warn("Filtering objective can have only VLAN_POP instruction.");
282 return;
283 }
284 } else {
285 log.warn("Filtering objective should have one instruction.");
Pier Ventre42287df2016-11-09 14:17:26 -0800286 return;
287 }
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700288
289 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
290 for (Criterion criterion : filteringObjective.conditions()) {
291 switch (criterion.type()) {
292 case ETH_DST:
293 case ETH_DST_MASKED:
294 ethCriterion = (EthCriterion) criterion;
295 break;
296 case VLAN_VID:
297 if (innervidCriterion == null) {
298 innervidCriterion = (VlanIdCriterion) criterion;
299 } else {
300 outerVidCriterion = innervidCriterion;
301 innervidCriterion = (VlanIdCriterion) criterion;
302 }
303 break;
304 default:
305 log.warn("Unsupported filter {}", criterion);
306 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
307 return;
308 }
309 }
310
311 if (innervidCriterion == null || outerVidCriterion == null) {
312 log.warn("filtering objective should have two vidCriterion.");
313 return;
314 }
315
316 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
317 // NOTE: it is possible that a filtering objective only has vidCriterion
318 log.warn("filtering objective missing dstMac, cannot program TMAC table");
319 return;
320 } else {
321 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
322 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
323 innervidCriterion.vlanId(), unicastMac,
324 applicationId);
325 for (List<FlowRule> flowRules : allStages) {
326 log.trace("Starting a new flow rule stage for TMAC table flow");
327 ops.newStage();
328
329 for (FlowRule flowRule : flowRules) {
330 log.trace("{} flow rules in TMAC table: {} for dev: {}",
331 (install) ? "adding" : "removing", flowRules, deviceId);
332 if (install) {
333 ops = ops.add(flowRule);
334 } else {
335 // NOTE: Only remove TMAC flow when there is no more enabled port within the
336 // same VLAN on this device if TMAC doesn't support matching on in_port.
337 if (matchInPortTmacTable()
338 || (filteringObjective.meta() != null
339 && filteringObjective.meta().clearedDeferred())) {
340 ops = ops.remove(flowRule);
341 } else {
342 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
343 }
344 }
345 }
346 }
347 }
348
349 List<FlowRule> rules;
350 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
351 outerVidCriterion, popVlan, applicationId);
352 for (FlowRule flowRule : rules) {
353 log.trace("{} flow rule in VLAN table: {} for dev: {}",
354 (install) ? "adding" : "removing", flowRule, deviceId);
355 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
356 }
357
358 // apply filtering flow rules
359 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
360 @Override
361 public void onSuccess(FlowRuleOperations ops) {
362 log.debug("Applied {} filtering rules in device {}",
363 ops.stages().get(0).size(), deviceId);
364 pass(filteringObjective);
365 }
366
367 @Override
368 public void onError(FlowRuleOperations ops) {
369 log.info("Failed to apply all filtering rules in dev {}", deviceId);
370 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
371 }
372 }));
373
374 }
375 /**
376 * Internal implementation of processDoubleVlanIdFilter.
377 *
378 * @param portCriterion port on device for which this filter is programmed
379 * @param innerVidCriterion inner vlan
380 * @param outerVidCriterion outer vlan
381 * @param popVlan true if outer vlan header needs to be removed
382 * @param applicationId for application programming this filter
383 * @return flow rules for port-vlan filters
384 */
385 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
386 VlanIdCriterion innerVidCriterion,
387 VlanIdCriterion outerVidCriterion,
388 boolean popVlan,
389 ApplicationId applicationId) {
390 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
391 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
392 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
393 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
394
395 VlanId outerVlanId = outerVidCriterion.vlanId();
396 VlanId innerVlanId = innerVidCriterion.vlanId();
397 PortNumber portNumber = portCriterion.port();
398 // Check arguments
399 if (PortNumber.ALL.equals(portNumber)
400 || outerVlanId.equals(VlanId.NONE)
401 || innerVlanId.equals(VlanId.NONE)) {
402 log.warn("Incomplete Filtering Objective. " +
403 "VLAN Table cannot be programmed for {}", deviceId);
404 return ImmutableList.of();
405 } else {
406 outerSelector.matchInPort(portNumber);
407 innerSelector.matchInPort(portNumber);
408 outerTreatment.transition(VLAN_1_TABLE);
409 innerTreatment.transition(TMAC_TABLE);
410
411 if (requireVlanExtensions()) {
412 OfdpaMatchVlanVid ofdpaOuterMatchVlanVid = new OfdpaMatchVlanVid(outerVlanId);
413 outerSelector.extension(ofdpaOuterMatchVlanVid, deviceId);
414 OfdpaMatchVlanVid ofdpaInnerMatchVlanVid = new OfdpaMatchVlanVid(innerVlanId);
415 innerSelector.extension(ofdpaInnerMatchVlanVid, deviceId);
416 } else {
417 outerSelector.matchVlanId(outerVlanId);
418 innerSelector.matchVlanId(innerVlanId);
419 }
420
421 innerSelector.extension(new Ofdpa3MatchOvid(outerVlanId), deviceId);
422 outerTreatment.extension(new Ofdpa3SetOvid(outerVlanId), deviceId);
423 if (popVlan) {
424 outerTreatment.popVlan();
425 }
426 }
427 FlowRule outerRule = DefaultFlowRule.builder()
428 .forDevice(deviceId)
429 .withSelector(outerSelector.build())
430 .withTreatment(outerTreatment.build())
431 .withPriority(DEFAULT_PRIORITY)
432 .fromApp(applicationId)
433 .makePermanent()
434 .forTable(VLAN_TABLE)
435 .build();
436 FlowRule innerRule = DefaultFlowRule.builder()
437 .forDevice(deviceId)
438 .withSelector(innerSelector.build())
439 .withTreatment(innerTreatment.build())
440 .withPriority(DEFAULT_PRIORITY)
441 .fromApp(applicationId)
442 .makePermanent()
443 .forTable(VLAN_1_TABLE)
444 .build();
445
446 return ImmutableList.of(outerRule, innerRule);
447 }
448
449 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800450 * Method to process the pw related filtering objectives.
451 *
452 * @param portCriterion the in port match
453 * @param innerVlanIdCriterion the inner vlan match
454 * @param outerVlanIdCriterion the outer vlan match
455 * @param tunnelId the tunnel id
456 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700457 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800458 * @return a list of flow rules to install
459 */
460 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700461 VlanIdCriterion innerVlanIdCriterion,
462 VlanIdCriterion outerVlanIdCriterion,
463 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700464 ApplicationId applicationId,
465 VlanId egressVlan) {
466
Pier Ventre42287df2016-11-09 14:17:26 -0800467 FlowRule vlan1FlowRule;
468 int mplsLogicalPort = ((int) portCriterion.port().toLong());
469 // We have to match on the inner vlan and outer vlan at the same time.
470 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800471
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700472 ImmutableList<FlowRule> toReturn;
473
474 // pseudowire configured with double tagged vlans
475 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
476 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
477
478 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
479
480 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
481 .matchInPort(portCriterion.port())
482 .matchVlanId(innerVlanIdCriterion.vlanId())
483 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
484 // TODO understand for the future how to manage the vlan rewrite.
485 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
486 .pushVlan()
487 .setVlanId(egressVlan)
488 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
489 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
490 .setTunnelId(tunnelId)
491 .transition(MPLS_L2_PORT_FLOW_TABLE);
492 vlan1FlowRule = DefaultFlowRule.builder()
493 .forDevice(deviceId)
494 .withSelector(vlan1Selector.build())
495 .withTreatment(vlan1Treatment.build())
496 .withPriority(DEFAULT_PRIORITY)
497 .fromApp(applicationId)
498 .makePermanent()
499 .forTable(VLAN_1_TABLE)
500 .build();
501 // Finally we create the flow rule for the vlan table.
502 FlowRule vlanFlowRule;
503 // We have to match on the outer vlan.
504 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
505 .matchInPort(portCriterion.port())
506 .matchVlanId(outerVlanIdCriterion.vlanId());
507 // TODO understand for the future how to manage the vlan rewrite.
508 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
509 .popVlan()
510 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
511 .transition(VLAN_1_TABLE);
512 vlanFlowRule = DefaultFlowRule.builder()
513 .forDevice(deviceId)
514 .withSelector(vlanSelector.build())
515 .withTreatment(vlanTreatment.build())
516 .withPriority(DEFAULT_PRIORITY)
517 .fromApp(applicationId)
518 .makePermanent()
519 .forTable(VLAN_TABLE)
520 .build();
521
522 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
523 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
524 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
525
526 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
527
528 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
529 .matchInPort(portCriterion.port())
530 .matchVlanId(innerVlanIdCriterion.vlanId());
531
532 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
Charles Chanf45552d2018-07-13 18:08:33 -0700533 // FIXME PW VLAN translation is not supported on Dune
534 // Need to explore doing that in egress table later if there is a requirement
535 // .setVlanId(egressVlan)
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700536 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
537 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
538 .setTunnelId(tunnelId)
539 .transition(MPLS_L2_PORT_FLOW_TABLE);
540
541 vlan1FlowRule = DefaultFlowRule.builder()
542 .forDevice(deviceId)
543 .withSelector(singleVlanSelector.build())
544 .withTreatment(singleVlanTreatment.build())
545 .withPriority(DEFAULT_PRIORITY)
546 .fromApp(applicationId)
547 .makePermanent()
548 .forTable(VLAN_TABLE)
549 .build();
550
551 return ImmutableList.of(vlan1FlowRule);
552 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
553 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
554
555 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
556 .matchInPort(portCriterion.port())
557 .matchVlanId(innerVlanIdCriterion.vlanId());
558
559 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
560 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
561 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
562 .setTunnelId(tunnelId)
563 .transition(MPLS_L2_PORT_FLOW_TABLE);
564
565 vlan1FlowRule = DefaultFlowRule.builder()
566 .forDevice(deviceId)
567 .withSelector(singleVlanSelector.build())
568 .withTreatment(singleVlanTreatment.build())
569 .withPriority(DEFAULT_PRIORITY)
570 .fromApp(applicationId)
571 .makePermanent()
572 .forTable(VLAN_TABLE)
573 .build();
574
575 return ImmutableList.of(vlan1FlowRule);
576 } else {
577 // failure...
578 return Collections.emptyList();
579 }
Pier Ventre42287df2016-11-09 14:17:26 -0800580 }
581
582 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700583 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa4020382018-02-14 14:14:54 -0800584 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
585 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
586 if (isNotMplsBos(fwd.selector())
587 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700588 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
589 }
Saurav Dasa4020382018-02-14 14:14:54 -0800590 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700591 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700592 }
Pier Ventre42287df2016-11-09 14:17:26 -0800593
594 @Override
595 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
596 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800597 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800598 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
599 .getCriterion(TUNNEL_ID);
600 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800601 return processInitPwVersatile(fwd);
602 }
603 // Looking for the fwd objective of the termination.
604 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
605 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
606 if (modTunnelIdInstruction != null && outputInstruction != null) {
607 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800608 }
609 // If it is not a pseudo wire flow we fall back
610 // to the OFDPA 2.0 pipeline.
611 return super.processVersatile(fwd);
612 }
613
Pier Ventre70d53ba2016-11-17 22:26:29 -0800614 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
615 ModTunnelIdInstruction modTunnelIdInstruction,
616 OutputInstruction outputInstruction) {
617 TrafficTreatment.Builder flowTreatment;
618 TrafficSelector.Builder flowSelector;
619 // We divide the mpls actions from the tunnel actions. We need
620 // this to order the actions in the final treatment.
621 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
622 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
623 // The match of the forwarding objective is ready to go.
624 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
625 // We verify the tunnel id and mpls port are correct.
626 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
627 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
628 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
629 MPLS_TUNNEL_ID_MAX);
630 fail(forwardingObjective, ObjectiveError.BADPARAMS);
631 return Collections.emptySet();
632 }
633 // 0x0002XXXX is NNI interface.
634 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
635 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
636 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
637 mplsLogicalPort);
638 fail(forwardingObjective, ObjectiveError.BADPARAMS);
639 return Collections.emptySet();
640 }
641 // Next id cannot be null.
642 if (forwardingObjective.nextId() == null) {
643 log.error("Pw Versatile Forwarding Objective must contain nextId ",
644 forwardingObjective.nextId());
645 fail(forwardingObjective, ObjectiveError.BADPARAMS);
646 return Collections.emptySet();
647 }
648 // We retrieve the l2 interface group and point the mpls
649 // flow to this.
650 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
651 if (next == null) {
652 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
653 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
654 return Collections.emptySet();
655 }
656 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
657 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
658 if (group == null) {
659 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
660 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
661 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
662 return Collections.emptySet();
663 }
664 // We prepare the treatment for the mpls flow table.
665 // The order of the actions has to be strictly this
666 // according to the OFDPA 2.0 specification.
667 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
668 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800669 // Even though the specification and the xml/json files
670 // specify is allowed, the switch rejects the flow. In the
671 // OFDPA 3.0 EA0 version was necessary
672 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800673 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
674 flowTreatment.setTunnelId(tunnelId);
675 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
676 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
677 flowTreatment.transition(MPLS_TYPE_TABLE);
678 flowTreatment.deferred().group(group.id());
679 // We prepare the flow rule for the mpls table.
680 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
681 .fromApp(forwardingObjective.appId())
682 .withPriority(forwardingObjective.priority())
683 .forDevice(deviceId)
684 .withSelector(flowSelector.build())
685 .withTreatment(flowTreatment.build())
686 .makePermanent()
687 .forTable(MPLS_TABLE_1);
688 return Collections.singletonList(ruleBuilder.build());
689 }
690
Pier Ventre42287df2016-11-09 14:17:26 -0800691 /**
692 * Helper method to process the pw forwarding objectives.
693 *
694 * @param forwardingObjective the fw objective to process
695 * @return a singleton list of flow rule
696 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800697 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800698 // We retrieve the matching criteria for mpls l2 port.
699 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
700 .getCriterion(TUNNEL_ID);
701 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
702 .getCriterion(IN_PORT);
703 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
704 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
705 int mplsLogicalPort;
706 long tunnelId;
707 // Mpls tunnel ids according to the OFDPA manual have to be
708 // in the range [2^17-1, 2^16].
709 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
710 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
711 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
712 MPLS_TUNNEL_ID_MAX);
713 fail(forwardingObjective, ObjectiveError.BADPARAMS);
714 return Collections.emptySet();
715 }
716 // Port has not been null.
717 if (portCriterion == null) {
718 log.error("Pw Versatile Forwarding Objective must include port");
719 fail(forwardingObjective, ObjectiveError.BADPARAMS);
720 return Collections.emptySet();
721 }
722 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800723 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800724 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
725 portCriterion.port().toLong());
726 fail(forwardingObjective, ObjectiveError.BADPARAMS);
727 return Collections.emptySet();
728 }
729 mplsLogicalPort = ((int) portCriterion.port().toLong());
730 if (forwardingObjective.nextId() == null) {
731 log.error("Pw Versatile Forwarding Objective must contain nextId ",
732 forwardingObjective.nextId());
733 fail(forwardingObjective, ObjectiveError.BADPARAMS);
734 return Collections.emptySet();
735 }
736 // We don't expect a treatment.
737 if (forwardingObjective.treatment() != null &&
738 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
739 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
740 forwardingObjective.nextId());
741 fail(forwardingObjective, ObjectiveError.BADPARAMS);
742 return Collections.emptySet();
743 }
744 // We retrieve the l2 vpn group and point the mpls
745 // l2 port to this.
746 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
747 if (next == null) {
748 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
749 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
750 return Collections.emptySet();
751 }
752 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
753 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
754 if (group == null) {
755 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
756 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
757 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
758 return Collections.emptySet();
759 }
760 // We prepare the flow rule for the mpls l2 port table.
761 selector.matchTunnelId(tunnelId);
762 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
763 // This should not be necessary but without we receive an error
764 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
765 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
766 treatment.deferred().group(group.id());
767 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
768 .fromApp(forwardingObjective.appId())
769 .withPriority(MPLS_L2_PORT_PRIORITY)
770 .forDevice(deviceId)
771 .withSelector(selector.build())
772 .withTreatment(treatment.build())
773 .makePermanent()
774 .forTable(MPLS_L2_PORT_FLOW_TABLE);
775 return Collections.singletonList(ruleBuilder.build());
776 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800777
778 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800779 * Helper method for dividing the tunnel instructions from the mpls
780 * instructions.
781 *
782 * @param treatment the treatment to analyze
783 * @param mplsTreatment the mpls treatment builder
784 */
785 private void createMplsTreatment(TrafficTreatment treatment,
786 TrafficTreatment.Builder mplsTreatment) {
787
788 for (Instruction ins : treatment.allInstructions()) {
789
790 if (ins.type() == Instruction.Type.L2MODIFICATION) {
791 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
792 switch (l2ins.subtype()) {
793 // These instructions have to go in the mpls
794 // treatment.
795 case TUNNEL_ID:
796 break;
797 case DEC_MPLS_TTL:
798 case MPLS_POP:
799 mplsTreatment.add(ins);
800 break;
801 default:
802 log.warn("Driver does not handle this type of TrafficTreatment"
803 + " instruction in nextObjectives: {} - {}",
804 ins.type(), ins);
805 break;
806 }
807 } else if (ins.type() == Instruction.Type.OUTPUT) {
808 break;
809 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
810 // We support partially the l3 instructions.
811 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
812 switch (l3ins.subtype()) {
813 case TTL_IN:
814 mplsTreatment.add(ins);
815 break;
816 default:
817 log.warn("Driver does not handle this type of TrafficTreatment"
818 + " instruction in nextObjectives: {} - {}",
819 ins.type(), ins);
820 }
821
822 } else {
823 log.warn("Driver does not handle this type of TrafficTreatment"
824 + " instruction in nextObjectives: {} - {}",
825 ins.type(), ins);
826 }
827 }
828 }
pier9469f3e2019-04-17 17:05:08 +0200829
Charles Chanf9e98652016-09-07 16:54:23 -0700830}