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