blob: 96c4eb0db89fe7f4fc6377f28a9335542af39c37 [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 Yuta14c04362015-11-12 10:12:04 -080018import com.google.common.base.Supplier;
19import com.google.common.base.Suppliers;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.ImmutableMap.Builder;
alshabib4680bb62014-09-04 17:15:08 -070022import com.google.common.primitives.UnsignedLongs;
tomca20e0c2014-09-03 23:22:24 -070023
Andrea Campanella5df35952015-12-08 15:46:49 -080024import java.util.Map;
25import java.util.regex.Matcher;
26import java.util.regex.Pattern;
27
28import static com.google.common.base.Preconditions.checkArgument;
29import static com.google.common.base.Preconditions.checkNotNull;
30
tom0eb04ca2014-08-25 14:34:51 -070031/**
32 * Representation of a port number.
33 */
tomca20e0c2014-09-03 23:22:24 -070034public final class PortNumber {
35
toma1d16b62014-10-02 23:45:11 -070036 public static final PortNumber P0 = portNumber(0);
37
tom613d8142014-09-11 15:09:37 -070038 // TODO: revisit the max and the logical port value assignments
39
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080040 static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
alshabib63d5afe2014-09-15 09:40:24 -070041
Ray Milkey8717be22015-01-12 14:16:27 -080042 static final long IN_PORT_NUMBER = -8L;
43 static final long TABLE_NUMBER = -7L;
44 static final long NORMAL_NUMBER = -6L;
45 static final long FLOOD_NUMBER = -5L;
46 static final long ALL_NUMBER = -4L;
Ray Milkey8717be22015-01-12 14:16:27 -080047 static final long CONTROLLER_NUMBER = -3L;
Charles Chan5270ed02016-01-30 23:22:37 -080048 static final long LOCAL_NUMBER = -2L;
49 static final long ANY_NUMBER = -1L;
Ray Milkey8717be22015-01-12 14:16:27 -080050
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080051 /**
52 * Logical PortNumbers.
53 */
54 public static enum Logical {
55 IN_PORT(IN_PORT_NUMBER),
56 TABLE(TABLE_NUMBER),
57 NORMAL(NORMAL_NUMBER),
58 FLOOD(FLOOD_NUMBER),
59 ALL(ALL_NUMBER),
60 LOCAL(LOCAL_NUMBER),
Charles Chan5270ed02016-01-30 23:22:37 -080061 CONTROLLER(CONTROLLER_NUMBER),
62 ANY(ANY_NUMBER);
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080063
64 private final long number;
65 private final PortNumber instance;
66
67 public long number() {
68 return number;
69 }
70
71 /**
72 * PortNumber instance for the logical port.
Andrea Campanella5df35952015-12-08 15:46:49 -080073 *
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080074 * @return {@link PortNumber}
75 */
76 public PortNumber instance() {
77 return instance;
78 }
79
80 Logical(long number) {
81 this.number = number;
82 this.instance = new PortNumber(number);
83 }
84 }
85
Ray Milkey8717be22015-01-12 14:16:27 -080086 public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER);
87 public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER);
88 public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER);
89 public static final PortNumber FLOOD = new PortNumber(FLOOD_NUMBER);
90 public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
91 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
92 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
Charles Chan5270ed02016-01-30 23:22:37 -080093 public static final PortNumber ANY = new PortNumber(ANY_NUMBER);
tom613d8142014-09-11 15:09:37 -070094
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080095 // lazily populated Logical port number to PortNumber
96 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
97 Builder<Long, Logical> builder = ImmutableMap.<Long, Logical>builder();
98 for (Logical lp : Logical.values()) {
99 builder.put(lp.number(), lp);
100 }
101 return builder.build();
102 });
103
tomca20e0c2014-09-03 23:22:24 -0700104 private final long number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700105 private final String name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700106 private final boolean hasName;
tomca20e0c2014-09-03 23:22:24 -0700107
108 // Public creation is prohibited
109 private PortNumber(long number) {
tomca20e0c2014-09-03 23:22:24 -0700110 this.number = number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700111 this.name = UnsignedLongs.toString(number);
Marc De Leenheer76d89742015-04-16 15:03:03 -0700112 this.hasName = false;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700113 }
114
115 private PortNumber(long number, String name) {
116 this.number = number;
117 this.name = name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700118 this.hasName = true;
tomca20e0c2014-09-03 23:22:24 -0700119 }
120
121 /**
122 * Returns the port number representing the specified long value.
123 *
124 * @param number port number as long value
125 * @return port number
126 */
127 public static PortNumber portNumber(long number) {
128 return new PortNumber(number);
129 }
130
131 /**
132 * Returns the port number representing the specified string value.
133 *
134 * @param string port number as string value
135 * @return port number
136 */
137 public static PortNumber portNumber(String string) {
138 return new PortNumber(UnsignedLongs.decode(string));
139 }
140
141 /**
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700142 * Returns the port number representing the specified long value and name.
143 *
144 * @param number port number as long value
145 * @param name port name as string value
146 * @return port number
147 */
148 public static PortNumber portNumber(long number, String name) {
149 return new PortNumber(number, name);
150 }
151
152 /**
Andrea Campanella5df35952015-12-08 15:46:49 -0800153 * Returns PortNumber instance from String representation.
154 *
155 * @param s String representation equivalent to {@link PortNumber#toString()}
156 * @return {@link PortNumber} instance
157 * @throws IllegalArgumentException if given String was malformed
158 */
159 public static PortNumber fromString(String s) {
160 checkNotNull(s);
161 checkArgument(!s.isEmpty(), "cannot be empty");
162
163 if (isAsciiDecimal(s.charAt(0))) {
164 // unsigned decimal string
165 return portNumber(s);
166 } else if (s.startsWith("[")) {
167 // named PortNumber
168 Matcher matcher = NAMED.matcher(s);
169 checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
170
171 String name = matcher.group("name");
172 String num = matcher.group("num");
173 return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
174 }
175
176 // Logical
177 if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
178 return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
179 } else {
180 return Logical.valueOf(s).instance;
181 }
182 }
183
184 /**
tom613d8142014-09-11 15:09:37 -0700185 * Indicates whether or not this port number is a reserved logical one or
186 * whether it corresponds to a normal physical port of a device or NIC.
187 *
188 * @return true if logical port number
189 */
190 public boolean isLogical() {
Marc De Leenheer76d89742015-04-16 15:03:03 -0700191 if (hasName) {
192 return false;
193 } else {
194 return (number < 0 || number > MAX_NUMBER);
195 }
tom613d8142014-09-11 15:09:37 -0700196 }
197
198 /**
tomca20e0c2014-09-03 23:22:24 -0700199 * Returns the backing long value.
200 *
201 * @return port number as long
202 */
203 public long toLong() {
204 return number;
205 }
206
Marc De Leenheerc0e37ec2015-04-14 22:53:23 -0700207 /**
208 * Returns the backing string value.
209 *
210 * @return port name as string value
211 */
212 public String name() {
213 return name;
214 }
215
Marc De Leenheer76d89742015-04-16 15:03:03 -0700216 /**
217 * Indicates whether this port number was created with a port name,
218 * or only with a number.
219 *
220 * @return true if port was created with name
221 */
222 public boolean hasName() {
223 return hasName;
224 }
225
Ray Milkey8717be22015-01-12 14:16:27 -0800226 private String decodeLogicalPort() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800227 Logical logical = LOGICAL.get().get(number);
228 if (logical != null) {
229 // enum name
230 return logical.toString();
Ray Milkey8717be22015-01-12 14:16:27 -0800231 }
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800232 return String.format("UNKNOWN(%s)", UnsignedLongs.toString(number));
233 }
234
235
236 /**
237 * Regular expression to match String representation of named PortNumber.
238 *
239 * Format: "[name](num:unsigned decimal string)"
240 */
241 private static final Pattern NAMED = Pattern.compile("^\\[(?<name>.*)\\]\\((?<num>\\d+)\\)$");
242
243 private static boolean isAsciiDecimal(char c) {
244 return '0' <= c && c <= '9';
245 }
246
tomca20e0c2014-09-03 23:22:24 -0700247 @Override
248 public String toString() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800249 if (isLogical()) {
Ray Milkey8717be22015-01-12 14:16:27 -0800250 return decodeLogicalPort();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800251 } else if (hasName()) {
252 // named port
253 return String.format("[%s](%d)", name, number);
254 } else {
255 // unsigned decimal string
256 return name;
Ray Milkey8717be22015-01-12 14:16:27 -0800257 }
tomca20e0c2014-09-03 23:22:24 -0700258 }
259
260 @Override
261 public int hashCode() {
Sho SHIMIZUd5c66af2015-06-30 09:43:11 -0700262 return Long.hashCode(number);
tomca20e0c2014-09-03 23:22:24 -0700263 }
264
265 @Override
266 public boolean equals(Object obj) {
tomfc9a4ff2014-09-22 18:22:47 -0700267 if (this == obj) {
268 return true;
269 }
tomca20e0c2014-09-03 23:22:24 -0700270 if (obj instanceof PortNumber) {
271 final PortNumber other = (PortNumber) obj;
272 return this.number == other.number;
273 }
274 return false;
275 }
tom0eb04ca2014-08-25 14:34:51 -0700276}