blob: 54c35fb6008d24693fe5123c9c626eef1f2f576c [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net;
tom0eb04ca2014-08-25 14:34:51 -070017
HIGUCHI Yutacc10558d2016-06-03 14:27:05 -070018import com.google.common.base.Objects;
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080019import com.google.common.base.Supplier;
20import com.google.common.base.Suppliers;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableMap.Builder;
alshabib4680bb62014-09-04 17:15:08 -070023import com.google.common.primitives.UnsignedLongs;
tomca20e0c2014-09-03 23:22:24 -070024
Andrea Campanella5df35952015-12-08 15:46:49 -080025import java.util.Map;
26import java.util.regex.Matcher;
27import java.util.regex.Pattern;
28
29import static com.google.common.base.Preconditions.checkArgument;
30import static com.google.common.base.Preconditions.checkNotNull;
31
tom0eb04ca2014-08-25 14:34:51 -070032/**
33 * Representation of a port number.
34 */
tomca20e0c2014-09-03 23:22:24 -070035public final class PortNumber {
36
toma1d16b62014-10-02 23:45:11 -070037 public static final PortNumber P0 = portNumber(0);
38
tom613d8142014-09-11 15:09:37 -070039 // TODO: revisit the max and the logical port value assignments
40
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080041 static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
alshabib63d5afe2014-09-15 09:40:24 -070042
Ray Milkey8717be22015-01-12 14:16:27 -080043 static final long IN_PORT_NUMBER = -8L;
44 static final long TABLE_NUMBER = -7L;
45 static final long NORMAL_NUMBER = -6L;
46 static final long FLOOD_NUMBER = -5L;
47 static final long ALL_NUMBER = -4L;
Ray Milkey8717be22015-01-12 14:16:27 -080048 static final long CONTROLLER_NUMBER = -3L;
Charles Chan5270ed02016-01-30 23:22:37 -080049 static final long LOCAL_NUMBER = -2L;
50 static final long ANY_NUMBER = -1L;
Ray Milkey8717be22015-01-12 14:16:27 -080051
DongRyeol Chada008e32020-01-09 10:55:08 +090052 public static final long NO_DISPLAY_NUMBER = -1L;
53
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080054 /**
55 * Logical PortNumbers.
56 */
Sho SHIMIZU3aa0b182016-08-12 15:03:00 -070057 public enum Logical {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080058 IN_PORT(IN_PORT_NUMBER),
59 TABLE(TABLE_NUMBER),
60 NORMAL(NORMAL_NUMBER),
61 FLOOD(FLOOD_NUMBER),
62 ALL(ALL_NUMBER),
63 LOCAL(LOCAL_NUMBER),
Charles Chan5270ed02016-01-30 23:22:37 -080064 CONTROLLER(CONTROLLER_NUMBER),
65 ANY(ANY_NUMBER);
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080066
67 private final long number;
68 private final PortNumber instance;
69
70 public long number() {
71 return number;
72 }
73
74 /**
75 * PortNumber instance for the logical port.
Andrea Campanella5df35952015-12-08 15:46:49 -080076 *
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080077 * @return {@link PortNumber}
78 */
79 public PortNumber instance() {
80 return instance;
81 }
82
83 Logical(long number) {
84 this.number = number;
85 this.instance = new PortNumber(number);
86 }
87 }
88
Ray Milkey8717be22015-01-12 14:16:27 -080089 public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER);
90 public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER);
91 public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER);
92 public static final PortNumber FLOOD = new PortNumber(FLOOD_NUMBER);
93 public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
94 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
95 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
Charles Chan5270ed02016-01-30 23:22:37 -080096 public static final PortNumber ANY = new PortNumber(ANY_NUMBER);
tom613d8142014-09-11 15:09:37 -070097
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080098 // lazily populated Logical port number to PortNumber
99 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700100 Builder<Long, Logical> builder = ImmutableMap.builder();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800101 for (Logical lp : Logical.values()) {
102 builder.put(lp.number(), lp);
103 }
104 return builder.build();
105 });
106
tomca20e0c2014-09-03 23:22:24 -0700107 private final long number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700108 private final String name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700109 private final boolean hasName;
tomca20e0c2014-09-03 23:22:24 -0700110
111 // Public creation is prohibited
112 private PortNumber(long number) {
tomca20e0c2014-09-03 23:22:24 -0700113 this.number = number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700114 this.name = UnsignedLongs.toString(number);
Marc De Leenheer76d89742015-04-16 15:03:03 -0700115 this.hasName = false;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700116 }
117
118 private PortNumber(long number, String name) {
119 this.number = number;
120 this.name = name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700121 this.hasName = true;
tomca20e0c2014-09-03 23:22:24 -0700122 }
123
124 /**
125 * Returns the port number representing the specified long value.
126 *
127 * @param number port number as long value
128 * @return port number
129 */
130 public static PortNumber portNumber(long number) {
131 return new PortNumber(number);
132 }
133
134 /**
135 * Returns the port number representing the specified string value.
136 *
Yuta HIGUCHIa8a13752017-03-31 10:29:15 -0700137 * @param string port number as decimal, hexadecimal, or octal number string
tomca20e0c2014-09-03 23:22:24 -0700138 * @return port number
139 */
140 public static PortNumber portNumber(String string) {
141 return new PortNumber(UnsignedLongs.decode(string));
142 }
143
144 /**
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700145 * Returns the port number representing the specified long value and name.
146 *
147 * @param number port number as long value
148 * @param name port name as string value
149 * @return port number
150 */
151 public static PortNumber portNumber(long number, String name) {
152 return new PortNumber(number, name);
153 }
154
155 /**
Andrea Campanella5df35952015-12-08 15:46:49 -0800156 * Returns PortNumber instance from String representation.
157 *
158 * @param s String representation equivalent to {@link PortNumber#toString()}
159 * @return {@link PortNumber} instance
160 * @throws IllegalArgumentException if given String was malformed
161 */
162 public static PortNumber fromString(String s) {
163 checkNotNull(s);
164 checkArgument(!s.isEmpty(), "cannot be empty");
165
166 if (isAsciiDecimal(s.charAt(0))) {
167 // unsigned decimal string
168 return portNumber(s);
169 } else if (s.startsWith("[")) {
170 // named PortNumber
171 Matcher matcher = NAMED.matcher(s);
172 checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
173
174 String name = matcher.group("name");
175 String num = matcher.group("num");
176 return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
177 }
178
179 // Logical
180 if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
181 return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
182 } else {
183 return Logical.valueOf(s).instance;
184 }
185 }
186
187 /**
tom613d8142014-09-11 15:09:37 -0700188 * Indicates whether or not this port number is a reserved logical one or
189 * whether it corresponds to a normal physical port of a device or NIC.
190 *
191 * @return true if logical port number
192 */
193 public boolean isLogical() {
Marc De Leenheer76d89742015-04-16 15:03:03 -0700194 if (hasName) {
195 return false;
196 } else {
197 return (number < 0 || number > MAX_NUMBER);
198 }
tom613d8142014-09-11 15:09:37 -0700199 }
200
201 /**
tomca20e0c2014-09-03 23:22:24 -0700202 * Returns the backing long value.
203 *
204 * @return port number as long
205 */
206 public long toLong() {
207 return number;
208 }
209
Marc De Leenheerc0e37ec2015-04-14 22:53:23 -0700210 /**
211 * Returns the backing string value.
212 *
213 * @return port name as string value
214 */
215 public String name() {
216 return name;
217 }
218
Marc De Leenheer76d89742015-04-16 15:03:03 -0700219 /**
220 * Indicates whether this port number was created with a port name,
221 * or only with a number.
222 *
223 * @return true if port was created with name
224 */
225 public boolean hasName() {
226 return hasName;
227 }
228
Ray Milkey8717be22015-01-12 14:16:27 -0800229 private String decodeLogicalPort() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800230 Logical logical = LOGICAL.get().get(number);
231 if (logical != null) {
232 // enum name
233 return logical.toString();
Ray Milkey8717be22015-01-12 14:16:27 -0800234 }
pierventreca0c0d02020-12-03 20:09:47 +0100235 return String.format("%s", UnsignedLongs.toString(number));
236 }
237
238 private String decodeLogicalPortExtended() {
239 Logical logical = LOGICAL.get().get(number);
240 if (logical != null) {
241 // enum name
242 return logical.toString();
243 }
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800244 return String.format("UNKNOWN(%s)", UnsignedLongs.toString(number));
245 }
246
247
248 /**
249 * Regular expression to match String representation of named PortNumber.
250 *
251 * Format: "[name](num:unsigned decimal string)"
252 */
253 private static final Pattern NAMED = Pattern.compile("^\\[(?<name>.*)\\]\\((?<num>\\d+)\\)$");
254
255 private static boolean isAsciiDecimal(char c) {
256 return '0' <= c && c <= '9';
257 }
258
tomca20e0c2014-09-03 23:22:24 -0700259 @Override
260 public String toString() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800261 if (isLogical()) {
pierventreca0c0d02020-12-03 20:09:47 +0100262 return decodeLogicalPortExtended();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800263 } else if (hasName()) {
264 // named port
DongRyeol Chada008e32020-01-09 10:55:08 +0900265 if (number == NO_DISPLAY_NUMBER) {
266 return String.format("[%s]", name);
267 } else {
268 return String.format("[%s](%d)", name, number);
269 }
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800270 } else {
271 // unsigned decimal string
272 return name;
Ray Milkey8717be22015-01-12 14:16:27 -0800273 }
tomca20e0c2014-09-03 23:22:24 -0700274 }
275
pierventreca0c0d02020-12-03 20:09:47 +0100276 // toString method that does not use the name.
277 // if it is a logical port will use either the enum or the number
278 // else if it has a name returns just the number
279 // else it does not have a name, it returns the number because name == number
280 public String toStringWithoutName() {
281 if (isLogical()) {
282 return decodeLogicalPort();
283 }
284 // Either named port or port without name
285 return UnsignedLongs.toString(number);
286 }
287
tomca20e0c2014-09-03 23:22:24 -0700288 @Override
289 public int hashCode() {
Sho SHIMIZUd5c66af2015-06-30 09:43:11 -0700290 return Long.hashCode(number);
tomca20e0c2014-09-03 23:22:24 -0700291 }
292
pierventreca0c0d02020-12-03 20:09:47 +0100293 public int hashCodeExtended() {
294 return Objects.hashCode(number, hasName() ? name : 0);
295 }
296
tomca20e0c2014-09-03 23:22:24 -0700297 @Override
298 public boolean equals(Object obj) {
tomfc9a4ff2014-09-22 18:22:47 -0700299 if (this == obj) {
300 return true;
301 }
tomca20e0c2014-09-03 23:22:24 -0700302 if (obj instanceof PortNumber) {
303 final PortNumber other = (PortNumber) obj;
304 return this.number == other.number;
305 }
306 return false;
307 }
HIGUCHI Yutacc10558d2016-06-03 14:27:05 -0700308
309 /**
310 * Indicates whether some other PortNumber object is equal to this one
311 * including it's name.
312 *
313 * @param that other {@link PortNumber} instance to compare
314 * @return true if equal, false otherwise
315 */
316 public boolean exactlyEquals(PortNumber that) {
317 if (this == that) {
318 return true;
319 }
320
321 return this.equals(that) &&
322 this.hasName == that.hasName &&
323 Objects.equal(this.name, that.name);
324 }
tom0eb04ca2014-08-25 14:34:51 -0700325}