Committed by
Gerrit Code Review
ONOS-4660 Additional GATEWAY type node bootstrap
- Add uplink interface to the router bridge - Set separate controller for the router bridge - Use OVSDB provider to check the ports list and keep OVSDB session Limitation: OVSDB provider does not provide port or bridge updates, that is, any changes on the router bridge may not be detected by ONOS Change-Id: I1f17f4fb2c050afdbda1e5ffc06f6485903d3d90
Showing
6 changed files
with
149 additions
and
22 deletions
| ... | @@ -23,7 +23,9 @@ | ... | @@ -23,7 +23,9 @@ |
| 23 | "managementIp" : "10.203.198.125", | 23 | "managementIp" : "10.203.198.125", |
| 24 | "dataIp" : "10.134.33.208", | 24 | "dataIp" : "10.134.33.208", |
| 25 | "integrationBridge" : "of:00000000000000a3", | 25 | "integrationBridge" : "of:00000000000000a3", |
| 26 | - "routerBridge" : "of:00000000000000b1" | 26 | + "routerBridge" : "of:00000000000000b3", |
| 27 | + "uplinkPort" : "veth1", | ||
| 28 | + "routerController" : "172.17.0.2" | ||
| 27 | }, | 29 | }, |
| 28 | { | 30 | { |
| 29 | "hostname" : "gateway-02", | 31 | "hostname" : "gateway-02", |
| ... | @@ -31,7 +33,9 @@ | ... | @@ -31,7 +33,9 @@ |
| 31 | "managementIp" : "10.203.198.131", | 33 | "managementIp" : "10.203.198.131", |
| 32 | "dataIp" : "10.134.33.209", | 34 | "dataIp" : "10.134.33.209", |
| 33 | "integrationBridge" : "of:00000000000000a4", | 35 | "integrationBridge" : "of:00000000000000a4", |
| 34 | - "routerBridge" : "of:00000000000000b2" | 36 | + "routerBridge" : "of:00000000000000b4", |
| 37 | + "uplinkPort" : "veth1", | ||
| 38 | + "routerController" : "172.17.0.2" | ||
| 35 | } | 39 | } |
| 36 | ] | 40 | ] |
| 37 | } | 41 | } | ... | ... |
| ... | @@ -28,4 +28,8 @@ public final class Constants { | ... | @@ -28,4 +28,8 @@ public final class Constants { |
| 28 | public static final String DEFAULT_TUNNEL = "vxlan"; | 28 | public static final String DEFAULT_TUNNEL = "vxlan"; |
| 29 | public static final String PATCH_INTG_BRIDGE = "patch-intg"; | 29 | public static final String PATCH_INTG_BRIDGE = "patch-intg"; |
| 30 | public static final String PATCH_ROUT_BRIDGE = "patch-rout"; | 30 | public static final String PATCH_ROUT_BRIDGE = "patch-rout"; |
| 31 | + | ||
| 32 | + public static final int DEFAULT_OVSDB_PORT = 6640; | ||
| 33 | + public static final int DEFAULT_OFPORT = 6653; | ||
| 34 | + public static final String DEFAULT_OF_PROTO = "tcp"; | ||
| 31 | } | 35 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -41,6 +41,9 @@ public final class OpenstackNode { | ... | @@ -41,6 +41,9 @@ public final class OpenstackNode { |
| 41 | private final IpAddress dataIp; | 41 | private final IpAddress dataIp; |
| 42 | private final DeviceId integrationBridge; | 42 | private final DeviceId integrationBridge; |
| 43 | private final Optional<DeviceId> routerBridge; | 43 | private final Optional<DeviceId> routerBridge; |
| 44 | + private final Optional<String> uplink; | ||
| 45 | + // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter | ||
| 46 | + private final Optional<IpAddress> routerController; | ||
| 44 | private final NodeState state; | 47 | private final NodeState state; |
| 45 | 48 | ||
| 46 | public static final Comparator<OpenstackNode> OPENSTACK_NODE_COMPARATOR = | 49 | public static final Comparator<OpenstackNode> OPENSTACK_NODE_COMPARATOR = |
| ... | @@ -52,6 +55,8 @@ public final class OpenstackNode { | ... | @@ -52,6 +55,8 @@ public final class OpenstackNode { |
| 52 | IpAddress dataIp, | 55 | IpAddress dataIp, |
| 53 | DeviceId integrationBridge, | 56 | DeviceId integrationBridge, |
| 54 | Optional<DeviceId> routerBridge, | 57 | Optional<DeviceId> routerBridge, |
| 58 | + Optional<String> uplink, | ||
| 59 | + Optional<IpAddress> routerController, | ||
| 55 | NodeState state) { | 60 | NodeState state) { |
| 56 | this.hostname = hostname; | 61 | this.hostname = hostname; |
| 57 | this.type = type; | 62 | this.type = type; |
| ... | @@ -59,6 +64,8 @@ public final class OpenstackNode { | ... | @@ -59,6 +64,8 @@ public final class OpenstackNode { |
| 59 | this.dataIp = dataIp; | 64 | this.dataIp = dataIp; |
| 60 | this.integrationBridge = integrationBridge; | 65 | this.integrationBridge = integrationBridge; |
| 61 | this.routerBridge = routerBridge; | 66 | this.routerBridge = routerBridge; |
| 67 | + this.uplink = uplink; | ||
| 68 | + this.routerController = routerController; | ||
| 62 | this.state = state; | 69 | this.state = state; |
| 63 | } | 70 | } |
| 64 | 71 | ||
| ... | @@ -76,6 +83,8 @@ public final class OpenstackNode { | ... | @@ -76,6 +83,8 @@ public final class OpenstackNode { |
| 76 | node.dataIp, | 83 | node.dataIp, |
| 77 | node.integrationBridge, | 84 | node.integrationBridge, |
| 78 | node.routerBridge, | 85 | node.routerBridge, |
| 86 | + node.uplink, | ||
| 87 | + node.routerController, | ||
| 79 | state); | 88 | state); |
| 80 | } | 89 | } |
| 81 | 90 | ||
| ... | @@ -135,6 +144,27 @@ public final class OpenstackNode { | ... | @@ -135,6 +144,27 @@ public final class OpenstackNode { |
| 135 | } | 144 | } |
| 136 | 145 | ||
| 137 | /** | 146 | /** |
| 147 | + * Returns the router bridge controller. | ||
| 148 | + * It returns valid value only if the node type is GATEWAY. | ||
| 149 | + * | ||
| 150 | + * @return device id; or empty value | ||
| 151 | + */ | ||
| 152 | + // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter | ||
| 153 | + public Optional<IpAddress> routerController() { | ||
| 154 | + return routerController; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + /** | ||
| 158 | + * Returns the uplink interface name. | ||
| 159 | + * It returns valid value only if the node type is GATEWAY. | ||
| 160 | + * | ||
| 161 | + * @return uplink interface name; or empty value | ||
| 162 | + */ | ||
| 163 | + public Optional<String> uplink() { | ||
| 164 | + return uplink; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + /** | ||
| 138 | * Returns the init state of the node. | 168 | * Returns the init state of the node. |
| 139 | * | 169 | * |
| 140 | * @return init state | 170 | * @return init state |
| ... | @@ -165,7 +195,9 @@ public final class OpenstackNode { | ... | @@ -165,7 +195,9 @@ public final class OpenstackNode { |
| 165 | Objects.equals(managementIp, that.managementIp) && | 195 | Objects.equals(managementIp, that.managementIp) && |
| 166 | Objects.equals(dataIp, that.dataIp) && | 196 | Objects.equals(dataIp, that.dataIp) && |
| 167 | Objects.equals(integrationBridge, that.integrationBridge) && | 197 | Objects.equals(integrationBridge, that.integrationBridge) && |
| 168 | - Objects.equals(routerBridge, that.routerBridge)) { | 198 | + Objects.equals(routerBridge, that.routerBridge) && |
| 199 | + Objects.equals(uplink, that.uplink) && | ||
| 200 | + Objects.equals(routerController, that.routerController)) { | ||
| 169 | return true; | 201 | return true; |
| 170 | } | 202 | } |
| 171 | } | 203 | } |
| ... | @@ -179,7 +211,9 @@ public final class OpenstackNode { | ... | @@ -179,7 +211,9 @@ public final class OpenstackNode { |
| 179 | managementIp, | 211 | managementIp, |
| 180 | dataIp, | 212 | dataIp, |
| 181 | integrationBridge, | 213 | integrationBridge, |
| 182 | - routerBridge); | 214 | + routerBridge, |
| 215 | + uplink, | ||
| 216 | + routerController); | ||
| 183 | } | 217 | } |
| 184 | 218 | ||
| 185 | @Override | 219 | @Override |
| ... | @@ -191,6 +225,8 @@ public final class OpenstackNode { | ... | @@ -191,6 +225,8 @@ public final class OpenstackNode { |
| 191 | .add("dataIp", dataIp) | 225 | .add("dataIp", dataIp) |
| 192 | .add("integrationBridge", integrationBridge) | 226 | .add("integrationBridge", integrationBridge) |
| 193 | .add("routerBridge", routerBridge) | 227 | .add("routerBridge", routerBridge) |
| 228 | + .add("uplink", uplink) | ||
| 229 | + .add("routerController", routerController) | ||
| 194 | .add("state", state) | 230 | .add("state", state) |
| 195 | .toString(); | 231 | .toString(); |
| 196 | } | 232 | } |
| ... | @@ -214,6 +250,9 @@ public final class OpenstackNode { | ... | @@ -214,6 +250,9 @@ public final class OpenstackNode { |
| 214 | private IpAddress dataIp; | 250 | private IpAddress dataIp; |
| 215 | private DeviceId integrationBridge; | 251 | private DeviceId integrationBridge; |
| 216 | private Optional<DeviceId> routerBridge = Optional.empty(); | 252 | private Optional<DeviceId> routerBridge = Optional.empty(); |
| 253 | + private Optional<String> uplink = Optional.empty(); | ||
| 254 | + // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter | ||
| 255 | + private Optional<IpAddress> routerController = Optional.empty(); | ||
| 217 | private NodeState state = INIT; | 256 | private NodeState state = INIT; |
| 218 | 257 | ||
| 219 | private Builder() { | 258 | private Builder() { |
| ... | @@ -226,12 +265,23 @@ public final class OpenstackNode { | ... | @@ -226,12 +265,23 @@ public final class OpenstackNode { |
| 226 | checkNotNull(dataIp); | 265 | checkNotNull(dataIp); |
| 227 | checkNotNull(integrationBridge); | 266 | checkNotNull(integrationBridge); |
| 228 | checkNotNull(routerBridge); | 267 | checkNotNull(routerBridge); |
| 268 | + checkNotNull(uplink); | ||
| 269 | + checkNotNull(routerController); | ||
| 270 | + | ||
| 271 | + if (type == NodeType.GATEWAY) { | ||
| 272 | + checkArgument(routerBridge.isPresent()); | ||
| 273 | + checkArgument(uplink.isPresent()); | ||
| 274 | + checkArgument(routerController.isPresent()); | ||
| 275 | + } | ||
| 276 | + | ||
| 229 | return new OpenstackNode(hostname, | 277 | return new OpenstackNode(hostname, |
| 230 | type, | 278 | type, |
| 231 | managementIp, | 279 | managementIp, |
| 232 | dataIp, | 280 | dataIp, |
| 233 | integrationBridge, | 281 | integrationBridge, |
| 234 | routerBridge, | 282 | routerBridge, |
| 283 | + uplink, | ||
| 284 | + routerController, | ||
| 235 | state); | 285 | state); |
| 236 | } | 286 | } |
| 237 | 287 | ||
| ... | @@ -302,6 +352,29 @@ public final class OpenstackNode { | ... | @@ -302,6 +352,29 @@ public final class OpenstackNode { |
| 302 | } | 352 | } |
| 303 | 353 | ||
| 304 | /** | 354 | /** |
| 355 | + * Returns node builder with the uplink interface name. | ||
| 356 | + * | ||
| 357 | + * @param uplink uplink interface name | ||
| 358 | + * @return openstack node builder | ||
| 359 | + */ | ||
| 360 | + public Builder uplink(String uplink) { | ||
| 361 | + this.uplink = Optional.ofNullable(uplink); | ||
| 362 | + return this; | ||
| 363 | + } | ||
| 364 | + | ||
| 365 | + /** | ||
| 366 | + * Returns node builder with the router controller. | ||
| 367 | + * | ||
| 368 | + * @param routerController router contoller | ||
| 369 | + * @return openstack node builder | ||
| 370 | + */ | ||
| 371 | + // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter | ||
| 372 | + public Builder routerController(IpAddress routerController) { | ||
| 373 | + this.routerController = Optional.ofNullable(routerController); | ||
| 374 | + return this; | ||
| 375 | + } | ||
| 376 | + | ||
| 377 | + /** | ||
| 305 | * Returns node builder with the init state. | 378 | * Returns node builder with the init state. |
| 306 | * | 379 | * |
| 307 | * @param state node init state | 380 | * @param state node init state | ... | ... |
| ... | @@ -40,7 +40,12 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { | ... | @@ -40,7 +40,12 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { |
| 40 | private static final String MANAGEMENT_IP = "managementIp"; | 40 | private static final String MANAGEMENT_IP = "managementIp"; |
| 41 | private static final String DATA_IP = "dataIp"; | 41 | private static final String DATA_IP = "dataIp"; |
| 42 | private static final String INTEGRATION_BRIDGE = "integrationBridge"; | 42 | private static final String INTEGRATION_BRIDGE = "integrationBridge"; |
| 43 | + | ||
| 44 | + // GATEWAY node specific fields | ||
| 43 | private static final String ROUTER_BRIDGE = "routerBridge"; | 45 | private static final String ROUTER_BRIDGE = "routerBridge"; |
| 46 | + private static final String UPLINK_PORT_NAME = "uplinkPort"; | ||
| 47 | + // TODO remove this when vRouter supports multiple switches | ||
| 48 | + private static final String ROUTER_CONTROLLER = "routerController"; | ||
| 44 | 49 | ||
| 45 | @Override | 50 | @Override |
| 46 | public boolean isValid() { | 51 | public boolean isValid() { |
| ... | @@ -59,7 +64,9 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { | ... | @@ -59,7 +64,9 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { |
| 59 | MANAGEMENT_IP, | 64 | MANAGEMENT_IP, |
| 60 | DATA_IP, | 65 | DATA_IP, |
| 61 | INTEGRATION_BRIDGE, | 66 | INTEGRATION_BRIDGE, |
| 62 | - ROUTER_BRIDGE | 67 | + ROUTER_BRIDGE, |
| 68 | + UPLINK_PORT_NAME, | ||
| 69 | + ROUTER_CONTROLLER | ||
| 63 | ); | 70 | ); |
| 64 | 71 | ||
| 65 | result &= isString(osNode, HOST_NAME, MANDATORY); | 72 | result &= isString(osNode, HOST_NAME, MANDATORY); |
| ... | @@ -74,6 +81,8 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { | ... | @@ -74,6 +81,8 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { |
| 74 | if (osNode.get(TYPE).asText().equals(GATEWAY.name())) { | 81 | if (osNode.get(TYPE).asText().equals(GATEWAY.name())) { |
| 75 | result &= isString(osNode, ROUTER_BRIDGE, MANDATORY); | 82 | result &= isString(osNode, ROUTER_BRIDGE, MANDATORY); |
| 76 | DeviceId.deviceId(osNode.get(ROUTER_BRIDGE).asText()); | 83 | DeviceId.deviceId(osNode.get(ROUTER_BRIDGE).asText()); |
| 84 | + result &= isString(osNode, UPLINK_PORT_NAME, MANDATORY); | ||
| 85 | + result &= isIpAddress(osNode, ROUTER_CONTROLLER, MANDATORY); | ||
| 77 | } | 86 | } |
| 78 | } | 87 | } |
| 79 | return result; | 88 | return result; |
| ... | @@ -97,7 +106,9 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { | ... | @@ -97,7 +106,9 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> { |
| 97 | .hostname(get(node, HOST_NAME)); | 106 | .hostname(get(node, HOST_NAME)); |
| 98 | 107 | ||
| 99 | if (type.equals(GATEWAY)) { | 108 | if (type.equals(GATEWAY)) { |
| 100 | - nodeBuilder.routerBridge(DeviceId.deviceId(get(node, ROUTER_BRIDGE))); | 109 | + nodeBuilder.routerBridge(DeviceId.deviceId(get(node, ROUTER_BRIDGE))) |
| 110 | + .uplink(get(node, UPLINK_PORT_NAME)) | ||
| 111 | + .routerController(IpAddress.valueOf(get(node, ROUTER_CONTROLLER))); | ||
| 101 | } | 112 | } |
| 102 | nodes.add(nodeBuilder.build()); | 113 | nodes.add(nodeBuilder.build()); |
| 103 | } | 114 | } | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -22,10 +22,14 @@ import org.onosproject.cli.AbstractShellCommand; | ... | @@ -22,10 +22,14 @@ import org.onosproject.cli.AbstractShellCommand; |
| 22 | import org.onosproject.net.DeviceId; | 22 | import org.onosproject.net.DeviceId; |
| 23 | import org.onosproject.net.Port; | 23 | import org.onosproject.net.Port; |
| 24 | import org.onosproject.net.Device; | 24 | import org.onosproject.net.Device; |
| 25 | +import org.onosproject.net.behaviour.BridgeConfig; | ||
| 25 | import org.onosproject.net.device.DeviceService; | 26 | import org.onosproject.net.device.DeviceService; |
| 27 | +import org.onosproject.net.device.PortDescription; | ||
| 26 | import org.onosproject.openstacknode.OpenstackNode; | 28 | import org.onosproject.openstacknode.OpenstackNode; |
| 27 | import org.onosproject.openstacknode.OpenstackNodeService; | 29 | import org.onosproject.openstacknode.OpenstackNodeService; |
| 28 | 30 | ||
| 31 | +import java.util.Optional; | ||
| 32 | + | ||
| 29 | import static org.onosproject.net.AnnotationKeys.PORT_NAME; | 33 | import static org.onosproject.net.AnnotationKeys.PORT_NAME; |
| 30 | import static org.onosproject.openstacknode.Constants.*; | 34 | import static org.onosproject.openstacknode.Constants.*; |
| 31 | import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY; | 35 | import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY; |
| ... | @@ -60,7 +64,7 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { | ... | @@ -60,7 +64,7 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { |
| 60 | return; | 64 | return; |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | - print("%n[Integration Bridge Status]"); | 67 | + print("[Integration Bridge Status]"); |
| 64 | Device device = deviceService.getDevice(node.intBridge()); | 68 | Device device = deviceService.getDevice(node.intBridge()); |
| 65 | if (device != null) { | 69 | if (device != null) { |
| 66 | print("%s %s=%s available=%s %s", | 70 | print("%s %s=%s available=%s %s", |
| ... | @@ -79,23 +83,30 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { | ... | @@ -79,23 +83,30 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | if (node.type().equals(GATEWAY)) { | 85 | if (node.type().equals(GATEWAY)) { |
| 86 | + print(getPortState(deviceService, node.intBridge(), PATCH_INTG_BRIDGE)); | ||
| 87 | + | ||
| 82 | print("%n[Router Bridge Status]"); | 88 | print("%n[Router Bridge Status]"); |
| 83 | - device = deviceService.getDevice(node.routerBridge().get()); | 89 | + device = deviceService.getDevice(node.ovsdbId()); |
| 84 | - if (device != null) { | 90 | + if (device == null || !device.is(BridgeConfig.class)) { |
| 85 | - print("%s %s=%s available=%s %s", | 91 | + print("%s %s=%s is not available(unable to connect OVSDB)", |
| 86 | - deviceService.isAvailable(device.id()) ? MSG_OK : MSG_NO, | 92 | + MSG_NO, |
| 87 | - ROUTER_BRIDGE, | 93 | + ROUTER_BRIDGE, |
| 88 | - device.id(), | 94 | + node.intBridge()); |
| 89 | - deviceService.isAvailable(device.id()), | ||
| 90 | - device.annotations()); | ||
| 91 | - | ||
| 92 | - print(getPortState(deviceService, node.routerBridge().get(), PATCH_ROUT_BRIDGE)); | ||
| 93 | - print(getPortState(deviceService, node.intBridge(), PATCH_INTG_BRIDGE)); | ||
| 94 | } else { | 95 | } else { |
| 95 | - print("%s %s=%s is not available", | 96 | + BridgeConfig bridgeConfig = device.as(BridgeConfig.class); |
| 96 | - MSG_NO, | 97 | + boolean available = bridgeConfig.getBridges().stream() |
| 97 | - ROUTER_BRIDGE, | 98 | + .filter(bridge -> bridge.name().equals(ROUTER_BRIDGE)) |
| 98 | - node.intBridge()); | 99 | + .findAny() |
| 100 | + .isPresent(); | ||
| 101 | + | ||
| 102 | + print("%s %s=%s available=%s", | ||
| 103 | + available ? MSG_OK : MSG_NO, | ||
| 104 | + ROUTER_BRIDGE, | ||
| 105 | + node.routerBridge().get(), | ||
| 106 | + available); | ||
| 107 | + | ||
| 108 | + print(getPortStateOvsdb(deviceService, node.ovsdbId(), PATCH_ROUT_BRIDGE)); | ||
| 109 | + print(getPortStateOvsdb(deviceService, node.ovsdbId(), node.uplink().get())); | ||
| 99 | } | 110 | } |
| 100 | } | 111 | } |
| 101 | } | 112 | } |
| ... | @@ -117,4 +128,28 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { | ... | @@ -117,4 +128,28 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand { |
| 117 | return String.format("%s %s does not exist", MSG_NO, portName); | 128 | return String.format("%s %s does not exist", MSG_NO, portName); |
| 118 | } | 129 | } |
| 119 | } | 130 | } |
| 131 | + | ||
| 132 | + private String getPortStateOvsdb(DeviceService deviceService, DeviceId deviceId, String portName) { | ||
| 133 | + Device device = deviceService.getDevice(deviceId); | ||
| 134 | + if (device == null || !device.is(BridgeConfig.class)) { | ||
| 135 | + return String.format("%s %s does not exist(unable to connect OVSDB)", | ||
| 136 | + MSG_NO, portName); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + BridgeConfig bridgeConfig = device.as(BridgeConfig.class); | ||
| 140 | + Optional<PortDescription> port = bridgeConfig.getPorts().stream() | ||
| 141 | + .filter(p -> p.annotations().value(PORT_NAME).contains(portName)) | ||
| 142 | + .findAny(); | ||
| 143 | + | ||
| 144 | + if (port.isPresent()) { | ||
| 145 | + return String.format("%s %s portNum=%s enabled=%s %s", | ||
| 146 | + port.get().isEnabled() ? MSG_OK : MSG_NO, | ||
| 147 | + portName, | ||
| 148 | + port.get().portNumber(), | ||
| 149 | + port.get().isEnabled() ? Boolean.TRUE : Boolean.FALSE, | ||
| 150 | + port.get().annotations()); | ||
| 151 | + } else { | ||
| 152 | + return String.format("%s %s does not exist", MSG_NO, portName); | ||
| 153 | + } | ||
| 154 | + } | ||
| 120 | } | 155 | } | ... | ... |
-
Please register or login to post a comment