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