ONOS-6742 Refactored OpenstackNode
- Removed gateway node uplink interface configuration steps
- Added checking group states
- Refactored interface, store, manager and handler
Change-Id: I9149edbec6481b15377848c8f24bdc5c6c73adc4
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncRulesCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncRulesCommand.java
index 30b040c..7336d92 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncRulesCommand.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncRulesCommand.java
@@ -17,7 +17,10 @@
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
/**
* Re-installs flow rules for OpenStack networking.
@@ -30,12 +33,16 @@
protected void execute() {
// All handlers in this application reacts the node complete event and
// tries to re-configure flow rules for the complete node.
- OpenstackNodeService nodeService = AbstractShellCommand.get(OpenstackNodeService.class);
- if (nodeService == null) {
+ OpenstackNodeService osNodeService = AbstractShellCommand.get(OpenstackNodeService.class);
+ OpenstackNodeAdminService osNodeAdminService = AbstractShellCommand.get(OpenstackNodeAdminService.class);
+ if (osNodeService == null) {
error("Failed to re-install flow rules for OpenStack networking.");
return;
}
- nodeService.completeNodes().forEach(nodeService::processCompleteState);
+ osNodeService.completeNodes().forEach(osNode -> {
+ OpenstackNode updated = osNode.updateState(NodeState.INIT);
+ osNodeAdminService.updateNode(updated);
+ });
print("Successfully requested re-installing flow rules.");
}
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
index 4f7ead7..8b93115 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
@@ -36,10 +36,10 @@
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.openstacknetworking.api.Constants;
import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.slf4j.Logger;
import java.util.concurrent.ExecutorService;
@@ -73,7 +73,7 @@
private final ExecutorService deviceEventExecutor =
Executors.newSingleThreadExecutor(groupedThreads("openstacknetworking", "device-event"));
- private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
+ private final OpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
private ApplicationId appId;
@@ -228,25 +228,25 @@
// TODO check leadership of the node and make only the leader process
switch (event.type()) {
- case COMPLETE:
+ case OPENSTACK_NODE_COMPLETE:
deviceEventExecutor.execute(() -> {
log.info("COMPLETE node {} is detected", osNode.hostname());
processCompleteNode(event.subject());
});
break;
- case INCOMPLETE:
- log.warn("{} is changed to INCOMPLETE state", osNode);
- break;
- case INIT:
- case DEVICE_CREATED:
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ case OPENSTACK_NODE_REMOVED:
+ case OPENSTACK_NODE_INCOMPLETE:
default:
+ // do nothing
break;
}
}
private void processCompleteNode(OpenstackNode osNode) {
- if (osNode.type().equals(OpenstackNodeService.NodeType.COMPUTE)) {
- initializePipeline(osNode.intBridge());
+ if (osNode.type().equals(OpenstackNode.NodeType.COMPUTE)) {
+ initializePipeline(osNode.intgBridge());
}
}
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index f99d2ae..fce18a0 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -25,6 +25,7 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.packet.DefaultOutboundPacket;
@@ -34,15 +35,19 @@
import org.onosproject.net.packet.PacketService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
import org.onosproject.openstacknetworking.api.Constants;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -68,7 +73,7 @@
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
- private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+ private final PacketProcessor packetProcessor = new InternalPacketProcessor();
@Activate
protected void activate() {
@@ -123,8 +128,13 @@
public void process(PacketContext context) {
if (context.isHandled()) {
return;
- } else if (!osNodeService.gatewayDeviceIds().contains(
- context.inPacket().receivedFrom().deviceId())) {
+ }
+
+ Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
+ .stream().map(OpenstackNode::intgBridge)
+ .collect(Collectors.toSet());
+
+ if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
// return if the packet is not from gateway nodes
return;
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index f1fdf29..50110a2 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -44,9 +44,10 @@
import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
import org.onosproject.openstacknetworking.api.OpenstackRouterService;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.NetFloatingIP;
import org.openstack4j.model.network.Network;
import org.openstack4j.model.network.NetworkType;
@@ -55,7 +56,6 @@
import org.slf4j.LoggerFactory;
import java.util.Objects;
-import java.util.Optional;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
@@ -65,7 +65,7 @@
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
-import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
/**
* Handles OpenStack floating IP events.
@@ -107,7 +107,7 @@
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
- private final OpenstackRouterListener floatingIpLisener = new InternalFloatingIpLisener();
+ private final OpenstackRouterListener floatingIpLisener = new InternalFloatingIpListener();
private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
private ApplicationId appId;
@@ -158,11 +158,21 @@
private void setDownstreamRules(NetFloatingIP floatingIp, Network osNet,
InstancePort instPort, boolean install) {
- Optional<IpAddress> dataIp = osNodeService.dataIp(instPort.deviceId());
- if (!dataIp.isPresent()) {
- log.warn(ERR_FLOW + "compute node {} is not ready",
- floatingIp, instPort.deviceId());
- return;
+ OpenstackNode cNode = osNodeService.node(instPort.deviceId());
+ if (cNode == null) {
+ final String error = String.format("Cannot find openstack node for device %s",
+ instPort.deviceId());
+ throw new IllegalStateException(error);
+ }
+ if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
+ final String error = String.format(ERR_FLOW +
+ "VXLAN mode is not ready for %s", floatingIp, cNode.hostname());
+ throw new IllegalStateException(error);
+ }
+ if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
+ final String error = String.format(ERR_FLOW +
+ "VLAN mode is not ready for %s", floatingIp, cNode.hostname());
+ throw new IllegalStateException(error);
}
IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
@@ -171,7 +181,7 @@
.matchIPDst(floating.toIpPrefix())
.build();
- osNodeService.gatewayDeviceIds().forEach(gnodeId -> {
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
TrafficTreatment.Builder externalBuilder = DefaultTrafficTreatment.builder()
.setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
.setEthDst(instPort.macAddress())
@@ -182,37 +192,36 @@
externalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
.extension(buildExtension(
deviceService,
- gnodeId,
- dataIp.get().getIp4Address()),
- gnodeId)
- .setOutput(osNodeService.tunnelPort(gnodeId).get());
+ gNode.intgBridge(),
+ cNode.dataIp().getIp4Address()),
+ gNode.intgBridge())
+ .setOutput(gNode.tunnelPortNum());
break;
case VLAN:
externalBuilder.pushVlan()
.setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
- .setOutput(osNodeService.vlanPort(gnodeId).get());
+ .setOutput(gNode.vlanPortNum());
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
- osNet.getNetworkType().toString());
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
+ osNet.getNetworkType());
throw new IllegalStateException(error);
}
osFlowRuleService.setRule(
appId,
- gnodeId,
+ gNode.intgBridge(),
externalSelector,
externalBuilder.build(),
PRIORITY_FLOATING_EXTERNAL,
GW_COMMON_TABLE,
install);
- // access from one VM to the other via floating IP
+ // access from one VM to the others via floating IP
TrafficSelector internalSelector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(floating.toIpPrefix())
- .matchInPort(osNodeService.tunnelPort(gnodeId).get())
+ .matchInPort(gNode.tunnelPortNum())
.build();
TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
@@ -225,9 +234,9 @@
internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
.extension(buildExtension(
deviceService,
- gnodeId,
- dataIp.get().getIp4Address()),
- gnodeId)
+ gNode.intgBridge(),
+ cNode.dataIp().getIp4Address()),
+ gNode.intgBridge())
.setOutput(PortNumber.IN_PORT);
break;
case VLAN:
@@ -236,15 +245,14 @@
.setOutput(PortNumber.IN_PORT);
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
- osNet.getNetworkType().toString());
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
+ osNet.getNetworkType());
throw new IllegalStateException(error);
}
osFlowRuleService.setRule(
appId,
- gnodeId,
+ gNode.intgBridge(),
internalSelector,
internalBuilder.build(),
PRIORITY_FLOATING_INTERNAL,
@@ -256,7 +264,6 @@
private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
InstancePort instPort, boolean install) {
IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
-
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPSrc(instPort.ipAddress().toIpPrefix());
@@ -269,13 +276,12 @@
sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
- osNet.getNetworkType().toString());
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
+ osNet.getNetworkType());
throw new IllegalStateException(error);
}
- osNodeService.gatewayDeviceIds().forEach(gnodeId -> {
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
.setIpSrc(floating.getIp4Address())
.setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
@@ -287,16 +293,16 @@
osFlowRuleService.setRule(
appId,
- gnodeId,
+ gNode.intgBridge(),
sBuilder.build(),
- tBuilder.setOutput(osNodeService.externalPort(gnodeId).get()).build(),
+ tBuilder.setOutput(gNode.patchPortNum()).build(),
PRIORITY_FLOATING_EXTERNAL,
GW_COMMON_TABLE,
install);
});
}
- private class InternalFloatingIpLisener implements OpenstackRouterListener {
+ private class InternalFloatingIpListener implements OpenstackRouterListener {
@Override
public boolean isRelevant(OpenstackRouterEvent event) {
@@ -401,7 +407,7 @@
public void event(OpenstackNodeEvent event) {
switch (event.type()) {
- case COMPLETE:
+ case OPENSTACK_NODE_COMPLETE:
eventExecutor.execute(() -> {
for (NetFloatingIP fip : osRouterService.floatingIps()) {
if (Strings.isNullOrEmpty(fip.getPortId())) {
@@ -416,10 +422,12 @@
}
});
break;
- case INIT:
- case DEVICE_CREATED:
- case INCOMPLETE:
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ case OPENSTACK_NODE_REMOVED:
+ case OPENSTACK_NODE_INCOMPLETE:
default:
+ // do nothing
break;
}
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
index e0b5ccb..084f1b8 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
@@ -26,7 +26,6 @@
import org.onlab.packet.IPv4;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
@@ -36,7 +35,6 @@
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
@@ -47,11 +45,11 @@
import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
import org.onosproject.openstacknetworking.api.OpenstackRouterService;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
-import org.onosproject.openstacknode.OpenstackNodeService;
-import org.onosproject.openstacknode.OpenstackNodeService.NetworkMode;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.ExternalGateway;
import org.openstack4j.model.network.Network;
import org.openstack4j.model.network.NetworkType;
@@ -68,16 +66,9 @@
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.AnnotationKeys.PORT_MAC;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
-import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
-import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
-import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
+import static org.onosproject.openstacknetworking.api.Constants.*;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
/**
* Handles OpenStack router events.
@@ -111,9 +102,6 @@
protected OpenstackRouterService osRouterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackFlowRuleService osFlowRuleService;
private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
@@ -173,7 +161,6 @@
if (exGateway != null && exGateway.isEnableSnat()) {
setSourceNat(osRouterIface, true);
}
-
log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
}
@@ -193,7 +180,6 @@
if (exGateway != null && exGateway.isEnableSnat()) {
setSourceNat(osRouterIface, false);
}
-
log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
}
@@ -201,22 +187,21 @@
Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
Network osNet = osNetworkService.network(osSubnet.getNetworkId());
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .forEach(osNode -> {
- setRulesToGateway(osNode.intBridge(), osNet.getProviderSegID(),
- IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
- install);
- });
+ osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
+ setRulesToGateway(cNode, osNet.getProviderSegID(),
+ IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
+ install);
+ });
// take the first outgoing packet to controller for source NAT
- osNodeService.gatewayDeviceIds()
- .forEach(gwDeviceId -> setRulesToController(
- gwDeviceId,
- osNet.getProviderSegID(),
- IpPrefix.valueOf(osSubnet.getCidr()),
- osNet.getNetworkType(),
- install));
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
+ setRulesToController(
+ gNode,
+ osNet.getProviderSegID(),
+ IpPrefix.valueOf(osSubnet.getCidr()),
+ osNet.getNetworkType(),
+ install);
+ });
final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
@@ -232,24 +217,22 @@
Network network = osNetworkService.network(osSubnet.getNetworkId());
switch (network.getNetworkType()) {
case VXLAN:
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .filter(osNode -> osNode.dataIp().isPresent())
- .forEach(osNode -> setRulesToGatewayWithDstIp(
- osNode.intBridge(),
- osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VXLAN),
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(cNode -> cNode.dataIp() != null)
+ .forEach(cNode -> setRulesToGatewayWithDstIp(
+ cNode,
+ cNode.gatewayGroupId(NetworkMode.VXLAN),
network.getProviderSegID(),
IpAddress.valueOf(osSubnet.getGateway()),
NetworkMode.VXLAN,
install));
break;
case VLAN:
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .filter(osNode -> osNode.vlanPort().isPresent())
- .forEach(osNode -> setRulesToGatewayWithDstIp(
- osNode.intBridge(),
- osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VLAN),
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(cNode -> cNode.vlanPortNum() != null)
+ .forEach(cNode -> setRulesToGatewayWithDstIp(
+ cNode,
+ cNode.gatewayGroupId(NetworkMode.VLAN),
network.getProviderSegID(),
IpAddress.valueOf(osSubnet.getGateway()),
NetworkMode.VLAN,
@@ -263,12 +246,13 @@
}
IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
- osNodeService.gatewayDeviceIds()
- .forEach(gwDeviceId -> setGatewayIcmpRule(
- gatewayIp,
- gwDeviceId,
- install
- ));
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
+ setGatewayIcmpRule(
+ gatewayIp,
+ gNode.intgBridge(),
+ install
+ );
+ });
final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
@@ -281,40 +265,38 @@
// installs rule from/to my subnet intentionally to fix ICMP failure
// to my subnet gateway if no external gateway added to the router
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .forEach(osNode -> {
- setInternalRouterRules(
- osNode.intBridge(),
- updatedSegmendId,
- updatedSegmendId,
- IpPrefix.valueOf(updatedSubnet.getCidr()),
- IpPrefix.valueOf(updatedSubnet.getCidr()),
- updatedNetwork.getNetworkType(),
- install
- );
+ osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
+ setInternalRouterRules(
+ cNode.intgBridge(),
+ updatedSegmendId,
+ updatedSegmendId,
+ IpPrefix.valueOf(updatedSubnet.getCidr()),
+ IpPrefix.valueOf(updatedSubnet.getCidr()),
+ updatedNetwork.getNetworkType(),
+ install
+ );
- routableSubnets.forEach(subnet -> {
- setInternalRouterRules(
- osNode.intBridge(),
- updatedSegmendId,
- getSegmentId(subnet),
- IpPrefix.valueOf(updatedSubnet.getCidr()),
- IpPrefix.valueOf(subnet.getCidr()),
- updatedNetwork.getNetworkType(),
- install
- );
- setInternalRouterRules(
- osNode.intBridge(),
- getSegmentId(subnet),
- updatedSegmendId,
- IpPrefix.valueOf(subnet.getCidr()),
- IpPrefix.valueOf(updatedSubnet.getCidr()),
- updatedNetwork.getNetworkType(),
- install
- );
- });
- });
+ routableSubnets.forEach(subnet -> {
+ setInternalRouterRules(
+ cNode.intgBridge(),
+ updatedSegmendId,
+ getSegmentId(subnet),
+ IpPrefix.valueOf(updatedSubnet.getCidr()),
+ IpPrefix.valueOf(subnet.getCidr()),
+ updatedNetwork.getNetworkType(),
+ install
+ );
+ setInternalRouterRules(
+ cNode.intgBridge(),
+ getSegmentId(subnet),
+ updatedSegmendId,
+ IpPrefix.valueOf(subnet.getCidr()),
+ IpPrefix.valueOf(updatedSubnet.getCidr()),
+ updatedNetwork.getNetworkType(),
+ install
+ );
+ });
+ });
final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
@@ -341,7 +323,7 @@
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
- .matchIPDst(gatewayIp.toIpPrefix())
+ .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
@@ -368,8 +350,8 @@
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(Long.parseLong(srcSegmentId))
- .matchIPSrc(srcSubnet)
- .matchIPDst(dstSubnet)
+ .matchIPSrc(srcSubnet.getIp4Prefix())
+ .matchIPDst(dstSubnet.getIp4Prefix())
.build();
treatment = DefaultTrafficTreatment.builder()
@@ -389,8 +371,8 @@
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(Long.parseLong(dstSegmentId))
- .matchIPSrc(srcSubnet)
- .matchIPDst(dstSubnet)
+ .matchIPSrc(srcSubnet.getIp4Prefix())
+ .matchIPDst(dstSubnet.getIp4Prefix())
.build();
treatment = DefaultTrafficTreatment.builder()
@@ -411,8 +393,8 @@
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchVlanId(VlanId.vlanId(srcSegmentId))
- .matchIPSrc(srcSubnet)
- .matchIPDst(dstSubnet)
+ .matchIPSrc(srcSubnet.getIp4Prefix())
+ .matchIPDst(dstSubnet.getIp4Prefix())
.build();
treatment = DefaultTrafficTreatment.builder()
@@ -432,8 +414,8 @@
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchVlanId(VlanId.vlanId(dstSegmentId))
- .matchIPSrc(srcSubnet)
- .matchIPDst(dstSubnet)
+ .matchIPSrc(srcSubnet.getIp4Prefix())
+ .matchIPDst(dstSubnet.getIp4Prefix())
.build();
treatment = DefaultTrafficTreatment.builder()
@@ -459,26 +441,24 @@
}
- private void setRulesToGateway(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
+ private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
NetworkType networkType, boolean install) {
TrafficTreatment treatment;
GroupId groupId;
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPSrc(srcSubnet)
+ .matchIPSrc(srcSubnet.getIp4Prefix())
.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
switch (networkType) {
case VXLAN:
sBuilder.matchTunnelId(Long.parseLong(segmentId));
-
- groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VXLAN);
+ groupId = osNode.gatewayGroupId(NetworkMode.VXLAN);
break;
case VLAN:
sBuilder.matchVlanId(VlanId.vlanId(segmentId));
-
- groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VLAN);
+ groupId = osNode.gatewayGroupId(NetworkMode.VLAN);
break;
default:
final String error = String.format(
@@ -493,7 +473,7 @@
osFlowRuleService.setRule(
appId,
- deviceId,
+ osNode.intgBridge(),
sBuilder.build(),
treatment,
PRIORITY_EXTERNAL_ROUTING_RULE,
@@ -501,11 +481,16 @@
install);
}
- private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
+ private void setRulesToController(OpenstackNode osNode, String segmentId,
+ IpPrefix srcSubnet,
NetworkType networkType, boolean install) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPSrc(srcSubnet);
+ .matchIPSrc(srcSubnet.getIp4Prefix());
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+ .setEthDst(Constants.DEFAULT_GATEWAY_MAC)
+ .setOutput(PortNumber.CONTROLLER);
switch (networkType) {
case VXLAN:
@@ -514,27 +499,18 @@
break;
case VLAN:
sBuilder.matchVlanId(VlanId.vlanId(segmentId))
- .matchEthDst(MacAddress.valueOf(vlanPortMac(deviceId)));
+ .matchEthDst(osNode.vlanPortMac());
+ tBuilder.popVlan();
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
networkType.toString());
throw new IllegalStateException(error);
}
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
- .setEthDst(Constants.DEFAULT_GATEWAY_MAC);
-
- if (networkType.equals(NetworkType.VLAN)) {
- tBuilder.popVlan();
- }
-
- tBuilder.setOutput(PortNumber.CONTROLLER);
-
osFlowRuleService.setRule(
appId,
- deviceId,
+ osNode.intgBridge(),
sBuilder.build(),
tBuilder.build(),
PRIORITY_EXTERNAL_ROUTING_RULE,
@@ -542,27 +518,21 @@
install);
}
- private String vlanPortMac(DeviceId deviceId) {
- return deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations()
- .value(PORT_NAME).equals(osNodeService.gatewayNode(deviceId).vlanPort().get()) && p.isEnabled())
- .findFirst().get().annotations().value(PORT_MAC);
- }
-
- private void setRulesToGatewayWithDstIp(DeviceId deviceId, GroupId groupId, String segmentId,
- IpAddress dstIp, NetworkMode networkMode, boolean install) {
+ private void setRulesToGatewayWithDstIp(OpenstackNode osNode, GroupId groupId,
+ String segmentId, IpAddress dstIp,
+ NetworkMode networkMode, boolean install) {
TrafficSelector selector;
if (networkMode.equals(NetworkMode.VXLAN)) {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(Long.valueOf(segmentId))
- .matchIPDst(dstIp.toIpPrefix())
+ .matchIPDst(dstIp.getIp4Address().toIpPrefix())
.build();
} else {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchVlanId(VlanId.vlanId(segmentId))
- .matchIPDst(dstIp.toIpPrefix())
+ .matchIPDst(dstIp.getIp4Address().toIpPrefix())
.build();
}
@@ -572,7 +542,7 @@
osFlowRuleService.setRule(
appId,
- deviceId,
+ osNode.intgBridge(),
selector,
treatment,
PRIORITY_SWITCHING_RULE,
@@ -659,15 +629,16 @@
OpenstackNode osNode = event.subject();
switch (event.type()) {
- case COMPLETE:
- case INCOMPLETE:
+ case OPENSTACK_NODE_COMPLETE:
+ case OPENSTACK_NODE_INCOMPLETE:
eventExecutor.execute(() -> {
log.info("Reconfigure routers for {}", osNode.hostname());
reconfigureRouters();
});
break;
- case INIT:
- case DEVICE_CREATED:
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ case OPENSTACK_NODE_REMOVED:
default:
break;
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
index ea716db..a6f0a39 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
@@ -47,10 +47,10 @@
import org.onosproject.openstacknetworking.api.InstancePortService;
import org.onosproject.openstacknetworking.api.OpenstackRouterService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.ExternalGateway;
import org.openstack4j.model.network.IP;
import org.openstack4j.model.network.Port;
@@ -70,7 +70,7 @@
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.openstacknetworking.api.Constants.*;
-import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
import static org.slf4j.LoggerFactory.getLogger;
@@ -111,8 +111,8 @@
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
- private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
- private final InternalNodeListener nodeListener = new InternalNodeListener();
+ private final PacketProcessor packetProcessor = new InternalPacketProcessor();
+ private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
private final Map<String, InstancePort> icmpInfoMap = Maps.newHashMap();
private ApplicationId appId;
@@ -121,7 +121,7 @@
protected void activate() {
appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
- osNodeService.addListener(nodeListener);
+ osNodeService.addListener(osNodeListener);
requestPacket(appId);
log.info("Started");
@@ -130,7 +130,7 @@
@Deactivate
protected void deactivate() {
packetService.removeProcessor(packetProcessor);
- osNodeService.removeListener(nodeListener);
+ osNodeService.removeListener(osNodeListener);
eventExecutor.shutdown();
log.info("Stopped");
@@ -142,13 +142,13 @@
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.build();
- osNodeService.gatewayDeviceIds().forEach(gateway -> {
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
packetService.requestPackets(
icmpSelector,
PacketPriority.CONTROL,
appId,
- Optional.of(gateway));
- log.debug("Requested ICMP packet to {}", gateway);
+ Optional.of(gNode.intgBridge()));
+ log.debug("Requested ICMP packet to {}", gNode.intgBridge());
});
}
@@ -210,9 +210,7 @@
if (externalIp == null) {
return;
}
- log.debug("1");
sendRequestForExternal(ipPacket, srcDevice, externalIp);
- log.debug("2");
String icmpInfoKey = String.valueOf(getIcmpId(icmp))
.concat(String.valueOf(externalIp.getIp4Address().toInt()))
.concat(String.valueOf(ipPacket.getDestinationAddress()));
@@ -329,8 +327,14 @@
.setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC)
.setPayload(ipPacket);
+ OpenstackNode osNode = osNodeService.node(srcDevice);
+ if (osNode == null) {
+ final String error = String.format("Cannot find openstack node for %s",
+ srcDevice);
+ throw new IllegalStateException(error);
+ }
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(osNodeService.externalPort(srcDevice).get())
+ .setOutput(osNode.patchPortNum())
.build();
OutboundPacket packet = new DefaultOutboundPacket(
@@ -379,10 +383,13 @@
@Override
public void process(PacketContext context) {
+ Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
+ .stream().map(OpenstackNode::intgBridge)
+ .collect(Collectors.toSet());
+
if (context.isHandled()) {
return;
- } else if (!osNodeService.gatewayDeviceIds().contains(
- context.inPacket().receivedFrom().deviceId())) {
+ } else if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
// return if the packet is not from gateway nodes
return;
}
@@ -406,7 +413,7 @@
public boolean isRelevant(OpenstackNodeEvent event) {
// do not proceed without mastership
OpenstackNode osNode = event.subject();
- return mastershipService.isLocalMaster(osNode.intBridge());
+ return mastershipService.isLocalMaster(osNode.intgBridge());
}
@Override
@@ -414,7 +421,7 @@
OpenstackNode osNode = event.subject();
switch (event.type()) {
- case COMPLETE:
+ case OPENSTACK_NODE_COMPLETE:
if (osNode.type() == GATEWAY) {
log.info("GATEWAY node {} detected", osNode.hostname());
eventExecutor.execute(() -> {
@@ -422,10 +429,12 @@
});
}
break;
- case INIT:
- case DEVICE_CREATED:
- case INCOMPLETE:
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ case OPENSTACK_NODE_REMOVED:
+ case OPENSTACK_NODE_INCOMPLETE:
default:
+ // do nothing
break;
}
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
index 9d62a34..1300188 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
@@ -47,7 +47,8 @@
import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
import org.onosproject.openstacknetworking.api.OpenstackRouterService;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.DistributedSet;
@@ -65,15 +66,14 @@
import java.nio.ByteBuffer;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
-import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
-import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
-import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
+import static org.onosproject.openstacknetworking.api.Constants.*;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -122,7 +122,7 @@
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
- private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+ private final PacketProcessor packetProcessor = new InternalPacketProcessor();
private ConsistentMap<Integer, Long> allocatedPortNumMap;
private DistributedSet<Integer> unUsedPortNumSet;
@@ -273,7 +273,8 @@
packetIn);
}
- private void setDownstreamRules(InstancePort srcInstPort, String segmentId, NetworkType networkType,
+ private void setDownstreamRules(InstancePort srcInstPort, String segmentId,
+ NetworkType networkType,
IpAddress externalIp, TpPort patPort,
InboundPacket packetIn) {
IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
@@ -282,7 +283,7 @@
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(iPacket.getProtocol())
- .matchIPDst(IpPrefix.valueOf(externalIp, 32))
+ .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), 32))
.matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
@@ -323,31 +324,30 @@
break;
}
- osNodeService.gatewayDeviceIds().forEach(deviceId -> {
- DeviceId srcDeviceId = srcInstPort.deviceId();
+ OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
TrafficTreatment.Builder tmpBuilder =
DefaultTrafficTreatment.builder(tBuilder.build());
switch (networkType) {
case VXLAN:
tmpBuilder.extension(RulePopulatorUtil.buildExtension(
deviceService,
- deviceId,
- osNodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
- .setOutput(osNodeService.tunnelPort(deviceId).get());
+ gNode.intgBridge(),
+ srcNode.dataIp().getIp4Address()), gNode.intgBridge())
+ .setOutput(gNode.tunnelPortNum());
break;
case VLAN:
- tmpBuilder.setOutput(osNodeService.vlanPort(deviceId).get());
+ tmpBuilder.setOutput(gNode.vlanPortNum());
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
networkType.toString());
throw new IllegalStateException(error);
}
osFlowRuleService.setRule(
appId,
- deviceId,
+ gNode.intgBridge(),
sBuilder.build(),
tmpBuilder.build(),
PRIORITY_SNAT_RULE,
@@ -356,7 +356,8 @@
});
}
- private void setUpstreamRules(String segmentId, NetworkType networkType, IpAddress externalIp, TpPort patPort,
+ private void setUpstreamRules(String segmentId, NetworkType networkType,
+ IpAddress externalIp, TpPort patPort,
InboundPacket packetIn) {
IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
@@ -377,8 +378,7 @@
tBuilder.popVlan();
break;
default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
+ final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
networkType.toString());
throw new IllegalStateException(error);
}
@@ -397,7 +397,6 @@
.matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
tBuilder.setUdpSrc(patPort)
.setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
-
break;
default:
log.debug("Unsupported IPv4 protocol {}");
@@ -405,14 +404,14 @@
}
tBuilder.setIpSrc(externalIp);
- osNodeService.gatewayDeviceIds().forEach(deviceId -> {
+ osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
TrafficTreatment.Builder tmpBuilder =
DefaultTrafficTreatment.builder(tBuilder.build());
- tmpBuilder.setOutput(osNodeService.externalPort(deviceId).get());
+ tmpBuilder.setOutput(gNode.patchPortNum());
osFlowRuleService.setRule(
appId,
- deviceId,
+ gNode.intgBridge(),
sBuilder.build(),
tmpBuilder.build(),
PRIORITY_SNAT_RULE,
@@ -424,7 +423,6 @@
private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
IpAddress externalIp) {
IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
-
switch (iPacket.getProtocol()) {
case IPv4.PROTOCOL_TCP:
TCP tcpPacket = (TCP) iPacket.getPayload();
@@ -452,9 +450,15 @@
ethPacketIn.setPayload(iPacket);
ethPacketIn.resetChecksum();
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(osNodeService.externalPort(srcDevice).get()).build();
+ OpenstackNode srcNode = osNodeService.node(srcDevice);
+ if (srcNode == null) {
+ final String error = String.format("Cannot find openstack node for %s",
+ srcDevice);
+ throw new IllegalStateException(error);
+ }
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(srcNode.patchPortNum()).build();
packetService.emit(new DefaultOutboundPacket(
srcDevice,
treatment,
@@ -465,13 +469,11 @@
if (unUsedPortNumSet.isEmpty()) {
clearPortNumMap();
}
-
int portNum = findUnusedPortNum();
if (portNum != 0) {
unUsedPortNumSet.remove(portNum);
allocatedPortNumMap.put(portNum, System.currentTimeMillis());
}
-
return portNum;
}
@@ -492,10 +494,12 @@
@Override
public void process(PacketContext context) {
+ Set<DeviceId> gateways = osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
+ .stream().map(OpenstackNode::intgBridge)
+ .collect(Collectors.toSet());
if (context.isHandled()) {
return;
- } else if (!osNodeService.gatewayDeviceIds().contains(
- context.inPacket().receivedFrom().deviceId())) {
+ } else if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
// return if the packet is not from gateway nodes
return;
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index 10b1776..0ec6ccc 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -38,7 +38,8 @@
import org.onosproject.openstacknetworking.api.InstancePortService;
import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.Network;
import org.slf4j.Logger;
@@ -53,7 +54,7 @@
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
-import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
import static org.slf4j.LoggerFactory.getLogger;
@@ -148,22 +149,27 @@
install);
// switching rules for the instPorts in the remote node
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
- .forEach(osNode -> {
+ OpenstackNode localNode = osNodeService.node(instPort.deviceId());
+ if (localNode == null) {
+ final String error = String.format("Cannot find openstack node for %s",
+ instPort.deviceId());
+ throw new IllegalStateException(error);
+ }
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
+ .forEach(remoteNode -> {
TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
.extension(buildExtension(
deviceService,
- osNode.intBridge(),
- osNodeService.dataIp(instPort.deviceId()).get().getIp4Address()),
- osNode.intBridge())
- .setOutput(osNodeService.tunnelPort(osNode.intBridge()).get())
+ remoteNode.intgBridge(),
+ localNode.dataIp().getIp4Address()),
+ remoteNode.intgBridge())
+ .setOutput(remoteNode.tunnelPortNum())
.build();
osFlowRuleService.setRule(
appId,
- osNode.intBridge(),
+ remoteNode.intgBridge(),
selector,
treatmentToRemote,
PRIORITY_SWITCHING_RULE,
@@ -196,25 +202,23 @@
install);
// switching rules for the instPorts in the remote node
- osNodeService.completeNodes().stream()
- .filter(osNode -> osNode.type() == COMPUTE)
- .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
- .filter(osNode -> osNode.vlanPort().isPresent())
- .forEach(osNode -> {
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
+ remoteNode.vlanIntf() != null)
+ .forEach(remoteNode -> {
TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
- .setOutput(osNodeService.vlanPort(osNode.intBridge()).get())
+ .setOutput(remoteNode.vlanPortNum())
.build();
osFlowRuleService.setRule(
appId,
- osNode.intBridge(),
+ remoteNode.intgBridge(),
selector,
treatmentToRemote,
PRIORITY_SWITCHING_RULE,
FORWARDING_TABLE,
install);
});
-
}
private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 5f776b3..c5de792 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -47,10 +47,10 @@
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.Network;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -260,24 +260,25 @@
// TODO check leadership of the node and make only the leader process
switch (event.type()) {
- case COMPLETE:
+ case OPENSTACK_NODE_COMPLETE:
deviceEventExecutor.execute(() -> {
log.info("COMPLETE node {} is detected", osNode.hostname());
processCompleteNode(event.subject());
});
break;
- case INCOMPLETE:
+ case OPENSTACK_NODE_INCOMPLETE:
log.warn("{} is changed to INCOMPLETE state", osNode);
break;
- case INIT:
- case DEVICE_CREATED:
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ case OPENSTACK_NODE_REMOVED:
default:
break;
}
}
private void processCompleteNode(OpenstackNode osNode) {
- deviceService.getPorts(osNode.intBridge()).stream()
+ deviceService.getPorts(osNode.intgBridge()).stream()
.filter(port -> port.annotations().value(PORT_NAME)
.startsWith(PORT_NAME_PREFIX_VM) &&
port.isEnabled())
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/ConnectionHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/ConnectionHandler.java
deleted file mode 100644
index b355fc6..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/ConnectionHandler.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknode;
-
-/**
- * Entity capable of handling a subject connected and disconnected situation.
- */
-public interface ConnectionHandler<T> {
- /**
- * Processes the connected subject.
- *
- * @param subject subject
- */
- void connected(T subject);
-
- /**
- * Processes the disconnected subject.
- *
- * @param subject subject.
- */
- void disconnected(T subject);
-}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java
deleted file mode 100644
index 0ff91a9..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknode;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Strings;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.DeviceId;
-import org.onosproject.openstacknode.OpenstackNodeEvent.NodeState;
-import org.onosproject.openstacknode.OpenstackNodeService.NodeType;
-
-import java.util.Comparator;
-import java.util.Objects;
-import java.util.Optional;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE;
-import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.INIT;
-
-/**
- * Representation of a compute/gateway node for OpenstackSwitching/Routing service.
- */
-public final class OpenstackNode {
-
- private final String hostname;
- private final NodeType type;
- private final IpAddress managementIp;
- 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 =
- (node1, node2) -> node1.hostname().compareTo(node2.hostname());
-
- private OpenstackNode(String hostname,
- NodeType type,
- IpAddress managementIp,
- 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;
- this.managementIp = managementIp;
- this.dataIp = dataIp;
- this.integrationBridge = integrationBridge;
- this.routerBridge = routerBridge;
- this.uplink = uplink;
- this.routerController = routerController;
- this.vlanPort = vlanPort;
- this.state = state;
- }
-
- /**
- * Returns OpenStack node with new state.
- *
- * @param node openstack node
- * @param state openstack node init state
- * @return openstack node
- */
- public static OpenstackNode getUpdatedNode(OpenstackNode node, NodeState state) {
- return new OpenstackNode(node.hostname,
- node.type,
- node.managementIp,
- node.dataIp,
- node.integrationBridge,
- node.routerBridge,
- node.uplink,
- node.routerController,
- node.vlanPort,
- state);
- }
-
- /**
- * Returns hostname of the node.
- *
- * @return hostname
- */
- public String hostname() {
- return hostname;
- }
-
- /**
- * Returns the type of the node.
- *
- * @return node type
- */
- public NodeType type() {
- return type;
- }
-
- /**
- * Returns the management network IP address of the node.
- *
- * @return management network ip address
- */
- public IpAddress managementIp() {
- return managementIp;
- }
-
- /**
- * Returns the data network IP address of the node.
- *
- * @return data network ip address; or empty value
- */
- public Optional<IpAddress> dataIp() {
- return dataIp;
- }
-
- /**
- * Returns the integration bridge device ID.
- *
- * @return device id
- */
- public DeviceId intBridge() {
- return integrationBridge;
- }
-
- /**
- * Returns the router bridge device ID.
- * It returns valid value only if the node type is GATEWAY.
- *
- * @return device id; or empty device id
- */
- public Optional<DeviceId> routerBridge() {
- return routerBridge;
- }
-
- /**
- * Returns the router bridge controller.
- * It returns valid value only if the node type is GATEWAY.
- *
- * @return device id; or empty value
- */
- // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter
- public Optional<IpAddress> routerController() {
- return routerController;
- }
-
- /**
- * Returns the uplink interface name.
- * It returns valid value only if the node type is GATEWAY.
- *
- * @return uplink interface name; or empty value
- */
- public Optional<String> uplink() {
- 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.
- *
- * @return init state
- */
- public NodeState state() {
- return state;
- }
-
- /**
- * Returns the device ID of the OVSDB session of the node.
- *
- * @return device id
- */
- public DeviceId ovsdbId() {
- return DeviceId.deviceId("ovsdb:" + managementIp.toString());
- }
-
- /**
- * Returns the name of the port connected to the external network.
- * It returns valid value only if the node is gateway node.
- *
- * @return external port name
- */
- public Optional<String> externalPortName() {
- if (type == NodeType.GATEWAY) {
- return Optional.of(PATCH_INTG_BRIDGE);
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (obj instanceof OpenstackNode) {
- OpenstackNode that = (OpenstackNode) obj;
- if (Objects.equals(hostname, that.hostname) &&
- Objects.equals(type, that.type) &&
- Objects.equals(managementIp, that.managementIp) &&
- Objects.equals(dataIp, that.dataIp) &&
- Objects.equals(integrationBridge, that.integrationBridge) &&
- Objects.equals(routerBridge, that.routerBridge) &&
- Objects.equals(uplink, that.uplink) &&
- Objects.equals(routerController, that.routerController) &&
- Objects.equals(vlanPort, that.vlanPort)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(hostname,
- type,
- managementIp,
- dataIp,
- integrationBridge,
- routerBridge,
- uplink,
- routerController,
- vlanPort);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(getClass())
- .add("hostname", hostname)
- .add("type", type)
- .add("managementIp", managementIp)
- .add("dataIp", dataIp)
- .add("integrationBridge", integrationBridge)
- .add("routerBridge", routerBridge)
- .add("uplink", uplink)
- .add("routerController", routerController)
- .add("vlanport", vlanPort)
- .add("state", state)
- .toString();
- }
-
- /**
- * Returns a new builder instance.
- *
- * @return openstack node builder
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Builder of OpenStack node entities.
- */
- public static final class Builder {
- private String hostname;
- private NodeType type;
- private IpAddress managementIp;
- 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;
-
- private Builder() {
- }
-
- public OpenstackNode build() {
- checkArgument(!Strings.isNullOrEmpty(hostname));
- checkNotNull(type);
- checkNotNull(managementIp);
- checkNotNull(dataIp);
- checkNotNull(integrationBridge);
- checkNotNull(routerBridge);
- checkNotNull(uplink);
- checkNotNull(routerController);
- checkNotNull(vlanPort);
-
- if (type == NodeType.GATEWAY) {
- checkArgument(routerBridge.isPresent());
- checkArgument(uplink.isPresent());
- checkArgument(routerController.isPresent());
- }
-
- return new OpenstackNode(hostname,
- type,
- managementIp,
- dataIp,
- integrationBridge,
- routerBridge,
- uplink,
- routerController,
- vlanPort,
- state);
- }
-
- /**
- * Returns node builder with the hostname.
- *
- * @param hostname hostname
- * @return openstack node builder
- */
- public Builder hostname(String hostname) {
- this.hostname = hostname;
- return this;
- }
-
- /**
- * Returns node builder with the node type.
- *
- * @param type openstack node type
- * @return openstack node builder
- */
- public Builder type(NodeType type) {
- this.type = type;
- return this;
- }
-
- /**
- * Returns node builder with the management network IP address.
- *
- * @param managementIp management ip address
- * @return openstack node builder
- */
- public Builder managementIp(IpAddress managementIp) {
- this.managementIp = managementIp;
- return this;
- }
-
- /**
- * Returns node builder with the data network IP address.
- *
- * @param dataIp data network ip address
- * @return openstack node builder
- */
- public Builder dataIp(IpAddress dataIp) {
- this.dataIp = Optional.ofNullable(dataIp);
- return this;
- }
-
- /**
- * Returns node builder with the integration bridge ID.
- *
- * @param integrationBridge integration bridge device id
- * @return openstack node builder
- */
- public Builder integrationBridge(DeviceId integrationBridge) {
- this.integrationBridge = integrationBridge;
- return this;
- }
-
- /**
- * Returns node builder with the router bridge ID.
- *
- * @param routerBridge router bridge device ID
- * @return openstack node builder
- */
- public Builder routerBridge(DeviceId routerBridge) {
- this.routerBridge = Optional.ofNullable(routerBridge);
- return this;
- }
-
- /**
- * Returns node builder with the uplink interface name.
- *
- * @param uplink uplink interface name
- * @return openstack node builder
- */
- public Builder uplink(String uplink) {
- this.uplink = Optional.ofNullable(uplink);
- return this;
- }
-
- /**
- * Returns node builder with the router controller.
- *
- * @param routerController router contoller
- * @return openstack node builder
- */
- // TODO remove this when we use single ONOS cluster for both openstackNode and vRouter
- public Builder routerController(IpAddress routerController) {
- this.routerController = Optional.ofNullable(routerController);
- 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.
- *
- * @param state node init state
- * @return openstack node builder
- */
- public Builder state(NodeState state) {
- this.state = state;
- return this;
- }
- }
-}
-
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeEvent.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeEvent.java
deleted file mode 100644
index 7e0fb78..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeEvent.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknode;
-
-import org.joda.time.LocalDateTime;
-import org.onosproject.event.AbstractEvent;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Describes OpenStack node init state event.
- */
-public class OpenstackNodeEvent extends AbstractEvent<OpenstackNodeEvent.NodeState, OpenstackNode> {
-
- public enum NodeState {
- /**
- * Indicates the node is newly added.
- */
- INIT {
- @Override
- public void process(OpenstackNodeService nodeService, OpenstackNode node) {
- nodeService.processInitState(node);
- }
- },
- /**
- * Indicates bridge devices are added according to the node state.
- */
- DEVICE_CREATED {
- @Override
- public void process(OpenstackNodeService nodeService, OpenstackNode node) {
- nodeService.processDeviceCreatedState(node);
- }
- },
- /**
- * Indicates all node initialization is done.
- */
- COMPLETE {
- @Override
- public void process(OpenstackNodeService nodeService, OpenstackNode node) {
- nodeService.processCompleteState(node);
- }
- },
- /**
- * Indicates node initialization is not done but unable to proceed to
- * the next step for some reason.
- */
- INCOMPLETE {
- @Override
- public void process(OpenstackNodeService nodeService, OpenstackNode node) {
- nodeService.processIncompleteState(node);
- }
- };
-
- public abstract void process(OpenstackNodeService nodeService, OpenstackNode node);
- }
-
- public OpenstackNodeEvent(NodeState state, OpenstackNode node) {
- super(state, node);
- }
-
- @Override
- public String toString() {
- return toStringHelper(this)
- .add("time", new LocalDateTime(time()))
- .add("state", type())
- .add("node", subject())
- .toString();
- }
-}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
deleted file mode 100644
index 3eb8095..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknode;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Modified;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.Service;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.TpPort;
-import org.onlab.util.KryoNamespace;
-import org.onlab.util.Tools;
-import org.onosproject.cfg.ComponentConfigService;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.ControllerNode;
-import org.onosproject.cluster.LeadershipService;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.core.GroupId;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.BridgeConfig;
-import org.onosproject.net.behaviour.BridgeDescription;
-import org.onosproject.net.behaviour.BridgeName;
-import org.onosproject.net.behaviour.ControllerInfo;
-import org.onosproject.net.behaviour.DefaultBridgeDescription;
-import org.onosproject.net.behaviour.DefaultPatchDescription;
-import org.onosproject.net.behaviour.DefaultTunnelDescription;
-import org.onosproject.net.behaviour.InterfaceConfig;
-import org.onosproject.net.behaviour.PatchDescription;
-import org.onosproject.net.behaviour.TunnelDescription;
-import org.onosproject.net.behaviour.TunnelEndPoints;
-import org.onosproject.net.behaviour.TunnelKeys;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.basics.SubjectFactories;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupKey;
-import org.onosproject.net.group.GroupService;
-import org.onosproject.openstacknode.OpenstackNodeEvent.NodeState;
-import org.onosproject.ovsdb.controller.OvsdbClientService;
-import org.onosproject.ovsdb.controller.OvsdbController;
-import org.onosproject.ovsdb.controller.OvsdbNodeId;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMap;
-import org.onosproject.store.service.MapEvent;
-import org.onosproject.store.service.MapEventListener;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.Versioned;
-import org.osgi.service.component.ComponentContext;
-import org.slf4j.Logger;
-
-import java.util.Dictionary;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.net.Device.Type.SWITCH;
-import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
-import static org.onosproject.openstacknode.Constants.*;
-import static org.onosproject.openstacknode.OpenstackNode.getUpdatedNode;
-import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.*;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Initializes devices in compute/gateway nodes according to there type.
- */
-@Component(immediate = true)
-@Service
-public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
- implements OpenstackNodeService {
- private final Logger log = getLogger(getClass());
-
- private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API)
- .register(OpenstackNode.class)
- .register(NodeType.class)
- .register(NodeState.class);
-
- private static final String OVSDB_PORT = "ovsdbPort";
- private static final int DPID_BEGIN = 3;
-
- private static final String APP_ID = "org.onosproject.openstacknode";
-
- private static final Class<OpenstackNodeConfig> CONFIG_CLASS = OpenstackNodeConfig.class;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OvsdbController ovsdbController;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ClusterService clusterService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected StorageService storageService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ComponentConfigService componentConfigService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected NetworkConfigRegistry configRegistry;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LeadershipService leadershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DriverService driverService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected GroupService groupService;
-
- @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
- label = "OVSDB server listen port")
- private int ovsdbPort = DEFAULT_OVSDB_PORT;
-
- private final ExecutorService eventExecutor =
- newSingleThreadScheduledExecutor(groupedThreads("onos/openstack-node", "event-handler", log));
-
- private final ConfigFactory configFactory =
- new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
- SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "openstacknode") {
- @Override
- public OpenstackNodeConfig createConfig() {
- return new OpenstackNodeConfig();
- }
- };
-
- private final NetworkConfigListener configListener = new InternalConfigListener();
- private final DeviceListener deviceListener = new InternalDeviceListener();
- private final MapEventListener<String, OpenstackNode> nodeStoreListener = new InternalMapListener();
-
- private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
- private final BridgeHandler bridgeHandler = new BridgeHandler();
-
- private ConsistentMap<String, OpenstackNode> nodeStore;
-
- private SelectGroupHandler selectGroupHandler;
- private ApplicationId appId;
- private NodeId localNodeId;
-
- @Activate
- protected void activate() {
- appId = coreService.getAppId(APP_ID);
-
- localNodeId = clusterService.getLocalNode().id();
- leadershipService.runForLeadership(appId.name());
-
- nodeStore = storageService.<String, OpenstackNode>consistentMapBuilder()
- .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
- .withName("openstack-nodestore")
- .withApplicationId(appId)
- .build();
-
- nodeStore.addListener(nodeStoreListener);
- deviceService.addListener(deviceListener);
-
- configRegistry.registerConfigFactory(configFactory);
- configRegistry.addListener(configListener);
- componentConfigService.registerProperties(getClass());
-
- selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
-
- readConfiguration();
- log.info("Started");
- }
-
- @Deactivate
- protected void deactivate() {
- configRegistry.removeListener(configListener);
- deviceService.removeListener(deviceListener);
- nodeStore.removeListener(nodeStoreListener);
-
- componentConfigService.unregisterProperties(getClass(), false);
- configRegistry.unregisterConfigFactory(configFactory);
-
- leadershipService.withdraw(appId.name());
- eventExecutor.shutdown();
-
- log.info("Stopped");
- }
-
- @Modified
- protected void modified(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
- if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
- ovsdbPort = updatedOvsdbPort;
- }
-
- log.info("Modified");
- }
-
- @Override
- public void addOrUpdateNode(OpenstackNode node) {
- nodeStore.computeIf(node.hostname(),
- v -> v == null || (!v.equals(node) || v.state() != COMPLETE),
- (k, v) -> getUpdatedNode(node, nodeState(node))
- );
- }
-
- @Override
- public void deleteNode(OpenstackNode node) {
- nodeStore.remove(node.hostname());
- process(new OpenstackNodeEvent(INCOMPLETE, node));
- }
-
- @Override
- public void processInitState(OpenstackNode node) {
- // make sure there is OVSDB connection
- if (!isOvsdbConnected(node)) {
- connectOvsdb(node);
- return;
- }
- process(new OpenstackNodeEvent(INIT, node));
-
- createBridge(node, INTEGRATION_BRIDGE, node.intBridge());
- if (node.type().equals(NodeType.GATEWAY)) {
- createBridge(node, ROUTER_BRIDGE, node.routerBridge().get());
- // TODO remove this when OVSDB provides port event
- setNodeState(node, nodeState(node));
- }
- }
-
- @Override
- public void processDeviceCreatedState(OpenstackNode node) {
- // make sure there is OVSDB connection
- if (!isOvsdbConnected(node)) {
- connectOvsdb(node);
- return;
- }
-
- process(new OpenstackNodeEvent(DEVICE_CREATED, node));
-
- if (node.dataIp().isPresent()) {
- createTunnelInterface(node);
- }
-
- if (node.vlanPort().isPresent()) {
- addVlanPort(node);
- }
-
- if (node.type().equals(NodeType.GATEWAY)) {
- createPatchInterface(node);
- addUplink(node);
- // TODO remove this when OVSDB provides port event
- setNodeState(node, nodeState(node));
- }
- }
-
- @Override
- public void processCompleteState(OpenstackNode node) {
- process(new OpenstackNodeEvent(COMPLETE, node));
- switch (node.type()) {
- case COMPUTE:
- selectGroupHandler.createGatewayGroup(node, gatewayNodes());
- break;
- case GATEWAY:
- updateGatewayGroup(node, true);
- break;
- default:
- break;
- }
- log.info("Finished init {}", node.hostname());
- }
-
- @Override
- public void processIncompleteState(OpenstackNode node) {
- process(new OpenstackNodeEvent(INCOMPLETE, node));
- if (node.type().equals(NodeType.GATEWAY)) {
- updateGatewayGroup(node, false);
- }
- }
-
- @Override
- public List<OpenstackNode> nodes() {
- return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
- }
-
- @Override
- public Set<OpenstackNode> completeNodes() {
- return nodeStore.values().stream().map(Versioned::value)
- .filter(node -> node.state().equals(COMPLETE))
- .collect(Collectors.toSet());
- }
-
- @Override
- public Optional<IpAddress> dataIp(DeviceId deviceId) {
- OpenstackNode node = nodeByDeviceId(deviceId);
- if (node == null) {
- log.warn("Failed to get node for {}", deviceId);
- return Optional.empty();
- }
- return node.dataIp();
- }
-
- @Override
- public Optional<PortNumber> tunnelPort(DeviceId deviceId) {
- return deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL) &&
- p.isEnabled())
- .map(Port::number).findFirst();
- }
-
- @Override
- public Optional<PortNumber> vlanPort(DeviceId intBridgeId) {
- Optional<String> vlanPortName = nodeByDeviceId(intBridgeId).vlanPort();
-
- return deviceService.getPorts(intBridgeId).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(vlanPortName.get()) &&
- p.isEnabled())
- .map(Port::number).findFirst();
-
- }
-
- @Override
- public Optional<DeviceId> routerBridge(DeviceId intBridgeId) {
- OpenstackNode node = nodeByDeviceId(intBridgeId);
- if (node == null || node.type().equals(NodeType.COMPUTE)) {
- log.warn("Failed to find router bridge connected to {}", intBridgeId);
- return Optional.empty();
- }
- return node.routerBridge();
- }
-
- @Override
- public Optional<PortNumber> externalPort(DeviceId intBridgeId) {
- return deviceService.getPorts(intBridgeId).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(PATCH_INTG_BRIDGE) &&
- p.isEnabled())
- .map(Port::number).findFirst();
- }
-
- @Override
- public OpenstackNode gatewayNode(DeviceId deviceId) {
- OpenstackNode gatewayNode = nodeByDeviceId(deviceId);
- if (gatewayNode == null || gatewayNode.type() != NodeType.GATEWAY) {
- log.warn("Gateway with device ID {} does not exist");
- return null;
- }
- return gatewayNode;
- }
-
- @Override
- public synchronized GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode) {
- GroupKey groupKey = selectGroupHandler.groupKey(srcDeviceId, networkMode);
- Group group = groupService.getGroup(srcDeviceId, groupKey);
-
- if (group == null) {
- log.info("Created gateway group for {}", srcDeviceId);
- selectGroupHandler.createGatewayGroup(nodeByDeviceId(srcDeviceId), gatewayNodes());
-
- return groupService.getGroup(srcDeviceId, selectGroupHandler.groupKey(srcDeviceId, networkMode)).id();
- } else {
- return group.id();
- }
- }
-
- @Override
- public List<OpenstackNode> gatewayNodes() {
- return nodeStore.values()
- .stream()
- .map(Versioned::value)
- .filter(node -> node.type().equals(NodeType.GATEWAY))
- .filter(node -> node.state().equals(COMPLETE))
- .collect(Collectors.toList());
- }
-
- @Override
- public List<DeviceId> gatewayDeviceIds() {
- return gatewayNodes().stream().map(OpenstackNode::intBridge)
- .collect(Collectors.toList());
- }
-
- private void updateGatewayGroup(OpenstackNode gatewayNode, boolean isInsert) {
- nodeStore.values()
- .stream()
- .map(Versioned::value)
- .filter(node -> node.type().equals(NodeType.COMPUTE))
- .filter(node -> node.dataIp().isPresent())
- .filter(node -> node.state().equals(COMPLETE))
- .forEach(computeNode -> {
- selectGroupHandler.updateGatewayGroupBuckets(computeNode,
- ImmutableList.of(gatewayNode), NetworkMode.VXLAN, isInsert);
- log.trace("Updated gateway group on {} for vxlan mode", computeNode.intBridge());
- });
-
- nodeStore.values()
- .stream()
- .map(Versioned::value)
- .filter(node -> node.type().equals(NodeType.COMPUTE))
- .filter(node -> node.vlanPort().isPresent())
- .filter(node -> node.state().equals(COMPLETE))
- .forEach(computeNode -> {
- selectGroupHandler.updateGatewayGroupBuckets(computeNode,
- ImmutableList.of(gatewayNode), NetworkMode.VLAN, isInsert);
- log.trace("Updated gateway group on {} for vlan mode", computeNode.intBridge());
- });
-
- }
-
- private void initNode(OpenstackNode node) {
- NodeState state = node.state();
- state.process(this, node);
- log.debug("Processing node: {} state: {}", node.hostname(), state);
- }
-
- private void setNodeState(OpenstackNode node, NodeState newState) {
- nodeStore.put(node.hostname(), getUpdatedNode(node, newState));
- }
-
- private NodeState nodeState(OpenstackNode node) {
- if (!isOvsdbConnected(node) || !deviceService.isAvailable(node.intBridge()) ||
- !isBridgeCreated(node.ovsdbId(), INTEGRATION_BRIDGE)) {
- return INIT;
- }
-
- // TODO use device service when we use single ONOS cluster for both openstackNode and vRouter
- if (node.type().equals(NodeType.GATEWAY) &&
- !isBridgeCreated(node.ovsdbId(), ROUTER_BRIDGE)) {
- return INIT;
- }
-
- 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;
- }
-
- if (node.type().equals(NodeType.GATEWAY) && (
- !isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE) ||
- !isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) ||
- !isIfaceCreated(node.ovsdbId(), node.uplink().get()))) {
- return DEVICE_CREATED;
- }
- return COMPLETE;
- }
-
- private boolean isIfaceCreated(DeviceId deviceId, String ifaceName) {
- Device device = deviceService.getDevice(deviceId);
- if (device == null || !device.is(BridgeConfig.class)) {
- return false;
- }
-
- BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
- return bridgeConfig.getPorts().stream()
- .anyMatch(port -> port.annotations().value(PORT_NAME).equals(ifaceName));
- }
-
- private boolean isBridgeCreated(DeviceId deviceId, String bridgeName) {
- Device device = deviceService.getDevice(deviceId);
- if (device == null || !device.is(BridgeConfig.class)) {
- return false;
- }
-
- BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
- return bridgeConfig.getBridges().stream()
- .anyMatch(bridge -> bridge.name().equals(bridgeName));
- }
-
- private void createBridge(OpenstackNode node, String bridgeName, DeviceId deviceId) {
- Device device = deviceService.getDevice(node.ovsdbId());
- if (device == null || !device.is(BridgeConfig.class)) {
- log.error("Failed to create integration bridge on {}", node.ovsdbId());
- return;
- }
-
- // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
- Set<IpAddress> controllerIps;
- if (bridgeName.equals(ROUTER_BRIDGE)) {
- controllerIps = Sets.newHashSet(node.routerController().get());
- } else {
- controllerIps = clusterService.getNodes().stream()
- .map(ControllerNode::ip)
- .collect(Collectors.toSet());
- }
-
- List<ControllerInfo> controllers = controllerIps.stream()
- .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
- .collect(Collectors.toList());
-
- String dpid = deviceId.toString().substring(DPID_BEGIN);
- BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
- .name(bridgeName)
- .failMode(BridgeDescription.FailMode.SECURE)
- .datapathId(dpid)
- .disableInBand()
- .controllers(controllers)
- .build();
-
- BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
- bridgeConfig.addBridge(bridgeDesc);
- }
-
- private void createTunnelInterface(OpenstackNode node) {
- if (isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
- return;
- }
-
- Device device = deviceService.getDevice(node.ovsdbId());
- if (device == null || !device.is(InterfaceConfig.class)) {
- log.error("Failed to create tunnel interface on {}", node.ovsdbId());
- return;
- }
-
- TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
- .deviceId(INTEGRATION_BRIDGE)
- .ifaceName(DEFAULT_TUNNEL)
- .type(VXLAN)
- .remote(TunnelEndPoints.flowTunnelEndpoint())
- .key(TunnelKeys.flowTunnelKey())
- .build();
-
- InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
- ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
- }
-
- private void createPatchInterface(OpenstackNode node) {
- checkArgument(node.type().equals(NodeType.GATEWAY));
- if (isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) &&
- isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE)) {
- return;
- }
-
- Device device = deviceService.getDevice(node.ovsdbId());
- if (device == null || !device.is(InterfaceConfig.class)) {
- log.error("Failed to create patch interfaces on {}", node.hostname());
- return;
- }
-
- PatchDescription patchIntg = DefaultPatchDescription.builder()
- .deviceId(INTEGRATION_BRIDGE)
- .ifaceName(PATCH_INTG_BRIDGE)
- .peer(PATCH_ROUT_BRIDGE)
- .build();
-
- PatchDescription patchRout = DefaultPatchDescription.builder()
- .deviceId(ROUTER_BRIDGE)
- .ifaceName(PATCH_ROUT_BRIDGE)
- .peer(PATCH_INTG_BRIDGE)
- .build();
-
- InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
- ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
- ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
- }
-
- private void addUplink(OpenstackNode node) {
- checkArgument(node.type().equals(NodeType.GATEWAY));
- if (isIfaceCreated(node.ovsdbId(), node.uplink().get())) {
- return;
- }
-
- Device device = deviceService.getDevice(node.ovsdbId());
- if (device == null || !device.is(BridgeConfig.class)) {
- log.error("Failed to add port {} on {}", node.uplink().get(), node.ovsdbId());
- return;
- }
-
- BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
- bridgeConfig.addPort(BridgeName.bridgeName(ROUTER_BRIDGE),
- 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);
- return deviceService.isAvailable(node.ovsdbId()) &&
- client != null &&
- client.isConnected();
- }
-
- private void connectOvsdb(OpenstackNode node) {
- ovsdbController.connect(node.managementIp(), TpPort.tpPort(ovsdbPort));
- }
-
- private Set<String> systemIfaces(OpenstackNode node) {
- Set<String> ifaces = Sets.newHashSet();
- node.dataIp().ifPresent(ip -> ifaces.add(DEFAULT_TUNNEL));
- node.vlanPort().ifPresent(ifaces::add);
- if (node.type().equals(NodeType.GATEWAY)) {
- ifaces.add(PATCH_INTG_BRIDGE);
- ifaces.add(PATCH_ROUT_BRIDGE);
- ifaces.add(node.uplink().get());
- }
- return ifaces;
- }
-
- private OpenstackNode nodeByDeviceId(DeviceId deviceId) {
- OpenstackNode node = nodes().stream()
- .filter(n -> n.intBridge().equals(deviceId))
- .findFirst().orElseGet(() -> nodes().stream()
- .filter(n -> n.routerBridge().isPresent())
- .filter(n -> n.routerBridge().get().equals(deviceId))
- .findFirst().orElseGet(() -> nodes().stream()
- .filter(n -> n.ovsdbId().equals(deviceId))
- .findFirst().orElse(null)));
- return node;
- }
-
- private class OvsdbHandler implements ConnectionHandler<Device> {
-
- @Override
- public void connected(Device device) {
- OpenstackNode node = nodes().stream()
- .filter(n -> n.ovsdbId().equals(device.id()))
- .findFirst()
- .orElse(null);
- if (node != null) {
- setNodeState(node, nodeState(node));
- } else {
- log.debug("{} is detected on unregistered node, ignore it.", device.id());
- }
- }
-
- @Override
- public void disconnected(Device device) {
- OpenstackNode node = nodeByDeviceId(device.id());
- if (node != null) {
- log.warn("Device {} is disconnected", device.id());
- setNodeState(node, NodeState.INCOMPLETE);
- }
- }
- }
-
- private class BridgeHandler implements ConnectionHandler<Device> {
-
- @Override
- public void connected(Device device) {
- OpenstackNode node = nodeByDeviceId(device.id());
- if (node != null) {
- setNodeState(node, nodeState(node));
- } else {
- log.debug("{} is detected on unregistered node, ignore it.", device.id());
- }
- }
-
- @Override
- public void disconnected(Device device) {
- OpenstackNode node = nodeByDeviceId(device.id());
- if (node != null) {
- log.warn("Device {} is disconnected", device.id());
- setNodeState(node, NodeState.INCOMPLETE);
- }
- }
-
- /**
- * Handles port added situation.
- * If the added port is tunnel or data plane interface, proceed to the remaining
- * node initialization. Otherwise, do nothing.
- *
- * @param port port
- */
- public void portAdded(Port port) {
- OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
- String portName = port.annotations().value(PORT_NAME);
- if (node == null) {
- log.debug("{} is added to unregistered node, ignore it.", portName);
- return;
- }
-
- log.info("Port {} is added to {}", portName, node.hostname());
- if (systemIfaces(node).contains(portName)) {
- setNodeState(node, nodeState(node));
- }
- }
-
- /**
- * Handles port removed situation.
- * If the removed port is tunnel or data plane interface, proceed to the remaining
- * node initialization.Others, do nothing.
- *
- * @param port port
- */
- public void portRemoved(Port port) {
- OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
- String portName = port.annotations().value(PORT_NAME);
-
- if (node == null) {
- return;
- }
-
- log.info("Port {} is removed from {}", portName, node.hostname());
- if (systemIfaces(node).contains(portName)) {
- setNodeState(node, NodeState.INCOMPLETE);
- }
- }
- }
-
- private class InternalDeviceListener implements DeviceListener {
-
- @Override
- public void event(DeviceEvent event) {
-
- NodeId leaderNodeId = leadershipService.getLeader(appId.name());
- if (!Objects.equals(localNodeId, leaderNodeId)) {
- // do not allow to proceed without leadership
- return;
- }
-
- Device device = event.subject();
- ConnectionHandler<Device> handler =
- (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
-
- switch (event.type()) {
- // TODO implement OVSDB port event so that we can handle updates on the OVSDB
- case PORT_ADDED:
- eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
- break;
- case PORT_UPDATED:
- if (!event.port().isEnabled()) {
- eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
- }
- break;
- case DEVICE_ADDED:
- case DEVICE_AVAILABILITY_CHANGED:
- if (deviceService.isAvailable(device.id())) {
- eventExecutor.execute(() -> handler.connected(device));
- } else {
- eventExecutor.execute(() -> handler.disconnected(device));
- log.warn("OpenstackNode with device ID {} is disconnected", device.id());
- }
- break;
- default:
- break;
- }
- }
- }
-
- private void readConfiguration() {
- OpenstackNodeConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
- if (config == null) {
- log.debug("No configuration found");
- return;
- }
-
- Map<String, OpenstackNode> prevNodeMap = Maps.newHashMap(nodeStore.asJavaMap());
- config.openstackNodes().forEach(node -> {
- prevNodeMap.remove(node.hostname());
- addOrUpdateNode(node);
- });
- prevNodeMap.values().forEach(this::deleteNode);
- }
-
- private class InternalConfigListener implements NetworkConfigListener {
-
- @Override
- public void event(NetworkConfigEvent event) {
- NodeId leaderNodeId = leadershipService.getLeader(appId.name());
- if (!Objects.equals(localNodeId, leaderNodeId)) {
- // do not allow to proceed without leadership
- return;
- }
-
- if (!event.configClass().equals(CONFIG_CLASS)) {
- return;
- }
-
- switch (event.type()) {
- case CONFIG_ADDED:
- case CONFIG_UPDATED:
- eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
- break;
- default:
- break;
- }
- }
- }
-
- private class InternalMapListener implements MapEventListener<String, OpenstackNode> {
-
- @Override
- public void event(MapEvent<String, OpenstackNode> event) {
- NodeId leaderNodeId = leadershipService.getLeader(appId.name());
- if (!Objects.equals(localNodeId, leaderNodeId)) {
- // do not allow to proceed without leadership
- return;
- }
-
- OpenstackNode oldNode;
- OpenstackNode newNode;
-
- switch (event.type()) {
- case UPDATE:
- oldNode = event.oldValue().value();
- newNode = event.newValue().value();
-
- log.info("Reloaded {}", newNode.hostname());
- if (!newNode.equals(oldNode)) {
- log.debug("New node: {}", newNode);
- }
- // performs init procedure even if the node is not changed
- // for robustness since it's no harm to run init procedure
- // multiple times
- eventExecutor.execute(() -> initNode(newNode));
- break;
- case INSERT:
- newNode = event.newValue().value();
- log.info("Added {}", newNode.hostname());
- eventExecutor.execute(() -> initNode(newNode));
- break;
- case REMOVE:
- oldNode = event.oldValue().value();
- log.info("Removed {}", oldNode.hostname());
- break;
- default:
- break;
- }
- }
- }
-}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java
deleted file mode 100644
index 9600280..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknode;
-
-import org.onlab.packet.IpAddress;
-import org.onosproject.core.GroupId;
-import org.onosproject.event.ListenerService;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-/**
- * Handles the bootstrap request for compute/gateway node.
- */
-public interface OpenstackNodeService
- extends ListenerService<OpenstackNodeEvent, OpenstackNodeListener> {
-
- enum NodeType {
- /**
- * Compute or Gateway Node.
- */
- COMPUTE,
- GATEWAY
- }
-
- enum NetworkMode {
- /**
- * VxLAN or VLAN mode.
- */
- VXLAN,
- VLAN
- }
-
- /**
- * Adds or updates a new node to the service.
- *
- * @param node openstack node
- */
- void addOrUpdateNode(OpenstackNode node);
-
- /**
- * Bootstraps node with INIT state.
- *
- * @param node openstack node
- */
- void processInitState(OpenstackNode node);
-
- /**
- * Bootstraps node with DEVICE_CREATED state.
- *
- * @param node openstack node
- */
- void processDeviceCreatedState(OpenstackNode node);
-
- /**
- * Bootstraps node with COMPLETE state.
- *
- * @param node openstack node
- */
- void processCompleteState(OpenstackNode node);
-
- /**
- * Bootstraps node with INCOMPLETE state.
- *
- * @param node openstack node
- */
- void processIncompleteState(OpenstackNode node);
-
- /**
- * Deletes a node from the service.
- *
- * @param node openstack node
- */
- void deleteNode(OpenstackNode node);
-
- /**
- * Returns all nodes known to the service.
- *
- * @return list of nodes
- */
- List<OpenstackNode> nodes();
-
- /**
- * Returns all nodes in complete state.
- *
- * @return set of nodes
- */
- Set<OpenstackNode> completeNodes();
-
- /**
- * Returns data network IP address of a given integration bridge device.
- *
- * @param intBridgeId integration bridge device id
- * @return ip address; empty value otherwise
- */
- Optional<IpAddress> dataIp(DeviceId intBridgeId);
-
- /**
- * Returns tunnel port number of a given integration bridge device.
- *
- * @param intBridgeId integration bridge device id
- * @return port number; or empty value
- */
- Optional<PortNumber> tunnelPort(DeviceId intBridgeId);
-
- /**
- * Returns vlan port number of a given integration bridge device.
- *
- * @param intBridgeId integration bridge device id
- * @return port number; or empty value
- */
- Optional<PortNumber> vlanPort(DeviceId intBridgeId);
-
- /**
- * Returns router bridge device ID connected to a given integration bridge.
- * It returns valid value only if the node type is GATEWAY.
- *
- * @param intBridgeId device id of the integration bridge
- * @return device id of a router bridge; or empty value
- */
- Optional<DeviceId> routerBridge(DeviceId intBridgeId);
-
- /**
- * Returns port number connected to the router bridge.
- * It returns valid value only if the node type is GATEWAY.
- *
- * @param intBridgeId integration bridge device id
- * @return port number; or empty value
- */
- Optional<PortNumber> externalPort(DeviceId intBridgeId);
-
- /**
- * Returns gateway node with the given device identifier.
- *
- * @param deviceId The gateway node deviceId
- * @return The gateway node information
- */
- OpenstackNode gatewayNode(DeviceId deviceId);
-
- /**
- * Returns group id for gateway load balance.
- * If the group does not exist in the supplied source device, creates one.
- *
- * @param srcDeviceId source device id
- * @param networkMode network mode
- * @return group id
- */
- GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode);
-
- /**
- * Returns the list of gateway node information with the given device identifier.
- *
- * @return The list of gateway node information
- */
- List<OpenstackNode> gatewayNodes();
-
- /**
- * Returns the list of gateway`s device identifiers.
- *
- * @return The list of device identifier]
- */
- List<DeviceId> gatewayDeviceIds();
-}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java
deleted file mode 100644
index 5f8e065..0000000
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.openstacknode;
-
-import com.google.common.collect.Lists;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.MacAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.GroupId;
-import org.onosproject.openstacknode.OpenstackNodeService.NetworkMode;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DefaultDriverData;
-import org.onosproject.net.driver.DefaultDriverHandler;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.ExtensionPropertyException;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
-import org.onosproject.net.group.DefaultGroupDescription;
-import org.onosproject.net.group.DefaultGroupKey;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupBuckets;
-import org.onosproject.net.group.GroupDescription;
-import org.onosproject.net.group.GroupKey;
-import org.onosproject.net.group.GroupService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-
-import static org.onosproject.net.AnnotationKeys.PORT_MAC;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.openstacknode.Constants.*;
-import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
-
-/**
- * Handles group generation request from OpenstackNode.
- */
-public class SelectGroupHandler {
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private static final String TUNNEL_DESTINATION = "tunnelDst";
- private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
-
- private final GroupService groupService;
- private final DeviceService deviceService;
- private final DriverService driverService;
- private final ApplicationId appId;
-
- /**
- * Default constructor.
- *
- * @param targetGroupService group service
- * @param targetDeviceService device service
- * @param targetDriverService driver service
- * @param appId application id for group service
- */
- public SelectGroupHandler(GroupService targetGroupService, DeviceService targetDeviceService,
- DriverService targetDriverService, ApplicationId appId) {
- groupService = targetGroupService;
- deviceService = targetDeviceService;
- driverService = targetDriverService;
- this.appId = appId;
- }
-
- /**
- * Creates select type group description according to given deviceId.
- *
- * @param computeNode target device id for group description
- * @param gatewayNodeList gateway node list for bucket action
- */
- public void createGatewayGroup(OpenstackNode computeNode, List<OpenstackNode> gatewayNodeList) {
- List<GroupBucket> bucketList;
- GroupId groupId;
-
- if (computeNode.dataIp().isPresent()) {
- bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, NetworkMode.VXLAN);
- groupId = groupId(computeNode.intBridge(), NetworkMode.VXLAN);
-
- GroupDescription groupDescription = new DefaultGroupDescription(
- computeNode.intBridge(),
- GroupDescription.Type.SELECT,
- new GroupBuckets(bucketList),
- groupKey(computeNode.intBridge(), NetworkMode.VXLAN),
- groupId.id(),
- appId);
-
- groupService.addGroup(groupDescription);
- }
-
- if (computeNode.vlanPort().isPresent()) {
- bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, NetworkMode.VLAN);
- groupId = groupId(computeNode.intBridge(), NetworkMode.VLAN);
-
- GroupDescription groupDescription = new DefaultGroupDescription(
- computeNode.intBridge(),
- GroupDescription.Type.SELECT,
- new GroupBuckets(bucketList),
- groupKey(computeNode.intBridge(), NetworkMode.VLAN),
- groupId.id(),
- appId);
-
- groupService.addGroup(groupDescription);
- }
- }
-
- /**
- * Returns unique group key with supplied source device ID and network mode as a hash.
- * @param srcDeviceId source device id
- * @param networkMode network mode
- * @return group key
- */
- public GroupKey groupKey(DeviceId srcDeviceId, NetworkMode networkMode) {
- if (networkMode.equals(NetworkMode.VXLAN)) {
- return new DefaultGroupKey(srcDeviceId.toString().concat(DEFAULT_TUNNEL).getBytes());
- } else {
- return new DefaultGroupKey(srcDeviceId.toString().concat(VLAN).getBytes());
- }
- }
-
- private GroupId groupId(DeviceId srcDeviceId, NetworkMode networkMode) {
- if (networkMode.equals(NetworkMode.VXLAN)) {
- return new GroupId(srcDeviceId.toString().concat(DEFAULT_TUNNEL).hashCode());
- } else {
- return new GroupId(srcDeviceId.toString().concat(VLAN).hashCode());
- }
- }
-
-
- /**
- * Updates groupBuckets in select type group.
- *
- * @param computeNode compute node
- * @param gatewayNodeList updated gateway node list for bucket action
- * @param networkMode network mode
- * @param isInsert update type(add or remove)
- */
- public void updateGatewayGroupBuckets(OpenstackNode computeNode,
- List<OpenstackNode> gatewayNodeList,
- NetworkMode networkMode,
- boolean isInsert) {
- List<GroupBucket> bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, networkMode);
- GroupKey groupKey = groupKey(computeNode.intBridge(), networkMode);
- if (groupService.getGroup(computeNode.intBridge(), groupKey) == null) {
- log.error("There's no group in compute node {}", computeNode.intBridge());
- return;
- }
-
- if (isInsert) {
- groupService.addBucketsToGroup(
- computeNode.intBridge(),
- groupKey,
- new GroupBuckets(bucketList),
- groupKey, appId);
- } else {
- groupService.removeBucketsFromGroup(
- computeNode.intBridge(),
- groupKey,
- new GroupBuckets(bucketList),
- groupKey, appId);
- }
- }
-
-
-
- private List<GroupBucket> generateBucketsForSelectGroup(OpenstackNode computeNode,
- List<OpenstackNode> gatewayNodeList,
- NetworkMode networkMode) {
- List<GroupBucket> bucketList = Lists.newArrayList();
-
- switch (networkMode) {
- case VXLAN:
- gatewayNodeList.stream()
- .filter(node -> node.dataIp().isPresent())
- .forEach(node -> {
- TrafficTreatment tBuilder = DefaultTrafficTreatment.builder()
- .extension(buildNiciraExtenstion(computeNode.intBridge(),
- node.dataIp().get().getIp4Address()),
- computeNode.intBridge())
- .setOutput(getTunnelPort(computeNode.intBridge()))
- .build();
- bucketList.add(createSelectGroupBucket(tBuilder));
- });
- return bucketList;
- case VLAN:
- gatewayNodeList.stream()
- .filter(node -> node.vlanPort().isPresent())
- .forEach(node -> {
- TrafficTreatment tBuilder = DefaultTrafficTreatment.builder()
- .setEthDst(MacAddress.valueOf(vlanPortMac(node)))
- .setOutput(vlanPortNum(computeNode))
- .build();
- bucketList.add(createSelectGroupBucket(tBuilder));
- });
- return bucketList;
- default:
- final String error = String.format(
- ERR_UNSUPPORTED_NET_TYPE + "%s",
- networkMode.toString());
- throw new IllegalStateException(error);
- }
- }
-
- /**
- * Builds Nicira extension for tagging remoteIp of vxlan.
- *
- * @param id device id of vxlan source device
- * @param hostIp remote ip of vxlan destination device
- * @return NiciraExtension Treatment
- */
- private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
- Driver driver = driverService.getDriver(id);
- DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
- ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
-
- ExtensionTreatment extensionInstruction =
- resolver.getExtensionInstruction(
- ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
-
- try {
- extensionInstruction.setPropertyValue(TUNNEL_DESTINATION, hostIp);
- } catch (ExtensionPropertyException e) {
- log.error("Error setting Nicira extension setting {}", e);
- }
-
- return extensionInstruction;
- }
-
- /**
- * Returns port number of vxlan tunnel.
- *
- * @param deviceId target Device Id
- * @return portNumber
- */
- private PortNumber getTunnelPort(DeviceId deviceId) {
- Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL))
- .findAny().orElse(null);
-
- if (port == null) {
- log.error("No TunnelPort was created.");
- return null;
- }
- return port.number();
- }
-
- private PortNumber vlanPortNum(OpenstackNode node) {
- return deviceService.getPorts(node.intBridge()).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(node.vlanPort().get()) &&
- p.isEnabled())
- .map(Port::number).findFirst().get();
-
- }
- private String vlanPortMac(OpenstackNode node) {
- return deviceService.getPorts(node.intBridge()).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(node.vlanPort().get()) && p.isEnabled())
- .findFirst().get().annotations().value(PORT_MAC);
- }
-}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/Constants.java
similarity index 80%
rename from apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java
rename to apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/Constants.java
index 8bb75a1..9f812db 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/Constants.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.openstacknode;
+package org.onosproject.openstacknode.api;
/**
* Provides constants used in OpenStack node services.
@@ -26,11 +26,6 @@
public static final String INTEGRATION_BRIDGE = "br-int";
public static final String ROUTER_BRIDGE = "br-router";
public static final String DEFAULT_TUNNEL = "vxlan";
- public static final String VLAN = "vlan";
public static final String PATCH_INTG_BRIDGE = "patch-intg";
public static final String PATCH_ROUT_BRIDGE = "patch-rout";
-
- public static final int DEFAULT_OVSDB_PORT = 6640;
- public static final int DEFAULT_OFPORT = 6653;
- public static final String DEFAULT_OF_PROTO = "tcp";
}
\ No newline at end of file
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/NodeState.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/NodeState.java
new file mode 100644
index 0000000..6d3a825
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/NodeState.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+/**
+ * Defines the initialization states of OpenStack node.
+ */
+public enum NodeState {
+
+ /**
+ * Indicates the node is newly added.
+ */
+ INIT {
+ @Override
+ public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
+ handler.processInitState(osNode);
+ }
+
+ @Override
+ public NodeState nextState() {
+ return DEVICE_CREATED;
+ }
+ },
+ /**
+ * Indicates bridge devices are added according to the node state.
+ */
+ DEVICE_CREATED {
+ @Override
+ public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
+ handler.processDeviceCreatedState(osNode);
+ }
+
+ @Override
+ public NodeState nextState() {
+ return PORT_CREATED;
+ }
+ },
+ /**
+ * Indicates required ports are added.
+ */
+ PORT_CREATED {
+ @Override
+ public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
+ handler.processPortCreatedState(osNode);
+ }
+
+ @Override
+ public NodeState nextState() {
+ return COMPLETE;
+ }
+ },
+ /**
+ * Indicates node initialization is done.
+ */
+ COMPLETE {
+ @Override
+ public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
+ handler.processCompleteState(osNode);
+ }
+
+ @Override
+ public NodeState nextState() {
+ return COMPLETE;
+ }
+
+ },
+ /**
+ * Indicates node is broken.
+ */
+ INCOMPLETE {
+ @Override
+ public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
+ handler.processIncompleteState(osNode);
+ }
+
+ @Override
+ public NodeState nextState() {
+ return INIT;
+ }
+ };
+
+ public abstract void process(OpenstackNodeHandler handler, OpenstackNode osNode);
+ public abstract NodeState nextState();
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
new file mode 100644
index 0000000..d380ec5
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.group.GroupKey;
+
+/**
+ * Representation of a node used in OpenstackNetworking service.
+ */
+public interface OpenstackNode {
+
+ /**
+ * List of valid virtual network modes.
+ */
+ enum NetworkMode {
+ VXLAN,
+ VLAN
+ }
+
+ /**
+ * List of valid node types.
+ */
+ enum NodeType {
+ COMPUTE,
+ GATEWAY
+ }
+
+ /**
+ * Returns hostname of the node.
+ *
+ * @return hostname
+ */
+ String hostname();
+
+ /**
+ * Returns the type of the node.
+ *
+ * @return node type
+ */
+ NodeType type();
+
+ /**
+ * Returns the OVSDB device ID of the node.
+ *
+ * @return ovsdb device id
+ */
+ DeviceId ovsdb();
+
+ /**
+ * Returns the device ID of the integration bridge at the node.
+ *
+ * @return device id
+ */
+ DeviceId intgBridge();
+
+ /**
+ * Returns the router bridge device ID.
+ *
+ * @return device id; null if the node type is compute
+ */
+ DeviceId routerBridge();
+
+ /**
+ * Returns the management network IP address of the node.
+ *
+ * @return ip address
+ */
+ IpAddress managementIp();
+
+ /**
+ * Returns the data network IP address used for tunneling.
+ *
+ * @return ip address; null if vxlan mode is not enabled
+ */
+ IpAddress dataIp();
+
+ /**
+ * Returns the name of the vlan interface.
+ *
+ * @return vlan interface name; null if vlan mode is not enabled
+ */
+ String vlanIntf();
+
+ /**
+ * Returns the initialization state of the node.
+ *
+ * @return node state
+ */
+ NodeState state();
+
+ /**
+ * Returns the gateway group ID of this node.
+ *
+ * @param mode network mode of the group
+ * @return gateway group identifier
+ */
+ GroupId gatewayGroupId(NetworkMode mode);
+
+ /**
+ * Returns the group key of this node.
+ *
+ * @param mode network mode of the group
+ * @return gateway group key
+ */
+ GroupKey gatewayGroupKey(NetworkMode mode);
+
+ /**
+ * Returns the tunnel port number.
+ *
+ * @return port number; null if tunnel port does not exist
+ */
+ PortNumber tunnelPortNum();
+
+ /**
+ * Returns the vlan port nubmer.
+ *
+ * @return port number; null if vlan port does not exist
+ */
+ PortNumber vlanPortNum();
+
+ /**
+ * Returns the patch port number of the integration bridge.
+ *
+ * @return port number; null if the node type is compute
+ */
+ PortNumber patchPortNum();
+
+ /**
+ * Returns the vlan port MAC address.
+ *
+ * @return mac address; null if vlan port does not exist
+ */
+ MacAddress vlanPortMac();
+
+ /**
+ * Returns new openstack node instance with given state.
+ *
+ * @param newState updated state
+ * @return updated openstack node
+ */
+ OpenstackNode updateState(NodeState newState);
+
+ /**
+ * Builder of new node entities.
+ */
+ interface Builder {
+
+ /**
+ * Builds an immutable openstack node instance.
+ *
+ * @return openstack node instance
+ */
+ OpenstackNode build();
+
+ /**
+ * Returns openstack node builder with supplied hostname.
+ *
+ * @param hostname hostname of the node
+ * @return opesntack node builder
+ */
+ Builder hostname(String hostname);
+
+ /**
+ * Returns openstack node builder with supplied type.
+ *
+ * @param type openstack node type
+ * @return openstack node builder
+ */
+ Builder type(NodeType type);
+
+ /**
+ * Returns openstack node builder with supplied integration bridge ID.
+ *
+ * @param intgBridge integration bridge device id
+ * @return openstack node builder
+ */
+ Builder intgBridge(DeviceId intgBridge);
+
+ /**
+ * Returns openstack node builder with supplied router bridge ID.
+ *
+ * @param routerBridge router bridge id
+ * @return openstack node builder
+ */
+ Builder routerBridge(DeviceId routerBridge);
+
+ /**
+ * Returns openstack node builder with supplied management IP address.
+ *
+ * @param managementIp management ip address
+ * @return openstack node builder
+ */
+ Builder managementIp(IpAddress managementIp);
+
+ /**
+ * Returns openstack node builder with supplied data network IP address.
+ *
+ * @param dataIp data network ip address
+ * @return openstack node builder
+ */
+ Builder dataIp(IpAddress dataIp);
+
+ /**
+ * Returns openstack node builder with supplied vlan interface.
+ *
+ * @param vlanIntf vlan interface name
+ * @return openstack node builder
+ */
+ Builder vlanIntf(String vlanIntf);
+
+ /**
+ * Returns openstack node builder with supplied node state.
+ *
+ * @param state node state
+ * @return openstack node builder
+ */
+ Builder state(NodeState state);
+ }
+}
+
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeAdminService.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeAdminService.java
new file mode 100644
index 0000000..cfef1aa
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeAdminService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+/**
+ * Service for administering inventory of opestackNode.
+ */
+public interface OpenstackNodeAdminService {
+
+ /**
+ * Creates a new node.
+ *
+ * @param osNode openstack node
+ */
+ void createNode(OpenstackNode osNode);
+
+ /**
+ * Updates the node.
+ *
+ * @param osNode openstack node
+ */
+ void updateNode(OpenstackNode osNode);
+
+ /**
+ * Removes the node.
+ *
+ * @param hostname openstack node hostname
+ * @return removed node; null if the node does not exist
+ */
+ OpenstackNode removeNode(String hostname);
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeConfig.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeConfig.java
similarity index 71%
rename from apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeConfig.java
rename to apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeConfig.java
index 0f264e9..774342a 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeConfig.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeConfig.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.openstacknode;
+package org.onosproject.openstacknode.api;
import com.fasterxml.jackson.databind.JsonNode;
@@ -22,13 +22,14 @@
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
-import org.onosproject.openstacknode.OpenstackNodeService.NodeType;
-import java.util.Set;
import org.onosproject.net.config.Config;
+import org.onosproject.openstacknode.impl.DefaultOpenstackNode;
+
+import java.util.Set;
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;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
/**
* Configuration object for OpensatckNode service.
@@ -44,22 +45,17 @@
// GATEWAY node specific fields
private static final String ROUTER_BRIDGE = "routerBridge";
- 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";
+ private static final String VLAN_INTF_NAME = "vlanPort";
@Override
public boolean isValid() {
boolean result = hasOnlyFields(NODES);
-
if (object.get(NODES) == null || object.get(NODES).size() < 1) {
- final String msg = "No node is present";
- throw new IllegalArgumentException(msg);
+ return true;
}
for (JsonNode node : object.get(NODES)) {
- if (get(node, DATA_IP) == null && get(node, VLAN_PORT_NAME) == null) {
+ if (get(node, DATA_IP) == null && get(node, VLAN_INTF_NAME) == null) {
final String msg = "There is neither tunnel interface nor vlan port";
throw new IllegalArgumentException(msg);
}
@@ -71,26 +67,22 @@
DATA_IP,
INTEGRATION_BRIDGE,
ROUTER_BRIDGE,
- UPLINK_PORT_NAME,
- ROUTER_CONTROLLER,
- VLAN_PORT_NAME
+ VLAN_INTF_NAME
);
result &= isString(osNode, HOST_NAME, MANDATORY);
result &= isString(osNode, TYPE, MANDATORY);
result &= isIpAddress(osNode, MANAGEMENT_IP, MANDATORY);
result &= isString(osNode, INTEGRATION_BRIDGE, MANDATORY);
- result &= isString(osNode, VLAN_PORT_NAME, OPTIONAL);
+ result &= isString(osNode, VLAN_INTF_NAME, OPTIONAL);
result &= isIpAddress(osNode, DATA_IP, OPTIONAL);
DeviceId.deviceId(osNode.get(INTEGRATION_BRIDGE).asText());
- NodeType.valueOf(osNode.get(TYPE).asText());
+ OpenstackNode.NodeType.valueOf(osNode.get(TYPE).asText());
if (osNode.get(TYPE).asText().equals(GATEWAY.name())) {
result &= isString(osNode, ROUTER_BRIDGE, MANDATORY);
DeviceId.deviceId(osNode.get(ROUTER_BRIDGE).asText());
- result &= isString(osNode, UPLINK_PORT_NAME, MANDATORY);
- result &= isIpAddress(osNode, ROUTER_CONTROLLER, MANDATORY);
}
}
return result;
@@ -104,25 +96,22 @@
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)))
+ OpenstackNode.NodeType type = OpenstackNode.NodeType.valueOf(get(node, TYPE));
+ OpenstackNode.Builder nodeBuilder = DefaultOpenstackNode.builder()
+ .intgBridge(DeviceId.deviceId(get(node, INTEGRATION_BRIDGE)))
.managementIp(IpAddress.valueOf(get(node, MANAGEMENT_IP)))
.type(type)
- .hostname(get(node, HOST_NAME));
+ .hostname(get(node, HOST_NAME))
+ .state(NodeState.INIT);
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 (get(node, VLAN_INTF_NAME) != null) {
+ nodeBuilder.vlanIntf(get(node, VLAN_INTF_NAME));
}
-
if (type.equals(GATEWAY)) {
- nodeBuilder.routerBridge(DeviceId.deviceId(get(node, ROUTER_BRIDGE)))
- .uplink(get(node, UPLINK_PORT_NAME))
- .routerController(IpAddress.valueOf(get(node, ROUTER_CONTROLLER)));
+ nodeBuilder.routerBridge(DeviceId.deviceId(get(node, ROUTER_BRIDGE)));
}
nodes.add(nodeBuilder.build());
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeEvent.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeEvent.java
new file mode 100644
index 0000000..68ac50e
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeEvent.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Describes OpenStack node init state event.
+ */
+public class OpenstackNodeEvent extends AbstractEvent<OpenstackNodeEvent.Type, OpenstackNode> {
+
+ public enum Type {
+
+ /**
+ * Signifies that new node is created.
+ */
+ OPENSTACK_NODE_CREATED,
+
+ /**
+ * Signifies that the node state is updated.
+ */
+ OPENSTACK_NODE_UPDATED,
+
+ /**
+ * Signifies that the node state is complete.
+ */
+ OPENSTACK_NODE_COMPLETE,
+
+ /**
+ * Signifies that the node state is removed.
+ */
+ OPENSTACK_NODE_REMOVED,
+
+ /**
+ * Signifies that the node state is changed to incomplete.
+ */
+ OPENSTACK_NODE_INCOMPLETE
+ }
+
+ /**
+ * Creates an event with the given type and node.
+ *
+ * @param type event type
+ * @param node openstack node
+ */
+ public OpenstackNodeEvent(Type type, OpenstackNode node) {
+ super(type, node);
+ }
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java
new file mode 100644
index 0000000..fa0bb33
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+/**
+ * Service handling openstack node state.
+ */
+public interface OpenstackNodeHandler {
+
+ /**
+ * Processes the given node for init state.
+ * It creates required bridges on OVS based on the node type.
+ *
+ * @param osNode openstack node
+ */
+ void processInitState(OpenstackNode osNode);
+
+ /**
+ * Processes the given node for device created state.
+ * It creates required ports on the bridges based on the node type.
+ *
+ * @param osNode openstack node
+ */
+ void processDeviceCreatedState(OpenstackNode osNode);
+
+ /**
+ * Processes the given node for port created state.
+ * It creates gateway groups on compute node.
+ *
+ * @param osNode openstack node
+ */
+ void processPortCreatedState(OpenstackNode osNode);
+
+ /**
+ * Processes the given node for complete state.
+ * It performs post-init jobs for the complete node.
+ *
+ * @param osNode openstack node
+ */
+ void processCompleteState(OpenstackNode osNode);
+
+ /**
+ * Processes the given node for incomplete state.
+ *
+ * @param osNode openstack node
+ */
+ void processIncompleteState(OpenstackNode osNode);
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeListener.java
similarity index 83%
rename from apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java
rename to apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeListener.java
index df8cf0d..b462624 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-present Open Networking Laboratory
+ * Copyright 2017-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.openstacknode;
+package org.onosproject.openstacknode.api;
import org.onosproject.event.EventListener;
/**
- * Listener for OpenStack node events.
+ * Listener for OpenstackNode event.
*/
public interface OpenstackNodeListener extends EventListener<OpenstackNodeEvent> {
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeService.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeService.java
new file mode 100644
index 0000000..592593a
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeService.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+import org.onosproject.event.ListenerService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackNode.NodeType;
+
+import java.util.Set;
+
+/**
+ * Service for interfacing with the inventory of {@link OpenstackNode}.
+ */
+public interface OpenstackNodeService extends ListenerService<OpenstackNodeEvent, OpenstackNodeListener> {
+
+ String APP_ID = "org.onosproject.openstacknode";
+
+ /**
+ * Returns all registered nodes.
+ *
+ * @return set of openstack nodes
+ */
+ Set<OpenstackNode> nodes();
+
+ /**
+ * Returns all nodes with the specified type.
+ *
+ * @param type node type
+ * @return set of openstack nodes
+ */
+ Set<OpenstackNode> nodes(NodeType type);
+
+ /**
+ * Returns all nodes with complete state.
+ *
+ * @return set of openstack nodes
+ */
+ Set<OpenstackNode> completeNodes();
+
+ /**
+ * Returns all nodes with complete state and the specified type.
+ *
+ * @param type node type
+ * @return set of openstack nodes
+ */
+ Set<OpenstackNode> completeNodes(NodeType type);
+
+ /**
+ * Returns the node with the specified hostname.
+ *
+ * @param hostname hostname
+ * @return openstack node
+ */
+ OpenstackNode node(String hostname);
+
+ /**
+ * Returns the node with the specified device ID.
+ * The device ID can be any one of integration bridge, router bridge,
+ * or ovsdb device.
+ *
+ * @param deviceId device id
+ * @return openstack node
+ */
+ OpenstackNode node(DeviceId deviceId);
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStore.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStore.java
new file mode 100644
index 0000000..3a0a1ca
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStore.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.api;
+
+import org.onosproject.store.Store;
+
+import java.util.Set;
+
+/**
+ * Manages inventory of OpenstackNode; not intended for direct use.
+ */
+public interface OpenstackNodeStore extends Store<OpenstackNodeEvent, OpenstackNodeStoreDelegate> {
+
+ /**
+ * Creates a new node.
+ *
+ * @param osNode openstack node
+ */
+ void createNode(OpenstackNode osNode);
+
+ /**
+ * Updates the node.
+ *
+ * @param osNode openstack node
+ */
+ void updateNode(OpenstackNode osNode);
+
+ /**
+ * Removes the node.
+ *
+ * @param hostname openstack node hostname
+ * @return removed openstack node; null if no node mapped for the hostname
+ */
+ OpenstackNode removeNode(String hostname);
+
+ /**
+ * Returns all registered nodes.
+ *
+ * @return set of openstack nodes
+ */
+ Set<OpenstackNode> nodes();
+
+ /**
+ * Returns the node with the specified hostname.
+ *
+ * @param hostname hostname
+ * @return openstack node
+ */
+ OpenstackNode node(String hostname);
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStoreDelegate.java
similarity index 68%
copy from apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java
copy to apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStoreDelegate.java
index df8cf0d..34de865 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeListener.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeStoreDelegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-present Open Networking Laboratory
+ * Copyright 2017-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.openstacknode;
+package org.onosproject.openstacknode.api;
-import org.onosproject.event.EventListener;
+import org.onosproject.store.StoreDelegate;
/**
- * Listener for OpenStack node events.
+ * OpenstackNode store delegate.
*/
-public interface OpenstackNodeListener extends EventListener<OpenstackNodeEvent> {
+public interface OpenstackNodeStoreDelegate extends StoreDelegate<OpenstackNodeEvent> {
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/package-info.java
similarity index 86%
copy from apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java
copy to apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/package-info.java
index c280f54..3bf6709 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/api/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-present Open Networking Laboratory
+ * Copyright 2017-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,4 +17,4 @@
/**
* Application for bootstrapping Compute/Gateway Node in OpenStack.
*/
-package org.onosproject.openstacknode;
\ No newline at end of file
+package org.onosproject.openstacknode.api;
\ No newline at end of file
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
index 4d54abd..a35ab1b 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
@@ -25,14 +25,14 @@
import org.onosproject.net.behaviour.BridgeConfig;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.PortDescription;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import java.util.Optional;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.openstacknode.Constants.*;
-import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
+import static org.onosproject.openstacknode.api.Constants.*;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
/**
* Checks detailed node init state.
@@ -50,22 +50,17 @@
@Override
protected void execute() {
- OpenstackNodeService nodeService = AbstractShellCommand.get(OpenstackNodeService.class);
+ OpenstackNodeService osNodeService = AbstractShellCommand.get(OpenstackNodeService.class);
DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
- OpenstackNode node = nodeService.nodes()
- .stream()
- .filter(n -> n.hostname().equals(hostname))
- .findFirst()
- .orElse(null);
-
- if (node == null) {
- print("Cannot find %s from registered nodes", hostname);
+ OpenstackNode osNode = osNodeService.node(hostname);
+ if (osNode == null) {
+ error("Cannot find %s from registered nodes", hostname);
return;
}
print("[Integration Bridge Status]");
- Device device = deviceService.getDevice(node.intBridge());
+ Device device = deviceService.getDevice(osNode.intgBridge());
if (device != null) {
print("%s %s=%s available=%s %s",
deviceService.isAvailable(device.id()) ? MSG_OK : MSG_NO,
@@ -73,41 +68,39 @@
device.id(),
deviceService.isAvailable(device.id()),
device.annotations());
-
- node.dataIp().ifPresent(ip -> print(getPortState(deviceService, node.intBridge(), DEFAULT_TUNNEL)));
- node.vlanPort().ifPresent(p -> print(getPortState(deviceService, node.intBridge(), p)));
+ if (osNode.dataIp() != null) {
+ print(getPortState(deviceService, osNode.intgBridge(), DEFAULT_TUNNEL));
+ }
+ if (osNode.vlanIntf() != null) {
+ print(getPortState(deviceService, osNode.intgBridge(), osNode.vlanIntf()));
+ }
} else {
print("%s %s=%s is not available",
MSG_NO,
INTEGRATION_BRIDGE,
- node.intBridge());
+ osNode.intgBridge());
}
- if (node.type().equals(GATEWAY)) {
- print(getPortState(deviceService, node.intBridge(), PATCH_INTG_BRIDGE));
+ if (osNode.type() == GATEWAY) {
+ print(getPortState(deviceService, osNode.intgBridge(), PATCH_INTG_BRIDGE));
print("%n[Router Bridge Status]");
- device = deviceService.getDevice(node.ovsdbId());
+ device = deviceService.getDevice(osNode.ovsdb());
if (device == null || !device.is(BridgeConfig.class)) {
print("%s %s=%s is not available(unable to connect OVSDB)",
MSG_NO,
ROUTER_BRIDGE,
- node.intBridge());
+ osNode.intgBridge());
} else {
BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
boolean available = bridgeConfig.getBridges().stream()
- .filter(bridge -> bridge.name().equals(ROUTER_BRIDGE))
- .findAny()
- .isPresent();
-
+ .anyMatch(bridge -> bridge.name().equals(ROUTER_BRIDGE));
print("%s %s=%s available=%s",
available ? MSG_OK : MSG_NO,
ROUTER_BRIDGE,
- node.routerBridge().get(),
+ osNode.routerBridge(),
available);
-
- print(getPortStateOvsdb(deviceService, node.ovsdbId(), PATCH_ROUT_BRIDGE));
- print(getPortStateOvsdb(deviceService, node.ovsdbId(), node.uplink().get()));
+ print(getPortStateOvsdb(deviceService, osNode.ovsdb(), PATCH_ROUT_BRIDGE));
}
}
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeInitCommand.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeInitCommand.java
index 8f4dbb1..85da391 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeInitCommand.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeInitCommand.java
@@ -19,10 +19,10 @@
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeService;
-
-import java.util.NoSuchElementException;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
/**
* Initializes nodes for OpenStack node service.
@@ -37,21 +37,19 @@
@Override
protected void execute() {
- OpenstackNodeService nodeService = AbstractShellCommand.get(OpenstackNodeService.class);
+ OpenstackNodeService osNodeService =
+ AbstractShellCommand.get(OpenstackNodeService.class);
+ OpenstackNodeAdminService osNodeAdminService =
+ AbstractShellCommand.get(OpenstackNodeAdminService.class);
for (String hostname : hostnames) {
- OpenstackNode node;
- try {
- node = nodeService.nodes()
- .stream()
- .filter(n -> n.hostname().equals(hostname))
- .findFirst().get();
- } catch (NoSuchElementException e) {
+ OpenstackNode osNode = osNodeService.node(hostname);
+ if (osNode == null) {
print("Unable to find %s", hostname);
continue;
}
-
- nodeService.addOrUpdateNode(node);
+ OpenstackNode updated = osNode.updateState(NodeState.INIT);
+ osNodeAdminService.updateNode(updated);
}
}
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
index 65a77e6..ceed2a7 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
@@ -19,11 +19,13 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import java.util.Comparator;
import java.util.List;
/**
@@ -37,43 +39,45 @@
@Override
protected void execute() {
- OpenstackNodeService nodeService = AbstractShellCommand.get(OpenstackNodeService.class);
- List<OpenstackNode> nodes = nodeService.nodes();
- nodes.sort(OpenstackNode.OPENSTACK_NODE_COMPARATOR);
+ OpenstackNodeService osNodeService = AbstractShellCommand.get(OpenstackNodeService.class);
+ List<OpenstackNode> osNodes = Lists.newArrayList(osNodeService.nodes());
+ osNodes.sort(Comparator.comparing(OpenstackNode::hostname));
if (outputJson()) {
- print("%s", json(nodes));
+ print("%s", json(osNodes));
} else {
print(FORMAT, "Hostname", "Type", "Integration Bridge", "Router Bridge",
"Management IP", "Data IP", "VLAN Intf", "State");
- for (OpenstackNode node : nodes) {
+ for (OpenstackNode osNode : osNodes) {
print(FORMAT,
- node.hostname(),
- node.type(),
- node.intBridge(),
- node.routerBridge().isPresent() ? node.routerBridge().get() : "",
- node.managementIp(),
- node.dataIp().isPresent() ? node.dataIp().get() : "",
- node.vlanPort().isPresent() ? node.vlanPort().get() : "",
- node.state());
+ osNode.hostname(),
+ osNode.type(),
+ osNode.intgBridge(),
+ osNode.routerBridge() != null ? osNode.routerBridge() : "",
+ osNode.managementIp(),
+ osNode.dataIp() != null ? osNode.dataIp() : "",
+ osNode.vlanIntf() != null ? osNode.vlanIntf() : "",
+ osNode.state());
}
- print("Total %s nodes", nodeService.nodes().size());
+ print("Total %s nodes", osNodeService.nodes().size());
}
}
- private JsonNode json(List<OpenstackNode> nodes) {
+ private JsonNode json(List<OpenstackNode> osNodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
- for (OpenstackNode node : nodes) {
+ for (OpenstackNode osNode : osNodes) {
result.add(mapper.createObjectNode()
- .put("hostname", node.hostname())
- .put("type", node.type().name())
- .put("intBridge", node.intBridge().toString())
- .put("routerBridge", node.routerBridge().toString())
- .put("managementIp", node.managementIp().toString())
- .put("dataIp", node.dataIp().toString())
- .put("vlanPort", node.vlanPort().toString())
- .put("state", node.state().name()));
+ .put("hostname", osNode.hostname())
+ .put("type", osNode.type().name())
+ .put("integrationBridge", osNode.intgBridge().toString())
+ .put("routerBridge", osNode.routerBridge().toString())
+ .put("managementIp", osNode.managementIp().toString())
+ .put("dataIp", osNode.dataIp().toString())
+ .put("vlanIntf", osNode.vlanIntf())
+ .put("tunnelPortNum", osNode.tunnelPortNum().toString())
+ .put("vlanPortNum", osNode.vlanPortNum().toString())
+ .put("state", osNode.state().name()));
}
return result;
}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
new file mode 100644
index 0000000..670d4e8
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.impl;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.group.DefaultGroupKey;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.AnnotationKeys.PORT_MAC;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.openstacknode.api.Constants.DEFAULT_TUNNEL;
+import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE;
+
+/**
+ * Representation of a openstack node.
+ */
+public final class DefaultOpenstackNode implements OpenstackNode {
+
+ private final String hostname;
+ private final NodeType type;
+ private final DeviceId intgBridge;
+ private final DeviceId routerBridge;
+ private final IpAddress managementIp;
+ private final IpAddress dataIp;
+ private final String vlanIntf;
+ private final NodeState state;
+
+ private DefaultOpenstackNode(String hostname,
+ NodeType type,
+ DeviceId intgBridge,
+ DeviceId routerBridge,
+ IpAddress managementIp,
+ IpAddress dataIp,
+ String vlanIntf,
+ NodeState state) {
+ this.hostname = hostname;
+ this.type = type;
+ this.intgBridge = intgBridge;
+ this.routerBridge = routerBridge;
+ this.managementIp = managementIp;
+ this.dataIp = dataIp;
+ this.vlanIntf = vlanIntf;
+ this.state = state;
+ }
+
+ @Override
+ public String hostname() {
+ return hostname;
+ }
+
+ @Override
+ public NodeType type() {
+ return type;
+ }
+
+ @Override
+ public DeviceId ovsdb() {
+ return DeviceId.deviceId("ovsdb:" + managementIp().toString());
+ }
+
+ @Override
+ public DeviceId intgBridge() {
+ return intgBridge;
+ }
+
+ @Override
+ public DeviceId routerBridge() {
+ return routerBridge;
+ }
+
+ @Override
+ public IpAddress managementIp() {
+ return managementIp;
+ }
+
+ @Override
+ public IpAddress dataIp() {
+ return dataIp;
+ }
+
+ @Override
+ public String vlanIntf() {
+ return vlanIntf;
+ }
+
+ @Override
+ public NodeState state() {
+ return state;
+ }
+
+ @Override
+ public GroupKey gatewayGroupKey(NetworkMode mode) {
+ return new DefaultGroupKey(intgBridge.toString().concat(mode.name()).getBytes());
+ }
+
+ @Override
+ public PortNumber tunnelPortNum() {
+ if (dataIp == null) {
+ return null;
+ }
+ DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+ Port port = deviceService.getPorts(intgBridge).stream()
+ .filter(p -> p.isEnabled() &&
+ Objects.equals(p.annotations().value(PORT_NAME), DEFAULT_TUNNEL))
+ .findAny().orElse(null);
+ return port != null ? port.number() : null;
+ }
+
+ @Override
+ public PortNumber vlanPortNum() {
+ if (vlanIntf == null) {
+ return null;
+ }
+ DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+ Port port = deviceService.getPorts(intgBridge).stream()
+ .filter(p -> p.isEnabled() &&
+ Objects.equals(p.annotations().value(PORT_NAME), vlanIntf))
+ .findAny().orElse(null);
+ return port != null ? port.number() : null;
+ }
+
+ @Override
+ public PortNumber patchPortNum() {
+ if (type == NodeType.COMPUTE) {
+ return null;
+ }
+ DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+ Port port = deviceService.getPorts(intgBridge).stream()
+ .filter(p -> p.isEnabled() &&
+ Objects.equals(p.annotations().value(PORT_NAME), PATCH_INTG_BRIDGE))
+ .findAny().orElse(null);
+ return port != null ? port.number() : null;
+ }
+
+ @Override
+ public MacAddress vlanPortMac() {
+ if (vlanIntf == null) {
+ return null;
+ }
+ DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+ Port port = deviceService.getPorts(intgBridge).stream()
+ .filter(p -> p.annotations().value(PORT_NAME).equals(vlanIntf))
+ .findAny().orElse(null);
+ return port != null ? MacAddress.valueOf(port.annotations().value(PORT_MAC)) : null;
+ }
+
+ @Override
+ public GroupId gatewayGroupId(NetworkMode mode) {
+ return new GroupId(intgBridge.toString().concat(mode.name()).hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof DefaultOpenstackNode) {
+ DefaultOpenstackNode that = (DefaultOpenstackNode) obj;
+ if (Objects.equals(hostname, that.hostname) &&
+ Objects.equals(type, that.type) &&
+ Objects.equals(intgBridge, that.intgBridge) &&
+ Objects.equals(routerBridge, that.routerBridge) &&
+ Objects.equals(managementIp, that.managementIp) &&
+ Objects.equals(dataIp, that.dataIp) &&
+ Objects.equals(vlanIntf, that.vlanIntf)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(hostname,
+ type,
+ intgBridge,
+ routerBridge,
+ managementIp,
+ dataIp,
+ vlanIntf);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("hostname", hostname)
+ .add("type", type)
+ .add("integrationBridge", intgBridge)
+ .add("routerBridge", routerBridge)
+ .add("managementIp", managementIp)
+ .add("dataIp", dataIp)
+ .add("vlanIntf", vlanIntf)
+ .add("state", state)
+ .toString();
+ }
+
+ @Override
+ public OpenstackNode updateState(NodeState newState) {
+ return new Builder()
+ .type(type)
+ .hostname(hostname)
+ .intgBridge(intgBridge)
+ .routerBridge(routerBridge)
+ .managementIp(managementIp)
+ .dataIp(dataIp)
+ .vlanIntf(vlanIntf)
+ .state(newState)
+ .build();
+ }
+
+ /**
+ * Returns new builder instance.
+ *
+ * @return openstack node builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Returns new builder instance with the given node as a default value.
+ *
+ * @param osNode openstack node
+ * @return openstack node builder
+ */
+ public static Builder from(OpenstackNode osNode) {
+ return new Builder()
+ .hostname(osNode.hostname())
+ .intgBridge(osNode.intgBridge())
+ .routerBridge(osNode.routerBridge())
+ .managementIp(osNode.managementIp())
+ .dataIp(osNode.dataIp())
+ .vlanIntf(osNode.vlanIntf())
+ .state(osNode.state());
+ }
+
+ public static final class Builder implements OpenstackNode.Builder {
+
+ private String hostname;
+ private NodeType type;
+ private DeviceId intgBridge;
+ private DeviceId routerBridge;
+ private IpAddress managementIp;
+ private IpAddress dataIp;
+ private String vlanIntf;
+ private NodeState state;
+
+ private Builder() {
+ }
+
+ @Override
+ public DefaultOpenstackNode build() {
+ checkArgument(hostname != null, "Node hostname cannot be null");
+ checkArgument(type != null, "Node type cannot be null");
+ checkArgument(intgBridge != null, "Node integration bridge cannot be null");
+ checkArgument(managementIp != null, "Node management IP cannot be null");
+ checkArgument(state != null, "Node state cannot be null");
+
+ if (type == NodeType.GATEWAY && routerBridge == null) {
+ throw new IllegalArgumentException("Router bridge is required for gateway node");
+ }
+ if (dataIp == null && Strings.isNullOrEmpty(vlanIntf)) {
+ throw new IllegalArgumentException("Either data IP or VLAN interface is required");
+ }
+
+ return new DefaultOpenstackNode(hostname,
+ type,
+ intgBridge,
+ routerBridge,
+ managementIp,
+ dataIp,
+ vlanIntf,
+ state);
+ }
+
+ @Override
+ public Builder hostname(String hostname) {
+ if (!Strings.isNullOrEmpty(hostname)) {
+ this.hostname = hostname;
+ }
+ return this;
+ }
+
+ @Override
+ public Builder type(NodeType type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public Builder intgBridge(DeviceId intgBridge) {
+ this.intgBridge = intgBridge;
+ return this;
+ }
+
+ @Override
+ public Builder routerBridge(DeviceId routerBridge) {
+ this.routerBridge = routerBridge;
+ return this;
+ }
+
+ @Override
+ public Builder managementIp(IpAddress managementIp) {
+ this.managementIp = managementIp;
+ return this;
+ }
+
+ @Override
+ public Builder dataIp(IpAddress dataIp) {
+ this.dataIp = dataIp;
+ return this;
+ }
+
+ @Override
+ public Builder vlanIntf(String vlanIntf) {
+ this.vlanIntf = vlanIntf;
+ return this;
+ }
+
+ @Override
+ public Builder state(NodeState state) {
+ this.state = state;
+ return this;
+ }
+ }
+}
+
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
new file mode 100644
index 0000000..c0d2c3c
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
@@ -0,0 +1,805 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.IpAddress;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.behaviour.BridgeConfig;
+import org.onosproject.net.behaviour.BridgeDescription;
+import org.onosproject.net.behaviour.BridgeName;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.behaviour.DefaultBridgeDescription;
+import org.onosproject.net.behaviour.DefaultPatchDescription;
+import org.onosproject.net.behaviour.DefaultTunnelDescription;
+import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.behaviour.InterfaceConfig;
+import org.onosproject.net.behaviour.PatchDescription;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelEndPoints;
+import org.onosproject.net.behaviour.TunnelKeys;
+import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionPropertyException;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupEvent;
+import org.onosproject.net.group.GroupListener;
+import org.onosproject.net.group.GroupService;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeHandler;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.packet.TpPort.tpPort;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
+import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
+import static org.onosproject.openstacknode.api.Constants.*;
+import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE;
+import static org.onosproject.openstacknode.api.NodeState.*;
+import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VLAN;
+import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VXLAN;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
+import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Service bootstraps openstack node based on its type.
+ */
+@Component(immediate = true)
+public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler {
+
+ protected final Logger log = getLogger(getClass());
+
+ private static final String OVSDB_PORT = "ovsdbPortNum";
+ private static final int DEFAULT_OVSDB_PORT = 6640;
+ private static final String DEFAULT_OF_PROTO = "tcp";
+ private static final int DEFAULT_OFPORT = 6653;
+ private static final int DPID_BEGIN = 3;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceAdminService deviceAdminService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OvsdbController ovsdbController;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected GroupService groupService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService osNodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeAdminService osNodeAdminService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService componentConfigService;
+
+ @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
+ label = "OVSDB server listen port")
+ private int ovsdbPort = DEFAULT_OVSDB_PORT;
+
+ private final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+ private final DeviceListener ovsdbListener = new InternalOvsdbListener();
+ private final DeviceListener bridgeListener = new InternalBridgeListener();
+ private final GroupListener groupListener = new InternalGroupListener();
+ private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
+
+ private ApplicationId appId;
+ private NodeId localNode;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.getAppId(APP_ID);
+ localNode = clusterService.getLocalNode().id();
+
+ componentConfigService.registerProperties(getClass());
+ leadershipService.runForLeadership(appId.name());
+ groupService.addListener(groupListener);
+ deviceService.addListener(ovsdbListener);
+ deviceService.addListener(bridgeListener);
+ osNodeService.addListener(osNodeListener);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ osNodeService.removeListener(osNodeListener);
+ deviceService.removeListener(bridgeListener);
+ deviceService.removeListener(ovsdbListener);
+ groupService.removeListener(groupListener);
+ componentConfigService.unregisterProperties(getClass(), false);
+ leadershipService.withdraw(appId.name());
+ eventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Modified
+ protected void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
+ if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
+ ovsdbPort = updatedOvsdbPort;
+ }
+
+ log.info("Modified");
+ }
+
+ @Override
+ public void processInitState(OpenstackNode osNode) {
+ if (!isOvsdbConnected(osNode)) {
+ ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
+ return;
+ }
+ if (!deviceService.isAvailable(osNode.intgBridge())) {
+ createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
+ }
+ if (osNode.type() == GATEWAY &&
+ !isBridgeCreated(osNode.ovsdb(), ROUTER_BRIDGE)) {
+ createBridge(osNode, ROUTER_BRIDGE, osNode.routerBridge());
+ }
+ }
+
+ @Override
+ public void processDeviceCreatedState(OpenstackNode osNode) {
+ if (!isOvsdbConnected(osNode)) {
+ ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
+ return;
+ }
+ if (osNode.type() == GATEWAY && (
+ !isIntfEnabled(osNode, PATCH_INTG_BRIDGE) ||
+ !isIntfCreated(osNode, PATCH_ROUT_BRIDGE)
+ )) {
+ createPatchInterface(osNode);
+ }
+ if (osNode.dataIp() != null &&
+ !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
+ createTunnelInterface(osNode);
+ }
+ if (osNode.vlanIntf() != null &&
+ !isIntfEnabled(osNode, osNode.vlanIntf())) {
+ addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.vlanIntf());
+ }
+ }
+
+ @Override
+ public void processPortCreatedState(OpenstackNode osNode) {
+ switch (osNode.type()) {
+ case COMPUTE:
+ if (osNode.dataIp() != null) {
+ addOrUpdateGatewayGroup(osNode,
+ osNodeService.completeNodes(GATEWAY),
+ VXLAN);
+ }
+ if (osNode.vlanIntf() != null) {
+ addOrUpdateGatewayGroup(osNode,
+ osNodeService.completeNodes(GATEWAY),
+ VLAN);
+ }
+ break;
+ case GATEWAY:
+ Set<OpenstackNode> gateways =
+ Sets.newHashSet(osNodeService.completeNodes(GATEWAY));
+ gateways.add(osNode);
+ osNodeService.completeNodes(COMPUTE).forEach(n -> {
+ if (n.dataIp() != null) {
+ addOrUpdateGatewayGroup(n, gateways, VXLAN);
+ }
+ if (n.vlanIntf() != null) {
+ addOrUpdateGatewayGroup(n, gateways, VLAN);
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void processCompleteState(OpenstackNode osNode) {
+ OvsdbClientService ovsdbClient = ovsdbController.getOvsdbClient(
+ new OvsdbNodeId(osNode.managementIp(), DEFAULT_OVSDB_PORT));
+ if (ovsdbClient != null && ovsdbClient.isConnected()) {
+ ovsdbClient.disconnect();
+ }
+ }
+
+ @Override
+ public void processIncompleteState(OpenstackNode osNode) {
+ if (osNode.type() == COMPUTE) {
+ if (osNode.dataIp() != null) {
+ groupService.removeGroup(osNode.intgBridge(), osNode.gatewayGroupKey(VXLAN), appId);
+ }
+ if (osNode.vlanIntf() != null) {
+ groupService.removeGroup(osNode.intgBridge(), osNode.gatewayGroupKey(VLAN), appId);
+ }
+ }
+ if (osNode.type() == GATEWAY) {
+ osNodeService.completeNodes(COMPUTE).forEach(n -> {
+ if (n.dataIp() != null) {
+ addOrUpdateGatewayGroup(n,
+ osNodeService.completeNodes(GATEWAY),
+ VXLAN);
+ }
+ if (n.vlanIntf() != null) {
+ addOrUpdateGatewayGroup(n,
+ osNodeService.completeNodes(GATEWAY),
+ VLAN);
+ }
+ });
+ }
+ }
+
+ private boolean isOvsdbConnected(OpenstackNode osNode) {
+ OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
+ OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
+ return deviceService.isAvailable(osNode.ovsdb()) &&
+ client != null &&
+ client.isConnected();
+ }
+
+ private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !device.is(BridgeConfig.class)) {
+ log.error("Failed to create integration bridge on {}", osNode.ovsdb());
+ return;
+ }
+
+ // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
+ Set<IpAddress> controllerIps;
+ if (bridgeName.equals(ROUTER_BRIDGE)) {
+ // TODO checks if empty controller does not break anything
+ controllerIps = ImmutableSet.of();
+ } else {
+ controllerIps = clusterService.getNodes().stream()
+ .map(ControllerNode::ip)
+ .collect(Collectors.toSet());
+ }
+
+ List<ControllerInfo> controllers = controllerIps.stream()
+ .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
+ .collect(Collectors.toList());
+
+ String dpid = deviceId.toString().substring(DPID_BEGIN);
+ BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
+ .name(bridgeName)
+ .failMode(BridgeDescription.FailMode.SECURE)
+ .datapathId(dpid)
+ .disableInBand()
+ .controllers(controllers)
+ .build();
+
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.addBridge(bridgeDesc);
+ }
+
+ private void addSystemInterface(OpenstackNode osNode, String bridgeName, String intfName) {
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !device.is(BridgeConfig.class)) {
+ return;
+ }
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.addPort(BridgeName.bridgeName(bridgeName), intfName);
+ }
+
+ private void createTunnelInterface(OpenstackNode osNode) {
+ if (isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
+ return;
+ }
+
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !device.is(InterfaceConfig.class)) {
+ log.error("Failed to create tunnel interface on {}", osNode.ovsdb());
+ return;
+ }
+
+ TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
+ .deviceId(INTEGRATION_BRIDGE)
+ .ifaceName(DEFAULT_TUNNEL)
+ .type(TunnelDescription.Type.VXLAN)
+ .remote(TunnelEndPoints.flowTunnelEndpoint())
+ .key(TunnelKeys.flowTunnelKey())
+ .build();
+
+ InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+ ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
+ }
+
+ private void createPatchInterface(OpenstackNode osNode) {
+ checkArgument(osNode.type().equals(OpenstackNode.NodeType.GATEWAY));
+ if (isIntfEnabled(osNode, PATCH_INTG_BRIDGE) &&
+ isIntfCreated(osNode, PATCH_ROUT_BRIDGE)) {
+ return;
+ }
+
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !device.is(InterfaceConfig.class)) {
+ log.error("Failed to create patch interfaces on {}", osNode.hostname());
+ return;
+ }
+
+ PatchDescription patchIntg = DefaultPatchDescription.builder()
+ .deviceId(INTEGRATION_BRIDGE)
+ .ifaceName(PATCH_INTG_BRIDGE)
+ .peer(PATCH_ROUT_BRIDGE)
+ .build();
+
+ PatchDescription patchRout = DefaultPatchDescription.builder()
+ .deviceId(ROUTER_BRIDGE)
+ .ifaceName(PATCH_ROUT_BRIDGE)
+ .peer(PATCH_INTG_BRIDGE)
+ .build();
+
+ InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+ ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
+ ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
+ }
+
+ private void addOrUpdateGatewayGroup(OpenstackNode osNode,
+ Set<OpenstackNode> gatewayNodes,
+ NetworkMode mode) {
+ GroupBuckets buckets = gatewayGroupBuckets(osNode, gatewayNodes, mode);
+ if (groupService.getGroup(osNode.intgBridge(), osNode.gatewayGroupKey(mode)) == null) {
+ GroupDescription groupDescription = new DefaultGroupDescription(
+ osNode.intgBridge(),
+ GroupDescription.Type.SELECT,
+ buckets,
+ osNode.gatewayGroupKey(mode),
+ osNode.gatewayGroupId(mode).id(),
+ appId);
+ groupService.addGroup(groupDescription);
+ log.debug("Created gateway group for {}", osNode.hostname());
+ } else {
+ groupService.setBucketsForGroup(
+ osNode.intgBridge(),
+ osNode.gatewayGroupKey(mode),
+ buckets,
+ osNode.gatewayGroupKey(mode),
+ appId);
+ log.debug("Updated gateway group for {}", osNode.hostname());
+ }
+ }
+
+ private GroupBuckets gatewayGroupBuckets(OpenstackNode osNode,
+ Set<OpenstackNode> gatewayNodes,
+ NetworkMode mode) {
+ List<GroupBucket> bucketList = Lists.newArrayList();
+ switch (mode) {
+ case VXLAN:
+ gatewayNodes.stream().filter(n -> n.dataIp() != null).forEach(n -> {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .extension(tunnelDstTreatment(osNode.intgBridge(),
+ n.dataIp()),
+ osNode.intgBridge())
+ .setOutput(osNode.tunnelPortNum())
+ .build();
+ bucketList.add(createSelectGroupBucket(treatment));
+ });
+ return new GroupBuckets(bucketList);
+ case VLAN:
+ gatewayNodes.stream().filter(n -> n.vlanIntf() != null).forEach(n -> {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(n.vlanPortMac())
+ .setOutput(osNode.vlanPortNum())
+ .build();
+ bucketList.add(createSelectGroupBucket(treatment));
+ });
+ return new GroupBuckets(bucketList);
+ default:
+ return null;
+ }
+ }
+
+ private ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, IpAddress remoteIp) {
+ Device device = deviceService.getDevice(deviceId);
+ if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
+ log.error("The extension treatment is not supported");
+ return null;
+ }
+
+ ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+ try {
+ treatment.setPropertyValue("tunnelDst", remoteIp.getIp4Address());
+ return treatment;
+ } catch (ExtensionPropertyException e) {
+ log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
+ return null;
+ }
+ }
+
+ private boolean isBridgeCreated(DeviceId ovsdbId, String bridgeName) {
+ Device device = deviceService.getDevice(ovsdbId);
+ if (device == null || !deviceService.isAvailable(device.id()) ||
+ !device.is(BridgeConfig.class)) {
+ return false;
+ }
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ return bridgeConfig.getBridges().stream()
+ .anyMatch(bridge -> bridge.name().equals(bridgeName));
+ }
+
+ private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
+ if (!deviceService.isAvailable(osNode.intgBridge())) {
+ return false;
+ }
+ return deviceService.getPorts(osNode.intgBridge()).stream()
+ .anyMatch(port -> Objects.equals(
+ port.annotations().value(PORT_NAME), intf) &&
+ port.isEnabled());
+ }
+
+ private boolean isIntfCreated(OpenstackNode osNode, String intf) {
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !deviceService.isAvailable(osNode.ovsdb()) ||
+ !device.is(BridgeConfig.class)) {
+ return false;
+ }
+
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ return bridgeConfig.getPorts().stream()
+ .anyMatch(port -> port.annotations().value(PORT_NAME).equals(intf));
+ }
+
+ private boolean isGroupCreated(OpenstackNode osNode) {
+ for (OpenstackNode gNode : osNodeService.completeNodes(GATEWAY)) {
+ if (!isGatewayBucketAdded(osNode, gNode)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isGatewayBucketAdded(OpenstackNode cNode, OpenstackNode gNode) {
+ if (cNode.dataIp() != null) {
+ Group osGroup = groupService.getGroup(cNode.intgBridge(),
+ cNode.gatewayGroupKey(VXLAN));
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .extension(tunnelDstTreatment(gNode.intgBridge(),
+ gNode.dataIp()),
+ cNode.intgBridge())
+ .setOutput(cNode.tunnelPortNum())
+ .build();
+ GroupBucket bucket = createSelectGroupBucket(treatment);
+ if (osGroup == null || osGroup.state() != Group.GroupState.ADDED ||
+ !osGroup.buckets().buckets().contains(bucket)) {
+ return false;
+ }
+ }
+ if (cNode.vlanIntf() != null) {
+ Group osGroup = groupService.getGroup(cNode.intgBridge(),
+ cNode.gatewayGroupKey(VLAN));
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(gNode.vlanPortMac())
+ .setOutput(cNode.vlanPortNum())
+ .build();
+ GroupBucket bucket = createSelectGroupBucket(treatment);
+ if (osGroup == null || osGroup.state() != Group.GroupState.ADDED ||
+ !osGroup.buckets().buckets().contains(bucket)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isCurrentStateDone(OpenstackNode osNode) {
+ switch (osNode.state()) {
+ case INIT:
+ if (!deviceService.isAvailable(osNode.intgBridge())) {
+ return false;
+ }
+ if (osNode.type() == GATEWAY &&
+ !isBridgeCreated(osNode.ovsdb(), ROUTER_BRIDGE)) {
+ return false;
+ }
+ return true;
+ case DEVICE_CREATED:
+ if (osNode.dataIp() != null &&
+ !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
+ return false;
+ }
+ if (osNode.vlanIntf() != null &&
+ !isIntfEnabled(osNode, osNode.vlanIntf())) {
+ return false;
+ }
+ if (osNode.type() == GATEWAY && (
+ !isIntfEnabled(osNode, PATCH_INTG_BRIDGE) ||
+ !isIntfCreated(osNode, PATCH_ROUT_BRIDGE))) {
+ return false;
+ }
+ return true;
+ case PORT_CREATED:
+ if (osNode.type() == COMPUTE) {
+ return isGroupCreated(osNode);
+ } else {
+ for (OpenstackNode cNode : osNodeService.completeNodes(COMPUTE)) {
+ if (!isGatewayBucketAdded(cNode, osNode)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ case COMPLETE:
+ return false;
+ case INCOMPLETE:
+ // always return false
+ // run init CLI to re-trigger node bootstrap
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ private void setState(OpenstackNode osNode, NodeState newState) {
+ if (osNode.state() == newState) {
+ return;
+ }
+ OpenstackNode updated = osNode.updateState(newState);
+ osNodeAdminService.updateNode(updated);
+ log.info("Changed {} state: {}", osNode.hostname(), newState);
+ }
+
+ private void bootstrapNode(OpenstackNode osNode) {
+ if (isCurrentStateDone(osNode)) {
+ setState(osNode, osNode.state().nextState());
+ } else {
+ log.trace("Processing {} state for {}", osNode.state(), osNode.hostname());
+ osNode.state().process(this, osNode);
+ }
+ }
+
+ private class InternalOvsdbListener implements DeviceListener {
+
+ @Override
+ public boolean isRelevant(DeviceEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ return Objects.equals(localNode, leader) &&
+ event.subject().type() == Device.Type.CONTROLLER &&
+ osNodeService.node(event.subject().id()) != null;
+ }
+
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ OpenstackNode osNode = osNodeService.node(device.id());
+
+ switch (event.type()) {
+ case DEVICE_AVAILABILITY_CHANGED:
+ case DEVICE_ADDED:
+ eventExecutor.execute(() -> {
+ if (deviceService.isAvailable(device.id())) {
+ log.debug("OVSDB {} detected", device.id());
+ bootstrapNode(osNode);
+ } else if (osNode.state() == COMPLETE) {
+ log.debug("Removing OVSDB {}", device.id());
+ deviceAdminService.removeDevice(device.id());
+ }
+ });
+ break;
+ case PORT_ADDED:
+ case PORT_REMOVED:
+ case DEVICE_REMOVED:
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ private class InternalBridgeListener implements DeviceListener {
+
+ @Override
+ public boolean isRelevant(DeviceEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ return Objects.equals(localNode, leader) &&
+ event.subject().type() == Device.Type.SWITCH &&
+ osNodeService.node(event.subject().id()) != null;
+ }
+
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ OpenstackNode osNode = osNodeService.node(device.id());
+
+ switch (event.type()) {
+ case DEVICE_AVAILABILITY_CHANGED:
+ case DEVICE_ADDED:
+ eventExecutor.execute(() -> {
+ if (deviceService.isAvailable(device.id())) {
+ log.debug("Integration bridge created on {}", osNode.hostname());
+ bootstrapNode(osNode);
+ } else if (osNode.state() == COMPLETE) {
+ log.warn("Device {} disconnected", device.id());
+ setState(osNode, INCOMPLETE);
+ }
+ });
+ break;
+ case PORT_ADDED:
+ eventExecutor.execute(() -> {
+ Port port = event.port();
+ String portName = port.annotations().value(PORT_NAME);
+ if (osNode.state() == DEVICE_CREATED && (
+ Objects.equals(portName, DEFAULT_TUNNEL) ||
+ Objects.equals(portName, osNode.vlanIntf()) ||
+ Objects.equals(portName, PATCH_INTG_BRIDGE) ||
+ Objects.equals(portName, PATCH_ROUT_BRIDGE))) {
+ // FIXME we never gets PATCH_ROUTE_BRIDGE port added events as of now
+ log.debug("Interface {} added to {}", portName, event.subject().id());
+ bootstrapNode(osNode);
+ }
+ });
+ break;
+ case PORT_REMOVED:
+ eventExecutor.execute(() -> {
+ Port port = event.port();
+ String portName = port.annotations().value(PORT_NAME);
+ if (osNode.state() == COMPLETE && (
+ Objects.equals(portName, DEFAULT_TUNNEL) ||
+ Objects.equals(portName, osNode.vlanIntf()) ||
+ Objects.equals(portName, PATCH_INTG_BRIDGE) ||
+ Objects.equals(portName, PATCH_ROUT_BRIDGE))) {
+ log.warn("Interface {} removed from {}", portName, event.subject().id());
+ setState(osNode, INCOMPLETE);
+ }
+ });
+ break;
+ case PORT_UPDATED:
+ case DEVICE_REMOVED:
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ private class InternalGroupListener implements GroupListener {
+
+ @Override
+ public boolean isRelevant(GroupEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ return Objects.equals(localNode, leader);
+ }
+
+ @Override
+ public void event(GroupEvent event) {
+ switch (event.type()) {
+ case GROUP_ADDED:
+ log.trace("Group added, ID:{} state:{}", event.subject().id(),
+ event.subject().state());
+ eventExecutor.execute(() -> {
+ OpenstackNode osNode = osNodeByGroupId(event.subject().id());
+ if (osNode != null && osNode.state() == PORT_CREATED) {
+ setState(osNode, COMPLETE);
+ }
+ });
+ break;
+ case GROUP_UPDATED:
+ log.trace("Group updated, ID:{} state:{}", event.subject().id(),
+ event.subject().state());
+ eventExecutor.execute(() -> {
+ osNodeService.nodes(GATEWAY).stream()
+ .filter(osNode -> osNode.state() == PORT_CREATED)
+ .forEach(osNode -> bootstrapNode(osNode));
+ });
+ break;
+ case GROUP_REMOVED:
+ // TODO handle group removed
+ break;
+ default:
+ break;
+ }
+ }
+
+ private OpenstackNode osNodeByGroupId(GroupId groupId) {
+ return osNodeService.nodes().stream()
+ .filter(n -> n.gatewayGroupId(VXLAN).equals(groupId) ||
+ n.gatewayGroupId(VLAN).equals(groupId))
+ .findAny().orElse(null);
+ }
+ }
+
+ private class InternalOpenstackNodeListener implements OpenstackNodeListener {
+
+ @Override
+ public boolean isRelevant(OpenstackNodeEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ return Objects.equals(localNode, leader);
+ }
+
+ @Override
+ public void event(OpenstackNodeEvent event) {
+ switch (event.type()) {
+ case OPENSTACK_NODE_CREATED:
+ case OPENSTACK_NODE_UPDATED:
+ eventExecutor.execute(() -> {
+ bootstrapNode(event.subject());
+ });
+ break;
+ case OPENSTACK_NODE_COMPLETE:
+ break;
+ case OPENSTACK_NODE_REMOVED:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
new file mode 100644
index 0000000..f248367
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeStore;
+import org.onosproject.openstacknode.api.OpenstackNodeStoreDelegate;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
+import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
+import static org.onosproject.openstacknode.api.OpenstackNodeEvent.Type.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of openstack node store using consistent map.
+ */
+@Service
+@Component(immediate = true)
+public class DistributedOpenstackNodeStore
+ extends AbstractStore<OpenstackNodeEvent, OpenstackNodeStoreDelegate>
+ implements OpenstackNodeStore {
+
+ protected final Logger log = getLogger(getClass());
+
+ private static final String ERR_NOT_FOUND = " does not exist";
+ private static final String ERR_DUPLICATE = " already exists";
+
+ private static final KryoNamespace SERIALIZER_OPENSTACK_NODE = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(OpenstackNode.class)
+ .register(DefaultOpenstackNode.class)
+ .register(OpenstackNode.NodeType.class)
+ .register(NodeState.class)
+ .build();
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ private final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+ private final MapEventListener<String, OpenstackNode> osNodeMapListener =
+ new OpenstackNodeMapListener();
+ private ConsistentMap<String, OpenstackNode> osNodeStore;
+
+ @Activate
+ protected void activate() {
+ ApplicationId appId = coreService.registerApplication("org.onosproject.openstacknode");
+ osNodeStore = storageService.<String, OpenstackNode>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_OPENSTACK_NODE))
+ .withName("openstack-nodestore")
+ .withApplicationId(appId)
+ .build();
+ osNodeStore.addListener(osNodeMapListener);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ osNodeStore.removeListener(osNodeMapListener);
+ eventExecutor.shutdown();
+ log.info("Stopped");
+ }
+
+ @Override
+ public void createNode(OpenstackNode osNode) {
+ osNodeStore.compute(osNode.hostname(), (hostname, existing) -> {
+ final String error = osNode.hostname() + ERR_DUPLICATE;
+ checkArgument(existing == null, error);
+ return osNode;
+ });
+ }
+
+ @Override
+ public void updateNode(OpenstackNode osNode) {
+ osNodeStore.compute(osNode.hostname(), (hostname, existing) -> {
+ final String error = osNode.hostname() + ERR_NOT_FOUND;
+ checkArgument(existing != null, error);
+ return osNode;
+ });
+ }
+
+ @Override
+ public OpenstackNode removeNode(String hostname) {
+ Versioned<OpenstackNode> osNode = osNodeStore.remove(hostname);
+ if (osNode == null) {
+ final String error = hostname + ERR_NOT_FOUND;
+ throw new IllegalArgumentException(error);
+ }
+ return osNode.value();
+ }
+
+ @Override
+ public Set<OpenstackNode> nodes() {
+ Set<OpenstackNode> osNodes = osNodeStore.values().stream()
+ .map(Versioned::value)
+ .collect(Collectors.toSet());
+ return ImmutableSet.copyOf(osNodes);
+ }
+
+ @Override
+ public OpenstackNode node(String hostname) {
+ Versioned<OpenstackNode> osNode = osNodeStore.get(hostname);
+ return osNode == null ? null : osNode.value();
+ }
+
+ private class OpenstackNodeMapListener implements MapEventListener<String, OpenstackNode> {
+
+ @Override
+ public void event(MapEvent<String, OpenstackNode> event) {
+ switch (event.type()) {
+ case INSERT:
+ log.debug("OpenStack node created {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new OpenstackNodeEvent(
+ OPENSTACK_NODE_CREATED,
+ event.newValue().value()
+ ));
+ });
+ break;
+ case UPDATE:
+ log.debug("OpenStack node updated {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new OpenstackNodeEvent(
+ OPENSTACK_NODE_UPDATED,
+ event.newValue().value()
+ ));
+ if (event.newValue().value().state() == COMPLETE) {
+ notifyDelegate(new OpenstackNodeEvent(
+ OPENSTACK_NODE_COMPLETE,
+ event.newValue().value()
+ ));
+ } else if (event.newValue().value().state() == INCOMPLETE) {
+ notifyDelegate(new OpenstackNodeEvent(
+ OPENSTACK_NODE_INCOMPLETE,
+ event.newValue().value()
+ ));
+ }
+ });
+ break;
+ case REMOVE:
+ log.debug("OpenStack node removed {}", event.oldValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new OpenstackNodeEvent(
+ OPENSTACK_NODE_REMOVED,
+ event.oldValue().value()
+ ));
+ });
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
new file mode 100644
index 0000000..65d565a
--- /dev/null
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.impl;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.openstacknode.api.OpenstackNodeConfig;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.openstacknode.api.OpenstackNodeStore;
+import org.onosproject.openstacknode.api.OpenstackNodeStoreDelegate;
+import org.slf4j.Logger;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Service administering the inventory of openstack nodes.
+ */
+@Service
+@Component(immediate = true)
+public class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
+ implements OpenstackNodeService, OpenstackNodeAdminService {
+
+ protected final Logger log = getLogger(getClass());
+
+ private static final String MSG_NODE = "OpenStack node %s %s";
+ private static final String MSG_CREATED = "created";
+ private static final String MSG_UPDATED = "updated";
+ private static final String MSG_REMOVED = "removed";
+
+ private static final String ERR_NULL_NODE = "OpenStack node cannot be null";
+ private static final String ERR_NULL_HOSTNAME = "OpenStack node hostname cannot be null";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeStore osNodeStore;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
+ private final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+ private final ConfigFactory configFactory =
+ new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
+ SubjectFactories.APP_SUBJECT_FACTORY, OpenstackNodeConfig.class, "openstacknode") {
+ @Override
+ public OpenstackNodeConfig createConfig() {
+ return new OpenstackNodeConfig();
+ }
+ };
+
+ private final NetworkConfigListener configListener = new InternalConfigListener();
+ private final OpenstackNodeStoreDelegate delegate = new InternalNodeStoreDelegate();
+
+ private ApplicationId appId;
+ private NodeId localNode;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(APP_ID);
+ osNodeStore.setDelegate(delegate);
+
+ localNode = clusterService.getLocalNode().id();
+ leadershipService.runForLeadership(appId.name());
+
+ configRegistry.registerConfigFactory(configFactory);
+ configRegistry.addListener(configListener);
+
+ readConfiguration();
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ osNodeStore.unsetDelegate(delegate);
+ configRegistry.removeListener(configListener);
+ configRegistry.unregisterConfigFactory(configFactory);
+
+ leadershipService.withdraw(appId.name());
+ eventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Override
+ public void createNode(OpenstackNode osNode) {
+ checkNotNull(osNode, ERR_NULL_NODE);
+ osNodeStore.createNode(osNode);
+ log.info(String.format(MSG_NODE, osNode.hostname(), MSG_CREATED));
+ }
+
+ @Override
+ public void updateNode(OpenstackNode osNode) {
+ checkNotNull(osNode, ERR_NULL_NODE);
+ osNodeStore.updateNode(osNode);
+ log.info(String.format(MSG_NODE, osNode.hostname(), MSG_UPDATED));
+ }
+
+ @Override
+ public OpenstackNode removeNode(String hostname) {
+ checkArgument(!Strings.isNullOrEmpty(hostname), ERR_NULL_HOSTNAME);
+ OpenstackNode osNode = osNodeStore.removeNode(hostname);
+ log.info(String.format(MSG_NODE, hostname, MSG_REMOVED));
+ return osNode;
+ }
+
+ @Override
+ public Set<OpenstackNode> nodes() {
+ return osNodeStore.nodes();
+ }
+
+ @Override
+ public Set<OpenstackNode> nodes(OpenstackNode.NodeType type) {
+ Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
+ .filter(osNode -> Objects.equals(osNode.type(), type))
+ .collect(Collectors.toSet());
+ return ImmutableSet.copyOf(osNodes);
+ }
+
+ @Override
+ public Set<OpenstackNode> completeNodes() {
+ Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
+ .filter(osNode -> Objects.equals(osNode.state(), COMPLETE))
+ .collect(Collectors.toSet());
+ return ImmutableSet.copyOf(osNodes);
+ }
+
+ @Override
+ public Set<OpenstackNode> completeNodes(OpenstackNode.NodeType type) {
+ Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
+ .filter(osNode -> osNode.type() == type &&
+ Objects.equals(osNode.state(), COMPLETE))
+ .collect(Collectors.toSet());
+ return ImmutableSet.copyOf(osNodes);
+ }
+
+ @Override
+ public OpenstackNode node(String hostname) {
+ return osNodeStore.node(hostname);
+ }
+
+ @Override
+ public OpenstackNode node(DeviceId deviceId) {
+ OpenstackNode result = osNodeStore.nodes().stream()
+ .filter(osNode -> Objects.equals(osNode.intgBridge(), deviceId) ||
+ Objects.equals(osNode.ovsdb(), deviceId) ||
+ Objects.equals(osNode.routerBridge(), deviceId))
+ .findFirst().orElse(null);
+ return result;
+ }
+
+ private class InternalNodeStoreDelegate implements OpenstackNodeStoreDelegate {
+
+ @Override
+ public void notify(OpenstackNodeEvent event) {
+ if (event != null) {
+ log.trace("send openstack node event {}", event);
+ process(event);
+ }
+ }
+ }
+
+ private void readConfiguration() {
+ OpenstackNodeConfig config = configRegistry.getConfig(appId, OpenstackNodeConfig.class);
+ if (config == null) {
+ log.debug("No configuration found");
+ return;
+ }
+
+ log.info("Read openstack node configurations...");
+ Set<String> hostnames = config.openstackNodes().stream()
+ .map(OpenstackNode::hostname)
+ .collect(Collectors.toSet());
+ nodes().stream().filter(osNode -> !hostnames.contains(osNode.hostname()))
+ .forEach(osNode -> removeNode(osNode.hostname()));
+
+ config.openstackNodes().forEach(osNode -> {
+ OpenstackNode existing = node(osNode.hostname());
+ if (existing == null) {
+ createNode(osNode);
+ } else if (!existing.equals(osNode)) {
+ updateNode(osNode);
+ }
+ });
+ }
+
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ NodeId leaderNodeId = leadershipService.getLeader(appId.name());
+ if (!Objects.equals(localNode, leaderNodeId)) {
+ // do not allow to proceed without leadership
+ return;
+ }
+
+ if (!event.configClass().equals(OpenstackNodeConfig.class)) {
+ return;
+ }
+
+ switch (event.type()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/package-info.java
similarity index 86%
rename from apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java
rename to apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/package-info.java
index c280f54..4982c44 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/package-info.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/impl/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-present Open Networking Laboratory
+ * Copyright 2017-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,4 +17,4 @@
/**
* Application for bootstrapping Compute/Gateway Node in OpenStack.
*/
-package org.onosproject.openstacknode;
\ No newline at end of file
+package org.onosproject.openstacknode.impl;
\ No newline at end of file