blob: 8c9b13496736b67aa911182f81a166507165961f [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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 static com.google.common.base.Preconditions.checkArgument;
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import java.util.Map;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24import com.google.common.base.Supplier;
25import com.google.common.base.Suppliers;
26import com.google.common.collect.ImmutableMap;
27import com.google.common.collect.ImmutableMap.Builder;
alshabib4680bb62014-09-04 17:15:08 -070028import com.google.common.primitives.UnsignedLongs;
tomca20e0c2014-09-03 23:22:24 -070029
tom0eb04ca2014-08-25 14:34:51 -070030/**
31 * Representation of a port number.
32 */
tomca20e0c2014-09-03 23:22:24 -070033public final class PortNumber {
34
toma1d16b62014-10-02 23:45:11 -070035 public static final PortNumber P0 = portNumber(0);
36
tom613d8142014-09-11 15:09:37 -070037 // TODO: revisit the max and the logical port value assignments
38
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080039 static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
alshabib63d5afe2014-09-15 09:40:24 -070040
Ray Milkey8717be22015-01-12 14:16:27 -080041 static final long IN_PORT_NUMBER = -8L;
42 static final long TABLE_NUMBER = -7L;
43 static final long NORMAL_NUMBER = -6L;
44 static final long FLOOD_NUMBER = -5L;
45 static final long ALL_NUMBER = -4L;
46 static final long LOCAL_NUMBER = -2L;
47 static final long CONTROLLER_NUMBER = -3L;
48
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080049 /**
50 * Logical PortNumbers.
51 */
52 public static enum Logical {
53 IN_PORT(IN_PORT_NUMBER),
54 TABLE(TABLE_NUMBER),
55 NORMAL(NORMAL_NUMBER),
56 FLOOD(FLOOD_NUMBER),
57 ALL(ALL_NUMBER),
58 LOCAL(LOCAL_NUMBER),
59 CONTROLLER(CONTROLLER_NUMBER);
60
61 private final long number;
62 private final PortNumber instance;
63
64 public long number() {
65 return number;
66 }
67
68 /**
69 * PortNumber instance for the logical port.
70 * @return {@link PortNumber}
71 */
72 public PortNumber instance() {
73 return instance;
74 }
75
76 Logical(long number) {
77 this.number = number;
78 this.instance = new PortNumber(number);
79 }
80 }
81
Ray Milkey8717be22015-01-12 14:16:27 -080082 public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER);
83 public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER);
84 public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER);
85 public static final PortNumber FLOOD = new PortNumber(FLOOD_NUMBER);
86 public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
87 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
88 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
tom613d8142014-09-11 15:09:37 -070089
HIGUCHI Yuta14c04362015-11-12 10:12:04 -080090 // lazily populated Logical port number to PortNumber
91 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
92 Builder<Long, Logical> builder = ImmutableMap.<Long, Logical>builder();
93 for (Logical lp : Logical.values()) {
94 builder.put(lp.number(), lp);
95 }
96 return builder.build();
97 });
98
tomca20e0c2014-09-03 23:22:24 -070099 private final long number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700100 private final String name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700101 private final boolean hasName;
tomca20e0c2014-09-03 23:22:24 -0700102
103 // Public creation is prohibited
104 private PortNumber(long number) {
tomca20e0c2014-09-03 23:22:24 -0700105 this.number = number;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700106 this.name = UnsignedLongs.toString(number);
Marc De Leenheer76d89742015-04-16 15:03:03 -0700107 this.hasName = false;
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700108 }
109
110 private PortNumber(long number, String name) {
111 this.number = number;
112 this.name = name;
Marc De Leenheer76d89742015-04-16 15:03:03 -0700113 this.hasName = true;
tomca20e0c2014-09-03 23:22:24 -0700114 }
115
116 /**
117 * Returns the port number representing the specified long value.
118 *
119 * @param number port number as long value
120 * @return port number
121 */
122 public static PortNumber portNumber(long number) {
123 return new PortNumber(number);
124 }
125
126 /**
127 * Returns the port number representing the specified string value.
128 *
129 * @param string port number as string value
130 * @return port number
131 */
132 public static PortNumber portNumber(String string) {
133 return new PortNumber(UnsignedLongs.decode(string));
134 }
135
136 /**
Marc De Leenheer171c2e82015-04-13 17:20:37 -0700137 * Returns the port number representing the specified long value and name.
138 *
139 * @param number port number as long value
140 * @param name port name as string value
141 * @return port number
142 */
143 public static PortNumber portNumber(long number, String name) {
144 return new PortNumber(number, name);
145 }
146
147 /**
tom613d8142014-09-11 15:09:37 -0700148 * Indicates whether or not this port number is a reserved logical one or
149 * whether it corresponds to a normal physical port of a device or NIC.
150 *
151 * @return true if logical port number
152 */
153 public boolean isLogical() {
Marc De Leenheer76d89742015-04-16 15:03:03 -0700154 if (hasName) {
155 return false;
156 } else {
157 return (number < 0 || number > MAX_NUMBER);
158 }
tom613d8142014-09-11 15:09:37 -0700159 }
160
161 /**
tomca20e0c2014-09-03 23:22:24 -0700162 * Returns the backing long value.
163 *
164 * @return port number as long
165 */
166 public long toLong() {
167 return number;
168 }
169
Marc De Leenheerc0e37ec2015-04-14 22:53:23 -0700170 /**
171 * Returns the backing string value.
172 *
173 * @return port name as string value
174 */
175 public String name() {
176 return name;
177 }
178
Marc De Leenheer76d89742015-04-16 15:03:03 -0700179 /**
180 * Indicates whether this port number was created with a port name,
181 * or only with a number.
182 *
183 * @return true if port was created with name
184 */
185 public boolean hasName() {
186 return hasName;
187 }
188
Ray Milkey8717be22015-01-12 14:16:27 -0800189 private String decodeLogicalPort() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800190 Logical logical = LOGICAL.get().get(number);
191 if (logical != null) {
192 // enum name
193 return logical.toString();
Ray Milkey8717be22015-01-12 14:16:27 -0800194 }
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800195 return String.format("UNKNOWN(%s)", UnsignedLongs.toString(number));
196 }
197
198
199 /**
200 * Regular expression to match String representation of named PortNumber.
201 *
202 * Format: "[name](num:unsigned decimal string)"
203 */
204 private static final Pattern NAMED = Pattern.compile("^\\[(?<name>.*)\\]\\((?<num>\\d+)\\)$");
205
206 private static boolean isAsciiDecimal(char c) {
207 return '0' <= c && c <= '9';
208 }
209
210 /**
211 * Returns PortNumber instance from String representation.
212 *
213 * @param s String representation equivalent to {@link PortNumber#toString()}
214 * @return {@link PortNumber} instance
215 * @throws IllegalArgumentException if given String was malformed
216 */
217 public static PortNumber fromString(String s) {
218 checkNotNull(s);
219 checkArgument(!s.isEmpty(), "cannot be empty");
220
221 if (isAsciiDecimal(s.charAt(0))) {
222 // unsigned decimal string
223 return portNumber(s);
224 } else if (s.startsWith("[")) {
225 // named PortNumber
226 Matcher matcher = NAMED.matcher(s);
227 checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
228
229 String name = matcher.group("name");
230 String num = matcher.group("num");
231 return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
232 }
233
234 // Logical
235 if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
236 return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
237 } else {
238 return Logical.valueOf(s).instance;
239 }
Ray Milkey8717be22015-01-12 14:16:27 -0800240 }
241
tomca20e0c2014-09-03 23:22:24 -0700242 @Override
243 public String toString() {
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800244 if (isLogical()) {
Ray Milkey8717be22015-01-12 14:16:27 -0800245 return decodeLogicalPort();
HIGUCHI Yuta14c04362015-11-12 10:12:04 -0800246 } else if (hasName()) {
247 // named port
248 return String.format("[%s](%d)", name, number);
249 } else {
250 // unsigned decimal string
251 return name;
Ray Milkey8717be22015-01-12 14:16:27 -0800252 }
tomca20e0c2014-09-03 23:22:24 -0700253 }
254
255 @Override
256 public int hashCode() {
Sho SHIMIZUd5c66af2015-06-30 09:43:11 -0700257 return Long.hashCode(number);
tomca20e0c2014-09-03 23:22:24 -0700258 }
259
260 @Override
261 public boolean equals(Object obj) {
tomfc9a4ff2014-09-22 18:22:47 -0700262 if (this == obj) {
263 return true;
264 }
tomca20e0c2014-09-03 23:22:24 -0700265 if (obj instanceof PortNumber) {
266 final PortNumber other = (PortNumber) obj;
267 return this.number == other.number;
268 }
269 return false;
270 }
tom0eb04ca2014-08-25 14:34:51 -0700271}