blob: bfdcc2ba1978c8771d692bb80d2a3681c7e2e5e4 [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;
Daniele Moro41ec1482019-10-29 18:45:33 -070035import org.onosproject.net.flow.instructions.Instructions;
Wailok Shumfb7e7872021-06-18 17:30:08 +080036import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
37import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080038import org.onosproject.net.flowobjective.FilteringObjective;
Daniele Moro41ec1482019-10-29 18:45:33 -070039import org.onosproject.net.flowobjective.Objective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080040import org.onosproject.net.flowobjective.ObjectiveError;
Wailok Shumfb7e7872021-06-18 17:30:08 +080041import org.onosproject.net.pi.model.PiTableId;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080042import org.onosproject.net.pi.runtime.PiAction;
43import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070044import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080045import org.onosproject.pipelines.fabric.FabricConstants;
Daniele Moro41ec1482019-10-29 18:45:33 -070046import org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080047
48import java.util.Collection;
49import java.util.List;
50
51import static java.lang.String.format;
Daniele Moro41ec1482019-10-29 18:45:33 -070052import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
53import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Wailok Shumfb7e7872021-06-18 17:30:08 +080054import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
55import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
56import static org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
57import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.DEFAULT_VLAN;
58import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.DEFAULT_PW_TRANSPORT_VLAN;
59import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ETH_TYPE_EXACT_MASK;
60import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_MPLS;
61import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV4_ROUTING;
62import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV6_ROUTING;
63import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ONE;
64import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_EDGE;
65import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_INFRA;
66import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ZERO;
67import 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/**
73 * ObjectiveTranslator implementation for FilteringObjective.
74 */
75class FilteringObjectiveTranslator
76 extends AbstractObjectiveTranslator<FilteringObjective> {
77
Carmelo Casconeb5324e72018-11-25 02:26:32 -080078 private static final PiAction DENY = PiAction.builder()
79 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
80 .build();
81
pierventre167d4482021-01-08 17:35:47 +010082 private static final int INTERFACE_CONFIG_UPDATE = 2;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080083
84 FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
85 super(deviceId, capabilities);
86 }
87
88 @Override
89 public ObjectiveTranslation doTranslate(FilteringObjective obj)
90 throws FabricPipelinerException {
91
92 final ObjectiveTranslation.Builder resultBuilder =
93 ObjectiveTranslation.builder();
94
95 if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
96 throw new FabricPipelinerException(
97 format("Unsupported or missing filtering key: key=%s", obj.key()),
98 ObjectiveError.BADPARAMS);
99 }
100
101 final PortCriterion inPort = (PortCriterion) obj.key();
Daniele Moro7c3a0022019-07-12 13:38:34 -0700102
103 final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800104 obj.conditions(), Criterion.Type.VLAN_VID);
Daniele Moro7c3a0022019-07-12 13:38:34 -0700105 final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
106 obj.conditions(), Criterion.Type.INNER_VLAN_VID);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800107 final EthCriterion ethDst = (EthCriterion) criterion(
108 obj.conditions(), Criterion.Type.ETH_DST);
109 final EthCriterion ethDstMasked = (EthCriterion) criterion(
110 obj.conditions(), Criterion.Type.ETH_DST_MASKED);
111
Daniele Moro7c3a0022019-07-12 13:38:34 -0700112 ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
pierventre167d4482021-01-08 17:35:47 +0100113 if (shouldModifyFwdClassifierTable(obj)) {
Daniele Moro41ec1482019-10-29 18:45:33 -0700114 fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
115 } else {
116 log.debug("Skipping fwd classifier rules for device {}.", deviceId);
117 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800118 return resultBuilder.build();
119 }
120
pierventre167d4482021-01-08 17:35:47 +0100121 private boolean shouldModifyFwdClassifierTable(FilteringObjective obj) {
Daniele Moro41ec1482019-10-29 18:45:33 -0700122 // NOTE: in fabric pipeline the forwarding classifier acts similarly
123 // to the TMAC table of OFDPA that matches on input port.
pierventre167d4482021-01-08 17:35:47 +0100124 // NOTE: that SR signals when it is a port update event by not setting
125 // the INTERFACE_CONFIG_UPDATE metadata. During the INTERFACE_CONFIG_UPDATE
126 // there is no need to add/remove rules in the fwd_classifier table.
127 // NOTE: that in scenarios like (T, N) -> T where we remove only the native
128 // VLAN there is not an ADD following the remove.
Daniele Moro41ec1482019-10-29 18:45:33 -0700129
pierventre167d4482021-01-08 17:35:47 +0100130 // Forwarding classifier rules should be added/removed to translation when:
131 // - the operation is ADD
132 // AND it is a port update event (ADD or UPDATE) OR
133 // - it doesn't refer to double tagged traffic
134 // AND it is a port REMOVE event OR
Daniele Moro41ec1482019-10-29 18:45:33 -0700135 // - it refers to double tagged traffic
136 // and SR is triggering the removal of forwarding classifier rules.
pierventre167d4482021-01-08 17:35:47 +0100137 return (obj.op() == Objective.Operation.ADD && !isInterfaceConfigUpdate(obj)) ||
138 (!isDoubleTagged(obj) && !isInterfaceConfigUpdate(obj)) ||
Daniele Moro41ec1482019-10-29 18:45:33 -0700139 (isDoubleTagged(obj) && isLastDoubleTaggedForPort(obj));
140 }
141
142 /**
pierventre167d4482021-01-08 17:35:47 +0100143 * Check if the given filtering objective is triggered by a interface config change.
144 *
145 * @param obj Filtering objective to check.
146 * @return True if SR is signaling to not remove the forwarding classifier rule,
147 * false otherwise.
148 */
149 private boolean isInterfaceConfigUpdate(FilteringObjective obj) {
150 if (obj.meta() == null) {
151 return false;
152 }
153 Instructions.MetadataInstruction meta = obj.meta().writeMetadata();
154 // SR is setting this metadata when an interface config update has
155 // been performed and thus fwd classifier rules should not be removed
156 return (meta != null && (meta.metadata() & meta.metadataMask()) == INTERFACE_CONFIG_UPDATE);
157 }
158
159 /**
Daniele Moro41ec1482019-10-29 18:45:33 -0700160 * Check if the given filtering objective is the last filtering objective
161 * for a double-tagged host for a specific port.
162 * <p>
163 * {@see org.onosproject.segmentrouting.RoutingRulePopulator#buildDoubleTaggedFilteringObj()}
164 * {@see org.onosproject.segmentrouting.RoutingRulePopulator#processDoubleTaggedFilter()}
165 *
166 * @param obj Filtering objective to check.
167 * @return True if SR is signaling to remove the forwarding classifier rule,
168 * false otherwise.
169 */
170 private boolean isLastDoubleTaggedForPort(FilteringObjective obj) {
171 Instructions.MetadataInstruction meta = obj.meta().writeMetadata();
172 // SR is setting this metadata when a double tagged filtering objective
173 // is removed and no other hosts is sharing the same input port.
174 return (meta != null && (meta.metadata() & meta.metadataMask()) == 1);
175 }
176
177 private boolean isDoubleTagged(FilteringObjective obj) {
178 return obj.meta() != null &&
Wailok Shumfb7e7872021-06-18 17:30:08 +0800179 FabricUtils.l2Instruction(obj.meta(), L2SubType.VLAN_POP) != null &&
Daniele Moro41ec1482019-10-29 18:45:33 -0700180 FabricUtils.criterion(obj.conditions(), VLAN_VID) != null &&
181 FabricUtils.criterion(obj.conditions(), INNER_VLAN_VID) != null;
182 }
183
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800184 private void ingressPortVlanRule(
185 FilteringObjective obj,
186 Criterion inPortCriterion,
Daniele Moro7c3a0022019-07-12 13:38:34 -0700187 VlanIdCriterion outerVlanCriterion,
188 VlanIdCriterion innerVlanCriterion,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800189 ObjectiveTranslation.Builder resultBuilder)
190 throws FabricPipelinerException {
191
Daniele Moro7c3a0022019-07-12 13:38:34 -0700192 final boolean outerVlanValid = outerVlanCriterion != null
193 && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
194 final boolean innerVlanValid = innerVlanCriterion != null
195 && !innerVlanCriterion.vlanId().equals(VlanId.NONE);
196
Daniele Morob3d199b2019-11-01 14:01:46 -0700197 if (innerVlanValid && !capabilities.supportDoubleVlanTerm()) {
198 throw new FabricPipelinerException(
199 "Found 2 VLAN IDs, but the pipeline does not support double VLAN termination",
200 ObjectiveError.UNSUPPORTED);
201 }
202
Daniele Moro7c3a0022019-07-12 13:38:34 -0700203 final PiCriterion piCriterion = PiCriterion.builder()
204 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
205 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800206
207 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
208 .add(inPortCriterion)
Daniele Moro7c3a0022019-07-12 13:38:34 -0700209 .add(piCriterion);
210 if (outerVlanValid) {
211 selector.add(outerVlanCriterion);
212 }
213 if (innerVlanValid) {
214 selector.add(innerVlanCriterion);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800215 }
216
Wailok Shumfb7e7872021-06-18 17:30:08 +0800217 final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800218 if (obj.type().equals(FilteringObjective.Type.DENY)) {
Wailok Shumfb7e7872021-06-18 17:30:08 +0800219 treatmentBuilder.piTableAction(DENY);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800220 } else {
Wailok Shumfb7e7872021-06-18 17:30:08 +0800221 byte portType = PORT_TYPE_EDGE;
222 if (!innerVlanValid && outerVlanValid &&
223 outerVlanCriterion.vlanId().toShort() == DEFAULT_PW_TRANSPORT_VLAN) {
224 portType = PORT_TYPE_INFRA;
225 } else if (obj.meta() != null) {
226 ModVlanIdInstruction modVlanIdInstruction = (ModVlanIdInstruction) l2Instruction(obj.meta(), VLAN_ID);
227 if (modVlanIdInstruction != null && modVlanIdInstruction.vlanId().toShort() == DEFAULT_VLAN) {
228 portType = PORT_TYPE_INFRA;
229 }
230 }
231 try {
232 treatmentBuilder.piTableAction(mapFilteringTreatment(obj.meta(),
233 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN, portType));
234 } catch (PiInterpreterException ex) {
235 throw new FabricPipelinerException(format("Unable to map treatment for table '%s': %s",
236 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
237 ex.getMessage()), ObjectiveError.UNSUPPORTED);
238 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800239 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800240 resultBuilder.addFlowRule(flowRule(
241 obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
Wailok Shumfb7e7872021-06-18 17:30:08 +0800242 selector.build(), treatmentBuilder.build()));
243 }
244
245 private PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId, byte portType)
246 throws PiInterpreterException {
247 if (treatment == null) {
248 treatment = DefaultTrafficTreatment.emptyTreatment();
249 }
250 // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
251 if (isFilteringNoAction(treatment) || isFilteringPopAction(treatment)) {
252 // Permit action if table is ingress_port_vlan;
253 return PiAction.builder()
254 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
255 .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
256 .build();
257 }
258
259 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
260 treatment, VLAN_ID, tableId);
261 return PiAction.builder()
262 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
263 .withParameter(new PiActionParam(FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
264 .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
265 .build();
266 }
267
268 // NOTE: we use clearDeferred to signal when there are no more ports associated to a given vlan
269 private static boolean isFilteringNoAction(TrafficTreatment treatment) {
270 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
271 (treatment.allInstructions().isEmpty()) ||
272 (treatment.allInstructions().size() == 1 && treatment.writeMetadata() != null);
273 }
274
275 private boolean isFilteringPopAction(TrafficTreatment treatment) {
276 return l2Instruction(treatment, VLAN_POP) != null;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800277 }
278
279 private void fwdClassifierRules(
280 FilteringObjective obj,
281 PortCriterion inPortCriterion,
282 EthCriterion ethDstCriterion,
283 EthCriterion ethDstMaskedCriterion,
284 ObjectiveTranslation.Builder resultBuilder)
285 throws FabricPipelinerException {
286
287 final List<FlowRule> flowRules = Lists.newArrayList();
288
289 final PortNumber inPort = inPortCriterion.port();
290 if (ethDstCriterion == null) {
291 if (ethDstMaskedCriterion == null) {
292 // No match. Do bridging (default action).
293 return;
294 }
295 // Masked fwd classifier rule
296 final MacAddress dstMac = ethDstMaskedCriterion.mac();
297 final MacAddress dstMacMask = ethDstMaskedCriterion.mask();
298 flowRules.add(maskedFwdClassifierRule(inPort, dstMac, dstMacMask, obj));
299 } else {
300 final MacAddress dstMac = ethDstCriterion.mac();
301 flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
Daniele Moro5a2de712019-09-24 14:34:07 -0700302 flowRules.addAll(mplsFwdClassifierRules(inPort, dstMac, obj));
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800303 }
304
305 for (FlowRule f : flowRules) {
306 resultBuilder.addFlowRule(f);
307 }
308 }
309
310 private FlowRule maskedFwdClassifierRule(
311 PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
312 FilteringObjective obj)
313 throws FabricPipelinerException {
314 final TrafficTreatment treatment;
315 final short ethType;
316 if (dstMac.equals(MacAddress.IPV4_MULTICAST)
317 && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
318 treatment = fwdClassifierTreatment(FWD_IPV4_ROUTING);
319 ethType = Ethernet.TYPE_IPV4;
320 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST)
321 && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
322 treatment = fwdClassifierTreatment(FWD_IPV6_ROUTING);
323 ethType = Ethernet.TYPE_IPV6;
324 } else {
325 throw new FabricPipelinerException(format(
326 "Unsupported masked Ethernet address for fwd " +
327 "classifier rule (mac=%s, mask=%s)",
328 dstMac, dstMacMask));
329 }
330 return fwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, obj);
331 }
332
333 private Collection<FlowRule> ipFwdClassifierRules(
334 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
335 throws FabricPipelinerException {
336 final Collection<FlowRule> flowRules = Lists.newArrayList();
337 flowRules.add(fwdClassifierRule(
338 inPort, Ethernet.TYPE_IPV4, dstMac, null,
339 fwdClassifierTreatment(FWD_IPV4_ROUTING), obj));
340 flowRules.add(fwdClassifierRule(
341 inPort, Ethernet.TYPE_IPV6, dstMac, null,
342 fwdClassifierTreatment(FWD_IPV6_ROUTING), obj));
343 return flowRules;
344 }
345
Daniele Moro5a2de712019-09-24 14:34:07 -0700346 private Collection<FlowRule> mplsFwdClassifierRules(
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800347 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
348 throws FabricPipelinerException {
Daniele Moro5a2de712019-09-24 14:34:07 -0700349 // Forwarding classifier for MPLS is composed of 2 rules
350 // with higher priority wrt standard forwarding classifier rules,
351 // this is due to overlap on ternary matching.
352 TrafficTreatment treatment = fwdClassifierTreatment(FWD_MPLS);
353 final PiCriterion ethTypeMplsIpv4 = PiCriterion.builder()
354 .matchTernary(FabricConstants.HDR_ETH_TYPE,
355 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
356 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
357 Ethernet.TYPE_IPV4)
358 .build();
359 final TrafficSelector selectorMplsIpv4 = DefaultTrafficSelector.builder()
360 .matchInPort(inPort)
361 .matchPi(ethTypeMplsIpv4)
362 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
363 .build();
364
365 final PiCriterion ethTypeMplsIpv6 = PiCriterion.builder()
366 .matchTernary(FabricConstants.HDR_ETH_TYPE,
367 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
368 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
369 Ethernet.TYPE_IPV6)
370 .build();
371 final TrafficSelector selectorMplsIpv6 = DefaultTrafficSelector.builder()
372 .matchInPort(inPort)
373 .matchPi(ethTypeMplsIpv6)
374 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
375 .build();
376
377 return List.of(
378 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
379 selectorMplsIpv4, treatment, obj.priority() + 1),
380 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
381 selectorMplsIpv6, treatment, obj.priority() + 1)
382 );
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800383 }
384
385 private FlowRule fwdClassifierRule(
386 PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
387 TrafficTreatment treatment, FilteringObjective obj)
388 throws FabricPipelinerException {
Daniele Moro5a2de712019-09-24 14:34:07 -0700389 // Match on ip_eth_type that is the eth_type of the L3 protocol.
390 // i.e., if the packet has an IP header, ip_eth_type should
391 // contain the corresponding eth_type (for IPv4 or IPv6)
392 final PiCriterion ethTypeCriterion = PiCriterion.builder()
393 .matchExact(FabricConstants.HDR_IP_ETH_TYPE, ethType)
394 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800395 final TrafficSelector selector = DefaultTrafficSelector.builder()
396 .matchInPort(inPort)
Daniele Moro5a2de712019-09-24 14:34:07 -0700397 .matchPi(ethTypeCriterion)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800398 .matchEthDstMasked(dstMac, dstMacMask == null
399 ? MacAddress.EXACT_MASK : dstMacMask)
400 .build();
401 return flowRule(
402 obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
403 selector, treatment);
404 }
405
406 private TrafficTreatment fwdClassifierTreatment(byte fwdType) {
407 final PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE, fwdType);
408 final PiAction action = PiAction.builder()
409 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
410 .withParameter(param)
411 .build();
412 return DefaultTrafficTreatment.builder()
413 .piTableAction(action)
414 .build();
415
416 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800417}