blob: 4e13a74d094f666a370850377d2bc6229818b955 [file] [log] [blame]
Yi Tseng0b809722017-11-03 10:23:26 -07001/*
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;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080021import com.google.common.collect.Lists;
Yi Tseng0b809722017-11-03 10:23:26 -070022import com.google.common.collect.Sets;
23import org.onosproject.net.flow.criteria.Criterion;
24import org.onosproject.net.flowobjective.ForwardingObjective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080025import org.slf4j.Logger;
Yi Tseng0b809722017-11-03 10:23:26 -070026
Carmelo Casconeb5324e72018-11-25 02:26:32 -080027import java.util.Arrays;
28import java.util.Collection;
29import java.util.Collections;
30import java.util.List;
Yi Tseng0b809722017-11-03 10:23:26 -070031import java.util.Map;
32import java.util.Set;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080033import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070034
35import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_DST;
36import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_TYPE;
37import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
38import static org.onosproject.net.flow.criteria.Criterion.Type.IPV6_DST;
39import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_BOS;
40import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_LABEL;
41import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080042import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_ETH_DST_NONE;
43import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_ETH_TYPE_IPV4;
44import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_ETH_TYPE_IPV6;
45import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_ETH_TYPE_MPLS;
46import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_MPLS_BOS_FALSE;
47import static org.onosproject.pipelines.fabric.pipeliner.ForwardingFunctionTypeCommons.MATCH_MPLS_BOS_TRUE;
48import static org.slf4j.LoggerFactory.getLogger;
Yi Tseng0b809722017-11-03 10:23:26 -070049
Carmelo Casconeb5324e72018-11-25 02:26:32 -080050/**
51 * Forwarding function types (FFTs) that can represent a given forwarding
52 * objective. Each FFT is defined by a subset of criterion types expected to be
53 * found in the selector of the given objective, and, optionally, by their
54 * respective values (criterion instances) to match or to mismatch.
55 */
56enum ForwardingFunctionType {
Yi Tseng0b809722017-11-03 10:23:26 -070057 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080058 * L2 unicast.
Yi Tseng0b809722017-11-03 10:23:26 -070059 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080060 L2_UNICAST(
61 Sets.newHashSet(VLAN_VID, ETH_DST), // Expected criterion types.
62 Collections.emptyList(), // Criteria to match.
63 Lists.newArrayList(MATCH_ETH_DST_NONE)), // Criteria NOT to match.
Yi Tseng0b809722017-11-03 10:23:26 -070064
65 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080066 * L2 broadcast.
Yi Tseng0b809722017-11-03 10:23:26 -070067 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080068 L2_BROADCAST(
69 Sets.newHashSet(VLAN_VID, ETH_DST),
70 Lists.newArrayList(MATCH_ETH_DST_NONE),
71 Collections.emptyList()),
72 L2_BROADCAST_ALIAS(
73 Sets.newHashSet(VLAN_VID),
74 Collections.emptyList(),
75 Collections.emptyList(),
76 L2_BROADCAST), // (Optional) FFT to return if selected.
Yi Tseng0b809722017-11-03 10:23:26 -070077
78 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080079 * IPv4 unicast.
Yi Tseng0b809722017-11-03 10:23:26 -070080 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080081 IPV4_ROUTING(
82 Sets.newHashSet(ETH_TYPE, IPV4_DST),
83 Lists.newArrayList(MATCH_ETH_TYPE_IPV4),
84 Collections.emptyList()),
Yi Tseng0b809722017-11-03 10:23:26 -070085
86 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080087 * IPv4 multicast.
Yi Tseng0b809722017-11-03 10:23:26 -070088 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080089 IPV4_ROUTING_MULTICAST(
90 Sets.newHashSet(ETH_TYPE, VLAN_VID, IPV4_DST),
91 Lists.newArrayList(MATCH_ETH_TYPE_IPV4),
92 Collections.emptyList()),
Yi Tseng0b809722017-11-03 10:23:26 -070093
94 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080095 * IPv6 unicast.
Yi Tseng0b809722017-11-03 10:23:26 -070096 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080097 IPV6_ROUTING(
98 Sets.newHashSet(ETH_TYPE, IPV6_DST),
99 Lists.newArrayList(MATCH_ETH_TYPE_IPV6),
100 Collections.emptyList()),
Yi Tseng0b809722017-11-03 10:23:26 -0700101
102 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800103 * IPv6 multicast.
Yi Tseng1b154bd2017-11-20 17:48:19 -0800104 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800105 IPV6_ROUTING_MULTICAST(
106 Sets.newHashSet(ETH_TYPE, VLAN_VID, IPV6_DST),
107 Lists.newArrayList(MATCH_ETH_TYPE_IPV6),
108 Collections.emptyList()),
109
110 /**
111 * MPLS segment routing.
112 */
113 MPLS_SEGMENT_ROUTING(
114 Sets.newHashSet(ETH_TYPE, MPLS_LABEL, MPLS_BOS),
115 Lists.newArrayList(MATCH_ETH_TYPE_MPLS, MATCH_MPLS_BOS_TRUE),
116 Collections.emptyList()),
117
118 /**
119 * Pseudo-wire.
120 */
121 PSEUDO_WIRE(
122 Sets.newHashSet(ETH_TYPE, MPLS_LABEL, MPLS_BOS),
123 Lists.newArrayList(MATCH_ETH_TYPE_MPLS, MATCH_MPLS_BOS_FALSE),
124 Collections.emptyList()),
Yi Tseng1b154bd2017-11-20 17:48:19 -0800125
126 /**
Yi Tseng0b809722017-11-03 10:23:26 -0700127 * Unsupported type.
128 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800129 UNKNOWN(
130 Collections.emptySet(),
131 Collections.emptyList(),
132 Collections.emptyList());
Yi Tseng0b809722017-11-03 10:23:26 -0700133
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800134 private static final Logger log = getLogger(ForwardingFunctionType.class);
Yi Tseng0b809722017-11-03 10:23:26 -0700135
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800136 private final Set<Criterion.Type> expectedCriterionTypes;
137 private final Map<Criterion.Type, List<Criterion>> matchCriteria;
138 private final Map<Criterion.Type, List<Criterion>> mismatchCriteria;
139 private final ForwardingFunctionType originalType;
Yi Tseng0b809722017-11-03 10:23:26 -0700140
141 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800142 * Creates a new FFT.
Yi Tseng0b809722017-11-03 10:23:26 -0700143 *
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800144 * @param expectedCriterionTypes expected criterion types
145 * @param matchCriteria criterion instances to match
146 * @param mismatchCriteria criterion instance not to be matched
Yi Tseng0b809722017-11-03 10:23:26 -0700147 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800148 ForwardingFunctionType(Set<Criterion.Type> expectedCriterionTypes,
149 Collection<Criterion> matchCriteria,
150 Collection<Criterion> mismatchCriteria) {
151 this(expectedCriterionTypes, matchCriteria, mismatchCriteria, null);
Yi Tseng0b809722017-11-03 10:23:26 -0700152 }
Esin Karaman971fb7f2017-12-28 13:44:52 +0000153
154 /**
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800155 * Creates a new alias FFT that if matched, should return the given original
156 * FFT.
Esin Karaman971fb7f2017-12-28 13:44:52 +0000157 *
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800158 * @param expectedCriterionTypes expected criterion types
159 * @param matchCriteria criterion instances to match
160 * @param mismatchCriteria criterion instance not to be matched
161 * @param original original FFT to return
Esin Karaman971fb7f2017-12-28 13:44:52 +0000162 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800163 ForwardingFunctionType(Set<Criterion.Type> expectedCriterionTypes,
164 Collection<Criterion> matchCriteria,
165 Collection<Criterion> mismatchCriteria,
166 ForwardingFunctionType original) {
167 this.expectedCriterionTypes = ImmutableSet.copyOf(expectedCriterionTypes);
168 this.matchCriteria = typeToCriteriaMap(matchCriteria);
169 this.mismatchCriteria = typeToCriteriaMap(mismatchCriteria);
170 this.originalType = original == null ? this : original;
171 }
172
173 /**
174 * Attempts to guess the forwarding function type of the given forwarding
175 * objective.
176 *
177 * @param fwd the forwarding objective
178 * @return forwarding function type. {@link #UNKNOWN} if the FFT cannot be
179 * determined.
180 */
181 public static ForwardingFunctionType getForwardingFunctionType(ForwardingObjective fwd) {
182 final Set<Criterion> criteria = criteriaIncludingMeta(fwd);
183 final Set<Criterion.Type> criterionTypes = criteria.stream()
184 .map(Criterion::type).collect(Collectors.toSet());
185
186 final List<ForwardingFunctionType> candidates = Arrays.stream(ForwardingFunctionType.values())
187 // Keep FFTs which expected criterion types are the same found
188 // in the fwd objective.
189 .filter(fft -> fft.expectedCriterionTypes.equals(criterionTypes))
190 // Keep FFTs which match criteria are found in the fwd objective.
191 .filter(fft -> matchFft(criteria, fft))
192 // Keep FFTs which mismatch criteria are NOT found in the objective.
193 .filter(fft -> mismatchFft(criteria, fft))
194 .collect(Collectors.toList());
195
196 switch (candidates.size()) {
197 case 1:
198 return candidates.get(0).originalType;
199 case 0:
200 return UNKNOWN;
201 default:
202 log.warn("Multiple FFT candidates found: {} [{}]", candidates, fwd);
203 return UNKNOWN;
204 }
205 }
206
207 private static boolean matchFft(Collection<Criterion> criteria, ForwardingFunctionType fft) {
208 return matchOrMismatchFft(criteria, fft.matchCriteria, false);
209 }
210
211 private static boolean mismatchFft(Collection<Criterion> criteria, ForwardingFunctionType fft) {
212 return matchOrMismatchFft(criteria, fft.mismatchCriteria, true);
213 }
214
215 private static boolean matchOrMismatchFft(
216 Collection<Criterion> criteria,
217 Map<Criterion.Type, List<Criterion>> criteriaToMatch,
218 boolean mismatch) {
219 final Map<Criterion.Type, Criterion> givenCriteria = typeToCriterionMap(criteria);
220 for (Criterion.Type typeToMatch : criteriaToMatch.keySet()) {
221 if (!givenCriteria.containsKey(typeToMatch)) {
222 return false;
223 }
224 final boolean matchFound = criteriaToMatch.get(typeToMatch).stream()
225 .anyMatch(c -> mismatch != givenCriteria.get(c.type()).equals(c));
226 if (!matchFound) {
227 return false;
228 }
229 }
230 return true;
231 }
232
233 private static Set<Criterion> criteriaIncludingMeta(ForwardingObjective fwd) {
234 final Set<Criterion> criteria = Sets.newHashSet();
235 criteria.addAll(fwd.selector().criteria());
236 // FIXME: Is this really needed? Meta is such an ambiguous field...
237 if (fwd.meta() != null) {
238 criteria.addAll(fwd.meta().criteria());
239 }
240 return criteria;
241 }
242
243 private static Map<Criterion.Type, List<Criterion>> typeToCriteriaMap(Collection<Criterion> criteria) {
244 return criteria.stream().collect(Collectors.groupingBy(Criterion::type));
245 }
246
247 private static Map<Criterion.Type, Criterion> typeToCriterionMap(Collection<Criterion> criteria) {
248 final ImmutableMap.Builder<Criterion.Type, Criterion> mapBuilder = ImmutableMap.builder();
249 criteria.forEach(c -> mapBuilder.put(c.type(), c));
250 return mapBuilder.build();
Esin Karaman971fb7f2017-12-28 13:44:52 +0000251 }
Yi Tseng0b809722017-11-03 10:23:26 -0700252}