Fix: retrieve port bridge port MAC from deviceService rather via ovsdb
1. Derive gateway IP address from POD subnet CIDR.
2. Remove the logic of injecting gateway IP address.
Change-Id: Ice44c1c4b41bc1689954041aee6441a379e5bacd
diff --git a/apps/k8s-networking/api/BUILD b/apps/k8s-networking/api/BUILD
index 1995985..e1e477c 100644
--- a/apps/k8s-networking/api/BUILD
+++ b/apps/k8s-networking/api/BUILD
@@ -6,6 +6,7 @@
"@logging_interceptor//jar",
"@jackson_dataformat_yaml//jar",
"@snakeyaml//jar",
+ "@commons_net//jar",
]
TEST_DEPS = TEST_ADAPTERS + [
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java
index fef1b1c..f3c7a82 100644
--- a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java
@@ -17,6 +17,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
+import org.apache.commons.net.util.SubnetUtils;
import org.onlab.packet.IpAddress;
import static com.google.common.base.Preconditions.checkArgument;
@@ -27,6 +28,8 @@
public final class DefaultK8sNetwork implements K8sNetwork {
private static final int DEFAULT_MTU = 1500;
+ private static final Type DEFAULT_TYPE = Type.VXLAN;
+ private static final String DEFAULT_SEGMENT_ID = String.valueOf(100);
private final String networkId;
private final String name;
@@ -147,11 +150,23 @@
public K8sNetwork build() {
checkArgument(networkId != null, NOT_NULL_MSG, "networkId");
checkArgument(name != null, NOT_NULL_MSG, "name");
- checkArgument(type != null, NOT_NULL_MSG, "type");
- checkArgument(segmentId != null, NOT_NULL_MSG, "segmentId");
- checkArgument(gatewayIp != null, NOT_NULL_MSG, "gatewayIp");
+
+ // TODO: CIDR can be retrieve from k8s node info, therefore, such
+ // value injection should be purged sooner
checkArgument(cidr != null, NOT_NULL_MSG, "cidr");
+ // gateway IP address is derived from subnet CIDR
+ gatewayIp = getGatewayIp(cidr);
+
+ if (segmentId == null) {
+ segmentId = DEFAULT_SEGMENT_ID;
+ }
+
+ // VXLAN as the default tunneling protocol if not specified
+ if (type == null) {
+ type = DEFAULT_TYPE;
+ }
+
if (mtu == null) {
mtu = DEFAULT_MTU;
}
@@ -200,5 +215,13 @@
this.cidr = cidr;
return this;
}
+
+ private IpAddress getGatewayIp(String cidr) {
+ SubnetUtils utils = new SubnetUtils(cidr);
+ utils.setInclusiveHostCount(false);
+ SubnetUtils.SubnetInfo info = utils.getInfo();
+
+ return IpAddress.valueOf(info.getLowAddress());
+ }
}
}
diff --git a/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java
index 058bc03..df1b611 100644
--- a/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java
+++ b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java
@@ -18,7 +18,6 @@
import com.google.common.testing.EqualsTester;
import org.junit.Before;
import org.junit.Test;
-import org.onlab.packet.IpAddress;
import static junit.framework.TestCase.assertEquals;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
@@ -38,10 +37,8 @@
private static final Integer MTU_2 = 1600;
private static final String SEGMENT_ID_1 = "1";
private static final String SEGMENT_ID_2 = "2";
- private static final IpAddress GATEWAY_IP_1 = IpAddress.valueOf("10.10.10.1");
- private static final IpAddress GATEWAY_IP_2 = IpAddress.valueOf("20.20.20.1");
- private static final String CIDR_1 = "32";
- private static final String CIDR_2 = "32";
+ private static final String CIDR_1 = "10.10.0.0/24";
+ private static final String CIDR_2 = "10.10.1.0/24";
private K8sNetwork k8sNetwork1;
private K8sNetwork sameAsK8sNetwork1;
@@ -58,7 +55,6 @@
.type(TYPE_1)
.mtu(MTU_1)
.segmentId(SEGMENT_ID_1)
- .gatewayIp(GATEWAY_IP_1)
.cidr(CIDR_1)
.build();
@@ -68,7 +64,6 @@
.type(TYPE_1)
.mtu(MTU_1)
.segmentId(SEGMENT_ID_1)
- .gatewayIp(GATEWAY_IP_1)
.cidr(CIDR_1)
.build();
@@ -78,7 +73,6 @@
.type(TYPE_2)
.mtu(MTU_2)
.segmentId(SEGMENT_ID_2)
- .gatewayIp(GATEWAY_IP_2)
.cidr(CIDR_2)
.build();
}
@@ -113,7 +107,6 @@
assertEquals(TYPE_1, k8sNetwork.type());
assertEquals(MTU_1, k8sNetwork.mtu());
assertEquals(SEGMENT_ID_1, k8sNetwork.segmentId());
- assertEquals(GATEWAY_IP_1, k8sNetwork.gatewayIp());
assertEquals(CIDR_1, k8sNetwork.cidr());
}
}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
index b9984bf..07e85da 100644
--- a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
@@ -15,8 +15,8 @@
*/
package org.onosproject.k8snetworking.codec;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.k8snetworking.api.DefaultK8sNetwork;
@@ -39,7 +39,6 @@
private static final String TYPE = "type";
private static final String MTU = "mtu";
private static final String SEGMENT_ID = "segmentId";
- private static final String GATEWAY_IP = "gatewayIp";
private static final String CIDR = "cidr";
private static final String MISSING_MESSAGE = " is required in K8sNetwork";
@@ -51,11 +50,16 @@
ObjectNode result = context.mapper().createObjectNode()
.put(NETWORK_ID, network.networkId())
.put(NAME, network.name())
- .put(TYPE, network.type().name())
- .put(SEGMENT_ID, network.segmentId())
- .put(GATEWAY_IP, network.gatewayIp().toString())
.put(CIDR, network.cidr());
+ if (network.type() != null) {
+ result.put(TYPE, network.type().name());
+ }
+
+ if (network.segmentId() != null) {
+ result.put(SEGMENT_ID, network.segmentId());
+ }
+
if (network.mtu() != null) {
result.put(MTU, network.mtu());
}
@@ -73,23 +77,25 @@
NETWORK_ID + MISSING_MESSAGE);
String name = nullIsIllegal(json.get(NAME).asText(),
NAME + MISSING_MESSAGE);
- String type = nullIsIllegal(json.get(TYPE).asText(),
- TYPE + MISSING_MESSAGE);
- String segmentId = nullIsIllegal(json.get(SEGMENT_ID).asText(),
- SEGMENT_ID + MISSING_MESSAGE);
- String gatewayIp = nullIsIllegal(json.get(GATEWAY_IP).asText(),
- GATEWAY_IP + MISSING_MESSAGE);
String cidr = nullIsIllegal(json.get(CIDR).asText(),
CIDR + MISSING_MESSAGE);
+ JsonNode type = json.get(TYPE);
+ JsonNode segmentId = json.get(SEGMENT_ID);
+
DefaultK8sNetwork.Builder networkBuilder = DefaultK8sNetwork.builder()
.networkId(networkId)
.name(name)
- .type(K8sNetwork.Type.valueOf(type))
- .segmentId(segmentId)
- .gatewayIp(IpAddress.valueOf(gatewayIp))
.cidr(cidr);
+ if (type != null) {
+ networkBuilder.type(K8sNetwork.Type.valueOf(type.asText()));
+ }
+
+ if (segmentId != null) {
+ networkBuilder.segmentId(segmentId.asText());
+ }
+
if (json.get(MTU) != null) {
networkBuilder.mtu(json.get(MTU).asInt());
}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
index fa894de..3055a91 100644
--- a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
@@ -21,7 +21,6 @@
import org.hamcrest.MatcherAssert;
import org.junit.Before;
import org.junit.Test;
-import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.codec.impl.CodecManager;
@@ -82,8 +81,7 @@
.name("network-1")
.segmentId("1")
.type(K8sNetwork.Type.VXLAN)
- .gatewayIp(IpAddress.valueOf("10.10.10.1"))
- .cidr("32")
+ .cidr("10.10.0.0/24")
.mtu(1500)
.build();
@@ -102,8 +100,8 @@
assertEquals("network-1", network.name());
assertEquals("1", network.segmentId());
assertEquals("VXLAN", network.type().name());
- assertEquals("10.10.10.1", network.gatewayIp().toString());
- assertEquals("32", network.cidr());
+ assertEquals("10.10.0.1", network.gatewayIp().toString());
+ assertEquals("10.10.0.0/24", network.cidr());
assertThat(network.mtu(), is(1500));
}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
index 73f2e58..1f3526f 100644
--- a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
@@ -32,7 +32,6 @@
private static final String TYPE = "type";
private static final String MTU = "mtu";
private static final String SEGMENT_ID = "segmentId";
- private static final String GATEWAY_IP = "gatewayIp";
private static final String CIDR = "cidr";
private K8sNetworkJsonMatcher(K8sNetwork network) {
@@ -59,11 +58,13 @@
}
// check type
- String jsonType = jsonNode.get(TYPE).asText();
- String type = network.type().name();
- if (!jsonType.equals(type)) {
- description.appendText("network type was " + jsonType);
- return false;
+ JsonNode jsonType = jsonNode.get(TYPE);
+ if (jsonType != null) {
+ String type = network.type().name();
+ if (!jsonType.asText().equals(type)) {
+ description.appendText("network type was " + jsonType);
+ return false;
+ }
}
// check MTU
@@ -75,19 +76,13 @@
}
// check segment ID
- String jsonSegmentId = jsonNode.get(SEGMENT_ID).asText();
- String segmentId = network.segmentId();
- if (!jsonSegmentId.equals(segmentId)) {
- description.appendText("segment ID was " + jsonSegmentId);
- return false;
- }
-
- // check gateway IP
- String jsonGatewayIp = jsonNode.get(GATEWAY_IP).asText();
- String gatewayIp = network.gatewayIp().toString();
- if (!jsonGatewayIp.equals(gatewayIp)) {
- description.appendText("gateway IP was " + jsonGatewayIp);
- return false;
+ JsonNode jsonSegmentId = jsonNode.get(SEGMENT_ID);
+ if (jsonSegmentId != null) {
+ String segmentId = network.segmentId();
+ if (!jsonSegmentId.asText().equals(segmentId)) {
+ description.appendText("segment ID was " + jsonSegmentId);
+ return false;
+ }
}
// check CIDR
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/impl/K8sNetworkManagerTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/impl/K8sNetworkManagerTest.java
index 874899b..468f682 100644
--- a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/impl/K8sNetworkManagerTest.java
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/impl/K8sNetworkManagerTest.java
@@ -67,8 +67,7 @@
.name(NETWORK_NAME)
.type(K8sNetwork.Type.VXLAN)
.segmentId("1")
- .gatewayIp(IpAddress.valueOf("10.10.10.1"))
- .cidr("32")
+ .cidr("10.10.0.0/24")
.mtu(1500)
.build();
private static final K8sNetwork NETWORK_UPDATED = DefaultK8sNetwork.builder()
@@ -76,8 +75,7 @@
.name(UPDATED_NAME)
.type(K8sNetwork.Type.VXLAN)
.segmentId("1")
- .gatewayIp(IpAddress.valueOf("10.10.10.1"))
- .cidr("32")
+ .cidr("10.10.0.0/24")
.mtu(1500)
.build();
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/web/K8sNetworkWebResourceTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/web/K8sNetworkWebResourceTest.java
index 9a4ca67..77153c3 100644
--- a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/web/K8sNetworkWebResourceTest.java
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/web/K8sNetworkWebResourceTest.java
@@ -20,7 +20,6 @@
import org.junit.Test;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.osgi.TestServiceDirectory;
-import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecService;
import org.onosproject.codec.impl.CodecManager;
import org.onosproject.k8snetworking.api.DefaultK8sNetwork;
@@ -80,8 +79,7 @@
.name("sona-network")
.type(K8sNetwork.Type.VXLAN)
.segmentId("1")
- .cidr("10.10.10.0/24")
- .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+ .cidr("10.10.0.0/24")
.mtu(1500)
.build();
}
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
index 6efe965..136c9e3 100644
--- a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
@@ -4,6 +4,5 @@
"type": "VXLAN",
"mtu": 1500,
"segmentId": "1",
- "gatewayIp": "10.10.10.1",
- "cidr": "32"
+ "cidr": "10.10.0.0/24"
}
\ No newline at end of file
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/web/k8s-network.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/web/k8s-network.json
index 6efe965..136c9e3 100644
--- a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/web/k8s-network.json
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/web/k8s-network.json
@@ -4,6 +4,5 @@
"type": "VXLAN",
"mtu": 1500,
"segmentId": "1",
- "gatewayIp": "10.10.10.1",
- "cidr": "32"
+ "cidr": "10.10.0.0/24"
}
\ No newline at end of file
diff --git a/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/DefaultK8sNode.java b/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/DefaultK8sNode.java
index 87e1f1d..ff0f9de 100644
--- a/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/DefaultK8sNode.java
+++ b/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/DefaultK8sNode.java
@@ -19,6 +19,7 @@
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.Annotations;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
@@ -48,10 +49,9 @@
private static final int DEFAULT_OVSDB_PORT = 6640;
private static final String IP_ADDRESS = "ip_address";
- private static final String MAC_ADDRESS = "mac_address";
private static final String EXT_INTF = "ext_interface";
private static final String EXT_GW_IP = "ext_gw_ip_address";
- private static final String EXT_GW_MAC = "ext_gw_mac_address";
+ private static final String PORT_MAC = "portMac";
private final String hostname;
private final Type type;
@@ -204,69 +204,7 @@
@Override
public PortNumber intgBridgePortNum() {
- DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
- Port port = deviceService.getPorts(intgBridge).stream()
- .filter(p -> p.isEnabled() &&
- Objects.equals(p.annotations().value(PORT_NAME), INTEGRATION_BRIDGE))
- .findAny().orElse(null);
- return port != null ? port.number() : null;
- }
-
- @Override
- public MacAddress intgBridgeMac() {
- OvsdbClientService client = getOvsClient();
-
- if (client == null) {
- return null;
- }
-
- Interface iface = getOvsClient().getInterface(INTEGRATION_BRIDGE);
- OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
- return MacAddress.valueOf((String) data.map().get(MAC_ADDRESS));
- }
-
- @Override
- public IpAddress extBridgeIp() {
- OvsdbClientService client = getOvsClient();
-
- if (client == null) {
- return null;
- }
-
- Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
- OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
- return IpAddress.valueOf((String) data.map().get(IP_ADDRESS));
- }
-
- @Override
- public MacAddress extBridgeMac() {
- OvsdbClientService client = getOvsClient();
-
- if (client == null) {
- return null;
- }
-
- Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
- OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
- return MacAddress.valueOf((String) data.map().get(MAC_ADDRESS));
- }
-
- @Override
- public IpAddress extGatewayIp() {
- OvsdbClientService client = getOvsClient();
-
- if (client == null) {
- return null;
- }
-
- Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
- OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
- return IpAddress.valueOf((String) data.map().get(EXT_GW_IP));
- }
-
- @Override
- public MacAddress extGatewayMac() {
- return extGatewayMac;
+ return portNumber(intgBridge, INTEGRATION_BRIDGE);
}
@Override
@@ -298,6 +236,47 @@
}
@Override
+ public MacAddress intgBridgeMac() {
+ return macAddress(intgBridge, INTEGRATION_BRIDGE);
+ }
+
+ @Override
+ public IpAddress extBridgeIp() {
+ OvsdbClientService client = getOvsClient();
+
+ if (client == null) {
+ return null;
+ }
+
+ Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
+ OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
+ return IpAddress.valueOf((String) data.map().get(IP_ADDRESS));
+ }
+
+ @Override
+ public MacAddress extBridgeMac() {
+ return macAddress(extBridge, EXTERNAL_BRIDGE);
+ }
+
+ @Override
+ public IpAddress extGatewayIp() {
+ OvsdbClientService client = getOvsClient();
+
+ if (client == null) {
+ return null;
+ }
+
+ Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
+ OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
+ return IpAddress.valueOf((String) data.map().get(EXT_GW_IP));
+ }
+
+ @Override
+ public MacAddress extGatewayMac() {
+ return extGatewayMac;
+ }
+
+ @Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
@@ -346,13 +325,23 @@
return portNumber(intgBridge, tunnelType);
}
+ private MacAddress macAddress(DeviceId deviceId, String portName) {
+ Port port = port(deviceId, portName);
+ Annotations annots = port.annotations();
+ return annots != null ? MacAddress.valueOf(annots.value(PORT_MAC)) : null;
+ }
+
private PortNumber portNumber(DeviceId deviceId, String portName) {
+ Port port = port(deviceId, portName);
+ return port != null ? port.number() : null;
+ }
+
+ private Port port(DeviceId deviceId, String portName) {
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
- Port port = deviceService.getPorts(deviceId).stream()
+ return deviceService.getPorts(deviceId).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), portName))
.findAny().orElse(null);
- return port != null ? port.number() : null;
}
private OvsdbClientService getOvsClient() {
diff --git a/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/K8sNode.java b/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/K8sNode.java
index 065f2dd..8d6f57c 100644
--- a/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/K8sNode.java
+++ b/apps/k8s-node/api/src/main/java/org/onosproject/k8snode/api/K8sNode.java
@@ -157,6 +157,27 @@
PortNumber intgBridgePortNum();
/**
+ * Returns the integration to external patch port number.
+ *
+ * @return patch port number
+ */
+ PortNumber intgToExtPatchPortNum();
+
+ /**
+ * Returns the external to integration patch port number.
+ *
+ * @return patch port number
+ */
+ PortNumber extToIntgPatchPortNum();
+
+ /**
+ * Returns the external bridge to router port number.
+ *
+ * @return port number, null if the port does not exist
+ */
+ PortNumber extBridgePortNum();
+
+ /**
* Returns the integration bridge's MAC address.
*
* @return MAC address; null if the MAC address does not exist
@@ -192,27 +213,6 @@
MacAddress extGatewayMac();
/**
- * Returns the integration to external patch port number.
- *
- * @return patch port number
- */
- PortNumber intgToExtPatchPortNum();
-
- /**
- * Returns the external to integration patch port number.
- *
- * @return patch port number
- */
- PortNumber extToIntgPatchPortNum();
-
- /**
- * Returns the external bridge to router port number.
- *
- * @return port number, null if the port does not exist
- */
- PortNumber extBridgePortNum();
-
- /**
* Builder of new node entity.
*/
interface Builder {