[ONOS-3948] Seperate mgmt and data network in OpenstackSwitching/RoutingService
- Supports the seperation of management and data network
Change-Id: I178dbe2af241123c5181f94a7b46fc15b4cb37c7
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingConfig.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingConfig.java
new file mode 100644
index 0000000..78443cc
--- /dev/null
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingConfig.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 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.openstacknetworking.switching;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Maps;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.slf4j.Logger;
+
+import java.util.Map;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Configuration object for OpenstackSwitching service.
+ */
+public class OpenstackSwitchingConfig extends Config<ApplicationId> {
+
+ protected final Logger log = getLogger(getClass());
+
+ public static final String NODES = "nodes";
+ public static final String DATAPLANE_IP = "dataPlaneIp";
+ public static final String BRIDGE_ID = "bridgeId";
+
+ /**
+ * Returns the data plane IP map of nodes read from network config.
+ *
+ * @return data plane IP map
+ */
+ public Map<DeviceId, Ip4Address> nodes() {
+ Map<DeviceId, Ip4Address> nodeMap = Maps.newHashMap();
+
+ JsonNode jsonNodes = object.get(NODES);
+ if (jsonNodes == null) {
+ log.error("There's no node information");
+ return null;
+ }
+
+ jsonNodes.forEach(jsonNode -> {
+ try {
+ nodeMap.putIfAbsent(DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()),
+ Ip4Address.valueOf(jsonNode.path(DATAPLANE_IP).asText()));
+ } catch (IllegalArgumentException | NullPointerException e) {
+ log.error("Failed to read {}", e.getMessage());
+ }
+ });
+ return nodeMap;
+ }
+}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
index 767530b..4d6d439 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -15,8 +15,8 @@
*/
package org.onosproject.openstacknetworking.switching;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -32,8 +32,13 @@
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
import org.onosproject.net.Port;
+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.NetworkConfigService;
+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;
@@ -70,8 +75,7 @@
*/
public class OpenstackSwitchingManager implements OpenstackSwitchingService {
- private final Logger log = LoggerFactory
- .getLogger(getClass());
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@@ -97,28 +101,52 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackInterfaceService openstackService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
public static final String PORTNAME_PREFIX_VM = "tap";
public static final String PORTNAME_PREFIX_ROUTER = "qr-";
public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
public static final String PORTNAME = "portName";
private static final String ROUTER_INTERFACE = "network:router_interface";
public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
+ public static final String DNS_SERVER_IP = "8.8.8.8";
+ private static final String FORWARD_SLASH = "/";
+
private ApplicationId appId;
private OpenstackArpHandler arpHandler;
private OpenstackSecurityGroupRulePopulator sgRulePopulator;
- private ExecutorService deviceEventExcutorService =
+ private ExecutorService deviceEventExecutorService =
Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
+ private ExecutorService configEventExecutorService =
+ Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
+
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
private InternalHostListener internalHostListener = new InternalHostListener();
- private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
+ private final Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
+ private final ConfigFactory configFactory =
+ new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
+ OpenstackSwitchingConfig.class, "openstackswitching") {
+ @Override
+ public OpenstackSwitchingConfig createConfig() {
+ return new OpenstackSwitchingConfig();
+ }
+ };
+ private final NetworkConfigListener configListener = new InternalConfigListener();
+
+ private OpenstackSwitchingConfig config;
+
@Activate
protected void activate() {
appId = coreService
@@ -127,12 +155,10 @@
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
deviceService.addListener(internalDeviceListener);
hostService.addListener(internalHostListener);
- arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
+ configRegistry.registerConfigFactory(configFactory);
+ configService.addListener(configListener);
- arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
- sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
-
- initializeFlowRules();
+ readConfiguration();
log.info("Started");
}
@@ -142,7 +168,11 @@
packetService.removeProcessor(internalPacketProcessor);
deviceService.removeListener(internalDeviceListener);
- deviceEventExcutorService.shutdown();
+ deviceEventExecutorService.shutdown();
+ configEventExecutorService.shutdown();
+ hostService.removeListener(internalHostListener);
+ configService.removeListener(configListener);
+ configRegistry.unregisterConfigFactory(configFactory);
log.info("Stopped");
}
@@ -151,10 +181,9 @@
public void createPorts(OpenstackPort openstackPort) {
if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
- && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
- if (!openstackPort.fixedIps().isEmpty()) {
+ && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)
+ && !openstackPort.fixedIps().isEmpty()) {
registerDhcpInfo(openstackPort);
- }
}
}
@@ -170,11 +199,11 @@
if (routerPortInfo != null) {
dhcpService.removeStaticMapping(routerPortInfo.mac());
deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
- String pName = port.annotations().value("portName");
+ String pName = port.annotations().value(PORTNAME);
if (pName.equals(routerPortName)) {
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
- deviceService, openstackService, driverService);
+ deviceService, openstackService, driverService, config);
rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
openstackPortInfoMap.remove(routerPortName);
@@ -219,10 +248,6 @@
return ImmutableMap.copyOf(this.openstackPortInfoMap);
}
- private void processDeviceAdded(Device device) {
- log.debug("device {} is added", device.id());
- }
-
private void processPortUpdated(Device device, Port port) {
String portName = port.annotations().value(PORTNAME);
synchronized (openstackPortInfoMap) {
@@ -230,7 +255,7 @@
if (port.isEnabled()) {
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
- deviceService, openstackService, driverService);
+ deviceService, openstackService, driverService, config);
rulePopulator.populateSwitchingRules(device, port);
OpenstackPort openstackPort = rulePopulator.openstackPort(port);
@@ -244,10 +269,10 @@
//In case portupdate event is driven by vm shutoff from openstack
} else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
- log.debug("Flowrules according to the port {} were removed", port.number().toString());
+ log.debug("Flowrules according to the port {} were removed", port.number());
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
- deviceService, openstackService, driverService);
+ deviceService, openstackService, driverService, config);
rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
@@ -259,14 +284,14 @@
}
}
- private void processPortRemoved(Device device, Port port) {
+ private void processPortRemoved(Port port) {
log.debug("port {} is removed", port.toString());
}
private void initializeFlowRules() {
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
- deviceService, openstackService, driverService);
+ deviceService, openstackService, driverService, config);
Collection<OpenstackNetwork> networks = openstackService.networks();
Collection<OpenstackSubnet> subnets = openstackService.subnets();
@@ -336,16 +361,8 @@
});
}
- private void processHostRemoved(Host host) {
- log.debug("host {} was removed", host.toString());
- }
-
private void registerDhcpInfo(OpenstackPort openstackPort) {
- Ip4Address ip4Address;
- Ip4Address subnetMask;
- Ip4Address gatewayIPAddress;
- Ip4Address dhcpServer;
- Ip4Address domainServer;
+ Ip4Address ip4Address, subnetMask, gatewayIPAddress, dhcpServer, domainServer;
OpenstackSubnet openstackSubnet;
ip4Address = (Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null);
@@ -359,22 +376,18 @@
dhcpServer = gatewayIPAddress;
// TODO: supports multiple DNS servers
if (openstackSubnet.dnsNameservers().isEmpty()) {
- domainServer = Ip4Address.valueOf("8.8.8.8");
+ domainServer = Ip4Address.valueOf(DNS_SERVER_IP);
} else {
domainServer = openstackSubnet.dnsNameservers().get(0);
}
- List<Ip4Address> options = Lists.newArrayList();
- options.add(subnetMask);
- options.add(dhcpServer);
- options.add(gatewayIPAddress);
- options.add(domainServer);
+ List<Ip4Address> options = ImmutableList.of(subnetMask, dhcpServer, gatewayIPAddress, domainServer);
dhcpService.setStaticMapping(openstackPort.macAddress(), ip4Address, true, options);
}
private byte[] buildSubnetMask(String cidr) {
int prefix;
- String[] parts = cidr.split("/");
+ String[] parts = cidr.split(FORWARD_SLASH);
prefix = Integer.parseInt(parts[1]);
int mask = 0xffffffff << (32 - prefix);
byte[] bytes = new byte[]{(byte) (mask >>> 24),
@@ -406,7 +419,7 @@
@Override
public void event(HostEvent hostEvent) {
- deviceEventExcutorService.execute(new InternalEventHandler(hostEvent));
+ deviceEventExecutorService.execute(new InternalEventHandler(hostEvent));
}
}
@@ -414,7 +427,7 @@
@Override
public void event(DeviceEvent deviceEvent) {
- deviceEventExcutorService.execute(new InternalEventHandler(deviceEvent));
+ deviceEventExecutorService.execute(new InternalEventHandler(deviceEvent));
}
}
@@ -434,22 +447,22 @@
switch (deviceEvent.type()) {
case DEVICE_ADDED:
- processDeviceAdded((Device) deviceEvent.subject());
+ log.debug("device {} is added", deviceEvent.subject().id());
break;
case DEVICE_AVAILABILITY_CHANGED:
- Device device = (Device) deviceEvent.subject();
+ Device device = deviceEvent.subject();
if (deviceService.isAvailable(device.id())) {
- processDeviceAdded(device);
+ log.debug("device {} is added", device.id());
}
break;
case PORT_ADDED:
- processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
+ processPortUpdated(deviceEvent.subject(), deviceEvent.port());
break;
case PORT_UPDATED:
- processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
+ processPortUpdated(deviceEvent.subject(), deviceEvent.port());
break;
case PORT_REMOVED:
- processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
+ processPortRemoved(deviceEvent.port());
break;
default:
log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
@@ -460,7 +473,7 @@
switch (hostEvent.type()) {
case HOST_REMOVED:
- processHostRemoved((Host) hostEvent.subject());
+ log.debug("host {} was removed", hostEvent.subject().toString());
break;
default:
log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
@@ -469,4 +482,34 @@
}
}
}
+
+ private void readConfiguration() {
+ config = configService.getConfig(appId, OpenstackSwitchingConfig.class);
+ if (config == null) {
+ log.error("No configuration found");
+ return;
+ }
+
+ arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
+ sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
+
+ initializeFlowRules();
+ }
+
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if (!event.configClass().equals(OpenstackSwitchingConfig.class)) {
+ return;
+ }
+
+ if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
+ event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
+ configEventExecutorService.execute(OpenstackSwitchingManager.this::readConfiguration);
+
+
+ }
+ }
+ }
}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
index e944e9d..5c7bd5e 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
@@ -59,11 +59,13 @@
.getLogger(OpenstackSwitchingRulePopulator.class);
private static final int SWITCHING_RULE_PRIORITY = 30000;
private static final int TUNNELTAG_RULE_PRIORITY = 30000;
-
+ private static final String PORT_NAME = "portName";
+ private static final String TUNNEL_DST = "tunnelDst";
private FlowObjectiveService flowObjectiveService;
private DriverService driverService;
private DeviceService deviceService;
private ApplicationId appId;
+ private OpenstackSwitchingConfig config;
private Collection<OpenstackNetwork> openstackNetworkList;
private Collection<OpenstackPort> openstackPortList;
@@ -76,16 +78,19 @@
* @param deviceService DeviceService reference
* @param openstackService openstack interface service
* @param driverService DriverService reference
+ * @param config OpenstackRoutingConfig
*/
public OpenstackSwitchingRulePopulator(ApplicationId appId,
FlowObjectiveService flowObjectiveService,
DeviceService deviceService,
OpenstackInterfaceService openstackService,
- DriverService driverService) {
+ DriverService driverService,
+ OpenstackSwitchingConfig config) {
this.flowObjectiveService = flowObjectiveService;
this.deviceService = deviceService;
this.driverService = driverService;
this.appId = appId;
+ this.config = config;
openstackNetworkList = openstackService.networks();
openstackPortList = openstackService.ports();
@@ -111,8 +116,8 @@
* @param port port info of the VM
*/
private void populateFlowRulesForTunnelTag(Device device, Port port) {
- Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
- String portName = port.annotations().value("portName");
+ Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value(PORT_NAME));
+ String portName = port.annotations().value(PORT_NAME);
String vni = getVniForPort(portName);
if (vmIp != null) {
@@ -148,8 +153,8 @@
* @param port port info of the VM
*/
private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
- Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
- String portName = port.annotations().value("portName");
+ Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value(PORT_NAME));
+ String portName = port.annotations().value(PORT_NAME);
String vni = getVniForPort(portName);
if (vmIp != null) {
@@ -197,24 +202,27 @@
* @param port port information of the VM
*/
private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
- String portName = port.annotations().value("portName");
- String channelId = device.annotations().value("channelId");
- Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
+ String portName = port.annotations().value(PORT_NAME);
Ip4Address fixedIp = getFixedIpAddressForPort(portName);
String vni = getVniForPort(portName);
+ Ip4Address hostDpIpAddress = config.nodes().get(device.id());
+
+ if (hostDpIpAddress == null) {
+ log.debug("There's no openstack node information for device id {}", device.id().toString());
+ return;
+ }
+
deviceService.getAvailableDevices().forEach(d -> {
if (!d.equals(device)) {
deviceService.getPorts(d.id()).forEach(p -> {
- String pName = p.annotations().value("portName");
+ String pName = p.annotations().value(PORT_NAME);
if (!p.equals(port) && vni.equals(getVniForPort(pName))) {
- String cidx = d.annotations().value("channelId");
- Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]);
+ Ip4Address hostxDpIpAddress = config.nodes().get(d.id());
+
Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
- if (port.isEnabled() ||
- port.annotations().value("portName").startsWith(
- OpenstackSwitchingManager.PORTNAME_PREFIX_ROUTER)) {
- setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx);
- setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp);
+ if (port.isEnabled()) {
+ setVxLanFlowRule(vni, device.id(), hostxDpIpAddress, fixedIpx);
+ setVxLanFlowRule(vni, d.id(), hostDpIpAddress, fixedIp);
}
}
});
@@ -259,7 +267,7 @@
* @return OpenstackPort reference, or null when not found
*/
public OpenstackPort openstackPort(Port port) {
- String uuid = port.annotations().value("portName").substring(3);
+ String uuid = port.annotations().value(PORT_NAME).substring(3);
return openstackPortList.stream().filter(p -> p.id().startsWith(uuid))
.findAny().orElse(null);
}
@@ -273,7 +281,7 @@
public void removeSwitchingRules(Port removedPort, Map<String,
OpenstackPortInfo> openstackPortInfoMap) {
OpenstackPortInfo openstackPortInfo = openstackPortInfoMap
- .get(removedPort.annotations().value("portName"));
+ .get(removedPort.annotations().value(PORT_NAME));
DeviceId deviceId = openstackPortInfo.deviceId();
Ip4Address vmIp = openstackPortInfo.ip();
@@ -397,7 +405,7 @@
Map<String, OpenstackPortInfo> openstackPortInfoMap) {
for (Map.Entry<String, OpenstackPortInfo> entry : openstackPortInfoMap.entrySet()) {
- if (!removedPort.annotations().value("portName").equals(entry.getKey())) {
+ if (!removedPort.annotations().value(PORT_NAME).equals(entry.getKey())) {
if (entry.getValue().vni() == vni && entry.getValue().deviceId().equals(deviceId)) {
return true;
}
@@ -469,7 +477,7 @@
ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
try {
- extensionInstruction.setPropertyValue("tunnelDst", hostIp);
+ extensionInstruction.setPropertyValue(TUNNEL_DST, hostIp);
} catch (ExtensionPropertyException e) {
log.error("Error setting Nicira extension setting {}", e);
}
@@ -479,7 +487,7 @@
private PortNumber getTunnelPort(DeviceId deviceId) {
Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations().value("portName").equals(
+ .filter(p -> p.annotations().value(PORT_NAME).equals(
OpenstackSwitchingManager.PORTNAME_PREFIX_TUNNEL))
.findAny().orElse(null);