blob: dd77d0cd3fde89d06d8a355946249662118484ee [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
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
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080052 /**
53 * Logical PortNumbers.
54 */
Sho SHIMIZU3aa0b182016-08-12 15:03:00 -070055 public enum Logical {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080056 IN_PORT(IN_PORT_NUMBER),
57 TABLE(TABLE_NUMBER),
58 NORMAL(NORMAL_NUMBER),
59 FLOOD(FLOOD_NUMBER),
60 ALL(ALL_NUMBER),
61 LOCAL(LOCAL_NUMBER),
Charles Chan5270ed02016-01-30 23:22:37 -080062 CONTROLLER(CONTROLLER_NUMBER),
63 ANY(ANY_NUMBER);
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080064
65 private final long number;
66 private final PortNumber instance;
67
68 public long number() {
69 return number;
70 }
71
72 /**
73 * PortNumber instance for the logical port.
Andrea Campanella5df35952015-12-08 15:46:49 -080074 *
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080075 * @return {@link PortNumber}
76 */
77 public PortNumber instance() {
78 return instance;
79 }
80
81 Logical(long number) {
82 this.number = number;
83 this.instance = new PortNumber(number);
84 }
85 }
86
Ray Milkey8717be22015-01-12 14:16:27 -080087 public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER);
88 public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER);
89 public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER);
90 public static final PortNumber FLOOD = new PortNumber(FLOOD_NUMBER);
91 public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
92 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
93 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
Charles Chan5270ed02016-01-30 23:22:37 -080094 public static final PortNumber ANY = new PortNumber(ANY_NUMBER);
tom613d8142014-09-11 15:09:37 -070095
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080096 // lazily populated Logical port number to PortNumber
97 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
Sho SHIMIZU21d00692016-08-15 11:15:28 -070098 Builder<Long, Logical> builder = ImmutableMap.builder();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080099 for (Logical lp : Logical.values()) {
100 builder.put(lp.number(), lp);
101 }
102 return builder.build();
103 });
104
tomca20e0c2014-09-03 23:22:24 -0700105 private final long number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700106 private final String name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700107 private final boolean hasName;
tomca20e0c2014-09-03 23:22:24 -0700108
109 // Public creation is prohibited
110 private PortNumber(long number) {
tomca20e0c2014-09-03 23:22:24 -0700111 this.number = number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700112 this.name = UnsignedLongs.toString(number);
Marc De Leenheer76d89742015-04-16 15:03:03 -0700113 this.hasName = false;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700114 }
115
116 private PortNumber(long number, String name) {
117 this.number = number;
118 this.name = name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700119 this.hasName = true;
tomca20e0c2014-09-03 23:22:24 -0700120 }
121
122 /**
123 * Returns the port number representing the specified long value.
124 *
125 * @param number port number as long value
126 * @return port number
127 */
128 public static PortNumber portNumber(long number) {
129 return new PortNumber(number);
130 }
131
132 /**
133 * Returns the port number representing the specified string value.
134 *
135 * @param string port number as string value
136 * @return port number
137 */
138 public static PortNumber portNumber(String string) {
139 return new PortNumber(UnsignedLongs.decode(string));
140 }
141
142 /**
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700143 * Returns the port number representing the specified long value and name.
144 *
145 * @param number port number as long value
146 * @param name port name as string value
147 * @return port number
148 */
149 public static PortNumber portNumber(long number, String name) {
150 return new PortNumber(number, name);
151 }
152
153 /**
Andrea Campanella5df35952015-12-08 15:46:49 -0800154 * Returns PortNumber instance from String representation.
155 *
156 * @param s String representation equivalent to {@link PortNumber#toString()}
157 * @return {@link PortNumber} instance
158 * @throws IllegalArgumentException if given String was malformed
159 */
160 public static PortNumber fromString(String s) {
161 checkNotNull(s);
162 checkArgument(!s.isEmpty(), "cannot be empty");
163
164 if (isAsciiDecimal(s.charAt(0))) {
165 // unsigned decimal string
166 return portNumber(s);
167 } else if (s.startsWith("[")) {
168 // named PortNumber
169 Matcher matcher = NAMED.matcher(s);
170 checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
171
172 String name = matcher.group("name");
173 String num = matcher.group("num");
174 return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
175 }
176
177 // Logical
178 if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
179 return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
180 } else {
181 return Logical.valueOf(s).instance;
182 }
183 }
184
185 /**
tom613d8142014-09-11 15:09:37 -0700186 * Indicates whether or not this port number is a reserved logical one or
187 * whether it corresponds to a normal physical port of a device or NIC.
188 *
189 * @return true if logical port number
190 */
191 public boolean isLogical() {
Marc De Leenheer76d89742015-04-16 15:03:03 -0700192 if (hasName) {
193 return false;
194 } else {
195 return (number < 0 || number > MAX_NUMBER);
196 }
tom613d8142014-09-11 15:09:37 -0700197 }
198
199 /**
tomca20e0c2014-09-03 23:22:24 -0700200 * Returns the backing long value.
201 *
202 * @return port number as long
203 */
204 public long toLong() {
205 return number;
206 }
207
Marc De Leenheerc0e37ec2015-04-14 22:53:23 -0700208 /**
209 * Returns the backing string value.
210 *
211 * @return port name as string value
212 */
213 public String name() {
214 return name;
215 }
216
Marc De Leenheer76d89742015-04-16 15:03:03 -0700217 /**
218 * Indicates whether this port number was created with a port name,
219 * or only with a number.
220 *
221 * @return true if port was created with name
222 */
223 public boolean hasName() {
224 return hasName;
225 }
226
Ray Milkey8717be22015-01-12 14:16:27 -0800227 private String decodeLogicalPort() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800228 Logical logical = LOGICAL.get().get(number);
229 if (logical != null) {
230 // enum name
231 return logical.toString();
Ray Milkey8717be22015-01-12 14:16:27 -0800232 }
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800233 return String.format("UNKNOWN(%s)", UnsignedLongs.toString(number));
234 }
235
236
237 /**
238 * Regular expression to match String representation of named PortNumber.
239 *
240 * Format: "[name](num:unsigned decimal string)"
241 */
242 private static final Pattern NAMED = Pattern.compile("^\\[(?<name>.*)\\]\\((?<num>\\d+)\\)$");
243
244 private static boolean isAsciiDecimal(char c) {
245 return '0' <= c && c <= '9';
246 }
247
tomca20e0c2014-09-03 23:22:24 -0700248 @Override
249 public String toString() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800250 if (isLogical()) {
Ray Milkey8717be22015-01-12 14:16:27 -0800251 return decodeLogicalPort();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800252 } else if (hasName()) {
253 // named port
254 return String.format("[%s](%d)", name, number);
255 } else {
256 // unsigned decimal string
257 return name;
Ray Milkey8717be22015-01-12 14:16:27 -0800258 }
tomca20e0c2014-09-03 23:22:24 -0700259 }
260
261 @Override
262 public int hashCode() {
Sho SHIMIZUd5c66af2015-06-30 09:43:11 -0700263 return Long.hashCode(number);
tomca20e0c2014-09-03 23:22:24 -0700264 }
265
266 @Override
267 public boolean equals(Object obj) {
tomfc9a4ff2014-09-22 18:22:47 -0700268 if (this == obj) {
269 return true;
270 }
tomca20e0c2014-09-03 23:22:24 -0700271 if (obj instanceof PortNumber) {
272 final PortNumber other = (PortNumber) obj;
273 return this.number == other.number;
274 }
275 return false;
276 }
HIGUCHI Yutacc10558d2016-06-03 14:27:05 -0700277
278 /**
279 * Indicates whether some other PortNumber object is equal to this one
280 * including it's name.
281 *
282 * @param that other {@link PortNumber} instance to compare
283 * @return true if equal, false otherwise
284 */
285 public boolean exactlyEquals(PortNumber that) {
286 if (this == that) {
287 return true;
288 }
289
290 return this.equals(that) &&
291 this.hasName == that.hasName &&
292 Objects.equal(this.name, that.name);
293 }
tom0eb04ca2014-08-25 14:34:51 -0700294}