[ONOS-6150] OpenstackNode application support creation of vlan interface on open vswitch

Change-Id: I4342a8bd5f8a0a802e05f6b89a7962e5d3c9c9af
This commit is contained in:
daniel park 2017-03-16 18:07:15 +09:00 committed by Daniel Park
parent 93722efa8f
commit 917beb4b9d
7 changed files with 131 additions and 65 deletions

View File

@ -427,7 +427,7 @@ public class OpenstackRoutingIcmpHandler {
// don't need to add gateway here and there
GatewayNode gnode = GatewayNode.builder()
.gatewayDeviceId(osNode.intBridge())
.dataIpAddress(osNode.dataIp().getIp4Address())
.dataIpAddress(osNode.dataIp().get().getIp4Address())
.uplinkIntf(osNode.externalPortName().get())
.build();
gatewayService.addGatewayNode(gnode);

View File

@ -2,41 +2,35 @@
"apps" : {
"org.onosproject.openstacknode" : {
"openstacknode" : {
"nodes" : [
{
"hostname" : "compute-01",
"type" : "COMPUTE",
"managementIp" : "10.203.25.244",
"dataIp" : "10.134.34.222",
"integrationBridge" : "of:00000000000000a1"
},
{
"hostname" : "compute-02",
"type" : "COMPUTE",
"managementIp" : "10.203.229.42",
"dataIp" : "10.134.34.223",
"integrationBridge" : "of:00000000000000a2"
},
{
"hostname" : "gateway-01",
"type" : "GATEWAY",
"managementIp" : "10.203.198.125",
"dataIp" : "10.134.33.208",
"integrationBridge" : "of:00000000000000a3",
"routerBridge" : "of:00000000000000b3",
"uplinkPort" : "veth1",
"routerController" : "172.17.0.2"
},
{
"hostname" : "gateway-02",
"type" : "GATEWAY",
"managementIp" : "10.203.198.131",
"dataIp" : "10.134.33.209",
"integrationBridge" : "of:00000000000000a4",
"routerBridge" : "of:00000000000000b4",
"uplinkPort" : "veth1",
"routerController" : "172.17.0.2"
}
"nodes" : [
{
"hostname" : "compute-01",
"type" : "COMPUTE",
"managementIp" : "172.16.130.4",
"dataIp" : "172.16.130.4",
"vlanPort" : "eth2",
"integrationBridge" : "of:00000000000000a1"
},
{
"hostname" : "compute-02",
"type" : "COMPUTE",
"managementIp" : "172.16.130.6",
"dataIp" : "172.16.130.6",
"vlanPort" : "eth2",
"integrationBridge" : "of:00000000000000a2"
},
{
"hostname" : "gateway-01",
"type" : "GATEWAY",
"managementIp" : "172.16.130.8",
"dataIp" : "172.16.130.7",
"vlanPort" : "eth2",
"integrationBridge" : "of:00000000000000a3",
"routerBridge" : "of:00000000000000b1",
"uplinkPort" : "quagga-router",
"routerController" : "172.17.0.2"
}
]
}
}
@ -51,16 +45,6 @@
"basic" : {
"driver" : "sona"
}
},
"of:00000000000000b1" : {
"basic" : {
"driver" : "softrouter"
}
},
"of:00000000000000b2" : {
"basic" : {
"driver" : "softrouter"
}
}
}
}

View File

