blob: a6f0e81793aba17fc5969790fd838f1b7635dc92 [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;
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;
35import org.onosproject.net.flowobjective.FilteringObjective;
36import org.onosproject.net.flowobjective.ObjectiveError;
37import org.onosproject.net.pi.runtime.PiAction;
38import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070039import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
40import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080041
42import java.util.Collection;
43import java.util.List;
44
45import static java.lang.String.format;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070046import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080047
48/**
49 * ObjectiveTranslator implementation for FilteringObjective.
50 */
51class FilteringObjectiveTranslator
52 extends AbstractObjectiveTranslator<FilteringObjective> {
53
54 // Forwarding types from fabric.p4.
55 static final byte FWD_MPLS = 1;
56 static final byte FWD_IPV4_ROUTING = 2;
57 static final byte FWD_IPV6_ROUTING = 3;
58
59 private static final byte[] ONE = new byte[]{1};
60 private static final byte[] ZERO = new byte[]{0};
61
Daniele Moro693d76f2019-09-24 14:34:07 -070062 private static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;
63
Carmelo Casconeb5324e72018-11-25 02:26:32 -080064 private static final PiAction DENY = PiAction.builder()
65 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
66 .build();
67
Carmelo Casconeb5324e72018-11-25 02:26:32 -080068
69 FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
70 super(deviceId, capabilities);
71 }
72
73 @Override
74 public ObjectiveTranslation doTranslate(FilteringObjective obj)
75 throws FabricPipelinerException {
76
77 final ObjectiveTranslation.Builder resultBuilder =
78 ObjectiveTranslation.builder();
79
80 if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
81 throw new FabricPipelinerException(
82 format("Unsupported or missing filtering key: key=%s", obj.key()),
83 ObjectiveError.BADPARAMS);
84 }
85
86 final PortCriterion inPort = (PortCriterion) obj.key();
Daniele Moro7c3a0022019-07-12 13:38:34 -070087
88 final VlanIdCriterion outerVlan = (VlanIdCriterion) criterion(
Carmelo Casconeb5324e72018-11-25 02:26:32 -080089 obj.conditions(), Criterion.Type.VLAN_VID);
Daniele Moro7c3a0022019-07-12 13:38:34 -070090 final VlanIdCriterion innerVlan = (VlanIdCriterion) criterion(
91 obj.conditions(), Criterion.Type.INNER_VLAN_VID);
Carmelo Casconeb5324e72018-11-25 02:26:32 -080092 final EthCriterion ethDst = (EthCriterion) criterion(
93 obj.conditions(), Criterion.Type.ETH_DST);
94 final EthCriterion ethDstMasked = (EthCriterion) criterion(
95 obj.conditions(), Criterion.Type.ETH_DST_MASKED);
96
Daniele Moro7c3a0022019-07-12 13:38:34 -070097 ingressPortVlanRule(obj, inPort, outerVlan, innerVlan, resultBuilder);
Carmelo Casconeb5324e72018-11-25 02:26:32 -080098 fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
99
100 return resultBuilder.build();
101 }
102
103 private void ingressPortVlanRule(
104 FilteringObjective obj,
105 Criterion inPortCriterion,
Daniele Moro7c3a0022019-07-12 13:38:34 -0700106 VlanIdCriterion outerVlanCriterion,
107 VlanIdCriterion innerVlanCriterion,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800108 ObjectiveTranslation.Builder resultBuilder)
109 throws FabricPipelinerException {
110
Daniele Moro7c3a0022019-07-12 13:38:34 -0700111 final boolean outerVlanValid = outerVlanCriterion != null
112 && !outerVlanCriterion.vlanId().equals(VlanId.NONE);
113 final boolean innerVlanValid = innerVlanCriterion != null
114 && !innerVlanCriterion.vlanId().equals(VlanId.NONE);
115
116 final PiCriterion piCriterion = PiCriterion.builder()
117 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, outerVlanValid ? ONE : ZERO)
118 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800119
120 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
121 .add(inPortCriterion)
Daniele Moro7c3a0022019-07-12 13:38:34 -0700122 .add(piCriterion);
123 if (outerVlanValid) {
124 selector.add(outerVlanCriterion);
125 }
126 if (innerVlanValid) {
127 selector.add(innerVlanCriterion);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800128 }
129
130 final TrafficTreatment treatment;
131 if (obj.type().equals(FilteringObjective.Type.DENY)) {
132 treatment = DefaultTrafficTreatment.builder()
133 .piTableAction(DENY)
134 .build();
135 } else {
136 treatment = obj.meta() == null
137 ? DefaultTrafficTreatment.emptyTreatment() : obj.meta();
138 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800139 resultBuilder.addFlowRule(flowRule(
140 obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
141 selector.build(), treatment));
142 }
143
144 private void fwdClassifierRules(
145 FilteringObjective obj,
146 PortCriterion inPortCriterion,
147 EthCriterion ethDstCriterion,
148 EthCriterion ethDstMaskedCriterion,
149 ObjectiveTranslation.Builder resultBuilder)
150 throws FabricPipelinerException {
151
152 final List<FlowRule> flowRules = Lists.newArrayList();
153
154 final PortNumber inPort = inPortCriterion.port();
155 if (ethDstCriterion == null) {
156 if (ethDstMaskedCriterion == null) {
157 // No match. Do bridging (default action).
158 return;
159 }
160 // Masked fwd classifier rule
161 final MacAddress dstMac = ethDstMaskedCriterion.mac();
162 final MacAddress dstMacMask = ethDstMaskedCriterion.mask();
163 flowRules.add(maskedFwdClassifierRule(inPort, dstMac, dstMacMask, obj));
164 } else {
165 final MacAddress dstMac = ethDstCriterion.mac();
166 flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
Daniele Moro693d76f2019-09-24 14:34:07 -0700167 flowRules.addAll(mplsFwdClassifierRules(inPort, dstMac, obj));
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800168 }
169
170 for (FlowRule f : flowRules) {
171 resultBuilder.addFlowRule(f);
172 }
173 }
174
175 private FlowRule maskedFwdClassifierRule(
176 PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
177 FilteringObjective obj)
178 throws FabricPipelinerException {
179 final TrafficTreatment treatment;
180 final short ethType;
181 if (dstMac.equals(MacAddress.IPV4_MULTICAST)
182 && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
183 treatment = fwdClassifierTreatment(FWD_IPV4_ROUTING);
184 ethType = Ethernet.TYPE_IPV4;
185 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST)
186 && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
187 treatment = fwdClassifierTreatment(FWD_IPV6_ROUTING);
188 ethType = Ethernet.TYPE_IPV6;
189 } else {
190 throw new FabricPipelinerException(format(
191 "Unsupported masked Ethernet address for fwd " +
192 "classifier rule (mac=%s, mask=%s)",
193 dstMac, dstMacMask));
194 }
195 return fwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, obj);
196 }
197
198 private Collection<FlowRule> ipFwdClassifierRules(
199 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
200 throws FabricPipelinerException {
201 final Collection<FlowRule> flowRules = Lists.newArrayList();
202 flowRules.add(fwdClassifierRule(
203 inPort, Ethernet.TYPE_IPV4, dstMac, null,
204 fwdClassifierTreatment(FWD_IPV4_ROUTING), obj));
205 flowRules.add(fwdClassifierRule(
206 inPort, Ethernet.TYPE_IPV6, dstMac, null,
207 fwdClassifierTreatment(FWD_IPV6_ROUTING), obj));
208 return flowRules;
209 }
210
Daniele Moro693d76f2019-09-24 14:34:07 -0700211 private Collection<FlowRule> mplsFwdClassifierRules(
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800212 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
213 throws FabricPipelinerException {
Daniele Moro693d76f2019-09-24 14:34:07 -0700214 // Forwarding classifier for MPLS is composed of 2 rules
215 // with higher priority wrt standard forwarding classifier rules,
216 // this is due to overlap on ternary matching.
217 TrafficTreatment treatment = fwdClassifierTreatment(FWD_MPLS);
218 final PiCriterion ethTypeMplsIpv4 = PiCriterion.builder()
219 .matchTernary(FabricConstants.HDR_ETH_TYPE,
220 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
221 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
222 Ethernet.TYPE_IPV4)
223 .build();
224 final TrafficSelector selectorMplsIpv4 = DefaultTrafficSelector.builder()
225 .matchInPort(inPort)
226 .matchPi(ethTypeMplsIpv4)
227 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
228 .build();
229
230 final PiCriterion ethTypeMplsIpv6 = PiCriterion.builder()
231 .matchTernary(FabricConstants.HDR_ETH_TYPE,
232 Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
233 .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
234 Ethernet.TYPE_IPV6)
235 .build();
236 final TrafficSelector selectorMplsIpv6 = DefaultTrafficSelector.builder()
237 .matchInPort(inPort)
238 .matchPi(ethTypeMplsIpv6)
239 .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
240 .build();
241
242 return List.of(
243 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
244 selectorMplsIpv4, treatment, obj.priority() + 1),
245 flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
246 selectorMplsIpv6, treatment, obj.priority() + 1)
247 );
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800248 }
249
250 private FlowRule fwdClassifierRule(
251 PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
252 TrafficTreatment treatment, FilteringObjective obj)
253 throws FabricPipelinerException {
Daniele Moro693d76f2019-09-24 14:34:07 -0700254 // Match on ip_eth_type that is the eth_type of the L3 protocol.
255 // i.e., if the packet has an IP header, ip_eth_type should
256 // contain the corresponding eth_type (for IPv4 or IPv6)
257 final PiCriterion ethTypeCriterion = PiCriterion.builder()
258 .matchExact(FabricConstants.HDR_IP_ETH_TYPE, ethType)
259 .build();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800260 final TrafficSelector selector = DefaultTrafficSelector.builder()
261 .matchInPort(inPort)
Daniele Moro693d76f2019-09-24 14:34:07 -0700262 .matchPi(ethTypeCriterion)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800263 .matchEthDstMasked(dstMac, dstMacMask == null
264 ? MacAddress.EXACT_MASK : dstMacMask)
265 .build();
266 return flowRule(
267 obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
268 selector, treatment);
269 }
270
271 private TrafficTreatment fwdClassifierTreatment(byte fwdType) {
272 final PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE, fwdType);
273 final PiAction action = PiAction.builder()
274 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
275 .withParameter(param)
276 .build();
277 return DefaultTrafficTreatment.builder()
278 .piTableAction(action)
279 .build();
280
281 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800282}