blob: 3ecdd613b0d6844340157e1b9f552aa83e269442 [file] [log] [blame]
Saurav Das261c3002017-06-13 15:35:54 -07001/*
2 * Copyright 2015-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.segmentrouting.grouphandler;
18
19import org.onosproject.net.DeviceId;
20import org.slf4j.Logger;
21
22import com.google.common.base.MoreObjects.ToStringHelper;
23import java.util.HashSet;
24import java.util.Objects;
25import java.util.Set;
26
27import static com.google.common.base.MoreObjects.toStringHelper;
28import static org.slf4j.LoggerFactory.getLogger;
29
30/**
Saurav Das97241862018-02-14 14:14:54 -080031 * Representation of a set of destination switch dpids along with their
32 * edge-node labels. Meant to be used as a lookup-key in a hash-map to retrieve
33 * an ECMP-group that hashes packets towards a specific destination switch, or
34 * paired-destination switches. May also be used to represent cases where the
35 * forwarding does not use ECMP groups (ie SIMPLE next objectives)
Saurav Das261c3002017-06-13 15:35:54 -070036 */
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070037public final class DestinationSet {
Saurav Das261c3002017-06-13 15:35:54 -070038 public static final int NO_EDGE_LABEL = -1;
39 private static final int NOT_ASSIGNED = 0;
Saurav Das261c3002017-06-13 15:35:54 -070040 private final DeviceId dstSw1;
41 private final int edgeLabel1;
42 private final DeviceId dstSw2;
43 private final int edgeLabel2;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070044 private final DestinationSetType typeOfDstSet;
Saurav Das261c3002017-06-13 15:35:54 -070045
Ray Milkey5247fa92018-01-12 14:22:06 -080046 private static final Logger log = getLogger(DestinationSet.class);
Saurav Das261c3002017-06-13 15:35:54 -070047
48 /**
49 * Constructor for a single destination with no Edge label.
50 *
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070051 * @param dsType type of next objective
Saurav Das261c3002017-06-13 15:35:54 -070052 * @param dstSw the destination switch
53 */
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070054 private DestinationSet(DestinationSetType dsType, DeviceId dstSw) {
Saurav Das261c3002017-06-13 15:35:54 -070055 this.edgeLabel1 = NO_EDGE_LABEL;
Saurav Das261c3002017-06-13 15:35:54 -070056 this.dstSw1 = dstSw;
57 this.edgeLabel2 = NOT_ASSIGNED;
58 this.dstSw2 = null;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070059 this.typeOfDstSet = dsType;
Saurav Das261c3002017-06-13 15:35:54 -070060 }
61
62 /**
63 * Constructor for a single destination with Edge label.
64 *
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070065 * @param dsType type of next objective
Saurav Das261c3002017-06-13 15:35:54 -070066 * @param edgeLabel label to be pushed as part of group operation
67 * @param dstSw the destination switch
68 */
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070069 private DestinationSet(DestinationSetType dsType,
70 int edgeLabel, DeviceId dstSw) {
Saurav Das261c3002017-06-13 15:35:54 -070071 this.edgeLabel1 = edgeLabel;
72 this.dstSw1 = dstSw;
73 this.edgeLabel2 = NOT_ASSIGNED;
74 this.dstSw2 = null;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070075 this.typeOfDstSet = dsType;
Saurav Das261c3002017-06-13 15:35:54 -070076 }
77
78 /**
Saurav Das97241862018-02-14 14:14:54 -080079 * Constructor for paired destination switches and their associated edge
80 * labels.
Saurav Das261c3002017-06-13 15:35:54 -070081 *
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070082 * @param dsType type of next objective
Saurav Das97241862018-02-14 14:14:54 -080083 * @param edgeLabel1 label to be pushed as part of group operation for
84 * dstSw1
Saurav Das261c3002017-06-13 15:35:54 -070085 * @param dstSw1 one of the paired destination switches
Saurav Das97241862018-02-14 14:14:54 -080086 * @param edgeLabel2 label to be pushed as part of group operation for
87 * dstSw2
Saurav Das261c3002017-06-13 15:35:54 -070088 * @param dstSw2 the other paired destination switch
89 */
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -070090 private DestinationSet(DestinationSetType dsType,
Saurav Das261c3002017-06-13 15:35:54 -070091 int edgeLabel1, DeviceId dstSw1,
92 int edgeLabel2, DeviceId dstSw2) {
Saurav Das261c3002017-06-13 15:35:54 -070093 if (dstSw1.toString().compareTo(dstSw2.toString()) <= 0) {
94 this.edgeLabel1 = edgeLabel1;
95 this.dstSw1 = dstSw1;
96 this.edgeLabel2 = edgeLabel2;
97 this.dstSw2 = dstSw2;
98 } else {
99 this.edgeLabel1 = edgeLabel2;
100 this.dstSw1 = dstSw2;
101 this.edgeLabel2 = edgeLabel1;
102 this.dstSw2 = dstSw1;
103 }
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700104 this.typeOfDstSet = dsType;
Saurav Das261c3002017-06-13 15:35:54 -0700105 }
Saurav Das261c3002017-06-13 15:35:54 -0700106 /**
107 * Default constructor for kryo serialization.
108 */
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700109 private DestinationSet() {
Saurav Das261c3002017-06-13 15:35:54 -0700110 this.edgeLabel1 = NOT_ASSIGNED;
111 this.edgeLabel2 = NOT_ASSIGNED;
Saurav Das261c3002017-06-13 15:35:54 -0700112 this.dstSw1 = DeviceId.NONE;
113 this.dstSw2 = DeviceId.NONE;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700114 this.typeOfDstSet = null;
Saurav Das261c3002017-06-13 15:35:54 -0700115 }
116
117 /**
Saurav Das261c3002017-06-13 15:35:54 -0700118 * Gets the label associated with given destination switch.
119 *
120 * @param dstSw the destination switch
121 * @return integer the label associated with the destination switch
122 */
123 public int getEdgeLabel(DeviceId dstSw) {
124 if (dstSw.equals(dstSw1)) {
125 return edgeLabel1;
126 } else if (dstSw.equals(dstSw2)) {
127 return edgeLabel2;
128 }
129 return NOT_ASSIGNED;
130 }
131
132 /**
133 * Gets all the destination switches in this destination set.
134 *
135 * @return a set of destination switch ids
136 */
137 public Set<DeviceId> getDestinationSwitches() {
138 Set<DeviceId> dests = new HashSet<>();
139 dests.add(dstSw1);
140 if (dstSw2 != null) {
141 dests.add(dstSw2);
142 }
143 return dests;
144 }
145
146 /**
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700147 * Returns the type of this ds.
148 *
149 * @return the type of the destination set
150 */
151 public DestinationSetType getTypeOfDstSet() {
152 return typeOfDstSet;
153 }
154
155 /**
156 * Returns true if the next objective represented by this destination set
157 * is of type SWAP_NOT_BOS or POP_NOT_BOS.
Saurav Das261c3002017-06-13 15:35:54 -0700158 *
Saurav Das97241862018-02-14 14:14:54 -0800159 * @return the value of notBos
Saurav Das261c3002017-06-13 15:35:54 -0700160 */
Saurav Das97241862018-02-14 14:14:54 -0800161 public boolean notBos() {
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700162 if ((typeOfDstSet == DestinationSetType.SWAP_NOT_BOS) || (typeOfDstSet == DestinationSetType.POP_NOT_BOS)) {
163 return true;
164 }
165 return false;
Saurav Das97241862018-02-14 14:14:54 -0800166 }
167
168 /**
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700169 * Returns true if the next objective represented by this destination set
170 * is of type SWAP_NOT_BOS or SWAP_BOS.
Saurav Das97241862018-02-14 14:14:54 -0800171 *
172 * @return the value of swap
173 */
174 public boolean swap() {
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700175 if ((typeOfDstSet == DestinationSetType.SWAP_BOS) || (typeOfDstSet == DestinationSetType.SWAP_NOT_BOS)) {
176 return true;
177 }
178 return false;
Saurav Das261c3002017-06-13 15:35:54 -0700179 }
180
181 // The list of destination ids and label are used for comparison.
182 @Override
183 public boolean equals(Object o) {
184 if (this == o) {
185 return true;
186 }
187 if (!(o instanceof DestinationSet)) {
188 return false;
189 }
190 DestinationSet that = (DestinationSet) o;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700191 if (this.typeOfDstSet != that.typeOfDstSet) {
192 return false;
193 }
Saurav Das261c3002017-06-13 15:35:54 -0700194 boolean equal = (this.edgeLabel1 == that.edgeLabel1 &&
Saurav Das261c3002017-06-13 15:35:54 -0700195 this.dstSw1.equals(that.dstSw1));
196 if (this.dstSw2 != null && that.dstSw2 == null ||
197 this.dstSw2 == null && that.dstSw2 != null) {
198 return false;
199 }
200 if (this.dstSw2 != null && that.dstSw2 != null) {
201 equal = equal && (this.edgeLabel2 == that.edgeLabel2 &&
202 this.dstSw2.equals(that.dstSw2));
203 }
204 return equal;
205 }
206
207 // The list of destination ids and label are used for comparison.
208 @Override
209 public int hashCode() {
210 if (dstSw2 == null) {
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700211 return Objects.hash(typeOfDstSet, edgeLabel1, dstSw1);
Saurav Das261c3002017-06-13 15:35:54 -0700212 }
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700213 return Objects.hash(typeOfDstSet, edgeLabel1, dstSw1, edgeLabel2,
Saurav Das97241862018-02-14 14:14:54 -0800214 dstSw2);
Saurav Das261c3002017-06-13 15:35:54 -0700215 }
216
217 @Override
218 public String toString() {
219 ToStringHelper h = toStringHelper(this)
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700220 .add("Type", typeOfDstSet.getType())
Saurav Das261c3002017-06-13 15:35:54 -0700221 .add("DstSw1", dstSw1)
222 .add("Label1", edgeLabel1);
223 if (dstSw2 != null) {
224 h.add("DstSw2", dstSw2)
225 .add("Label2", edgeLabel2);
226 }
227 return h.toString();
228 }
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700229
230 public enum DestinationSetType {
231 /**
232 * Used to represent DestinationSetType where the next hop
233 * is the same as the final destination.
234 */
235 PUSH_NONE("pushnon"),
236 /**
237 * Used to represent DestinationSetType where we need to
238 * push a single mpls label, that of the destination.
239 */
240 PUSH_BOS("pushbos"),
241 /**
242 * Used to represent DestinationSetType where we need to pop
243 * an mpls label which has the bos bit set.
244 */
245 POP_BOS("pop-bos"),
246 /**
247 * Used to represent DestinationSetType where we swap the outer
248 * mpls label with a new one, and where the outer label has the
249 * bos bit set.
250 */
251 SWAP_BOS("swapbos"),
252 /**
253 * Used to represent DestinationSetType where we need to pop
254 * an mpls label which does not have the bos bit set.
255 */
256 POP_NOT_BOS("popnbos"),
257 /**
258 * Used to represent DestinationSetType where we swap the outer
259 * mpls label with a new one, and where the outer label does not
260 * have the bos bit set.
261 */
262 SWAP_NOT_BOS("swap-nb");
263
264 private final String typeOfDstDest;
265 DestinationSetType(String s) {
266 typeOfDstDest = s;
267 }
268
269 public String getType() {
270 return typeOfDstDest;
271 }
272 }
273
274 /*
275 * Static methods for creating DestinationSet objects in
276 * order to remove ambiquity with multiple constructors.
277 */
278
279 /**
280 * Returns a DestinationSet with type PUSH_NONE.
281 *
282 * @param destSw The deviceId for this next objective.
283 * @return The DestinationSet of this type.
284 */
285 public static DestinationSet createTypePushNone(DeviceId destSw) {
286 return new DestinationSet(DestinationSetType.PUSH_NONE, destSw);
287 }
288
289 /**
290 * Returns a DestinationSet with type PUSH_BOS.
291 *
292 * @param edgeLabel1 The mpls label to push.
293 * @param destSw1 The device on which the label is assigned.
294 * @return The DestinationSet of this type.
295 */
296 public static DestinationSet createTypePushBos(int edgeLabel1, DeviceId destSw1) {
297 return new DestinationSet(DestinationSetType.PUSH_BOS, edgeLabel1, destSw1);
298 }
299
300 /**
301 * Returns a DestinationSet with type PUSH_BOS used for paired leafs.
302 *
303 * @param edgeLabel1 The label of first paired leaf.
304 * @param destSw1 The device id of first paired leaf.
305 * @param edgeLabel2 The label of the second leaf.
306 * @param destSw2 The device id of the second leaf.
307 * @return The DestinationSet of this type.
308 */
309 public static DestinationSet createTypePushBos(int edgeLabel1, DeviceId destSw1, int edgeLabel2, DeviceId destSw2) {
310 return new DestinationSet(DestinationSetType.PUSH_BOS, edgeLabel1, destSw1, edgeLabel2, destSw2);
311 }
312
313 /**
314 * Returns a DestinationSet with type POP_BOS.
315 *
316 * @param deviceId The deviceId for this next objective.
317 * @return The DestinationSet of this type.
318 */
319 public static DestinationSet createTypePopBos(DeviceId deviceId) {
320 return new DestinationSet(DestinationSetType.POP_BOS, deviceId);
321 }
322
323 /**
324 * Returns a DestinationSet with type SWAP_BOS.
325 *
326 * @param edgeLabel The edge label to swap with.
327 * @param deviceId The deviceId for this next objective.
328 * @return The DestinationSet of this type.
329 */
330 public static DestinationSet createTypeSwapBos(int edgeLabel, DeviceId deviceId) {
331 return new DestinationSet(DestinationSetType.SWAP_BOS, edgeLabel, deviceId);
332 }
333
334 /**
335 * Returns a DestinationSet with type POP_NOT_BOS.
336 *
337 * @param deviceId The device-id this next objective should be installed.
338 * @return The DestinationSet of this type.
339 */
340 public static DestinationSet createTypePopNotBos(DeviceId deviceId) {
341 return new DestinationSet(DestinationSetType.POP_NOT_BOS, deviceId);
342 }
343
344 /**
345 * Returns a DestinationSet with type SWAP_NOT_BOS.
346 *
347 * @param edgeLabel The edge label to swap with.
348 * @param deviceId The deviceId for this next objective.
349 * @return The DestinationSet of this type.
350 */
351 public static DestinationSet createTypeSwapNotBos(int edgeLabel, DeviceId deviceId) {
352 return new DestinationSet(DestinationSetType.SWAP_NOT_BOS, edgeLabel, deviceId);
353 }
Saurav Das261c3002017-06-13 15:35:54 -0700354}