blob: d682d8c3de016c9c2ac9b3d7081e5971712ef851 [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 Cascone36d5e7a2019-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;
Daniele Moro7c3a0022019-07-12 13:38:34 -070020import org.onlab.packet.EthType;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080021import org.onlab.packet.Ethernet;
22import org.onlab.packet.MacAddress;
23import org.onlab.packet.VlanId;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.PortNumber;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.TrafficSelector;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.flow.criteria.Criterion;
32import org.onosproject.net.flow.criteria.EthCriterion;
33import org.onosproject.net.flow.criteria.PiCriterion;
34import org.onosproject.net.flow.criteria.PortCriterion;
35import org.onosproject.net.flow.criteria.VlanIdCriterion;
36import org.onosproject.net.flowobjective.FilteringObjective;
37import org.onosproject.net.flowobjective.ObjectiveError;
38import org.onosproject.net.pi.runtime.PiAction;
39import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070040import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
41import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080042
43import java.util.Collection;
44import java.util.List;
45
46import static java.lang.String.format;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070047import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080048
49/**
50 * ObjectiveTranslator implementation for FilteringObjective.
51 */
52class FilteringObjectiveTranslator
53 extends AbstractObjectiveTranslator<FilteringObjective> {
54
55 // Forwarding types from fabric.p4.
56 static final byte FWD_MPLS = 1;
57 static final byte FWD_IPV4_ROUTING = 2;
58 static final byte FWD_IPV6_ROUTING = 3;
59
60 private static final byte[] ONE = new byte[]{1};
61 private static final byte[] ZERO = new byte[]{0};
62
63 private static final PiAction DENY = PiAction.builder()
64 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
65 .build();
66
Carmelo Casconeb5324e72018-11-25 02:26:32 -080067
68 FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
69 super(deviceId, capabilities);
70 }
71
72 @Override
73 public ObjectiveTranslation doTranslate(FilteringObjective obj)
74 throws FabricPipelinerException {
75
76 final ObjectiveTranslation.Builder resultBuilder =
77 ObjectiveTranslation.builder();
78
79 if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
80 throw new FabricPipelinerException(
81 format("Unsupported or missing filtering key: key=%s", obj.key()),
82 ObjectiveError.BADPARAMS);
83 }
84
85 final PortCriterion inPort = (PortCriterion) obj.key();
Daniele Moro7c3a0022019-07-12 13:38:34 -070086
87 final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
Carmelo Casconeb5324e72018-11-25 02:26:32 -080088 obj.conditions(), Criterion.Type.VLAN_VID);
Daniele Moro7c3a0022019-07-12 13:38:34 -070089 final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
90 obj.conditions(), Criterion.Type.INNER_VLAN_VID);
Carmelo Casconeb5324e72018-11-25 02:26:32 -080091 final EthCriterion ethDst = (EthCriterion) criterion(
92 obj.conditions(), Criterion.Type.ETH_DST);
93 final EthCriterion ethDstMasked = (EthCriterion) criterion(
94 obj.conditions(), Criterion.Type.ETH_DST_MASKED);
95
Daniele Moro7c3a0022019-07-12 13:38:34 -070096 ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
Carmelo Casconeb5324e72018-11-25 02:26:32 -080097 fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
98
99 return resultBuilder.build();
100 }
101
102 private void ingressPortVlanRule(
103 FilteringObjective obj,
104 Criterion inPortCriterion,
Daniele Moro7c3a0022019-07-12 13:38:34 -0700105 VlanIdCriterion outerVlanCriterion,
106 VlanIdCriterion innerVlanCriterion,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800107 ObjectiveTranslation.Builder resultBuilder)
108 throws FabricPipelinerException {
109
Daniele Moro7c3a0022019-07-12 13:38:34 -0700110 final boolean outerVlanValid = outerVlanCriterion != null
111 && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
112 final boolean innerVlanValid = innerVlanCriterion != null
113 && !innerVlanCriterion.vlanId().equals(VlanId.NONE);
114
115 final PiCriterion piCriterion = PiCriterion.builder()
116 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
117 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800118
119 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
120 .add(inPortCriterion)
Daniele Moro7c3a0022019-07-12 13:38:34 -0700121 .add(piCriterion);
122 if (outerVlanValid) {
123 selector.add(outerVlanCriterion);
124 }
125 if (innerVlanValid) {
126 selector.add(innerVlanCriterion);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800127 }
128
129 final TrafficTreatment treatment;
130 if (obj.type().equals(FilteringObjective.Type.DENY)) {
131 treatment = DefaultTrafficTreatment.builder()
132 .piTableAction(DENY)
133 .build();
134 } else {
135 treatment = obj.meta() == null
136 ? DefaultTrafficTreatment.emptyTreatment() : obj.meta();
137 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800138 resultBuilder.addFlowRule(flowRule(
139 obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
140 selector.build(), treatment));
141 }
142
143 private void fwdClassifierRules(
144 FilteringObjective obj,
145 PortCriterion inPortCriterion,
146 EthCriterion ethDstCriterion,
147 EthCriterion ethDstMaskedCriterion,
148 ObjectiveTranslation.Builder resultBuilder)
149 throws FabricPipelinerException {
150
151 final List<FlowRule> flowRules = Lists.newArrayList();
152
153 final PortNumber inPort = inPortCriterion.port();
154 if (ethDstCriterion == null) {
155 if (ethDstMaskedCriterion == null) {
156 // No match. Do bridging (default action).
157 return;
158 }
159 // Masked fwd classifier rule
160 final MacAddress dstMac = ethDstMaskedCriterion.mac();
161 final MacAddress dstMacMask = ethDstMaskedCriterion.mask();
162 flowRules.add(maskedFwdClassifierRule(inPort, dstMac, dstMacMask, obj));
163 } else {
164 final MacAddress dstMac = ethDstCriterion.mac();
165 flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
166 flowRules.add(mplsFwdClassifierRule(inPort, dstMac, obj));
167 }
168
169 for (FlowRule f : flowRules) {
170 resultBuilder.addFlowRule(f);
171 }
172 }
173
174 private FlowRule maskedFwdClassifierRule(
175 PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
176 FilteringObjective obj)
177 throws FabricPipelinerException {
178 final TrafficTreatment treatment;
179 final short ethType;
180 if (dstMac.equals(MacAddress.IPV4_MULTICAST)
181 && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
182 treatment = fwdClassifierTreatment(FWD_IPV4_ROUTING);
183 ethType = Ethernet.TYPE_IPV4;
184 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST)
185 && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
186 treatment = fwdClassifierTreatment(FWD_IPV6_ROUTING);
187 ethType = Ethernet.TYPE_IPV6;
188 } else {
189 throw new FabricPipelinerException(format(
190 "Unsupported masked Ethernet address for fwd " +
191 "classifier rule (mac=%s, mask=%s)",
192 dstMac, dstMacMask));
193 }
194 return fwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, obj);
195 }
196
197 private Collection<FlowRule> ipFwdClassifierRules(
198 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
199 throws FabricPipelinerException {
200 final Collection<FlowRule> flowRules = Lists.newArrayList();
201 flowRules.add(fwdClassifierRule(
202 inPort, Ethernet.TYPE_IPV4, dstMac, null,
203 fwdClassifierTreatment(FWD_IPV4_ROUTING), obj));
204 flowRules.add(fwdClassifierRule(
205 inPort, Ethernet.TYPE_IPV6, dstMac, null,
206 fwdClassifierTreatment(FWD_IPV6_ROUTING), obj));
207 return flowRules;
208 }
209
210 private FlowRule mplsFwdClassifierRule(
211 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
212 throws FabricPipelinerException {
213 return fwdClassifierRule(
214 inPort, Ethernet.MPLS_UNICAST, dstMac, null,
215 fwdClassifierTreatment(FWD_MPLS), obj);
216 }
217
218 private FlowRule fwdClassifierRule(
219 PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
220 TrafficTreatment treatment, FilteringObjective obj)
221 throws FabricPipelinerException {
222 final TrafficSelector selector = DefaultTrafficSelector.builder()
223 .matchInPort(inPort)
Daniele Moro7c3a0022019-07-12 13:38:34 -0700224 .matchPi(mapEthTypeFwdClassifier(ethType))
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800225 .matchEthDstMasked(dstMac, dstMacMask == null
226 ? MacAddress.EXACT_MASK : dstMacMask)
227 .build();
228 return flowRule(
229 obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
230 selector, treatment);
231 }
232
233 private TrafficTreatment fwdClassifierTreatment(byte fwdType) {
234 final PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE, fwdType);
235 final PiAction action = PiAction.builder()
236 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
237 .withParameter(param)
238 .build();
239 return DefaultTrafficTreatment.builder()
240 .piTableAction(action)
241 .build();
242
243 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700244
245 static PiCriterion mapEthTypeFwdClassifier(short ethType) {
246 // Map the Ethernet type to the validity bits of the fabric pipeline
247 switch (EthType.EtherType.lookup(ethType)) {
248 case IPV4: {
249 return PiCriterion.builder()
250 .matchExact(FabricConstants.HDR_IS_IPV4, ONE)
251 .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
252 .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
253 .build();
254 }
255 case IPV6: {
256 return PiCriterion.builder()
257 .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
258 .matchExact(FabricConstants.HDR_IS_IPV6, ONE)
259 .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
260 .build();
261 }
262 case MPLS_UNICAST: {
263 return PiCriterion.builder()
264 .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
265 .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
266 .matchExact(FabricConstants.HDR_IS_MPLS, ONE)
267 .build();
268 }
269 default: {
270 return PiCriterion.builder()
271 .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
272 .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
273 .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
274 .build();
275 }
276 }
277 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800278}