blob: 1d7d5c00954b94514b8c8f05ad61a6d8bcbae482 [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
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070019import com.google.common.collect.ImmutableList;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080020import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Sets;
24import org.onlab.packet.IpPrefix;
25import org.onlab.packet.MacAddress;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070026import org.onosproject.core.ApplicationId;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080027import org.onosproject.net.DeviceId;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070028import org.onosproject.net.PortNumber;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080029import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.FlowRule;
32import org.onosproject.net.flow.TrafficSelector;
33import org.onosproject.net.flow.TrafficTreatment;
34import org.onosproject.net.flow.criteria.Criterion;
35import org.onosproject.net.flow.criteria.EthCriterion;
36import org.onosproject.net.flow.criteria.IPCriterion;
37import org.onosproject.net.flow.criteria.MplsCriterion;
38import org.onosproject.net.flow.criteria.VlanIdCriterion;
39import org.onosproject.net.flowobjective.ForwardingObjective;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070040import org.onosproject.net.flowobjective.Objective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080041import org.onosproject.net.flowobjective.ObjectiveError;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070042import org.onosproject.net.group.DefaultGroupDescription;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070043import org.onosproject.net.group.DefaultGroupKey;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070044import org.onosproject.net.group.GroupBucket;
45import org.onosproject.net.group.GroupBuckets;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070046import org.onosproject.net.group.GroupDescription;
47import org.onosproject.net.group.GroupKey;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080048import org.onosproject.net.pi.model.PiActionId;
49import org.onosproject.net.pi.model.PiTableId;
50import org.onosproject.net.pi.runtime.PiAction;
51import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070052import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
53import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080054
55import java.util.List;
56import java.util.Map;
57import java.util.Set;
58import java.util.stream.Collectors;
59
60import static java.lang.String.format;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070061import static org.onosproject.net.group.DefaultGroupBucket.createCloneGroupBucket;
Carmelo Cascone36d5e7a2019-09-25 01:02:53 -070062import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterionNotNull;
63import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.outputPort;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070064
Carmelo Casconeb5324e72018-11-25 02:26:32 -080065
66/**
67 * ObjectiveTranslator implementation ForwardingObjective.
68 */
69class ForwardingObjectiveTranslator
70 extends AbstractObjectiveTranslator<ForwardingObjective> {
71
Daniele Moro01ca2ab2019-06-25 11:48:48 -070072 //FIXME: Max number supported by PI
73 static final int CLONE_TO_CPU_ID = 511;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080074 private static final List<String> DEFAULT_ROUTE_PREFIXES = Lists.newArrayList(
75 "0.0.0.0/1", "128.0.0.0/1");
76
77 private static final Set<Criterion.Type> ACL_CRITERIA = ImmutableSet.of(
78 Criterion.Type.IN_PORT,
79 Criterion.Type.IN_PHY_PORT,
80 Criterion.Type.ETH_DST,
81 Criterion.Type.ETH_DST_MASKED,
82 Criterion.Type.ETH_SRC,
83 Criterion.Type.ETH_SRC_MASKED,
84 Criterion.Type.ETH_TYPE,
85 Criterion.Type.VLAN_VID,
86 Criterion.Type.IP_PROTO,
87 Criterion.Type.IPV4_SRC,
88 Criterion.Type.IPV4_DST,
89 Criterion.Type.TCP_SRC,
90 Criterion.Type.TCP_SRC_MASKED,
91 Criterion.Type.TCP_DST,
92 Criterion.Type.TCP_DST_MASKED,
93 Criterion.Type.UDP_SRC,
94 Criterion.Type.UDP_SRC_MASKED,
95 Criterion.Type.UDP_DST,
96 Criterion.Type.UDP_DST_MASKED,
97 Criterion.Type.ICMPV4_TYPE,
98 Criterion.Type.ICMPV4_CODE,
99 Criterion.Type.PROTOCOL_INDEPENDENT);
100
101 private static final Map<PiTableId, PiActionId> NEXT_ID_ACTIONS = ImmutableMap.<PiTableId, PiActionId>builder()
102 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING,
103 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_BRIDGING)
104 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
105 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4)
106 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
107 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6)
108 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
109 FabricConstants.FABRIC_INGRESS_FORWARDING_POP_MPLS_AND_NEXT)
110 .build();
111
112 ForwardingObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
113 super(deviceId, capabilities);
114 }
115
116 @Override
117 public ObjectiveTranslation doTranslate(ForwardingObjective obj)
118 throws FabricPipelinerException {
119 final ObjectiveTranslation.Builder resultBuilder =
120 ObjectiveTranslation.builder();
121 switch (obj.flag()) {
122 case SPECIFIC:
123 processSpecificFwd(obj, resultBuilder);
124 break;
125 case VERSATILE:
126 processVersatileFwd(obj, resultBuilder);
127 break;
128 case EGRESS:
129 default:
130 log.warn("Unsupported ForwardingObjective type '{}'", obj.flag());
131 return ObjectiveTranslation.ofError(ObjectiveError.UNSUPPORTED);
132 }
133 return resultBuilder.build();
134 }
135
136 private void processVersatileFwd(ForwardingObjective obj,
137 ObjectiveTranslation.Builder resultBuilder)
138 throws FabricPipelinerException {
139
140 final Set<Criterion.Type> unsupportedCriteria = obj.selector().criteria()
141 .stream()
142 .map(Criterion::type)
143 .filter(t -> !ACL_CRITERIA.contains(t))
144 .collect(Collectors.toSet());
145
146 if (!unsupportedCriteria.isEmpty()) {
147 throw new FabricPipelinerException(format(
148 "unsupported ACL criteria %s", unsupportedCriteria.toString()));
149 }
150
151 aclRule(obj, resultBuilder);
152 }
153
154 private void processSpecificFwd(ForwardingObjective obj,
155 ObjectiveTranslation.Builder resultBuilder)
156 throws FabricPipelinerException {
157
158 final Set<Criterion> criteriaWithMeta = Sets.newHashSet(obj.selector().criteria());
159
160 // FIXME: Is this really needed? Meta is such an ambiguous field...
161 // Why would we match on a META field?
162 if (obj.meta() != null) {
163 criteriaWithMeta.addAll(obj.meta().criteria());
164 }
165
166 final ForwardingFunctionType fft = ForwardingFunctionType.getForwardingFunctionType(obj);
167
168 switch (fft) {
169 case UNKNOWN:
170 throw new FabricPipelinerException(
171 "unable to detect forwarding function type");
172 case L2_UNICAST:
173 bridgingRule(obj, criteriaWithMeta, resultBuilder, false);
174 break;
175 case L2_BROADCAST:
176 bridgingRule(obj, criteriaWithMeta, resultBuilder, true);
177 break;
178 case IPV4_ROUTING:
179 case IPV4_ROUTING_MULTICAST:
180 ipv4RoutingRule(obj, criteriaWithMeta, resultBuilder);
181 break;
182 case MPLS_SEGMENT_ROUTING:
183 mplsRule(obj, criteriaWithMeta, resultBuilder);
184 break;
185 case IPV6_ROUTING:
186 case IPV6_ROUTING_MULTICAST:
187 default:
188 throw new FabricPipelinerException(format(
189 "unsupported forwarding function type '%s'",
190 fft));
191 }
192 }
193
194 private void bridgingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
195 ObjectiveTranslation.Builder resultBuilder,
196 boolean broadcast)
197 throws FabricPipelinerException {
198
199 final VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterionNotNull(
200 criteriaWithMeta, Criterion.Type.VLAN_VID);
201 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
202 .add(vlanIdCriterion);
203
204 if (!broadcast) {
205 final EthCriterion ethDstCriterion = (EthCriterion) criterionNotNull(
206 obj.selector(), Criterion.Type.ETH_DST);
207 selector.matchEthDstMasked(ethDstCriterion.mac(), MacAddress.EXACT_MASK);
208 }
209
210 resultBuilder.addFlowRule(flowRule(
211 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING, selector.build()));
212 }
213
214 private void ipv4RoutingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
215 ObjectiveTranslation.Builder resultBuilder)
216 throws FabricPipelinerException {
217 final IPCriterion ipDstCriterion = (IPCriterion) criterionNotNull(
218 criteriaWithMeta, Criterion.Type.IPV4_DST);
219
220 if (ipDstCriterion.ip().prefixLength() == 0) {
221 defaultIpv4Route(obj, resultBuilder);
222 return;
223 }
224
225 final TrafficSelector selector = DefaultTrafficSelector.builder()
226 .add(ipDstCriterion)
227 .build();
228
229 resultBuilder.addFlowRule(flowRule(
230 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
231 }
232
233 private void defaultIpv4Route(ForwardingObjective obj,
234 ObjectiveTranslation.Builder resultBuilder)
235 throws FabricPipelinerException {
236
237 // Hack to work around the inability to program default rules.
238 for (String prefix : DEFAULT_ROUTE_PREFIXES) {
239 final TrafficSelector selector = DefaultTrafficSelector.builder()
240 .matchIPDst(IpPrefix.valueOf(prefix)).build();
241 resultBuilder.addFlowRule(flowRule(
242 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
243 }
244 }
245
246 private void mplsRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
247 ObjectiveTranslation.Builder resultBuilder)
248 throws FabricPipelinerException {
249
250 final MplsCriterion mplsCriterion = (MplsCriterion) criterionNotNull(
251 criteriaWithMeta, Criterion.Type.MPLS_LABEL);
252 final TrafficSelector selector = DefaultTrafficSelector.builder()
253 .add(mplsCriterion)
254 .build();
255
256 resultBuilder.addFlowRule(flowRule(
257 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS, selector));
258 }
259
260 private void aclRule(ForwardingObjective obj,
261 ObjectiveTranslation.Builder resultBuilder)
262 throws FabricPipelinerException {
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700263 if (obj.nextId() == null && obj.treatment() != null) {
264 final TrafficTreatment treatment = obj.treatment();
265 final PortNumber outPort = outputPort(treatment);
266 if (outPort != null
267 && outPort.equals(PortNumber.CONTROLLER)
268 && treatment.allInstructions().size() == 1) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800269
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700270 final PiAction aclAction;
271 if (treatment.clearedDeferred()) {
272 aclAction = PiAction.builder()
273 .withId(FabricConstants.FABRIC_INGRESS_ACL_PUNT_TO_CPU)
274 .build();
275 } else {
276 // Action is SET_CLONE_SESSION_ID
277 if (obj.op() == Objective.Operation.ADD) {
278 // Action is ADD, create clone group
279 final DefaultGroupDescription cloneGroup =
280 createCloneGroup(obj.appId(),
281 CLONE_TO_CPU_ID,
282 outPort);
283 resultBuilder.addGroup(cloneGroup);
284 }
285 aclAction = PiAction.builder()
286 .withId(FabricConstants.FABRIC_INGRESS_ACL_SET_CLONE_SESSION_ID)
287 .withParameter(new PiActionParam(
288 FabricConstants.CLONE_ID, CLONE_TO_CPU_ID))
289 .build();
290 }
291 final TrafficTreatment piTreatment = DefaultTrafficTreatment.builder()
292 .piTableAction(aclAction)
293 .build();
294 resultBuilder.addFlowRule(flowRule(
295 obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, obj.selector(), piTreatment));
296 return;
297 }
298 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800299 resultBuilder.addFlowRule(flowRule(
300 obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, obj.selector()));
301 }
302
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700303 private DefaultGroupDescription createCloneGroup(
304 ApplicationId appId,
305 int cloneSessionId,
306 PortNumber outPort) {
307 final GroupKey groupKey = new DefaultGroupKey(
308 FabricPipeliner.KRYO.serialize(cloneSessionId));
309
310 final List<GroupBucket> bucketList = ImmutableList.of(
311 createCloneGroupBucket(DefaultTrafficTreatment.builder()
312 .setOutput(outPort)
313 .build()));
314 final DefaultGroupDescription cloneGroup = new DefaultGroupDescription(
315 deviceId, GroupDescription.Type.CLONE,
316 new GroupBuckets(bucketList),
317 groupKey, cloneSessionId, appId);
318 return cloneGroup;
319 }
320
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800321 private FlowRule flowRule(
322 ForwardingObjective obj, PiTableId tableId, TrafficSelector selector)
323 throws FabricPipelinerException {
324 return flowRule(obj, tableId, selector, nextIdOrTreatment(obj, tableId));
325 }
326
327 private static TrafficTreatment nextIdOrTreatment(
328 ForwardingObjective obj, PiTableId tableId)
329 throws FabricPipelinerException {
330 if (obj.nextId() == null) {
331 return obj.treatment();
332 } else {
333 if (!NEXT_ID_ACTIONS.containsKey(tableId)) {
334 throw new FabricPipelinerException(format(
335 "BUG? no next_id action set for table %s", tableId));
336 }
337 return DefaultTrafficTreatment.builder()
338 .piTableAction(
339 setNextIdAction(obj.nextId(),
340 NEXT_ID_ACTIONS.get(tableId)))
341 .build();
342 }
343 }
344
345 private static PiAction setNextIdAction(Integer nextId, PiActionId actionId) {
346 final PiActionParam nextIdParam = new PiActionParam(FabricConstants.NEXT_ID, nextId);
347 return PiAction.builder()
348 .withId(actionId)
349 .withParameter(nextIdParam)
350 .build();
351 }
352}