blob: 5647d263e887cb62453809006bebbececc789b81 [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
17package org.onosproject.pipelines.fabric.pipeliner;
18
19import com.google.common.collect.ImmutableMap;
20import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Lists;
22import com.google.common.collect.Sets;
23import org.onlab.packet.IpPrefix;
24import org.onlab.packet.MacAddress;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.TrafficSelector;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.flow.criteria.Criterion;
32import org.onosproject.net.flow.criteria.EthCriterion;
33import org.onosproject.net.flow.criteria.IPCriterion;
34import org.onosproject.net.flow.criteria.MplsCriterion;
35import org.onosproject.net.flow.criteria.VlanIdCriterion;
36import org.onosproject.net.flowobjective.ForwardingObjective;
37import org.onosproject.net.flowobjective.ObjectiveError;
38import org.onosproject.net.pi.model.PiActionId;
39import org.onosproject.net.pi.model.PiTableId;
40import org.onosproject.net.pi.runtime.PiAction;
41import org.onosproject.net.pi.runtime.PiActionParam;
42import org.onosproject.pipelines.fabric.FabricCapabilities;
43import org.onosproject.pipelines.fabric.FabricConstants;
44
45import java.util.List;
46import java.util.Map;
47import java.util.Set;
48import java.util.stream.Collectors;
49
50import static java.lang.String.format;
51import static org.onosproject.pipelines.fabric.FabricUtils.criterionNotNull;
52
53/**
54 * ObjectiveTranslator implementation ForwardingObjective.
55 */
56class ForwardingObjectiveTranslator
57 extends AbstractObjectiveTranslator<ForwardingObjective> {
58
59 private static final List<String> DEFAULT_ROUTE_PREFIXES = Lists.newArrayList(
60 "0.0.0.0/1", "128.0.0.0/1");
61
62 private static final Set<Criterion.Type> ACL_CRITERIA = ImmutableSet.of(
63 Criterion.Type.IN_PORT,
64 Criterion.Type.IN_PHY_PORT,
65 Criterion.Type.ETH_DST,
66 Criterion.Type.ETH_DST_MASKED,
67 Criterion.Type.ETH_SRC,
68 Criterion.Type.ETH_SRC_MASKED,
69 Criterion.Type.ETH_TYPE,
70 Criterion.Type.VLAN_VID,
71 Criterion.Type.IP_PROTO,
72 Criterion.Type.IPV4_SRC,
73 Criterion.Type.IPV4_DST,
74 Criterion.Type.TCP_SRC,
75 Criterion.Type.TCP_SRC_MASKED,
76 Criterion.Type.TCP_DST,
77 Criterion.Type.TCP_DST_MASKED,
78 Criterion.Type.UDP_SRC,
79 Criterion.Type.UDP_SRC_MASKED,
80 Criterion.Type.UDP_DST,
81 Criterion.Type.UDP_DST_MASKED,
82 Criterion.Type.ICMPV4_TYPE,
83 Criterion.Type.ICMPV4_CODE,
84 Criterion.Type.PROTOCOL_INDEPENDENT);
85
86 private static final Map<PiTableId, PiActionId> NEXT_ID_ACTIONS = ImmutableMap.<PiTableId, PiActionId>builder()
87 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING,
88 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_BRIDGING)
89 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
90 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4)
91 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
92 FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6)
93 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
94 FabricConstants.FABRIC_INGRESS_FORWARDING_POP_MPLS_AND_NEXT)
95 .build();
96
97 ForwardingObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
98 super(deviceId, capabilities);
99 }
100
101 @Override
102 public ObjectiveTranslation doTranslate(ForwardingObjective obj)
103 throws FabricPipelinerException {
104 final ObjectiveTranslation.Builder resultBuilder =
105 ObjectiveTranslation.builder();
106 switch (obj.flag()) {
107 case SPECIFIC:
108 processSpecificFwd(obj, resultBuilder);
109 break;
110 case VERSATILE:
111 processVersatileFwd(obj, resultBuilder);
112 break;
113 case EGRESS:
114 default:
115 log.warn("Unsupported ForwardingObjective type '{}'", obj.flag());
116 return ObjectiveTranslation.ofError(ObjectiveError.UNSUPPORTED);
117 }
118 return resultBuilder.build();
119 }
120
121 private void processVersatileFwd(ForwardingObjective obj,
122 ObjectiveTranslation.Builder resultBuilder)
123 throws FabricPipelinerException {
124
125 final Set<Criterion.Type> unsupportedCriteria = obj.selector().criteria()
126 .stream()
127 .map(Criterion::type)
128 .filter(t -> !ACL_CRITERIA.contains(t))
129 .collect(Collectors.toSet());
130
131 if (!unsupportedCriteria.isEmpty()) {
132 throw new FabricPipelinerException(format(
133 "unsupported ACL criteria %s", unsupportedCriteria.toString()));
134 }
135
136 aclRule(obj, resultBuilder);
137 }
138
139 private void processSpecificFwd(ForwardingObjective obj,
140 ObjectiveTranslation.Builder resultBuilder)
141 throws FabricPipelinerException {
142
143 final Set<Criterion> criteriaWithMeta = Sets.newHashSet(obj.selector().criteria());
144
145 // FIXME: Is this really needed? Meta is such an ambiguous field...
146 // Why would we match on a META field?
147 if (obj.meta() != null) {
148 criteriaWithMeta.addAll(obj.meta().criteria());
149 }
150
151 final ForwardingFunctionType fft = ForwardingFunctionType.getForwardingFunctionType(obj);
152
153 switch (fft) {
154 case UNKNOWN:
155 throw new FabricPipelinerException(
156 "unable to detect forwarding function type");
157 case L2_UNICAST:
158 bridgingRule(obj, criteriaWithMeta, resultBuilder, false);
159 break;
160 case L2_BROADCAST:
161 bridgingRule(obj, criteriaWithMeta, resultBuilder, true);
162 break;
163 case IPV4_ROUTING:
164 case IPV4_ROUTING_MULTICAST:
165 ipv4RoutingRule(obj, criteriaWithMeta, resultBuilder);
166 break;
167 case MPLS_SEGMENT_ROUTING:
168 mplsRule(obj, criteriaWithMeta, resultBuilder);
169 break;
170 case IPV6_ROUTING:
171 case IPV6_ROUTING_MULTICAST:
172 default:
173 throw new FabricPipelinerException(format(
174 "unsupported forwarding function type '%s'",
175 fft));
176 }
177 }
178
179 private void bridgingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
180 ObjectiveTranslation.Builder resultBuilder,
181 boolean broadcast)
182 throws FabricPipelinerException {
183
184 final VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterionNotNull(
185 criteriaWithMeta, Criterion.Type.VLAN_VID);
186 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
187 .add(vlanIdCriterion);
188
189 if (!broadcast) {
190 final EthCriterion ethDstCriterion = (EthCriterion) criterionNotNull(
191 obj.selector(), Criterion.Type.ETH_DST);
192 selector.matchEthDstMasked(ethDstCriterion.mac(), MacAddress.EXACT_MASK);
193 }
194
195 resultBuilder.addFlowRule(flowRule(
196 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING, selector.build()));
197 }
198
199 private void ipv4RoutingRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
200 ObjectiveTranslation.Builder resultBuilder)
201 throws FabricPipelinerException {
202 final IPCriterion ipDstCriterion = (IPCriterion) criterionNotNull(
203 criteriaWithMeta, Criterion.Type.IPV4_DST);
204
205 if (ipDstCriterion.ip().prefixLength() == 0) {
206 defaultIpv4Route(obj, resultBuilder);
207 return;
208 }
209
210 final TrafficSelector selector = DefaultTrafficSelector.builder()
211 .add(ipDstCriterion)
212 .build();
213
214 resultBuilder.addFlowRule(flowRule(
215 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
216 }
217
218 private void defaultIpv4Route(ForwardingObjective obj,
219 ObjectiveTranslation.Builder resultBuilder)
220 throws FabricPipelinerException {
221
222 // Hack to work around the inability to program default rules.
223 for (String prefix : DEFAULT_ROUTE_PREFIXES) {
224 final TrafficSelector selector = DefaultTrafficSelector.builder()
225 .matchIPDst(IpPrefix.valueOf(prefix)).build();
226 resultBuilder.addFlowRule(flowRule(
227 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, selector));
228 }
229 }
230
231 private void mplsRule(ForwardingObjective obj, Set<Criterion> criteriaWithMeta,
232 ObjectiveTranslation.Builder resultBuilder)
233 throws FabricPipelinerException {
234
235 final MplsCriterion mplsCriterion = (MplsCriterion) criterionNotNull(
236 criteriaWithMeta, Criterion.Type.MPLS_LABEL);
237 final TrafficSelector selector = DefaultTrafficSelector.builder()
238 .add(mplsCriterion)
239 .build();
240
241 resultBuilder.addFlowRule(flowRule(
242 obj, FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS, selector));
243 }
244
245 private void aclRule(ForwardingObjective obj,
246 ObjectiveTranslation.Builder resultBuilder)
247 throws FabricPipelinerException {
248
249 resultBuilder.addFlowRule(flowRule(
250 obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, obj.selector()));
251 }
252
253 private FlowRule flowRule(
254 ForwardingObjective obj, PiTableId tableId, TrafficSelector selector)
255 throws FabricPipelinerException {
256 return flowRule(obj, tableId, selector, nextIdOrTreatment(obj, tableId));
257 }
258
259 private static TrafficTreatment nextIdOrTreatment(
260 ForwardingObjective obj, PiTableId tableId)
261 throws FabricPipelinerException {
262 if (obj.nextId() == null) {
263 return obj.treatment();
264 } else {
265 if (!NEXT_ID_ACTIONS.containsKey(tableId)) {
266 throw new FabricPipelinerException(format(
267 "BUG? no next_id action set for table %s", tableId));
268 }
269 return DefaultTrafficTreatment.builder()
270 .piTableAction(
271 setNextIdAction(obj.nextId(),
272 NEXT_ID_ACTIONS.get(tableId)))
273 .build();
274 }
275 }
276
277 private static PiAction setNextIdAction(Integer nextId, PiActionId actionId) {
278 final PiActionParam nextIdParam = new PiActionParam(FabricConstants.NEXT_ID, nextId);
279 return PiAction.builder()
280 .withId(actionId)
281 .withParameter(nextIdParam)
282 .build();
283 }
284}