blob: e0c7ec103744fd6c8338af7765600c1a8ee89a9f [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
Carmelo Cascone356ab8b2019-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;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080022import com.google.common.collect.Sets;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080023import org.onlab.packet.MacAddress;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070024import org.onosproject.core.ApplicationId;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080025import org.onosproject.net.DeviceId;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070026import org.onosproject.net.PortNumber;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080027import org.onosproject.net.flow.DefaultTrafficSelector;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.FlowRule;
30import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.flow.criteria.Criterion;
33import org.onosproject.net.flow.criteria.EthCriterion;
34import org.onosproject.net.flow.criteria.IPCriterion;
35import org.onosproject.net.flow.criteria.MplsCriterion;
Wailok Shumfb7e7872021-06-18 17:30:08 +080036import org.onosproject.net.flow.criteria.PiCriterion;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080037import org.onosproject.net.flow.criteria.VlanIdCriterion;
38import org.onosproject.net.flowobjective.ForwardingObjective;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070039import org.onosproject.net.flowobjective.Objective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080040import org.onosproject.net.flowobjective.ObjectiveError;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070041import org.onosproject.net.group.DefaultGroupDescription;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070042import org.onosproject.net.group.DefaultGroupKey;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070043import org.onosproject.net.group.GroupBucket;
44import org.onosproject.net.group.GroupBuckets;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070045import org.onosproject.net.group.GroupDescription;
46import org.onosproject.net.group.GroupKey;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080047import org.onosproject.net.pi.model.PiActionId;
48import org.onosproject.net.pi.model.PiTableId;
49import org.onosproject.net.pi.runtime.PiAction;
50import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070051import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080052import org.onosproject.pipelines.fabric.FabricConstants;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080053
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57import java.util.stream.Collectors;
58
59import static java.lang.String.format;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070060import static org.onosproject.net.group.DefaultGroupBucket.createCloneGroupBucket;
pierventre4d29d3c2021-08-27 17:20:00 +020061import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PAIR_PORT;
62import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.isSrMetadataSet;
63import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.isValidSrMetadata;
64import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.portType;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070065import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterionNotNull;
66import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.outputPort;
Wailok Shumfb7e7872021-06-18 17:30:08 +080067import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_MASK;
68import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_EDGE;
69import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_INFRA;
Daniele Moro01ca2ab2019-06-25 11:48:48 -070070
Carmelo Casconeb5324e72018-11-25 02:26:32 -080071
72/**
73 * ObjectiveTranslator implementation ForwardingObjective.
74 */
75class ForwardingObjectiveTranslator
76 extends AbstractObjectiveTranslator<ForwardingObjective> {
77
Daniele Moro01ca2ab2019-06-25 11:48:48 -070078 //FIXME: Max number supported by PI
79 static final int CLONE_TO_CPU_ID = 511;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080080
81 private static final Set<Criterion.Type> ACL_CRITERIA = ImmutableSet.of(
82 Criterion.Type.IN_PORT,
83 Criterion.Type.IN_PHY_PORT,
84 Criterion.Type.ETH_DST,
85 Criterion.Type.ETH_DST_MASKED,
86 Criterion.Type.ETH_SRC,
87 Criterion.Type.ETH_SRC_MASKED,
88 Criterion.Type.ETH_TYPE,
89 Criterion.Type.VLAN_VID,
90 Criterion.Type.IP_PROTO,
91 Criterion.Type.IPV4_SRC,
92 Criterion.Type.IPV4_DST,
93 Criterion.Type.TCP_SRC,
94 Criterion.Type.TCP_SRC_MASKED,
95 Criterion.Type.TCP_DST,
96 Criterion.Type.TCP_DST_MASKED,
97 Criterion.Type.UDP_SRC,
98 Criterion.Type.UDP_SRC_MASKED,
99 Criterion.Type.UDP_DST,
100 Criterion.Type.UDP_DST_MASKED,
101 Criterion.Type.ICMPV4_TYPE,
102 Criterion.Type.ICMPV4_CODE,
103 Criterion.Type.PROTOCOL_INDEPENDENT);
104
105 private static final Map<PiTableId, PiActionId> NEXT_ID_ACTIONS = ImmutableMap.<PiTableId, PiActionId>builder()
106 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING,
107 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_BRIDGING)
108 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
109 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4)
110 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
111 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6)
112 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
113 FabricConstants.FABRIC_INGRESS_FORWARDING_POP_MPLS_AND_NEXT)
Wailok Shumfb7e7872021-06-18 17:30:08 +0800114 .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
115 FabricConstants.FABRIC_INGRESS_ACL_SET_NEXT_ID_ACL)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800116 .build();
117
118 ForwardingObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
119 super(deviceId, capabilities);
120 }
121
122 @Override
123 public ObjectiveTranslation doTranslate(ForwardingObjective obj)
124 throws FabricPipelinerException {
pierventre4d29d3c2021-08-27 17:20:00 +0200125
126 if (!isValidSrMetadata(obj)) {
127 throw new FabricPipelinerException(
128 format("Unsupported metadata configuration: metadata=%s", obj.meta()),
129 ObjectiveError.BADPARAMS);
130 }
131
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800132 final ObjectiveTranslation.Builder resultBuilder =
133 ObjectiveTranslation.builder();
134 switch (obj.flag()) {
135 case SPECIFIC:
136 processSpecificFwd(obj, resultBuilder);
137 break;
138 case VERSATILE:
139 processVersatileFwd(obj, resultBuilder);
140 break;
141 case EGRESS:
142 default:
143 log.warn("Unsupported ForwardingObjective type '{}'", obj.flag());
144 return ObjectiveTranslation.ofError(ObjectiveError.UNSUPPORTED);
145 }
146 return resultBuilder.build();
147 }
148
149 private void processVersatileFwd(ForwardingObjective obj,
150 ObjectiveTranslation.Builder resultBuilder)
151 throws FabricPipelinerException {
152
153 final Set<Criterion.Type> unsupportedCriteria = obj.selector().criteria()
154 .stream()
155 .map(Criterion::type)
156 .filter(t -> !ACL_CRITERIA.contains(t))
157 .collect(Collectors.toSet());
158
159 if (!unsupportedCriteria.isEmpty()) {
160 throw new FabricPipelinerException(format(
161 "unsupported ACL criteria %s", unsupportedCriteria.toString()));
162 }
163
164 aclRule(obj, resultBuilder);
165 }
166
167 private void processSpecificFwd(ForwardingObjective obj,
168 ObjectiveTranslation.Builder resultBuilder)
169 throws FabricPipelinerException {
170
171 final Set<Criterion> criteriaWithMeta = Sets.newHashSet(obj.selector().criteria());
172
173 // FIXME: Is this really needed? Meta is such an ambiguous field...
174 // Why would we match on a META field?
175 if (obj.meta() != null) {
176 criteriaWithMeta.addAll(obj.meta().criteria());
177 }
178
179 final ForwardingFunctionType fft = ForwardingFunctionType.getForwardingFunctionType(obj);
180
181 switch (fft) {
182 case UNKNOWN:
183 throw new FabricPipelinerException(
184 "unable to detect forwarding function type");
185 case L2_UNICAST:
186 bridgingRule(obj, criteriaWithMeta, resultBuilder, false);
187 break;
188 case L2_BROADCAST:
189 bridgingRule(obj, criteriaWithMeta, resultBuilder, true);
190 break;
191 case IPV4_ROUTING:
192 case IPV4_ROUTING_MULTICAST:
193 ipv4RoutingRule(obj, criteriaWithMeta, resultBuilder);
194 break;
195 case MPLS_SEGMENT_ROUTING:
196 mplsRule(obj, criteriaWithMeta, resultBuilder);
197 break;
198 case IPV6_ROUTING:
199 case IPV6_ROUTING_MULTICAST:
200 default:
201 throw new FabricPipelinerException(format(
202 "unsupported forwarding function type '%s'",
203 fft));
204 }
205 }
206
207 private void bridgingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
208 ObjectiveTranslation.Builder resultBuilder,
209 boolean broadcast)
210 throws FabricPipelinerException {
211
212 final VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterionNotNull(
213 criteriaWithMeta, Criterion.Type.VLAN_VID);
214 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
215 .add(vlanIdCriterion);
216
217 if (!broadcast) {
218 final EthCriterion ethDstCriterion = (EthCriterion) criterionNotNull(
219 obj.selector(), Criterion.Type.ETH_DST);
220 selector.matchEthDstMasked(ethDstCriterion.mac(), MacAddress.EXACT_MASK);
221 }
222
223 resultBuilder.addFlowRule(flowRule(
224 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING, selector.build()));
225 }
226
227 private void ipv4RoutingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
228 ObjectiveTranslation.Builder resultBuilder)
229 throws FabricPipelinerException {
230 final IPCriterion ipDstCriterion = (IPCriterion) criterionNotNull(
231 criteriaWithMeta, Criterion.Type.IPV4_DST);
232
233 if (ipDstCriterion.ip().prefixLength() == 0) {
234 defaultIpv4Route(obj, resultBuilder);
235 return;
236 }
237
238 final TrafficSelector selector = DefaultTrafficSelector.builder()
239 .add(ipDstCriterion)
240 .build();
241
242 resultBuilder.addFlowRule(flowRule(
243 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
244 }
245
246 private void defaultIpv4Route(ForwardingObjective obj,
247 ObjectiveTranslation.Builder resultBuilder)
248 throws FabricPipelinerException {
CyberHasHe9ba39c2019-10-11 05:59:12 +0800249 ForwardingObjective defaultObj = obj.copy()
250 .withPriority(0)
251 .add();
252 final TrafficSelector selector = DefaultTrafficSelector.emptySelector();
253 resultBuilder.addFlowRule(flowRule(
254 defaultObj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800255 }
256
257 private void mplsRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
258 ObjectiveTranslation.Builder resultBuilder)
259 throws FabricPipelinerException {
260
261 final MplsCriterion mplsCriterion = (MplsCriterion) criterionNotNull(
262 criteriaWithMeta, Criterion.Type.MPLS_LABEL);
263 final TrafficSelector selector = DefaultTrafficSelector.builder()
264 .add(mplsCriterion)
265 .build();
266
267 resultBuilder.addFlowRule(flowRule(
268 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS, selector));
269 }
270
271 private void aclRule(ForwardingObjective obj,
272 ObjectiveTranslation.Builder resultBuilder)
273 throws FabricPipelinerException {
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700274 if (obj.nextId() == null && obj.treatment() != null) {
275 final TrafficTreatment treatment = obj.treatment();
276 final PortNumber outPort = outputPort(treatment);
277 if (outPort != null
278 && outPort.equals(PortNumber.CONTROLLER)
279 && treatment.allInstructions().size() == 1) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800280
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700281 final PiAction aclAction;
282 if (treatment.clearedDeferred()) {
283 aclAction = PiAction.builder()
284 .withId(FabricConstants.FABRIC_INGRESS_ACL_PUNT_TO_CPU)
285 .build();
286 } else {
287 // Action is SET_CLONE_SESSION_ID
288 if (obj.op() == Objective.Operation.ADD) {
289 // Action is ADD, create clone group
290 final DefaultGroupDescription cloneGroup =
291 createCloneGroup(obj.appId(),
292 CLONE_TO_CPU_ID,
293 outPort);
294 resultBuilder.addGroup(cloneGroup);
295 }
296 aclAction = PiAction.builder()
297 .withId(FabricConstants.FABRIC_INGRESS_ACL_SET_CLONE_SESSION_ID)
298 .withParameter(new PiActionParam(
299 FabricConstants.CLONE_ID, CLONE_TO_CPU_ID))
300 .build();
301 }
302 final TrafficTreatment piTreatment = DefaultTrafficTreatment.builder()
303 .piTableAction(aclAction)
304 .build();
305 resultBuilder.addFlowRule(flowRule(
306 obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, obj.selector(), piTreatment));
307 return;
308 }
309 }
Wailok Shumfb7e7872021-06-18 17:30:08 +0800310 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(obj.selector());
311 // Meta are used to signal the port type which can be edge or infra
pierventre4d29d3c2021-08-27 17:20:00 +0200312 Byte portType = portType(obj);
313 if (portType != null && !isSrMetadataSet(obj, PAIR_PORT)) {
Wailok Shumfb7e7872021-06-18 17:30:08 +0800314 if (portType == PORT_TYPE_EDGE || portType == PORT_TYPE_INFRA) {
315 selectorBuilder.matchPi(PiCriterion.builder()
pierventre4d29d3c2021-08-27 17:20:00 +0200316 .matchTernary(FabricConstants.HDR_PORT_TYPE, (long) portType, PORT_TYPE_MASK)
Wailok Shumfb7e7872021-06-18 17:30:08 +0800317 .build());
318 } else {
319 throw new FabricPipelinerException(format("Port type '%s' is not allowed for table '%s'",
320 portType, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN),
321 ObjectiveError.UNSUPPORTED);
322 }
323 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800324 resultBuilder.addFlowRule(flowRule(
Wailok Shumfb7e7872021-06-18 17:30:08 +0800325 obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, selectorBuilder.build()));
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800326 }
327
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700328 private DefaultGroupDescription createCloneGroup(
329 ApplicationId appId,
330 int cloneSessionId,
331 PortNumber outPort) {
332 final GroupKey groupKey = new DefaultGroupKey(
333 FabricPipeliner.KRYO.serialize(cloneSessionId));
334
335 final List<GroupBucket> bucketList = ImmutableList.of(
336 createCloneGroupBucket(DefaultTrafficTreatment.builder()
337 .setOutput(outPort)
338 .build()));
339 final DefaultGroupDescription cloneGroup = new DefaultGroupDescription(
340 deviceId, GroupDescription.Type.CLONE,
341 new GroupBuckets(bucketList),
342 groupKey, cloneSessionId, appId);
343 return cloneGroup;
344 }
345
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800346 private FlowRule flowRule(
347 ForwardingObjective obj, PiTableId tableId, TrafficSelector selector)
348 throws FabricPipelinerException {
349 return flowRule(obj, tableId, selector, nextIdOrTreatment(obj, tableId));
350 }
351
352 private static TrafficTreatment nextIdOrTreatment(
353 ForwardingObjective obj, PiTableId tableId)
354 throws FabricPipelinerException {
355 if (obj.nextId() == null) {
356 return obj.treatment();
357 } else {
358 if (!NEXT_ID_ACTIONS.containsKey(tableId)) {
359 throw new FabricPipelinerException(format(
360 "BUG? no next_id action set for table %s", tableId));
361 }
362 return DefaultTrafficTreatment.builder()
363 .piTableAction(
364 setNextIdAction(obj.nextId(),
365 NEXT_ID_ACTIONS.get(tableId)))
366 .build();
367 }
368 }
369
370 private static PiAction setNextIdAction(Integer nextId, PiActionId actionId) {
371 final PiActionParam nextIdParam = new PiActionParam(FabricConstants.NEXT_ID, nextId);
372 return PiAction.builder()
373 .withId(actionId)
374 .withParameter(nextIdParam)
375 .build();
376 }
377}