@ -39,12 +39,13 @@ public final class OpenstackNode {
private final String hostname;
private final NodeType type;
private final IpAddress managementIp;
private final IpAddress dataIp;
private final Optional<IpAddress> dataIp;
private final DeviceId integrationBridge;
private final Optional<DeviceId> routerBridge;
private final Optional<String> uplink;
// TODO remove this when we use single ONOS cluster for both openstackNode and vRouter
private final Optional<IpAddress> routerController;
private final Optional<String> vlanPort;
private final NodeState state;
public static final Comparator<OpenstackNode> OPENSTACK_NODE_COMPARATOR =
@ -53,11 +54,12 @@ public final class OpenstackNode {
private OpenstackNode(String hostname,
NodeType type,
IpAddress managementIp,
IpAddress dataIp,
Optional<IpAddress> dataIp,
DeviceId integrationBridge,
Optional<DeviceId> routerBridge,
Optional<String> uplink,
Optional<IpAddress> routerController,
Optional<String> vlanPort,
NodeState state) {
this.hostname = hostname;
this.type = type;
@ -67,6 +69,7 @@ public final class OpenstackNode {
this.routerBridge = routerBridge;
this.uplink = uplink;
this.routerController = routerController;
this.vlanPort = vlanPort;
this.state = state;
}
@ -86,6 +89,7 @@ public final class OpenstackNode {
node.routerBridge,
node.uplink,
node.routerController,
node.vlanPort,
state);
}
@ -119,9 +123,9 @@ public final class OpenstackNode {
/**
* Returns the data network IP address of the node.
*
* @return data network ip address
* @return data network ip address; or empty value
*/
public IpAddress dataIp() {
public Optional<IpAddress> dataIp() {
return dataIp;
}
@ -165,6 +169,15 @@ public final class OpenstackNode {
return uplink;
}
/**
* Returns the vlan interface name.
*
* @return vlan interface name; or empty value
*/
public Optional<String> vlanPort() {
return vlanPort;
}
/**
* Returns the init state of the node.
*
@ -212,7 +225,8 @@ public final class OpenstackNode {
Objects.equals(integrationBridge, that.integrationBridge) &&
Objects.equals(routerBridge, that.routerBridge) &&
Objects.equals(uplink, that.uplink) &&
Objects.equals(routerController, that.routerController)) {
Objects.equals(routerController, that.routerController) &&
Objects.equals(vlanPort, that.vlanPort)) {
return true;
}
}
@ -228,7 +242,8 @@ public final class OpenstackNode {
integrationBridge,
routerBridge,
uplink,
routerController);
routerController,
vlanPort);
}
@Override
@ -242,6 +257,7 @@ public final class OpenstackNode {
.add("routerBridge", routerBridge)
.add("uplink", uplink)
.add("routerController", routerController)
.add("vlanport", vlanPort)
.add("state", state)
.toString();
}
@ -262,10 +278,11 @@ public final class OpenstackNode {
private String hostname;
private NodeType type;
private IpAddress managementIp;
private IpAddress dataIp;
private Optional<IpAddress> dataIp = Optional.empty();
private DeviceId integrationBridge;
private Optional<DeviceId> routerBridge = Optional.empty();
private Optional<String> uplink = Optional.empty();
private Optional<String> vlanPort = Optional.empty();
// TODO remove this when we use single ONOS cluster for both openstackNode and vRouter
private Optional<IpAddress> routerController = Optional.empty();
private NodeState state = INIT;
@ -282,6 +299,7 @@ public final class OpenstackNode {
checkNotNull(routerBridge);
checkNotNull(uplink);
checkNotNull(routerController);
checkNotNull(vlanPort);
if (type == NodeType.GATEWAY) {
checkArgument(routerBridge.isPresent());
@ -297,6 +315,7 @@ public final class OpenstackNode {
routerBridge,
uplink,
routerController,
vlanPort,
state);
}
@ -340,7 +359,7 @@ public final class OpenstackNode {
* @return openstack node builder
*/
public Builder dataIp(IpAddress dataIp) {
this.dataIp = dataIp;
this.dataIp = Optional.ofNullable(dataIp);
return this;
}
@ -389,6 +408,17 @@ public final class OpenstackNode {
return this;
}
/**
* Returns node builder with the vlan interface name.
*
* @param vlanPort vlan interface name
* @return openstack node builder
*/
public Builder vlanPort(String vlanPort) {
this.vlanPort = Optional.ofNullable(vlanPort);
return this;
}
/**
* Returns node builder with the init state.
*

View File

@ -27,6 +27,7 @@ import java.util.Set;
import org.onosproject.net.config.Config;
import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
/**
@ -46,6 +47,7 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> {
private static final String UPLINK_PORT_NAME = "uplinkPort";
// TODO remove this when vRouter supports multiple switches
private static final String ROUTER_CONTROLLER = "routerController";
private static final String VLAN_PORT_NAME = "vlanPort";
@Override
public boolean isValid() {
@ -57,6 +59,10 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> {
}
for (JsonNode node : object.get(NODES)) {
if (get(node, DATA_IP) == null && get(node, VLAN_PORT_NAME) == null) {
final String msg = "There is neither tunnel interface nor vlan port";
throw new IllegalArgumentException(msg);
}
ObjectNode osNode = (ObjectNode) node;
result &= hasOnlyFields(osNode,
HOST_NAME,
@ -66,14 +72,16 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> {
INTEGRATION_BRIDGE,
ROUTER_BRIDGE,
UPLINK_PORT_NAME,
ROUTER_CONTROLLER
ROUTER_CONTROLLER,
VLAN_PORT_NAME
);
result &= isString(osNode, HOST_NAME, MANDATORY);
result &= isString(osNode, TYPE, MANDATORY);
result &= isIpAddress(osNode, MANAGEMENT_IP, MANDATORY);
result &= result && isIpAddress(osNode, DATA_IP, MANDATORY);
result &= isString(osNode, INTEGRATION_BRIDGE, MANDATORY);
result &= isString(osNode, VLAN_PORT_NAME, OPTIONAL);
result &= isIpAddress(osNode, DATA_IP, OPTIONAL);
DeviceId.deviceId(osNode.get(INTEGRATION_BRIDGE).asText());
NodeType.valueOf(osNode.get(TYPE).asText());
@ -95,16 +103,22 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> {
*/
public Set<OpenstackNode> openstackNodes() {
Set<OpenstackNode> nodes = Sets.newHashSet();
for (JsonNode node : object.get(NODES)) {
NodeType type = NodeType.valueOf(get(node, TYPE));
OpenstackNode.Builder nodeBuilder = OpenstackNode.builder()
.integrationBridge(DeviceId.deviceId(get(node, INTEGRATION_BRIDGE)))
.dataIp(IpAddress.valueOf(get(node, DATA_IP)))
.managementIp(IpAddress.valueOf(get(node, MANAGEMENT_IP)))
.type(type)
.hostname(get(node, HOST_NAME));
if (get(node, DATA_IP) != null) {
nodeBuilder.dataIp(IpAddress.valueOf(get(node, DATA_IP)));
}
if (get(node, VLAN_PORT_NAME) != null) {
nodeBuilder.vlanPort(get(node, VLAN_PORT_NAME));
}
if (type.equals(GATEWAY)) {
nodeBuilder.routerBridge(DeviceId.deviceId(get(node, ROUTER_BRIDGE)))
.uplink(get(node, UPLINK_PORT_NAME))
@ -116,6 +130,10 @@ public final class OpenstackNodeConfig extends Config<ApplicationId> {
}
private String get(JsonNode jsonNode, String path) {
return jsonNode.get(path).asText();
JsonNode jNode = jsonNode.get(path);
if (jNode == null || jNode.isMissingNode()) {
return null;
}
return jNode.asText();
}
}

View File

@ -253,9 +253,17 @@ public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEv
connectOvsdb(node);
return;
}
process(new OpenstackNodeEvent(DEVICE_CREATED, node));
createTunnelInterface(node);
if (node.dataIp().isPresent()) {
createTunnelInterface(node);
}
if (node.vlanPort().isPresent()) {
addVlanPort(node);
}
if (node.type().equals(NodeType.GATEWAY)) {
createPatchInterface(node);
addUplink(node);
@ -294,7 +302,7 @@ public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEv
log.warn("Failed to get node for {}", deviceId);
return Optional.empty();
}
return Optional.of(node.dataIp());
return node.dataIp();
}
@Override
@ -348,7 +356,11 @@ public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEv
return INIT;
}
if (!isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
if (node.dataIp().isPresent() && !isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
return DEVICE_CREATED;
}
if (node.vlanPort().isPresent() && !isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
return DEVICE_CREATED;
}
@ -491,6 +503,22 @@ public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEv
node.uplink().get());
}
private void addVlanPort(OpenstackNode node) {
if (isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
return;
}
Device device = deviceService.getDevice(node.ovsdbId());
if (device == null || !device.is(BridgeConfig.class)) {
log.error("Failed to add port {} on {}", node.vlanPort().get(), node.ovsdbId());
return;
}
BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE),
node.vlanPort().get());
}
private boolean isOvsdbConnected(OpenstackNode node) {
OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
@ -504,7 +532,9 @@ public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEv
}
private Set<String> systemIfaces(OpenstackNode node) {
Set<String> ifaces = Sets.newHashSet(DEFAULT_TUNNEL);
Set<String> ifaces = Sets.newHashSet();
node.dataIp().ifPresent(ip -> ifaces.add(DEFAULT_TUNNEL));
node.vlanPort().ifPresent(p -> ifaces.add(p));
if (node.type().equals(NodeType.GATEWAY)) {
ifaces.add(PATCH_INTG_BRIDGE);
ifaces.add(PATCH_ROUT_BRIDGE);

View File

@ -74,7 +74,8 @@ public class OpenstackNodeCheckCommand extends AbstractShellCommand {
deviceService.isAvailable(device.id()),
device.annotations());
print(getPortState(deviceService, node.intBridge(), DEFAULT_TUNNEL));
node.dataIp().ifPresent(ip -> print(getPortState(deviceService, node.intBridge(), DEFAULT_TUNNEL)));
node.vlanPort().ifPresent(p -> print(getPortState(deviceService, node.intBridge(), p)));
} else {
print("%s %s=%s is not available",
MSG_NO,

View File

@ -44,11 +44,13 @@ public class OpenstackNodeListCommand extends AbstractShellCommand {
print("%s", json(nodes));
} else {
for (OpenstackNode node : nodes) {
print("hostname=%s, type=%s, managementIp=%s, dataIp=%s, intBridge=%s, routerBridge=%s init=%s",
print("hostname=%s, type=%s, managementIp=%s, dataIp=%s, vlanPort=%s," +
"intBridge=%s, routerBridge=%s init=%s",
node.hostname(),
node.type(),
node.managementIp(),
node.dataIp(),
node.vlanPort(),
node.intBridge(),
node.routerBridge(),
node.state());
@ -66,6 +68,7 @@ public class OpenstackNodeListCommand extends AbstractShellCommand {
.put("type", node.type().name())
.put("managementIp", node.managementIp().toString())
.put("dataIp", node.dataIp().toString())
.put("vlanPort", node.vlanPort().toString())
.put("intBridge", node.intBridge().toString())
.put("routerBridge", node.routerBridge().toString())
.put("state", node.state().name()));