aboutsummaryrefslogtreecommitdiffstats
path: root/framework
diff options
context:
space:
mode:
Diffstat (limited to 'framework')
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java129
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java37
2 files changed, 146 insertions, 20 deletions
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java
index 03e6dba9..8c9b1349 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java
@@ -15,6 +15,16 @@
*/
package org.onosproject.net;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.primitives.UnsignedLongs;
/**
@@ -26,8 +36,7 @@ public final class PortNumber {
// TODO: revisit the max and the logical port value assignments
- private static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
-
+ static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
static final long IN_PORT_NUMBER = -8L;
static final long TABLE_NUMBER = -7L;
@@ -37,6 +46,39 @@ public final class PortNumber {
static final long LOCAL_NUMBER = -2L;
static final long CONTROLLER_NUMBER = -3L;
+ /**
+ * Logical PortNumbers.
+ */
+ public static enum Logical {
+ IN_PORT(IN_PORT_NUMBER),
+ TABLE(TABLE_NUMBER),
+ NORMAL(NORMAL_NUMBER),
+ FLOOD(FLOOD_NUMBER),
+ ALL(ALL_NUMBER),
+ LOCAL(LOCAL_NUMBER),
+ CONTROLLER(CONTROLLER_NUMBER);
+
+ private final long number;
+ private final PortNumber instance;
+
+ public long number() {
+ return number;
+ }
+
+ /**
+ * PortNumber instance for the logical port.
+ * @return {@link PortNumber}
+ */
+ public PortNumber instance() {
+ return instance;
+ }
+
+ Logical(long number) {
+ this.number = number;
+ this.instance = new PortNumber(number);
+ }
+ }
+
public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER);
public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER);
public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER);
@@ -45,6 +87,15 @@ public final class PortNumber {
public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
+ // lazily populated Logical port number to PortNumber
+ static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
+ Builder<Long, Logical> builder = ImmutableMap.<Long, Logical>builder();
+ for (Logical lp : Logical.values()) {
+ builder.put(lp.number(), lp);
+ }
+ return builder.build();
+ });
+
private final long number;
private final String name;
private final boolean hasName;
@@ -136,30 +187,68 @@ public final class PortNumber {
}
private String decodeLogicalPort() {
- if (number == CONTROLLER_NUMBER) {
- return "CONTROLLER";
- } else if (number == LOCAL_NUMBER) {
- return "LOCAL";
- } else if (number == ALL_NUMBER) {
- return "ALL";
- } else if (number == FLOOD_NUMBER) {
- return "FLOOD";
- } else if (number == NORMAL_NUMBER) {
- return "NORMAL";
- } else if (number == TABLE_NUMBER) {
- return "TABLE";
- } else if (number == IN_PORT_NUMBER) {
- return "IN_PORT";
+ Logical logical = LOGICAL.get().get(number);
+ if (logical != null) {
+ // enum name
+ return logical.toString();
+ }
+ return String.format("UNKNOWN(%s)", UnsignedLongs.toString(number));
+ }
+
+
+ /**
+ * Regular expression to match String representation of named PortNumber.
+ *
+ * Format: "[name](num:unsigned decimal string)"
+ */
+ private static final Pattern NAMED = Pattern.compile("^\\[(?<name>.*)\\]\\((?<num>\\d+)\\)$");
+
+ private static boolean isAsciiDecimal(char c) {
+ return '0' <= c && c <= '9';
+ }
+
+ /**
+ * Returns PortNumber instance from String representation.
+ *
+ * @param s String representation equivalent to {@link PortNumber#toString()}
+ * @return {@link PortNumber} instance
+ * @throws IllegalArgumentException if given String was malformed
+ */
+ public static PortNumber fromString(String s) {
+ checkNotNull(s);
+ checkArgument(!s.isEmpty(), "cannot be empty");
+
+ if (isAsciiDecimal(s.charAt(0))) {
+ // unsigned decimal string
+ return portNumber(s);
+ } else if (s.startsWith("[")) {
+ // named PortNumber
+ Matcher matcher = NAMED.matcher(s);
+ checkArgument(matcher.matches(), "Invalid named PortNumber %s", s);
+
+ String name = matcher.group("name");
+ String num = matcher.group("num");
+ return portNumber(UnsignedLongs.parseUnsignedLong(num), name);
+ }
+
+ // Logical
+ if (s.startsWith("UNKNOWN(") && s.endsWith(")")) {
+ return portNumber(s.substring("UNKNOWN(".length(), s.length() - 1));
+ } else {
+ return Logical.valueOf(s).instance;
}
- return "UNKNOWN";
}
@Override
public String toString() {
- if (!isLogical()) {
- return name;
- } else {
+ if (isLogical()) {
return decodeLogicalPort();
+ } else if (hasName()) {
+ // named port
+ return String.format("[%s](%d)", name, number);
+ } else {
+ // unsigned decimal string
+ return name;
}
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java
index 6f7b2c2d..de153dc2 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java
@@ -15,12 +15,17 @@
*/
package org.onosproject.net;
+import com.google.common.collect.ImmutableList;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
+import org.onosproject.net.PortNumber.Logical;
+import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import static org.onosproject.net.PortNumber.portNumber;
+import java.util.List;
+
/**
* Test of the port number.
*/
@@ -39,5 +44,37 @@ public class PortNumberTest {
assertEquals("incorrect long value", 12345, portNumber(12345).toLong());
}
+ @Test
+ public void decimalPortNumberIsReconstructableFromString() {
+ List<PortNumber> ps = ImmutableList.<PortNumber>builder()
+ .add(portNumber(0))
+ .add(portNumber(1))
+ .add(portNumber(6653))
+ .add(portNumber(PortNumber.MAX_NUMBER))
+ .build();
+ ps.forEach(p -> assertEquals(p, PortNumber.fromString(p.toString())));
+ }
+
+ @Test
+ public void logicalPortNumberIsReconstructableFromString() {
+ List<PortNumber> ps = ImmutableList.copyOf(Logical.values())
+ .stream().map(Logical::instance).collect(toList());
+
+ ps.forEach(p -> assertEquals(p, PortNumber.fromString(p.toString())));
+
+ PortNumber unknown = portNumber(-42);
+ assertEquals(unknown, PortNumber.fromString(unknown.toString()));
+ }
+
+ @Test
+ public void namedPortNumberIsReconstructableFromString() {
+ List<PortNumber> ps = ImmutableList.<PortNumber>builder()
+ .add(portNumber(0, "Zero"))
+ .add(portNumber(1, "[ONE]"))
+ .add(portNumber(6653, "OpenFlow (1.3+)"))
+ .add(portNumber(PortNumber.MAX_NUMBER, "(大)"))
+ .build();
+ ps.forEach(p -> assertEquals(p, PortNumber.fromString(p.toString())));
+ }
}