blob: 4632a4f2a8fd36e10bef4f6e091d64e9af41160d [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;
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -070041import org.onosproject.net.flow.IndexTableId;
Pier Ventre42287df2016-11-09 14:17:26 -080042import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070044import org.onosproject.net.flow.criteria.Criteria;
Pier Ventre42287df2016-11-09 14:17:26 -080045import org.onosproject.net.flow.criteria.Criterion;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070046import org.onosproject.net.flow.criteria.EthCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070047import org.onosproject.net.flow.criteria.PortCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080048import org.onosproject.net.flow.criteria.TunnelIdCriterion;
Charles Chanf9e98652016-09-07 16:54:23 -070049import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre70d53ba2016-11-17 22:26:29 -080050import org.onosproject.net.flow.instructions.Instruction;
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -070051import org.onosproject.net.flow.instructions.Instructions;
Pier Ventre70d53ba2016-11-17 22:26:29 -080052import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080053import org.onosproject.net.flow.instructions.L2ModificationInstruction;
54import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Pier Ventre70d53ba2016-11-17 22:26:29 -080055import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre42287df2016-11-09 14:17:26 -080056import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chanf9e98652016-09-07 16:54:23 -070057import org.onosproject.net.flowobjective.ForwardingObjective;
Pier Ventre42287df2016-11-09 14:17:26 -080058import org.onosproject.net.flowobjective.ObjectiveError;
59import org.onosproject.net.group.Group;
60import org.onosproject.net.group.GroupKey;
61import org.slf4j.Logger;
Charles Chanf9e98652016-09-07 16:54:23 -070062
63import java.util.Collection;
Pier Ventre42287df2016-11-09 14:17:26 -080064import java.util.Collections;
65import java.util.Deque;
Charles Chanf9e98652016-09-07 16:54:23 -070066import java.util.List;
67
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070068import static org.onlab.packet.MacAddress.NONE;
pier9469f3e2019-04-17 17:05:08 +020069import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Pier Ventre42287df2016-11-09 14:17:26 -080070import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS;
Andrea Campanellad980c6d2018-04-30 11:48:55 +020071import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
72import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
73import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
74import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Pier Ventre42287df2016-11-09 14:17:26 -080075import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
76import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
77import static org.slf4j.LoggerFactory.getLogger;
78
Charles Chanf9e98652016-09-07 16:54:23 -070079/**
80 * Pipeliner for Broadcom OF-DPA 3.0 TTP.
81 */
82public class Ofdpa3Pipeline extends Ofdpa2Pipeline {
Pier Ventre42287df2016-11-09 14:17:26 -080083
84 private final Logger log = getLogger(getClass());
85
Charles Chanf9e98652016-09-07 16:54:23 -070086 @Override
Charles Chan40132b32017-01-22 00:19:37 -080087 protected void initDriverId() {
Charles Chanf9e98652016-09-07 16:54:23 -070088 driverId = coreService.registerApplication(
89 "org.onosproject.driver.Ofdpa3Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -080090 }
Charles Chanf9e98652016-09-07 16:54:23 -070091
Charles Chan40132b32017-01-22 00:19:37 -080092 @Override
93 protected void initGroupHander(PipelinerContext context) {
94 groupHandler = new Ofdpa3GroupHandler();
95 groupHandler.init(deviceId, context);
Charles Chanf9e98652016-09-07 16:54:23 -070096 }
97
98 @Override
Charles Chand1172632017-03-15 17:33:09 -070099 protected boolean requireVlanExtensions() {
100 return false;
101 }
102
103 @Override
Saurav Dasc568c342018-01-25 09:49:01 -0800104 protected boolean shouldRetry() {
105 return false;
106 }
107
108 @Override
Andrea Campanellad980c6d2018-04-30 11:48:55 +0200109 protected boolean supportsUnicastBlackHole() {
110 return true;
111 }
112
113 @Override
Pier Ventre42287df2016-11-09 14:17:26 -0800114 protected void processFilter(FilteringObjective filteringObjective,
115 boolean install,
116 ApplicationId applicationId) {
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700117
118 // Check if filter is intended for pseudowire
119 boolean isPw = isPseudowire(filteringObjective);
120
121 if (isPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800122 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
123 PortCriterion portCriterion;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700124
125 VlanIdCriterion innerVlanIdCriterion = null;
126 for (Criterion criterion : filteringObjective.conditions()) {
127 if (criterion.type() == INNER_VLAN_VID) {
128 innerVlanIdCriterion = (VlanIdCriterion) criterion;
129 break;
130 }
131 }
132
Pier Ventre42287df2016-11-09 14:17:26 -0800133 VlanIdCriterion outerVlanIdCriterion = null;
134 // We extract the expected port criterion in the key.
135 portCriterion = (PortCriterion) filteringObjective.key();
136 // We extract the outer vlan id criterion.
137 for (Criterion criterion : filteringObjective.conditions()) {
138 if (criterion.type() == VLAN_VID) {
139 outerVlanIdCriterion = (VlanIdCriterion) criterion;
140 break;
141 }
142 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700143
Pier Ventre42287df2016-11-09 14:17:26 -0800144 // We extract the tunnel id.
145 long tunnelId;
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700146 VlanId egressVlan;
147
Pier Ventre42287df2016-11-09 14:17:26 -0800148 if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700149 filteringObjective.meta().allInstructions().size() != 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800150 log.warn("Bad filtering objective from app: {}. Not"
151 + "processing filtering objective", applicationId);
152 fail(filteringObjective, ObjectiveError.BADPARAMS);
153 return;
154 } else if (filteringObjective.meta() != null &&
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700155 filteringObjective.meta().allInstructions().size() == 2 &&
156 filteringObjective.meta().allInstructions().get(0).type() == L2MODIFICATION &&
157 filteringObjective.meta().allInstructions().get(1).type() == L2MODIFICATION) {
158
Pier Ventre42287df2016-11-09 14:17:26 -0800159 L2ModificationInstruction l2instruction = (L2ModificationInstruction)
160 filteringObjective.meta().allInstructions().get(0);
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700161
Pier Ventre42287df2016-11-09 14:17:26 -0800162 if (l2instruction.subtype() != L2SubType.TUNNEL_ID) {
163 log.warn("Bad filtering objective from app: {}. Not"
164 + "processing filtering objective", applicationId);
165 fail(filteringObjective, ObjectiveError.BADPARAMS);
166 return;
167 } else {
168 tunnelId = ((ModTunnelIdInstruction) l2instruction).tunnelId();
169 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700170
171 L2ModificationInstruction vlanInstruction = (L2ModificationInstruction)
172 filteringObjective.meta().allInstructions().get(1);
173
174 if (vlanInstruction.subtype() != L2SubType.VLAN_ID) {
175 log.warn("Bad filtering objective from app: {}. Not"
176 + "processing filtering objective", applicationId);
177 fail(filteringObjective, ObjectiveError.BADPARAMS);
178 return;
179 } else {
180 egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) vlanInstruction).vlanId();
181 }
Pier Ventre42287df2016-11-09 14:17:26 -0800182 } else {
183 log.warn("Bad filtering objective from app: {}. Not"
184 + "processing filtering objective", applicationId);
185 fail(filteringObjective, ObjectiveError.BADPARAMS);
186 return;
187 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700188
Pier Ventre42287df2016-11-09 14:17:26 -0800189 // Mpls tunnel ids according to the OFDPA manual have to be
190 // in the range [2^17-1, 2^16].
191 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelId;
192 // Sanity check for the filtering objective.
193 if (portCriterion == null ||
194 outerVlanIdCriterion == null ||
195 tunnelId > MPLS_TUNNEL_ID_MAX) {
196 log.warn("Bad filtering objective from app: {}. Not"
197 + "processing filtering objective", applicationId);
198 fail(filteringObjective, ObjectiveError.BADPARAMS);
199 return;
200 }
201 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800202 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Sivachidambaram Subramaniana0efdcc2017-06-22 05:26:46 +0530203 log.error("Filtering Objective invalid logical port {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800204 portCriterion.port().toLong());
205 fail(filteringObjective, ObjectiveError.BADPARAMS);
206 return;
207 }
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700208
Pier Ventre42287df2016-11-09 14:17:26 -0800209 // We create the flows.
210 List<FlowRule> pwRules = processPwFilter(portCriterion,
211 innerVlanIdCriterion,
212 outerVlanIdCriterion,
213 tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700214 applicationId,
215 egressVlan
Pier Ventre42287df2016-11-09 14:17:26 -0800216 );
217 // We tag the flow for adding or for removing.
218 for (FlowRule pwRule : pwRules) {
219 log.debug("adding filtering rule in VLAN tables: {} for dev: {}",
220 pwRule, deviceId);
221 ops = install ? ops.add(pwRule) : ops.remove(pwRule);
222 }
223 // We push the filtering rules for the pw.
224 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
225 @Override
226 public void onSuccess(FlowRuleOperations ops) {
227 log.info("Applied {} filtering rules in device {}",
228 ops.stages().get(0).size(), deviceId);
229 pass(filteringObjective);
230 }
231
232 @Override
233 public void onError(FlowRuleOperations ops) {
234 log.info("Failed to apply all filtering rules in dev {}", deviceId);
235 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
236 }
237 }));
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700238 } else if (isDoubleTagged(filteringObjective)) {
239 processDoubleTaggedFilter(filteringObjective, install, applicationId);
240 } else {
241 // If it is not a pseudo wire flow or double-tagged filter, we fall back
242 // to the OFDPA 2.0 pipeline.
243 super.processFilter(filteringObjective, install, applicationId);
244 }
245 }
Pier Ventre42287df2016-11-09 14:17:26 -0800246
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700247 /**
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -0700248 *
249 * @param meta The metadata instruction of this treatment
250 * @return True if we should remove both VLAN and Mac Termination flow entries.
251 * This is only used for double tagged hosts.
252 */
253 public boolean shouldRemoveDoubleTagged(Instruction meta) {
254
255 Instructions.MetadataInstruction metadataInstruction = (Instructions.MetadataInstruction) meta;
256 return ((metadataInstruction.metadata() & metadataInstruction.metadataMask()) == 1);
257 }
258
259 /**
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700260 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
261 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
262 *
263 * @param filteringObjective the filtering objective
264 * @param install true to add, false to remove
265 * @param applicationId for application programming this filter
266 */
267 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
268 boolean install,
269 ApplicationId applicationId) {
270 PortCriterion portCriterion = null;
271 EthCriterion ethCriterion = null;
272 VlanIdCriterion innervidCriterion = null;
273 VlanIdCriterion outerVidCriterion = null;
274 boolean popVlan = false;
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -0700275 boolean removeDoubleTagged = true;
276 if (filteringObjective.meta().writeMetadata() != null) {
277 removeDoubleTagged = shouldRemoveDoubleTagged(filteringObjective.meta().writeMetadata());
278 }
279 log.info("HERE , removeDoubleTagged {}", removeDoubleTagged);
280
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700281 TrafficTreatment meta = filteringObjective.meta();
282 if (!filteringObjective.key().equals(Criteria.dummy()) &&
283 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
284 portCriterion = (PortCriterion) filteringObjective.key();
285 }
286 if (portCriterion == null) {
287 log.warn("No IN_PORT defined in filtering objective from app: {}" +
288 "Failed to program VLAN tables.", applicationId);
289 return;
290 } else {
291 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
292 portCriterion.port());
293 }
294
295 // meta should have only one instruction, popVlan.
296 if (meta != null && meta.allInstructions().size() == 1) {
297 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
298 if (l2Inst.subtype().equals(L2SubType.VLAN_POP)) {
299 popVlan = true;
300 } else {
301 log.warn("Filtering objective can have only VLAN_POP instruction.");
302 return;
303 }
304 } else {
305 log.warn("Filtering objective should have one instruction.");
Pier Ventre42287df2016-11-09 14:17:26 -0800306 return;
307 }
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700308
309 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
310 for (Criterion criterion : filteringObjective.conditions()) {
311 switch (criterion.type()) {
312 case ETH_DST:
313 case ETH_DST_MASKED:
314 ethCriterion = (EthCriterion) criterion;
315 break;
316 case VLAN_VID:
Daniele Morofa382c22019-07-12 17:58:54 -0700317 outerVidCriterion = (VlanIdCriterion) criterion;
318 break;
319 case INNER_VLAN_VID:
320 innervidCriterion = (VlanIdCriterion) criterion;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700321 break;
322 default:
323 log.warn("Unsupported filter {}", criterion);
324 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
325 return;
326 }
327 }
328
329 if (innervidCriterion == null || outerVidCriterion == null) {
330 log.warn("filtering objective should have two vidCriterion.");
331 return;
332 }
333
334 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
335 // NOTE: it is possible that a filtering objective only has vidCriterion
336 log.warn("filtering objective missing dstMac, cannot program TMAC table");
337 return;
338 } else {
339 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
340 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
341 innervidCriterion.vlanId(), unicastMac,
342 applicationId);
343 for (List<FlowRule> flowRules : allStages) {
344 log.trace("Starting a new flow rule stage for TMAC table flow");
345 ops.newStage();
346
347 for (FlowRule flowRule : flowRules) {
348 log.trace("{} flow rules in TMAC table: {} for dev: {}",
349 (install) ? "adding" : "removing", flowRules, deviceId);
350 if (install) {
351 ops = ops.add(flowRule);
352 } else {
353 // NOTE: Only remove TMAC flow when there is no more enabled port within the
354 // same VLAN on this device if TMAC doesn't support matching on in_port.
355 if (matchInPortTmacTable()
356 || (filteringObjective.meta() != null
357 && filteringObjective.meta().clearedDeferred())) {
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -0700358
359 // if metadata instruction not null and not removeDoubleTagged move on.
360 if ((filteringObjective.meta().writeMetadata() != null) && (!removeDoubleTagged)) {
361 log.info("Skipping removal of tmac rule for device {}", deviceId);
362 continue;
363 } else {
364 ops = ops.remove(flowRule);
365 }
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700366 } else {
367 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
368 }
369 }
370 }
371 }
372 }
373
374 List<FlowRule> rules;
375 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
376 outerVidCriterion, popVlan, applicationId);
377 for (FlowRule flowRule : rules) {
378 log.trace("{} flow rule in VLAN table: {} for dev: {}",
379 (install) ? "adding" : "removing", flowRule, deviceId);
Andreas Pantelopoulos2fef3112018-06-28 17:06:14 -0700380 // if context is remove, table is vlan_1 and removeDoubleTagged is false, continue.
381 if (flowRule.table().equals(IndexTableId.of(VLAN_TABLE)) &&
382 !removeDoubleTagged && !install) {
383 log.info("Skipping removal of vlan table rule for now!");
384 continue;
385 }
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700386 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
387 }
388
389 // apply filtering flow rules
390 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
391 @Override
392 public void onSuccess(FlowRuleOperations ops) {
393 log.debug("Applied {} filtering rules in device {}",
394 ops.stages().get(0).size(), deviceId);
395 pass(filteringObjective);
396 }
397
398 @Override
399 public void onError(FlowRuleOperations ops) {
400 log.info("Failed to apply all filtering rules in dev {}", deviceId);
401 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
402 }
403 }));
404
405 }
406 /**
407 * Internal implementation of processDoubleVlanIdFilter.
408 *
409 * @param portCriterion port on device for which this filter is programmed
410 * @param innerVidCriterion inner vlan
411 * @param outerVidCriterion outer vlan
412 * @param popVlan true if outer vlan header needs to be removed
413 * @param applicationId for application programming this filter
414 * @return flow rules for port-vlan filters
415 */
416 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
417 VlanIdCriterion innerVidCriterion,
418 VlanIdCriterion outerVidCriterion,
419 boolean popVlan,
420 ApplicationId applicationId) {
421 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
422 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
423 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
424 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
425
426 VlanId outerVlanId = outerVidCriterion.vlanId();
427 VlanId innerVlanId = innerVidCriterion.vlanId();
428 PortNumber portNumber = portCriterion.port();
429 // Check arguments
430 if (PortNumber.ALL.equals(portNumber)
431 || outerVlanId.equals(VlanId.NONE)
432 || innerVlanId.equals(VlanId.NONE)) {
433 log.warn("Incomplete Filtering Objective. " +
434 "VLAN Table cannot be programmed for {}", deviceId);
435 return ImmutableList.of();
436 } else {
437 outerSelector.matchInPort(portNumber);
438 innerSelector.matchInPort(portNumber);
439 outerTreatment.transition(VLAN_1_TABLE);
440 innerTreatment.transition(TMAC_TABLE);
441
442 if (requireVlanExtensions()) {
443 OfdpaMatchVlanVid ofdpaOuterMatchVlanVid = new OfdpaMatchVlanVid(outerVlanId);
444 outerSelector.extension(ofdpaOuterMatchVlanVid, deviceId);
445 OfdpaMatchVlanVid ofdpaInnerMatchVlanVid = new OfdpaMatchVlanVid(innerVlanId);
446 innerSelector.extension(ofdpaInnerMatchVlanVid, deviceId);
447 } else {
448 outerSelector.matchVlanId(outerVlanId);
449 innerSelector.matchVlanId(innerVlanId);
450 }
451
452 innerSelector.extension(new Ofdpa3MatchOvid(outerVlanId), deviceId);
453 outerTreatment.extension(new Ofdpa3SetOvid(outerVlanId), deviceId);
454 if (popVlan) {
455 outerTreatment.popVlan();
456 }
457 }
458 FlowRule outerRule = DefaultFlowRule.builder()
459 .forDevice(deviceId)
460 .withSelector(outerSelector.build())
461 .withTreatment(outerTreatment.build())
462 .withPriority(DEFAULT_PRIORITY)
463 .fromApp(applicationId)
464 .makePermanent()
465 .forTable(VLAN_TABLE)
466 .build();
467 FlowRule innerRule = DefaultFlowRule.builder()
468 .forDevice(deviceId)
469 .withSelector(innerSelector.build())
470 .withTreatment(innerTreatment.build())
471 .withPriority(DEFAULT_PRIORITY)
472 .fromApp(applicationId)
473 .makePermanent()
474 .forTable(VLAN_1_TABLE)
475 .build();
476
477 return ImmutableList.of(outerRule, innerRule);
478 }
479
480 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800481 * Method to process the pw related filtering objectives.
482 *
483 * @param portCriterion the in port match
484 * @param innerVlanIdCriterion the inner vlan match
485 * @param outerVlanIdCriterion the outer vlan match
486 * @param tunnelId the tunnel id
487 * @param applicationId the application id
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700488 * @param egressVlan the vlan to modify, was passed in metadata
Pier Ventre42287df2016-11-09 14:17:26 -0800489 * @return a list of flow rules to install
490 */
491 private List<FlowRule> processPwFilter(PortCriterion portCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700492 VlanIdCriterion innerVlanIdCriterion,
493 VlanIdCriterion outerVlanIdCriterion,
494 long tunnelId,
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700495 ApplicationId applicationId,
496 VlanId egressVlan) {
497
Pier Ventre42287df2016-11-09 14:17:26 -0800498 FlowRule vlan1FlowRule;
499 int mplsLogicalPort = ((int) portCriterion.port().toLong());
500 // We have to match on the inner vlan and outer vlan at the same time.
501 // Ofdpa supports this through the OVID meta-data type.
Pier Ventre42287df2016-11-09 14:17:26 -0800502
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700503 ImmutableList<FlowRule> toReturn;
504
505 // pseudowire configured with double tagged vlans
506 if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
507 && !(outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
508
509 log.info("Installing filter objective for double tagged CE for tunnel {}", tunnelId);
510
511 TrafficSelector.Builder vlan1Selector = DefaultTrafficSelector.builder()
512 .matchInPort(portCriterion.port())
513 .matchVlanId(innerVlanIdCriterion.vlanId())
514 .extension(new Ofdpa3MatchOvid(outerVlanIdCriterion.vlanId()), deviceId);
515 // TODO understand for the future how to manage the vlan rewrite.
516 TrafficTreatment.Builder vlan1Treatment = DefaultTrafficTreatment.builder()
517 .pushVlan()
518 .setVlanId(egressVlan)
519 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
520 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
521 .setTunnelId(tunnelId)
522 .transition(MPLS_L2_PORT_FLOW_TABLE);
523 vlan1FlowRule = DefaultFlowRule.builder()
524 .forDevice(deviceId)
525 .withSelector(vlan1Selector.build())
526 .withTreatment(vlan1Treatment.build())
527 .withPriority(DEFAULT_PRIORITY)
528 .fromApp(applicationId)
529 .makePermanent()
530 .forTable(VLAN_1_TABLE)
531 .build();
532 // Finally we create the flow rule for the vlan table.
533 FlowRule vlanFlowRule;
534 // We have to match on the outer vlan.
535 TrafficSelector.Builder vlanSelector = DefaultTrafficSelector.builder()
536 .matchInPort(portCriterion.port())
537 .matchVlanId(outerVlanIdCriterion.vlanId());
538 // TODO understand for the future how to manage the vlan rewrite.
539 TrafficTreatment.Builder vlanTreatment = DefaultTrafficTreatment.builder()
540 .popVlan()
541 .extension(new Ofdpa3SetOvid(outerVlanIdCriterion.vlanId()), deviceId)
542 .transition(VLAN_1_TABLE);
543 vlanFlowRule = DefaultFlowRule.builder()
544 .forDevice(deviceId)
545 .withSelector(vlanSelector.build())
546 .withTreatment(vlanTreatment.build())
547 .withPriority(DEFAULT_PRIORITY)
548 .fromApp(applicationId)
549 .makePermanent()
550 .forTable(VLAN_TABLE)
551 .build();
552
553 return ImmutableList.of(vlan1FlowRule, vlanFlowRule);
554 } else if (!(innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
555 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
556
557 log.info("Installing filter objective for single tagged CE for tunnel {}", tunnelId);
558
559 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
560 .matchInPort(portCriterion.port())
561 .matchVlanId(innerVlanIdCriterion.vlanId());
562
563 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
Charles Chanf45552d2018-07-13 18:08:33 -0700564 // FIXME PW VLAN translation is not supported on Dune
565 // Need to explore doing that in egress table later if there is a requirement
566 // .setVlanId(egressVlan)
Andreas Pantelopoulos27532cd2017-10-23 12:18:25 -0700567 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
568 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
569 .setTunnelId(tunnelId)
570 .transition(MPLS_L2_PORT_FLOW_TABLE);
571
572 vlan1FlowRule = DefaultFlowRule.builder()
573 .forDevice(deviceId)
574 .withSelector(singleVlanSelector.build())
575 .withTreatment(singleVlanTreatment.build())
576 .withPriority(DEFAULT_PRIORITY)
577 .fromApp(applicationId)
578 .makePermanent()
579 .forTable(VLAN_TABLE)
580 .build();
581
582 return ImmutableList.of(vlan1FlowRule);
583 } else if ((innerVlanIdCriterion.vlanId().equals(VlanId.NONE))
584 && (outerVlanIdCriterion.vlanId().equals(VlanId.NONE))) {
585
586 TrafficSelector.Builder singleVlanSelector = DefaultTrafficSelector.builder()
587 .matchInPort(portCriterion.port())
588 .matchVlanId(innerVlanIdCriterion.vlanId());
589
590 TrafficTreatment.Builder singleVlanTreatment = DefaultTrafficTreatment.builder()
591 .extension(new Ofdpa3SetMplsType(VPWS), deviceId)
592 .extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId)
593 .setTunnelId(tunnelId)
594 .transition(MPLS_L2_PORT_FLOW_TABLE);
595
596 vlan1FlowRule = DefaultFlowRule.builder()
597 .forDevice(deviceId)
598 .withSelector(singleVlanSelector.build())
599 .withTreatment(singleVlanTreatment.build())
600 .withPriority(DEFAULT_PRIORITY)
601 .fromApp(applicationId)
602 .makePermanent()
603 .forTable(VLAN_TABLE)
604 .build();
605
606 return ImmutableList.of(vlan1FlowRule);
607 } else {
608 // failure...
609 return Collections.emptyList();
610 }
Pier Ventre42287df2016-11-09 14:17:26 -0800611 }
612
613 @Override
Charles Chanf9e98652016-09-07 16:54:23 -0700614 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Dasa4020382018-02-14 14:14:54 -0800615 // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
616 // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
617 if (isNotMplsBos(fwd.selector())
618 || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
Pier Ventre140a8942016-11-02 07:26:38 -0700619 return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
620 }
Saurav Dasa4020382018-02-14 14:14:54 -0800621 // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
Pier Ventre140a8942016-11-02 07:26:38 -0700622 return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700623 }
Pier Ventre42287df2016-11-09 14:17:26 -0800624
625 @Override
626 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
627 // We use the tunnel id to identify pw related flows.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800628 // Looking for the fwd objective of the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800629 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
630 .getCriterion(TUNNEL_ID);
631 if (tunnelIdCriterion != null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800632 return processInitPwVersatile(fwd);
633 }
634 // Looking for the fwd objective of the termination.
635 ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
636 OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
637 if (modTunnelIdInstruction != null && outputInstruction != null) {
638 return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
Pier Ventre42287df2016-11-09 14:17:26 -0800639 }
640 // If it is not a pseudo wire flow we fall back
641 // to the OFDPA 2.0 pipeline.
642 return super.processVersatile(fwd);
643 }
644
Pier Ventre70d53ba2016-11-17 22:26:29 -0800645 private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
646 ModTunnelIdInstruction modTunnelIdInstruction,
647 OutputInstruction outputInstruction) {
648 TrafficTreatment.Builder flowTreatment;
649 TrafficSelector.Builder flowSelector;
650 // We divide the mpls actions from the tunnel actions. We need
651 // this to order the actions in the final treatment.
652 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
653 createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
654 // The match of the forwarding objective is ready to go.
655 flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
656 // We verify the tunnel id and mpls port are correct.
657 long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
658 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
659 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
660 MPLS_TUNNEL_ID_MAX);
661 fail(forwardingObjective, ObjectiveError.BADPARAMS);
662 return Collections.emptySet();
663 }
664 // 0x0002XXXX is NNI interface.
665 int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
666 if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
667 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
668 mplsLogicalPort);
669 fail(forwardingObjective, ObjectiveError.BADPARAMS);
670 return Collections.emptySet();
671 }
672 // Next id cannot be null.
673 if (forwardingObjective.nextId() == null) {
674 log.error("Pw Versatile Forwarding Objective must contain nextId ",
675 forwardingObjective.nextId());
676 fail(forwardingObjective, ObjectiveError.BADPARAMS);
677 return Collections.emptySet();
678 }
679 // We retrieve the l2 interface group and point the mpls
680 // flow to this.
681 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
682 if (next == null) {
683 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
684 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
685 return Collections.emptySet();
686 }
687 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
688 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
689 if (group == null) {
690 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
691 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
692 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
693 return Collections.emptySet();
694 }
695 // We prepare the treatment for the mpls flow table.
696 // The order of the actions has to be strictly this
697 // according to the OFDPA 2.0 specification.
698 flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
699 flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
Pier Luigi3bfe32c2017-01-30 09:47:36 -0800700 // Even though the specification and the xml/json files
701 // specify is allowed, the switch rejects the flow. In the
702 // OFDPA 3.0 EA0 version was necessary
703 //flowTreatment.popVlan();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800704 flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
705 flowTreatment.setTunnelId(tunnelId);
706 flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
707 flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
708 flowTreatment.transition(MPLS_TYPE_TABLE);
709 flowTreatment.deferred().group(group.id());
710 // We prepare the flow rule for the mpls table.
711 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
712 .fromApp(forwardingObjective.appId())
713 .withPriority(forwardingObjective.priority())
714 .forDevice(deviceId)
715 .withSelector(flowSelector.build())
716 .withTreatment(flowTreatment.build())
717 .makePermanent()
718 .forTable(MPLS_TABLE_1);
719 return Collections.singletonList(ruleBuilder.build());
720 }
721
Pier Ventre42287df2016-11-09 14:17:26 -0800722 /**
723 * Helper method to process the pw forwarding objectives.
724 *
725 * @param forwardingObjective the fw objective to process
726 * @return a singleton list of flow rule
727 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800728 private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
Pier Ventre42287df2016-11-09 14:17:26 -0800729 // We retrieve the matching criteria for mpls l2 port.
730 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
731 .getCriterion(TUNNEL_ID);
732 PortCriterion portCriterion = (PortCriterion) forwardingObjective.selector()
733 .getCriterion(IN_PORT);
734 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
735 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
736 int mplsLogicalPort;
737 long tunnelId;
738 // Mpls tunnel ids according to the OFDPA manual have to be
739 // in the range [2^17-1, 2^16].
740 tunnelId = MPLS_TUNNEL_ID_BASE | tunnelIdCriterion.tunnelId();
741 if (tunnelId > MPLS_TUNNEL_ID_MAX) {
742 log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
743 MPLS_TUNNEL_ID_MAX);
744 fail(forwardingObjective, ObjectiveError.BADPARAMS);
745 return Collections.emptySet();
746 }
747 // Port has not been null.
748 if (portCriterion == null) {
749 log.error("Pw Versatile Forwarding Objective must include port");
750 fail(forwardingObjective, ObjectiveError.BADPARAMS);
751 return Collections.emptySet();
752 }
753 // 0x0000XXXX is UNI interface.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800754 if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
Pier Ventre42287df2016-11-09 14:17:26 -0800755 log.error("Pw Versatile Forwarding Objective invalid logical port {}",
756 portCriterion.port().toLong());
757 fail(forwardingObjective, ObjectiveError.BADPARAMS);
758 return Collections.emptySet();
759 }
760 mplsLogicalPort = ((int) portCriterion.port().toLong());
761 if (forwardingObjective.nextId() == null) {
762 log.error("Pw Versatile Forwarding Objective must contain nextId ",
763 forwardingObjective.nextId());
764 fail(forwardingObjective, ObjectiveError.BADPARAMS);
765 return Collections.emptySet();
766 }
767 // We don't expect a treatment.
768 if (forwardingObjective.treatment() != null &&
769 !forwardingObjective.treatment().equals(DefaultTrafficTreatment.emptyTreatment())) {
770 log.error("Pw Versatile Forwarding Objective cannot contain a treatment ",
771 forwardingObjective.nextId());
772 fail(forwardingObjective, ObjectiveError.BADPARAMS);
773 return Collections.emptySet();
774 }
775 // We retrieve the l2 vpn group and point the mpls
776 // l2 port to this.
777 NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
778 if (next == null) {
779 log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
780 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
781 return Collections.emptySet();
782 }
783 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
784 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
785 if (group == null) {
786 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
787 gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
788 fail(forwardingObjective, ObjectiveError.GROUPMISSING);
789 return Collections.emptySet();
790 }
791 // We prepare the flow rule for the mpls l2 port table.
792 selector.matchTunnelId(tunnelId);
793 selector.extension(new Ofdpa3MatchMplsL2Port(mplsLogicalPort), deviceId);
794 // This should not be necessary but without we receive an error
795 treatment.extension(new Ofdpa3SetQosIndex(0), deviceId);
796 treatment.transition(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE);
797 treatment.deferred().group(group.id());
798 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
799 .fromApp(forwardingObjective.appId())
800 .withPriority(MPLS_L2_PORT_PRIORITY)
801 .forDevice(deviceId)
802 .withSelector(selector.build())
803 .withTreatment(treatment.build())
804 .makePermanent()
805 .forTable(MPLS_L2_PORT_FLOW_TABLE);
806 return Collections.singletonList(ruleBuilder.build());
807 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800808
809 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800810 * Helper method for dividing the tunnel instructions from the mpls
811 * instructions.
812 *
813 * @param treatment the treatment to analyze
814 * @param mplsTreatment the mpls treatment builder
815 */
816 private void createMplsTreatment(TrafficTreatment treatment,
817 TrafficTreatment.Builder mplsTreatment) {
818
819 for (Instruction ins : treatment.allInstructions()) {
820
821 if (ins.type() == Instruction.Type.L2MODIFICATION) {
822 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
823 switch (l2ins.subtype()) {
824 // These instructions have to go in the mpls
825 // treatment.
826 case TUNNEL_ID:
827 break;
828 case DEC_MPLS_TTL:
829 case MPLS_POP:
830 mplsTreatment.add(ins);
831 break;
832 default:
833 log.warn("Driver does not handle this type of TrafficTreatment"
834 + " instruction in nextObjectives: {} - {}",
835 ins.type(), ins);
836 break;
837 }
838 } else if (ins.type() == Instruction.Type.OUTPUT) {
839 break;
840 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
841 // We support partially the l3 instructions.
842 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
843 switch (l3ins.subtype()) {
844 case TTL_IN:
845 mplsTreatment.add(ins);
846 break;
847 default:
848 log.warn("Driver does not handle this type of TrafficTreatment"
849 + " instruction in nextObjectives: {} - {}",
850 ins.type(), ins);
851 }
852
853 } else {
854 log.warn("Driver does not handle this type of TrafficTreatment"
855 + " instruction in nextObjectives: {} - {}",
856 ins.type(), ins);
857 }
858 }
859 }
pier9469f3e2019-04-17 17:05:08 +0200860
Charles Chanf9e98652016-09-07 16:54:23 -0700861}