blob: 387230b5f2186568d4565b99a6f4c9b5874524f2 [file] [log] [blame]
Carmelo Casconeb5324e72018-11-25 02:26:32 -08001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070017package org.onosproject.pipelines.fabric.impl.behaviour.pipeliner;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080018
19import com.google.common.collect.Lists;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.flow.DefaultTrafficSelector;
26import org.onosproject.net.flow.DefaultTrafficTreatment;
27import org.onosproject.net.flow.FlowRule;
28import org.onosproject.net.flow.TrafficSelector;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.flow.criteria.Criterion;
31import org.onosproject.net.flow.criteria.EthCriterion;
32import org.onosproject.net.flow.criteria.PiCriterion;
33import org.onosproject.net.flow.criteria.PortCriterion;
34import org.onosproject.net.flow.criteria.VlanIdCriterion;
Wailok Shumfb7e7872021-06-18 17:30:08 +080035import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
36import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080037import org.onosproject.net.flowobjective.FilteringObjective;
Daniele Moro41ec1482019-10-29 18:45:33 -070038import org.onosproject.net.flowobjective.Objective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080039import org.onosproject.net.flowobjective.ObjectiveError;
Wailok Shumfb7e7872021-06-18 17:30:08 +080040import org.onosproject.net.pi.model.PiTableId;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080041import org.onosproject.net.pi.runtime.PiAction;
42import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070043import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080044import org.onosproject.pipelines.fabric.FabricConstants;
Daniele Moro41ec1482019-10-29 18:45:33 -070045import org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080046
47import java.util.Collection;
48import java.util.List;
49
50import static java.lang.String.format;
Daniele Moro41ec1482019-10-29 18:45:33 -070051import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
52import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Wailok Shumfb7e7872021-06-18 17:30:08 +080053import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
54import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
55import static org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
pierventre4d29d3c2021-08-27 17:20:00 +020056import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES;
Wailok Shumfb7e7872021-06-18 17:30:08 +080057import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ETH_TYPE_EXACT_MASK;
58import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_MPLS;
59import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV4_ROUTING;
60import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV6_ROUTING;
pierventre4d29d3c2021-08-27 17:20:00 +020061import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.INTERFACE_CONFIG_UPDATE;
Wailok Shumfb7e7872021-06-18 17:30:08 +080062import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ONE;
Wailok Shumfb7e7872021-06-18 17:30:08 +080063import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ZERO;
pierventre4d29d3c2021-08-27 17:20:00 +020064import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.isSrMetadataSet;
65import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.isValidSrMetadata;
66import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.portType;
Wailok Shumfb7e7872021-06-18 17:30:08 +080067import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2InstructionOrFail;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070068import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
Wailok Shumfb7e7872021-06-18 17:30:08 +080069import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
70
Carmelo Casconeb5324e72018-11-25 02:26:32 -080071/**
72 * ObjectiveTranslator implementation for FilteringObjective.
73 */
74class FilteringObjectiveTranslator
75 extends AbstractObjectiveTranslator<FilteringObjective> {
76
Carmelo Casconeb5324e72018-11-25 02:26:32 -080077 private static final PiAction DENY = PiAction.builder()
78 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
79 .build();
80
Carmelo Casconeb5324e72018-11-25 02:26:32 -080081 FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
82 super(deviceId, capabilities);
83 }
84
85 @Override
86 public ObjectiveTranslation doTranslate(FilteringObjective obj)
87 throws FabricPipelinerException {
88
89 final ObjectiveTranslation.Builder resultBuilder =
90 ObjectiveTranslation.builder();
91
92 if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
93 throw new FabricPipelinerException(
94 format("Unsupported or missing filtering key: key=%s", obj.key()),
95 ObjectiveError.BADPARAMS);
96 }
97
pierventre4d29d3c2021-08-27 17:20:00 +020098 if (!isValidSrMetadata(obj)) {
99 throw new FabricPipelinerException(
100 format("Unsupported metadata configuration: metadata=%s", obj.meta()),
101 ObjectiveError.BADPARAMS);
102 }
103
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800104 final PortCriterion inPort = (PortCriterion) obj.key();
Daniele Moro7c3a0022019-07-12 13:38:34 -0700105
106 final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800107 obj.conditions(), Criterion.Type.VLAN_VID);
Daniele Moro7c3a0022019-07-12 13:38:34 -0700108 final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
109 obj.conditions(), Criterion.Type.INNER_VLAN_VID);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800110 final EthCriterion ethDst = (EthCriterion) criterion(
111 obj.conditions(), Criterion.Type.ETH_DST);
112 final EthCriterion ethDstMasked = (EthCriterion) criterion(
113 obj.conditions(), Criterion.Type.ETH_DST_MASKED);
114
Daniele Moro7c3a0022019-07-12 13:38:34 -0700115 ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
pierventre167d4482021-01-08 17:35:47 +0100116 if (shouldModifyFwdClassifierTable(obj)) {
Daniele Moro41ec1482019-10-29 18:45:33 -0700117 fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
118 } else {
119 log.debug("Skipping fwd classifier rules for device {}.", deviceId);
120 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800121 return resultBuilder.build();
122 }
123
pierventre167d4482021-01-08 17:35:47 +0100124 private boolean shouldModifyFwdClassifierTable(FilteringObjective obj) {
Daniele Moro41ec1482019-10-29 18:45:33 -0700125 // NOTE: in fabric pipeline the forwarding classifier acts similarly
126 // to the TMAC table of OFDPA that matches on input port.
pierventre167d4482021-01-08 17:35:47 +0100127 // NOTE: that SR signals when it is a port update event by not setting
128 // the INTERFACE_CONFIG_UPDATE metadata. During the INTERFACE_CONFIG_UPDATE
129 // there is no need to add/remove rules in the fwd_classifier table.
130 // NOTE: that in scenarios like (T, N) -> T where we remove only the native
131 // VLAN there is not an ADD following the remove.
Daniele Moro41ec1482019-10-29 18:45:33 -0700132
pierventre167d4482021-01-08 17:35:47 +0100133 // Forwarding classifier rules should be added/removed to translation when:
134 // - the operation is ADD
135 // AND it is a port update event (ADD or UPDATE) OR
136 // - it doesn't refer to double tagged traffic
137 // AND it is a port REMOVE event OR
Daniele Moro41ec1482019-10-29 18:45:33 -0700138 // - it refers to double tagged traffic
139 // and SR is triggering the removal of forwarding classifier rules.
pierventre4d29d3c2021-08-27 17:20:00 +0200140 return (obj.op() == Objective.Operation.ADD && !isSrMetadataSet(obj, INTERFACE_CONFIG_UPDATE)) ||
141 (!isDoubleTagged(obj) && !isSrMetadataSet(obj, INTERFACE_CONFIG_UPDATE)) ||
142 (isDoubleTagged(obj) && isSrMetadataSet(obj, CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES));
Daniele Moro41ec1482019-10-29 18:45:33 -0700143 }
144
145 private boolean isDoubleTagged(FilteringObjective obj) {
146 return obj.meta() != null &&
Wailok Shumfb7e7872021-06-18 17:30:08 +0800147 FabricUtils.l2Instruction(obj.meta(), L2SubType.VLAN_POP) != null &&
Daniele Moro41ec1482019-10-29 18:45:33 -0700148 FabricUtils.criterion(obj.conditions(), VLAN_VID) != null &&
149 FabricUtils.criterion(obj.conditions(), INNER_VLAN_VID) != null;
150 }
151
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800152 private void ingressPortVlanRule(
153 FilteringObjective obj,
154 Criterion inPortCriterion,
Daniele Moro7c3a0022019-07-12 13:38:34 -0700155 VlanIdCriterion outerVlanCriterion,
156 VlanIdCriterion innerVlanCriterion,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800157 ObjectiveTranslation.Builder resultBuilder)
158 throws FabricPipelinerException {
159
Daniele Moro7c3a0022019-07-12 13:38:34 -0700160 final boolean outerVlanValid = outerVlanCriterion != null
161 && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
162 final boolean innerVlanValid = innerVlanCriterion != null
163 && !innerVlanCriterion.vlanId().equals(VlanId.NONE);
164
Daniele Morob3d199b2019-11-01 14:01:46 -0700165 if (innerVlanValid && !capabilities.supportDoubleVlanTerm()) {
166 throw new FabricPipelinerException(
167 "Found 2 VLAN IDs, but the pipeline does not support double VLAN termination",
168 ObjectiveError.UNSUPPORTED);
169 }
170
Daniele Moro7c3a0022019-07-12 13:38:34 -0700171 final PiCriterion piCriterion = PiCriterion.builder()
172 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
173 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800174
175 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
176 .add(inPortCriterion)
Daniele Moro7c3a0022019-07-12 13:38:34 -0700177 .add(piCriterion);
178 if (outerVlanValid) {
179 selector.add(outerVlanCriterion);
180 }
181 if (innerVlanValid) {
182 selector.add(innerVlanCriterion);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800183 }
184
Wailok Shumfb7e7872021-06-18 17:30:08 +0800185 final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800186 if (obj.type().equals(FilteringObjective.Type.DENY)) {
Wailok Shumfb7e7872021-06-18 17:30:08 +0800187 treatmentBuilder.piTableAction(DENY);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800188 } else {
pierventre4d29d3c2021-08-27 17:20:00 +0200189 // FIXME SDFAB-52 to complete the work on metadata
190 Byte portType = portType(obj);
191 if (portType == null) {
192 throw new FabricPipelinerException(
193 format("Unsupported port_type configuration: metadata=%s", obj.meta()),
194 ObjectiveError.BADPARAMS);
Wailok Shumfb7e7872021-06-18 17:30:08 +0800195 }
196 try {
197 treatmentBuilder.piTableAction(mapFilteringTreatment(obj.meta(),
198 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN, portType));
199 } catch (PiInterpreterException ex) {
200 throw new FabricPipelinerException(format("Unable to map treatment for table '%s': %s",
201 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
202 ex.getMessage()), ObjectiveError.UNSUPPORTED);
203 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800204 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800205 resultBuilder.addFlowRule(flowRule(
206 obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
Wailok Shumfb7e7872021-06-18 17:30:08 +0800207 selector.build(), treatmentBuilder.build()));
208 }
209
210 private PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId, byte portType)
211 throws PiInterpreterException {
212 if (treatment == null) {
213 treatment = DefaultTrafficTreatment.emptyTreatment();
214 }
215 // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
216 if (isFilteringNoAction(treatment) || isFilteringPopAction(treatment)) {
217 // Permit action if table is ingress_port_vlan;
218 return PiAction.builder()
219 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
220 .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
221 .build();
222 }
223
224 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
225 treatment, VLAN_ID, tableId);
226 return PiAction.builder()
227 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
228 .withParameter(new PiActionParam(FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
229 .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
230 .build();
231 }
232
233 // NOTE: we use clearDeferred to signal when there are no more ports associated to a given vlan
234 private static boolean isFilteringNoAction(TrafficTreatment treatment) {
235 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
236 (treatment.allInstructions().isEmpty()) ||
237 (treatment.allInstructions().size() == 1 && treatment.writeMetadata() != null);
238 }
239
240 private boolean isFilteringPopAction(TrafficTreatment treatment) {
241 return l2Instruction(treatment, VLAN_POP) != null;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800242 }
243
244 private void fwdClassifierRules(
245 FilteringObjective obj,
246 PortCriterion inPortCriterion,
247 EthCriterion ethDstCriterion,
248 EthCriterion ethDstMaskedCriterion,
249 ObjectiveTranslation.Builder resultBuilder)
250 throws FabricPipelinerException {
251
252 final List<FlowRule> flowRules = Lists.newArrayList();
253
254 final PortNumber inPort = inPortCriterion.port();
255 if (ethDstCriterion == null) {
256 if (ethDstMaskedCriterion == null) {
257 // No match. Do bridging (default action).
258 return;
259 }
260 // Masked fwd classifier rule
261 final MacAddress dstMac = ethDstMaskedCriterion.mac();
262 final MacAddress dstMacMask = ethDstMaskedCriterion.mask();
263 flowRules.add(maskedFwdClassifierRule(inPort, dstMac, dstMacMask, obj));
264 } else {
265 final MacAddress dstMac = ethDstCriterion.mac();
266 flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
Daniele Moro5a2de712019-09-24 14:34:07 -0700267 flowRules.addAll(mplsFwdClassifierRules(inPort, dstMac, obj));
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800268 }
269
270 for (FlowRule f : flowRules) {
271 resultBuilder.addFlowRule(f);
272 }
273 }
274
275 private FlowRule maskedFwdClassifierRule(
276 PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
277 FilteringObjective obj)
278 throws FabricPipelinerException {
279 final TrafficTreatment treatment;
280 final short ethType;
281 if (dstMac.equals(MacAddress.IPV4_MULTICAST)
282 && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
283 treatment = fwdClassifierTreatment(FWD_IPV4_ROUTING);
284 ethType = Ethernet.TYPE_IPV4;
285 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST)
286 && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
287 treatment = fwdClassifierTreatment(FWD_IPV6_ROUTING);
288 ethType = Ethernet.TYPE_IPV6;
289 } else {
290 throw new FabricPipelinerException(format(
291 "Unsupported masked Ethernet address for fwd " +
292 "classifier rule (mac=%s, mask=%s)",
293 dstMac, dstMacMask));
294 }
295 return fwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, obj);
296 }
297
298 private Collection<FlowRule> ipFwdClassifierRules(
299 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
300 throws FabricPipelinerException {
301 final Collection<FlowRule> flowRules = Lists.newArrayList();
302 flowRules.add(fwdClassifierRule(
303 inPort, Ethernet.TYPE_IPV4, dstMac, null,
304 fwdClassifierTreatment(FWD_IPV4_ROUTING), obj));
305 flowRules.add(fwdClassifierRule(
306 inPort, Ethernet.TYPE_IPV6, dstMac, null,
307 fwdClassifierTreatment(FWD_IPV6_ROUTING), obj));
308 return flowRules;
309 }
310
Daniele Moro5a2de712019-09-24 14:34:07 -0700311 private Collection<FlowRule> mplsFwdClassifierRules(
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800312 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
313 throws FabricPipelinerException {
Daniele Moro5a2de712019-09-24 14:34:07 -0700314 // Forwarding classifier for MPLS is composed of 2 rules
315 // with higher priority wrt standard forwarding classifier rules,
316 // this is due to overlap on ternary matching.
317 TrafficTreatment treatment = fwdClassifierTreatment(FWD_MPLS);
318 final PiCriterion ethTypeMplsIpv4 = PiCriterion.builder()
319 .matchTernary(FabricConstants.HDR_ETH_TYPE,
320 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
321 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
322 Ethernet.TYPE_IPV4)
323 .build();
324 final TrafficSelector selectorMplsIpv4 = DefaultTrafficSelector.builder()
325 .matchInPort(inPort)
326 .matchPi(ethTypeMplsIpv4)
327 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
328 .build();
329
330 final PiCriterion ethTypeMplsIpv6 = PiCriterion.builder()
331 .matchTernary(FabricConstants.HDR_ETH_TYPE,
332 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
333 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
334 Ethernet.TYPE_IPV6)
335 .build();
336 final TrafficSelector selectorMplsIpv6 = DefaultTrafficSelector.builder()
337 .matchInPort(inPort)
338 .matchPi(ethTypeMplsIpv6)
339 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
340 .build();
341
342 return List.of(
343 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
344 selectorMplsIpv4, treatment, obj.priority() + 1),
345 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
346 selectorMplsIpv6, treatment, obj.priority() + 1)
347 );
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800348 }
349
350 private FlowRule fwdClassifierRule(
351 PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
352 TrafficTreatment treatment, FilteringObjective obj)
353 throws FabricPipelinerException {
Daniele Moro5a2de712019-09-24 14:34:07 -0700354 // Match on ip_eth_type that is the eth_type of the L3 protocol.
355 // i.e., if the packet has an IP header, ip_eth_type should
356 // contain the corresponding eth_type (for IPv4 or IPv6)
357 final PiCriterion ethTypeCriterion = PiCriterion.builder()
358 .matchExact(FabricConstants.HDR_IP_ETH_TYPE, ethType)
359 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800360 final TrafficSelector selector = DefaultTrafficSelector.builder()
361 .matchInPort(inPort)
Daniele Moro5a2de712019-09-24 14:34:07 -0700362 .matchPi(ethTypeCriterion)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800363 .matchEthDstMasked(dstMac, dstMacMask == null
364 ? MacAddress.EXACT_MASK : dstMacMask)
365 .build();
366 return flowRule(
367 obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
368 selector, treatment);
369 }
370
371 private TrafficTreatment fwdClassifierTreatment(byte fwdType) {
372 final PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE, fwdType);
373 final PiAction action = PiAction.builder()
374 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
375 .withParameter(param)
376 .build();
377 return DefaultTrafficTreatment.builder()
378 .piTableAction(action)
379 .build();
380
381 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800382}