sangho
Committed by Gerrit Code Review

OpenstackRouting refactoring

- Replace OpenstackPortInfo with HostService
- Replace OpenstackRoutingConfig with OpenstackNodeService
  (Remove OpenstackRoutingConfig)
- Rebased with 10330 (existing_vm)
- Added initialization process using OpenstackNodeListener

Change-Id: If2ce8eb86d242a7180c9154e1a0f1668b266bf1c
Showing 17 changed files with 452 additions and 538 deletions
......@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.openstacknetworking.switching;
package org.onosproject.openstacknetworking;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
/**
* Provides constants used in OpenStack node services.
* Provides constants used in OpenStackSwitching.
*/
public final class Constants {
......@@ -33,9 +34,11 @@ public final class Constants {
public static final String PORTNAME_PREFIX_ROUTER = "qr-";
public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
// TODO remove this
public static final String ROUTER_INTERFACE = "network:router_interface";
public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
public static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
// TODO: Please change these valuses following the way vrouter is implemented
public static final MacAddress GW_EXT_INT_MAC = MacAddress.valueOf("56:e6:30:a6:8c:e5");
public static final MacAddress PHY_ROUTER_MAC = MacAddress.valueOf("00:00:00:00:01:01");
public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
public static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
......@@ -51,4 +54,5 @@ public final class Constants {
public static final int SWITCHING_RULE_PRIORITY = 30000;
public static final int TUNNELTAG_RULE_PRIORITY = 30000;
public static final int ACL_RULE_PRIORITY = 30000;
}
\ No newline at end of file
......
/*
* 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.openstacknetworking;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains OpenstackPort Information.
*/
// TODO remove this
public final class OpenstackPortInfo {
private final Ip4Address hostIp;
private final MacAddress hostMac;
private final DeviceId deviceId;
private final long vni;
private final Ip4Address gatewayIP;
private final String networkId;
/**
* Returns OpenstackPortInfo reference.
*
* @param hostIp host IP address
* @param hostMac host MAC address
* @param deviceId device ID
* @param vni tunnel ID
* @param gatewayIP gateway IP address
* @param networkId network identifier
*/
public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
Ip4Address gatewayIP, String networkId) {
this.hostIp = hostIp;
this.hostMac = hostMac;
this.deviceId = deviceId;
this.vni = vni;
this.gatewayIP = gatewayIP;
this.networkId = networkId;
}
/**
* Returns IP address of the port.
*
* @return IP address
*/
public Ip4Address ip() {
return hostIp;
}
/**
* Returns MAC address of the port.
*
* @return MAC address
*/
public MacAddress mac() {
return hostMac;
}
/**
* Returns device ID.
*
* @return device ID
*/
public DeviceId deviceId() {
return deviceId;
}
/**
* Returns tunnel ID.
*
* @return tunnel ID
*/
public long vni() {
return vni;
}
/**
* Returns gateway IP address.
*
* @return gateway IP address
*/
public Ip4Address gatewayIP() {
return gatewayIP;
}
/**
* Returns network ID.
*
* @return network ID
*/
public String networkId() {
return networkId;
}
/**
* Returns the builder of the OpenstackPortInfo.
*
* @return OpenstackPortInfo builder reference
*/
public static OpenstackPortInfo.Builder builder() {
return new Builder();
}
/**
* Represents the OpenstackPortInfo Builder.
*
*/
public static final class Builder {
private Ip4Address hostIp;
private MacAddress hostMac;
private DeviceId deviceId;
private long vni;
private Ip4Address gatewayIP;
private String networkId;
/**
* Sets the IP address of the port.
*
* @param gatewayIP gateway IP
* @return Builder reference
*/
public Builder setGatewayIP(Ip4Address gatewayIP) {
this.gatewayIP = checkNotNull(gatewayIP, "gatewayIP cannot be null");
return this;
}
/**
* Sets the network ID.
*
* @param networkId network id
* @return Builder reference
*/
public Builder setNetworkId(String networkId) {
this.networkId = checkNotNull(networkId, "networkId cannot be null");
return this;
}
/**
* Sets the host IP address of the port.
*
* @param hostIp host IP address
* @return Builder reference
*/
public Builder setHostIp(Ip4Address hostIp) {
this.hostIp = checkNotNull(hostIp, "hostIp cannot be null");
return this;
}
/**
* Sets the host MAC address of the port.
*
* @param hostMac host MAC address
* @return Builder reference
*/
public Builder setHostMac(MacAddress hostMac) {
this.hostMac = checkNotNull(hostMac, "hostMac cannot be bull");
return this;
}
/**
* Sets the device ID.
*
* @param deviceId device ID
* @return Builder reference
*/
public Builder setDeviceId(DeviceId deviceId) {
this.deviceId = checkNotNull(deviceId, "deviceId cannot be null");
return this;
}
/**
* Sets the tunnel ID.
*
* @param vni tunnel ID
* @return Builder reference
*/
public Builder setVni(long vni) {
this.vni = checkNotNull(vni, "vni cannot be null");
return this;
}
/**
* Builds the OpenstackPortInfo reference.
*
* @return OpenstackPortInfo reference
*/
public OpenstackPortInfo build() {
return new OpenstackPortInfo(hostIp, hostMac, deviceId, vni, gatewayIP, networkId);
}
}
}
......@@ -85,8 +85,8 @@ public interface OpenstackRoutingService {
*
* @param portId Deleted vm
* @param portInfo stored information about deleted vm
*/
void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo);
*/
/**
* Returns network id for routerInterface.
......
/*
* 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.openstacknetworking;
import java.util.Map;
/**
* Handles port management REST API from Openstack for VMs.
*/
// TODO remove this
public interface OpenstackSwitchingService {
/**
* Retruns OpenstackPortInfo map.
*
* @return OpenstackPortInfo map
*/
// TODO remove this
Map<String, OpenstackPortInfo> openstackPortInfo();
}
......@@ -68,6 +68,11 @@
<artifactId>onos-scalablegateway</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-openstacknode</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
......@@ -15,34 +15,39 @@
*/
package org.onosproject.openstacknetworking.routing;
import org.onosproject.net.Host;
import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
/**
* Handle FloatingIP Event for Managing Flow Rules In Openstack Nodes.
*/
public class OpenstackFloatingIPHandler implements Runnable {
public enum Action {
ASSOCIATE,
DISSASSOCIATE
}
private final OpenstackFloatingIP floatingIP;
private final OpenstackRoutingRulePopulator rulePopulator;
private boolean associate;
private final OpenstackPortInfo portInfo;
private final Host host;
private final Action action;
OpenstackFloatingIPHandler(OpenstackRoutingRulePopulator rulePopulator,
OpenstackFloatingIP openstackFloatingIP, boolean associate, OpenstackPortInfo portInfo) {
OpenstackFloatingIP openstackFloatingIP, Action action, Host host) {
this.floatingIP = openstackFloatingIP;
this.rulePopulator = rulePopulator;
this.associate = associate;
this.portInfo = portInfo;
this.action = action;
this.host = host;
}
@Override
public void run() {
if (associate) {
if (action == Action.ASSOCIATE) {
rulePopulator.populateFloatingIpRules(floatingIP);
} else {
rulePopulator.removeFloatingIpRules(floatingIP, portInfo);
rulePopulator.removeFloatingIpRules(floatingIP, host);
}
}
}
......
......@@ -20,9 +20,11 @@ import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
......@@ -30,16 +32,17 @@ import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketService;
import org.onosproject.openstacknetworking.Constants;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.openstacknode.OpenstackNode;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.slf4j.Logger;
......@@ -58,37 +61,39 @@ import static org.slf4j.LoggerFactory.getLogger;
public class OpenstackIcmpHandler {
protected final Logger log = getLogger(getClass());
private final PacketService packetService;
private final DeviceService deviceService;
private final Map<String, OpenstackPortInfo> icmpInfoMap = Maps.newHashMap();
private final OpenstackSwitchingService openstackSwitchingService;
private final OpenstackInterfaceService openstackService;
private final ScalableGatewayService gatewayService;
private final OpenstackNetworkingConfig config;
private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
private static final String NETWORK_ROUTER_INTERFACE = "network:router_interface";
private static final String PORTNAME = "portName";
private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
private static final String NETWORK_FLOATING_IP = "network:floatingip";
private static final String EXTERNAL_NODE_NULL = "There is no external node about this deviceId []";
private final PacketService packetService;
private final DeviceService deviceService;
private final ScalableGatewayService gatewayService;
private final HostService hostService;
private final Map<String, Host> icmpInfoMap = Maps.newHashMap();
private final OpenstackInterfaceService openstackService;
private final OpenstackNodeService nodeService;
/**
* Default constructor.
*
* @param packetService packet service
* @param deviceService device service
* @param openstackService openstackInterface service
* @param config openstackRoutingConfig
* @param openstackSwitchingService openstackSwitching service
* @param gatewayService scalable gateway service
*/
OpenstackIcmpHandler(PacketService packetService, DeviceService deviceService,
OpenstackInterfaceService openstackService, OpenstackNetworkingConfig config,
OpenstackSwitchingService openstackSwitchingService, ScalableGatewayService gatewayService) {
OpenstackIcmpHandler(PacketService packetService,
DeviceService deviceService,
HostService hostService,
OpenstackInterfaceService openstackService,
OpenstackNodeService nodeService,
ScalableGatewayService gatewayService
) {
this.packetService = packetService;
this.deviceService = deviceService;
this.hostService = hostService;
this.openstackService = checkNotNull(openstackService);
this.config = checkNotNull(config);
this.openstackSwitchingService = checkNotNull(openstackSwitchingService);
this.nodeService = nodeService;
this.gatewayService = gatewayService;
}
......@@ -103,13 +108,20 @@ public class OpenstackIcmpHandler {
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.build();
Map<DeviceId, PortNumber> externalInfoMap = getExternalInfo();
// TODO: Return the correct gateway node
Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
.filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
.findFirst();
if (!gwNode.isPresent()) {
log.warn("No Gateway is defined.");
return;
}
externalInfoMap.keySet().forEach(deviceId ->
packetService.requestPackets(icmpSelector,
PacketPriority.CONTROL,
appId,
Optional.of(deviceId)));
packetService.requestPackets(icmpSelector,
PacketPriority.CONTROL,
appId,
Optional.of(gwNode.get().intBridge()));
}
/**
......@@ -135,11 +147,13 @@ public class OpenstackIcmpHandler {
if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REQUEST) {
//TODO: Considers icmp between internal subnets which are belonged to the same router.
OpenstackPortInfo openstackPortInfo =
getOpenstackPortInfo(Ip4Address.valueOf(ipPacket.getSourceAddress()), ethernet.getSourceMAC());
//OpenstackPortInfo openstackPortInfo =
// getOpenstackPortInfo(Ip4Address.valueOf(ipPacket.getSourceAddress()), ethernet.getSourceMAC());
//checkNotNull(openstackPortInfo, "openstackPortInfo can not be null");
/* XXX Is this handling ICMP to gateway ?????
if (requestToOpenstackRoutingNetwork(ipPacket.getDestinationAddress())) {
Host host =
if (openstackPortInfo == null) {
if (config.gatewayBridgeId().equals(context.inPacket().receivedFrom().deviceId().toString())) {
if (portNumber.equals(getPortForAnnotationPortName(deviceId,
......@@ -151,15 +165,23 @@ public class OpenstackIcmpHandler {
}
return;
} else {
processIcmpPacketSentToGateway(ipPacket, icmp, openstackPortInfo);
processIcmpPacketSentToGateway(ipPacket, icmp, host);
return;
}
}
*/
if (ipPacket.getDestinationAddress() == openstackPortInfo.gatewayIP().toInt()) {
processIcmpPacketSentToGateway(ipPacket, icmp, openstackPortInfo);
Optional<Host> host = hostService.getHostsByMac(ethernet.getSourceMAC()).stream().findFirst();
if (!host.isPresent()) {
log.warn("No host found for MAC {}", ethernet.getSourceMAC());
return;
}
IpAddress gatewayIp = IpAddress.valueOf(host.get().annotations().value(Constants.GATEWAY_IP));
if (ipPacket.getDestinationAddress() == gatewayIp.getIp4Address().toInt()) {
processIcmpPacketSentToGateway(ipPacket, icmp, host.get());
} else {
Ip4Address pNatIpAddress = pNatIpForPort(openstackPortInfo);
Ip4Address pNatIpAddress = pNatIpForPort(host.get());
checkNotNull(pNatIpAddress, "pNatIpAddress can not be null");
sendRequestPacketToExt(ipPacket, icmp, deviceId, pNatIpAddress);
......@@ -167,7 +189,7 @@ public class OpenstackIcmpHandler {
String icmpInfoKey = String.valueOf(icmpId)
.concat(String.valueOf(pNatIpAddress.toInt()))
.concat(String.valueOf(ipPacket.getDestinationAddress()));
icmpInfoMap.putIfAbsent(icmpInfoKey, openstackPortInfo);
icmpInfoMap.putIfAbsent(icmpInfoKey, host.get());
}
} else if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REPLY) {
String icmpInfoKey = String.valueOf(icmpId)
......@@ -190,7 +212,8 @@ public class OpenstackIcmpHandler {
icmpRequestIpv4.setPayload(icmpRequest);
Ethernet icmpResponseEth = new Ethernet();
icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
.setSourceMACAddress(config.gatewayExternalInterfaceMac())
// TODO: Get the correct GW MAC
.setSourceMACAddress(Constants.GW_EXT_INT_MAC)
.setDestinationMACAddress(destMac).setPayload(icmpRequestIpv4);
TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(portNumber).build();
OutboundPacket packet = new DefaultOutboundPacket(deviceId,
......@@ -199,13 +222,14 @@ public class OpenstackIcmpHandler {
}
private void processIcmpPacketSentToGateway(IPv4 icmpRequestIpv4, ICMP icmpRequest,
OpenstackPortInfo openstackPortInfo) {
Host host) {
icmpRequest.setChecksum((short) 0);
icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY)
.resetChecksum();
Ip4Address ipAddress = host.ipAddresses().stream().findAny().get().getIp4Address();
icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress())
.setDestinationAddress(openstackPortInfo.ip().toInt())
.setDestinationAddress(ipAddress.toInt())
.resetChecksum();
icmpRequestIpv4.setPayload(icmpRequest);
......@@ -213,11 +237,11 @@ public class OpenstackIcmpHandler {
Ethernet icmpResponseEth = new Ethernet();
icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
.setSourceMACAddress(GATEWAY_MAC)
.setDestinationMACAddress(openstackPortInfo.mac())
.setSourceMACAddress(Constants.GATEWAY_MAC)
.setDestinationMACAddress(host.mac())
.setPayload(icmpRequestIpv4);
sendResponsePacketToHost(icmpResponseEth, openstackPortInfo);
sendResponsePacketToHost(icmpResponseEth, host);
}
private void sendRequestPacketToExt(IPv4 icmpRequestIpv4, ICMP icmpRequest, DeviceId deviceId,
......@@ -230,19 +254,27 @@ public class OpenstackIcmpHandler {
Ethernet icmpRequestEth = new Ethernet();
icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
// TODO: Get the correct one - Scalable Gateway ...
.setSourceMACAddress(Constants.GW_EXT_INT_MAC)
.setDestinationMACAddress(Constants.PHY_ROUTER_MAC)
.setPayload(icmpRequestIpv4);
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
// TODO: Return the correct gateway node
Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
.filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
.findFirst();
Map<DeviceId, PortNumber> externalInforMap = getExternalInfo();
if (externalInforMap.size() == 0 || !externalInforMap.containsKey(deviceId)) {
log.error(EXTERNAL_NODE_NULL, deviceId.toString());
if (!gwNode.isPresent()) {
log.warn("No Gateway is defined.");
return;
}
tBuilder.setOutput(externalInforMap.get(deviceId));
TrafficTreatment treatment = tBuilder.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
// FIXME: please double check this.
.setOutput(getPortForAnnotationPortName(gwNode.get().intBridge(),
// FIXME: please double check this.
org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
.build();
OutboundPacket packet = new DefaultOutboundPacket(deviceId,
treatment, ByteBuffer.wrap(icmpRequestEth.serialize()));
......@@ -251,59 +283,45 @@ public class OpenstackIcmpHandler {
}
private void processResponsePacketFromExternalToHost(IPv4 icmpResponseIpv4, ICMP icmpResponse,
OpenstackPortInfo openstackPortInfo) {
Host host) {
icmpResponse.resetChecksum();
icmpResponseIpv4.setDestinationAddress(openstackPortInfo.ip().toInt())
Ip4Address ipAddress = host.ipAddresses().stream().findFirst().get().getIp4Address();
icmpResponseIpv4.setDestinationAddress(ipAddress.toInt())
.resetChecksum();
icmpResponseIpv4.setPayload(icmpResponse);
Ethernet icmpResponseEth = new Ethernet();
icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
.setSourceMACAddress(GATEWAY_MAC)
.setDestinationMACAddress(openstackPortInfo.mac())
.setSourceMACAddress(Constants.GATEWAY_MAC)
.setDestinationMACAddress(host.mac())
.setPayload(icmpResponseIpv4);
sendResponsePacketToHost(icmpResponseEth, openstackPortInfo);
sendResponsePacketToHost(icmpResponseEth, host);
}
private void sendResponsePacketToHost(Ethernet icmpResponseEth, OpenstackPortInfo openstackPortInfo) {
Map.Entry<String, OpenstackPortInfo> entry = openstackSwitchingService.openstackPortInfo().entrySet().stream()
.filter(e -> e.getValue().mac().equals(openstackPortInfo.mac()))
.findAny().orElse(null);
if (entry == null) {
return;
}
private void sendResponsePacketToHost(Ethernet icmpResponseEth, Host host) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(getPortForAnnotationPortName(openstackPortInfo.deviceId(), entry.getKey()))
.setOutput(host.location().port())
.build();
OutboundPacket packet = new DefaultOutboundPacket(openstackPortInfo.deviceId(),
OutboundPacket packet = new DefaultOutboundPacket(host.location().deviceId(),
treatment, ByteBuffer.wrap(icmpResponseEth.serialize()));
packetService.emit(packet);
}
private OpenstackPortInfo getOpenstackPortInfo(Ip4Address sourceIp, MacAddress sourceMac) {
checkNotNull(openstackSwitchingService.openstackPortInfo(), "openstackportinfo collection can not be null");
return openstackSwitchingService.openstackPortInfo().values()
.stream().filter(p -> p.ip().equals(sourceIp) && p.mac().equals(sourceMac))
.findAny().orElse(null);
}
private short getIcmpId(ICMP icmp) {
return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort();
}
private Ip4Address pNatIpForPort(OpenstackPortInfo openstackPortInfo) {
private Ip4Address pNatIpForPort(Host host) {
OpenstackPort openstackPort = openstackService.ports().stream()
.filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_INTERFACE) &&
p.networkId().equals(openstackPortInfo.networkId()))
p.networkId().equals(host.annotations().value(Constants.NETWORK_ID)))
.findAny().orElse(null);
checkNotNull(openstackPort, "openstackPort can not be null");
......
......@@ -32,7 +32,6 @@ import org.onosproject.net.packet.PacketService;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.scalablegateway.api.GatewayNode;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.slf4j.Logger;
......@@ -52,25 +51,21 @@ public class OpenstackPnatHandler implements Runnable {
volatile PacketContext context;
private final Logger log = LoggerFactory.getLogger(getClass());
protected PacketService packetService;
private final OpenstackRoutingRulePopulator rulePopulator;
private final int portNum;
private final OpenstackPort openstackPort;
private final Port port;
private OpenstackNetworkingConfig config;
private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
private static final String EXTERNAL_PORT_NULL = "There is no external port in this deviceId []";
OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
int portNum, OpenstackPort openstackPort, Port port, OpenstackNetworkingConfig config) {
int portNum, OpenstackPort openstackPort, Port port) {
this.rulePopulator = checkNotNull(rulePopulator);
this.context = checkNotNull(context);
this.portNum = checkNotNull(portNum);
this.openstackPort = checkNotNull(openstackPort);
this.port = checkNotNull(port);
this.config = checkNotNull(config);
}
@Override
......@@ -149,6 +144,7 @@ public class OpenstackPnatHandler implements Runnable {
iPacket.resetChecksum();
iPacket.setParent(ethernet);
ethernet.setPayload(iPacket);
ScalableGatewayService gatewayService = getService(ScalableGatewayService.class);
GatewayNode gatewayNode = gatewayService.getGatewayNode(deviceId);
if (gatewayNode.getGatewayExternalInterfaceNames().size() == 0) {
......@@ -159,7 +155,6 @@ public class OpenstackPnatHandler implements Runnable {
ethernet.resetChecksum();
packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
ByteBuffer.wrap(ethernet.serialize())));
}
......
......@@ -34,8 +34,9 @@ import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketService;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.onosproject.openstacknetworking.Constants;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
......@@ -53,23 +54,24 @@ public class OpenstackRoutingArpHandler {
private final PacketService packetService;
private final OpenstackInterfaceService openstackService;
private final OpenstackNetworkingConfig config;
private final ScalableGatewayService gatewayService;
private final OpenstackNodeService nodeService;
private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
private static final String NETWORK_FLOATING_IP = "network:floatingip";
/**
* Default constructor.
* @param packetService packet service
*
* @param packetService packet service
* @param openstackService openstackInterface service
* @param config openstackRoutingConfig
* @param gatewayService
* @param gatewayService gateway service
* @param nodeService openstackNodeService
*/
OpenstackRoutingArpHandler(PacketService packetService, OpenstackInterfaceService openstackService,
OpenstackNetworkingConfig config, ScalableGatewayService gatewayService) {
OpenstackNodeService nodeService, ScalableGatewayService gatewayService) {
this.packetService = packetService;
this.openstackService = checkNotNull(openstackService);
this.config = checkNotNull(config);
this.nodeService = nodeService;
this.gatewayService = gatewayService;
}
......@@ -118,7 +120,8 @@ public class OpenstackRoutingArpHandler {
if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) {
return;
}
MacAddress targetMac = MacAddress.valueOf(config.gatewayExternalInterfaceMac());
// FIXME: Set the correct gateway
MacAddress targetMac = Constants.GW_EXT_INT_MAC;
Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
targetMac, ethernet);
......
......@@ -16,6 +16,7 @@
package org.onosproject.openstacknetworking.routing;
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;
......@@ -25,38 +26,47 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.UDP;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.DefaultAnnotations;
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.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.OpenstackRoutingService;
import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.onosproject.openstacknetworking.routing.OpenstackFloatingIPHandler.Action;
import org.onosproject.openstacknetworking.Constants;
import org.onosproject.openstacknode.OpenstackNode;
import org.onosproject.openstacknode.OpenstackNodeEvent;
import org.onosproject.openstacknode.OpenstackNodeListener;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.Serializer;
......@@ -66,8 +76,8 @@ import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
......@@ -97,31 +107,35 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
protected OpenstackInterfaceService openstackService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackSwitchingService openstackSwitchingService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService configService;
protected StorageService storageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry configRegistry;
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
protected HostProviderRegistry hostProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ScalableGatewayService gatewayService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackNodeService nodeService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
private ApplicationId appId;
private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
// Map<RouterInterface`s portId, Corresponded port`s network id>
private ConsistentMap<String, String> routerInterfaceMap;
private static final ProviderId PID = new ProviderId("of", "org.onosproject.openstackroutering", true);
private static final String APP_ID = "org.onosproject.openstackrouting";
private static final String PORT_NAME = "portName";
private static final String PORTNAME_PREFIX_VM = "tap";
......@@ -134,18 +148,6 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
private static final int TP_PORT_MINIMUM_NUM = 1024;
private static final int TP_PORT_MAXIMUM_NUM = 65535;
private final ConfigFactory configFactory =
new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
"config") {
@Override
public OpenstackNetworkingConfig createConfig() {
return new OpenstackNetworkingConfig();
}
};
private final NetworkConfigListener configListener = new InternalConfigListener();
private OpenstackNetworkingConfig config;
private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(OpenstackFloatingIP.FloatingIpStatus.class)
......@@ -158,7 +160,8 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
.register(KryoNamespaces.API);
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
private InternalHostListener internalHostListener = new InternalHostListener();
private InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
private ExecutorService l3EventExecutorService =
Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
private ExecutorService icmpEventExecutorService =
......@@ -168,15 +171,16 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
private OpenstackIcmpHandler openstackIcmpHandler;
private OpenstackRoutingArpHandler openstackArpHandler;
private OpenstackRoutingRulePopulator rulePopulator;
private Map<DeviceId, Ip4Address> computeNodeMap;
private HostProviderService hostProviderService;
private final HostProvider hostProvider = new InternalHostProvider();
@Activate
protected void activate() {
appId = coreService.registerApplication(APP_ID);
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
configRegistry.registerConfigFactory(configFactory);
configService.addListener(configListener);
deviceService.addListener(internalDeviceListener);
hostService.addListener(internalHostListener);
nodeService.addListener(internalNodeListener);
hostProviderService = hostProviderRegistry.register(hostProvider);
floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
.withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
......@@ -194,15 +198,15 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
.withApplicationId(appId)
.build();
readConfiguration();
log.info("started");
}
@Deactivate
protected void deactivate() {
packetService.removeProcessor(internalPacketProcessor);
deviceService.removeListener(internalDeviceListener);
hostService.removeListener(internalHostListener);
nodeService.removeListener(internalNodeListener);
l3EventExecutorService.shutdown();
icmpEventExecutorService.shutdown();
arpEventExecutorService.shutdown();
......@@ -228,20 +232,27 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
}
if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) {
OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value();
OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
.get(PORTNAME_PREFIX_VM.concat(floatingIp.portId().substring(0, 11)));
if (portInfo == null) {
log.warn("There`s no portInfo information about portId {}", floatingIp.portId());
// XXX When the VM has been removed, host information has been removed or not ???
Optional<Host> host = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress().getIp4Address())
.stream()
.findFirst();
if (!host.isPresent()) {
log.warn("No Host info with the VM IP the Floating IP address {} is found",
openstackFloatingIp.floatingIpAddress());
return;
}
l3EventExecutorService.execute(
new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
new OpenstackFloatingIPHandler(rulePopulator, floatingIp, Action.DISSASSOCIATE, host.get()));
floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
registerFloatingIpToHostService(openstackFloatingIp, Action.DISSASSOCIATE);
} else {
floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
l3EventExecutorService.execute(
new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, true, null));
new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, Action.ASSOCIATE, null));
registerFloatingIpToHostService(openstackFloatingIp, Action.ASSOCIATE);
}
}
@Override
......@@ -356,6 +367,10 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router,
List<OpenstackRouterInterface> newList) {
if (!routerInterfaceMap.containsKey(routerInterface.portId())) {
log.warn("No router interface information found for {}", routerInterface.portId());
return;
}
openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
if (newList == null) {
......@@ -368,6 +383,7 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
);
}
/*
@Override
public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
if (floatingIpMap.size() < 1) {
......@@ -393,6 +409,7 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
}
}
*/
@Override
public String networkIdForRouterInterface(String portId) {
......@@ -445,6 +462,11 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
@Override
public void process(PacketContext context) {
DeviceId senderDeviceId = context.inPacket().receivedFrom().deviceId();
if (!nodeService.routerBridge(senderDeviceId).isPresent()) {
log.warn("No router bridge for {} is found.", senderDeviceId);
return;
}
if (context.isHandled()) {
return;
} else if (!checkGatewayNode(context.inPacket().receivedFrom().deviceId())) {
......@@ -482,7 +504,8 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
Ip4Address.valueOf(iPacket.getSourceAddress()));
l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
portNum, openstackPort, port, config));
portNum, openstackPort, port));
} else {
log.warn("There`s no external interface");
}
......@@ -602,75 +625,166 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
return null;
}
private void readConfiguration() {
config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
if (config == null) {
log.error("No configuration found");
private Optional<OpenstackPort> getRouterInterfacePort(String networkId) {
return openstackService.ports()
.stream()
.filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
&& p.networkId().equals(networkId))
.findAny();
}
// TODO: Remove the function and the related codes when vRouter is running on different ONOS instance.
private void registerFloatingIpToHostService(OpenstackFloatingIP openstackFloatingIp, Action action) {
Optional<Host> hostOptional = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress())
.stream()
.findFirst();
if (!hostOptional.isPresent()) {
log.warn("No host with IP {} is registered and cannot add the floating IP. ",
openstackFloatingIp.floatingIpAddress());
return;
}
rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
deviceService, driverService, config, gatewayService);
openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
openstackService, config, openstackSwitchingService, gatewayService);
openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService,
config, gatewayService);
openstackIcmpHandler.requestPacket(appId);
openstackArpHandler.requestPacket(appId);
openstackService.floatingIps().stream()
.forEach(f -> floatingIpMap.put(f.id(), f));
Host host = hostOptional.get();
Set<IpAddress> ipAddresses = Sets.newHashSet();
if (action == Action.ASSOCIATE) {
ipAddresses.add(openstackFloatingIp.floatingIpAddress());
}
reloadInitL3Rules();
HostDescription hostDescription =
new DefaultHostDescription(host.mac(), host.vlan(), host.location(), ipAddresses,
(DefaultAnnotations) host.annotations());
log.info("OpenstackRouting configured");
hostProviderService.hostDetected(host.id(), hostDescription, false);
}
private class InternalConfigListener implements NetworkConfigListener {
private class InternalHostListener implements HostListener {
private void hostDetected(Host host) {
String portId = host.annotations().value(Constants.PORT_ID);
OpenstackPort openstackPort = openstackService.port(portId);
if (openstackPort == null) {
log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
return;
}
Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
if (routerPort.isPresent()) {
OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
l3EventExecutorService.execute(() ->
setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
}
}
private void hostRemoved(Host host) {
String portId = host.annotations().value(Constants.PORT_ID);
OpenstackPort openstackPort = openstackService.port(portId);
if (openstackPort == null) {
log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
return;
}
Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
if (routerPort.isPresent()) {
OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
IpAddress ipAddress = host.ipAddresses().stream().findFirst().get();
l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(ipAddress.getIp4Address(),
getL3ConnectionList(host.annotations().value(Constants.NETWORK_ID),
getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
}
}
private boolean isValidHost(Host host) {
return !host.ipAddresses().isEmpty() &&
host.annotations().value(Constants.VXLAN_ID) != null &&
host.annotations().value(Constants.NETWORK_ID) != null &&
host.annotations().value(Constants.TENANT_ID) != null &&
host.annotations().value(Constants.PORT_ID) != null;
}
@Override
public void event(NetworkConfigEvent event) {
if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
public void event(HostEvent event) {
Host host = event.subject();
if (!mastershipService.isLocalMaster(host.location().deviceId())) {
// do not allow to proceed without mastership
return;
}
if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
if (!isValidHost(host)) {
log.debug("Invalid host event, ignore it {}", host);
return;
}
switch (event.type()) {
case HOST_UPDATED:
case HOST_ADDED:
l3EventExecutorService.execute(() -> hostDetected(host));
break;
case HOST_REMOVED:
l3EventExecutorService.execute(() -> hostRemoved(host));
break;
default:
break;
}
}
}
private class InternalDeviceListener implements DeviceListener {
private class InternalOpenstackNodeListener implements OpenstackNodeListener {
private void nodeComplete() {
rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
deviceService, driverService, nodeService, gatewayService);
openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService, hostService,
openstackService, nodeService, gatewayService);
openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, nodeService,
gatewayService);
// Packet handlers must be started AFTER all initialization processes.
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
openstackIcmpHandler.requestPacket(appId);
openstackArpHandler.requestPacket(appId);
openstackService.floatingIps().stream()
.forEach(f -> floatingIpMap.put(f.id(), f));
reloadInitL3Rules();
}
@Override
public void event(DeviceEvent deviceEvent) {
if (deviceEvent.type() == DeviceEvent.Type.PORT_UPDATED) {
Port port = deviceEvent.port();
OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
.get(port.annotations().value(PORT_NAME));
OpenstackPort openstackPort = openstackService.port(port);
OpenstackPort interfacePort = openstackService.ports()
.stream()
.filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
&& p.networkId().equals(openstackPort.networkId()))
.findAny()
.orElse(null);
if (portInfo == null && openstackPort == null) {
log.warn("As delete event timing issue between routing and switching, Can`t delete L3 rules");
return;
}
if ((port.isEnabled()) && (interfacePort != null)) {
OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
l3EventExecutorService.execute(() ->
setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
} else if (interfacePort != null) {
OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(portInfo.ip(),
getL3ConnectionList(portInfo.networkId(),
getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
}
public void event(OpenstackNodeEvent event) {
OpenstackNode node = event.node();
switch (event.type()) {
case COMPLETE:
log.info("COMPLETE node {} detected", node.hostname());
l3EventExecutorService.execute(() -> nodeComplete());
break;
case INCOMPLETE:
break;
default:
break;
}
}
}
private class InternalHostProvider extends AbstractProvider implements HostProvider {
/**
* Creates a provider with the supplier identifier.
*/
protected InternalHostProvider() {
super(PID);
}
@Override
public void triggerProbe(Host host) {
// nothing to do
}
}
......
......@@ -29,6 +29,7 @@ import org.onosproject.core.ApplicationId;
import org.onosproject.core.GroupId;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
......@@ -54,14 +55,16 @@ import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
import org.onosproject.openstackinterface.OpenstackSubnet;
import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.Constants;
import org.onosproject.openstacknetworking.OpenstackRoutingService;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.onosproject.openstacknode.OpenstackNode;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -79,8 +82,8 @@ public class OpenstackRoutingRulePopulator {
private final OpenstackInterfaceService openstackService;
private final DeviceService deviceService;
private final DriverService driverService;
private final OpenstackNetworkingConfig config;
private final ScalableGatewayService gatewayService;
private final OpenstackNodeService nodeService;
private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
private static final String PORTNAME = "portName";
......@@ -95,7 +98,6 @@ public class OpenstackRoutingRulePopulator {
private static final int PNAT_RULE_PRIORITY = 26000;
private static final int PNAT_TIMEOUT = 120;
private static final int PREFIX_LENGTH = 32;
private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
private InboundPacket inboundPacket;
private OpenstackPort openstackPort;
......@@ -111,20 +113,22 @@ public class OpenstackRoutingRulePopulator {
* @param flowObjectiveService FlowObjectiveService
* @param deviceService DeviceService
* @param driverService DriverService
* @param config Configuration for openstack environment
* @param gatewayService scalable gateway service
*/
public OpenstackRoutingRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
FlowObjectiveService flowObjectiveService, DeviceService deviceService,
DriverService driverService, OpenstackNetworkingConfig config,
public OpenstackRoutingRulePopulator(ApplicationId appId,
OpenstackInterfaceService openstackService,
FlowObjectiveService flowObjectiveService,
DeviceService deviceService,
DriverService driverService,
OpenstackNodeService nodeService,
ScalableGatewayService gatewayService) {
this.appId = appId;
this.flowObjectiveService = flowObjectiveService;
this.openstackService = checkNotNull(openstackService);
this.deviceService = deviceService;
this.driverService = driverService;
this.config = config;
this.gatewayService = gatewayService;
this.nodeService = nodeService;
}
/**
......@@ -201,7 +205,8 @@ public class OpenstackRoutingRulePopulator {
private Port getPortOfExternalInterface() {
return deviceService.getPorts(getGatewayNode().id()).stream()
.filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
.filter(p -> p.annotations().value(PORTNAME)
.equals(org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
.findAny().orElse(null);
}
......@@ -239,7 +244,8 @@ public class OpenstackRoutingRulePopulator {
getGatewayNodeList().forEach(node -> {
DeviceId deviceId = node.id();
tBuilder.extension(buildNiciraExtenstion(deviceId, getHostIpfromOpenstackPort(openstackPort)), deviceId)
tBuilder.extension(buildNiciraExtenstion(deviceId,
getHostIpfromOpenstackPort(openstackPort).getIp4Address()), deviceId)
.setOutput(getTunnelPort(deviceId));
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -262,9 +268,16 @@ public class OpenstackRoutingRulePopulator {
return devices;
}
private Ip4Address getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
private IpAddress getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
Device device = getDevicefromOpenstackPort(openstackPort);
return config.nodes().get(device.id());
Optional<IpAddress> ipAddress = nodeService.dataIp(device.id());
if (!ipAddress.isPresent()) {
log.warn("No IP address found for device {}", device.id());
return null;
}
return ipAddress.get();
}
private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
......@@ -349,7 +362,7 @@ public class OpenstackRoutingRulePopulator {
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(vni)
.matchEthDst(GATEWAYMAC);
.matchEthDst(Constants.GATEWAY_MAC);
tBuilder.setOutput(PortNumber.CONTROLLER);
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -365,7 +378,7 @@ public class OpenstackRoutingRulePopulator {
private void populateComputeNodeRules(long vni) {
StreamSupport.stream(deviceService.getDevices().spliterator(), false)
.filter(d -> !checkGatewayNode(d.id()))
.filter(d -> isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE))
.forEach(d -> populateRuleToGatewayBySgw(d.id(),
gatewayService.getGroupIdForGatewayLoadBalance(d.id()), vni));
}
......@@ -376,7 +389,8 @@ public class OpenstackRoutingRulePopulator {
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(vni)
.matchEthDst(GATEWAYMAC);
.matchEthDst(Constants.GATEWAY_MAC);
tBuilder.group(groupId);
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -390,14 +404,15 @@ public class OpenstackRoutingRulePopulator {
flowObjectiveService.forward(deviceId, fo);
}
/*
private void populateRuleToGateway(DeviceId deviceId, Device gatewayDevice, long vni) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(vni)
.matchEthDst(GATEWAYMAC);
tBuilder.extension(buildNiciraExtenstion(deviceId, config.nodes().get(gatewayDevice.id())), deviceId)
.matchEthDst(Constants.GATEWAY_MAC);
tBuilder.extension(buildNiciraExtenstion(deviceId, nodeService.nodes().get(gatewayDevice.id())), deviceId)
.setOutput(getTunnelPort(deviceId));
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -410,13 +425,36 @@ public class OpenstackRoutingRulePopulator {
flowObjectiveService.forward(deviceId, fo);
}
*/
private Device getGatewayNode() {
return checkNotNull(deviceService.getDevice(DeviceId.deviceId(config.gatewayBridgeId())));
// TODO Return the correct gateway node
Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
.filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
.findFirst();
if (!gwNode.isPresent()) {
log.warn("No Gateway is defined.");
return null;
}
return deviceService.getDevice(gwNode.get().intBridge());
}
private boolean checkGatewayNode(DeviceId deviceId) {
return gatewayService.getGatewayDeviceIds().stream().anyMatch(dId -> dId.equals(deviceId));
private boolean isTypeOf(DeviceId deviceId, OpenstackNodeService.NodeType type) {
Optional<OpenstackNode> node = nodeService.nodes().stream()
.filter(n -> n.intBridge().equals(deviceId) ||
(n.routerBridge().isPresent() && n.routerBridge().get().equals(deviceId)))
.filter(n -> n.type().equals(type))
.findFirst();
if (node.isPresent()) {
return true;
}
return false;
}
private long getVni(String netId) {
......@@ -433,11 +471,11 @@ public class OpenstackRoutingRulePopulator {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(getVni(openstackSubnet.networkId()))
.matchEthDst(GATEWAYMAC);
.matchEthDst(Constants.GATEWAY_MAC);
StreamSupport.stream(deviceService.getDevices().spliterator(), false)
.forEach(d -> {
ForwardingObjective.Flag flag = checkGatewayNode(d.id()) ?
ForwardingObjective.Flag flag = isTypeOf(d.id(), OpenstackNodeService.NodeType.GATEWAY) ?
ForwardingObjective.Flag.VERSATILE :
ForwardingObjective.Flag.SPECIFIC;
removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
......@@ -474,33 +512,35 @@ public class OpenstackRoutingRulePopulator {
}
private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
DeviceId portDeviceId = getDevicefromOpenstackPort(port).id();
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
getGatewayNodeList().forEach(device -> {
DeviceId deviceId = device.id();
tBuilder.setEthSrc(GATEWAYMAC)
.setEthDst(port.macAddress())
.setIpDst(floatingIP.fixedIpAddress())
.setTunnelId(getVni(port.networkId()))
.extension(buildNiciraExtenstion(deviceId, config.nodes().get(portDeviceId)), deviceId)
.setOutput(getTunnelPort(deviceId));
DeviceId gatewayDeviceId = DeviceId.deviceId(port.deviceId());
Optional<IpAddress> ipAddress = nodeService.dataIp(gatewayDeviceId);
if (!ipAddress.isPresent()) {
log.warn("No IP address found for device {}", port.deviceId());
return;
}
tBuilder.setEthSrc(Constants.GATEWAY_MAC)
.setEthDst(port.macAddress())
.setIpDst(floatingIP.fixedIpAddress())
.setTunnelId(getVni(port.networkId()))
.extension(buildNiciraExtenstion(gatewayDeviceId,
ipAddress.get().getIp4Address()), gatewayDeviceId)
.setOutput(getTunnelPort(gatewayDeviceId));
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(FLOATING_RULE_PRIORITY)
.fromApp(appId)
.add();
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(FLOATING_RULE_PRIORITY)
.fromApp(appId)
.add();
flowObjectiveService.forward(deviceId, fo);
});
flowObjectiveService.forward(getGatewayNode().id(), fo);
}
private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
......@@ -514,6 +554,8 @@ public class OpenstackRoutingRulePopulator {
getGatewayNodeList().forEach(device -> {
DeviceId deviceId = device.id();
tBuilder.setIpSrc(floatingIP.floatingIpAddress())
.setEthSrc(Constants.GW_EXT_INT_MAC)
.setEthDst(Constants.PHY_ROUTER_MAC)
.setOutput(getExternalPortNum(deviceId));
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -535,19 +577,20 @@ public class OpenstackRoutingRulePopulator {
/**
* Removes flow rules for floating ip configuration.
*
* @param floatingIP Corresponding floating ip information
* @param portInfo stored information about deleted vm
* @param floatingIp Corresponding floating ip information
* @param host host information for vm to remove
*/
public void removeFloatingIpRules(OpenstackFloatingIP floatingIP, OpenstackPortInfo portInfo) {
public void removeFloatingIpRules(OpenstackFloatingIP floatingIp, Host host) {
TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
// XXX FloatingIp.tenant_id() == host.vxlan_id ???
sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(portInfo.vni())
.matchIPSrc(IpPrefix.valueOf(portInfo.ip(), PREFIX_LENGTH));
.matchTunnelId(Integer.parseInt(host.annotations().value(Constants.VXLAN_ID)))
.matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIpAddress(), PREFIX_LENGTH));
sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
.matchIPDst(IpPrefix.valueOf(floatingIp.floatingIpAddress(), PREFIX_LENGTH));
getGatewayNodeList().forEach(device -> {
removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
......@@ -580,8 +623,9 @@ public class OpenstackRoutingRulePopulator {
populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
deviceService.getAvailableDevices().forEach(d -> {
if (!d.equals(device) && !checkGatewayNode(d.id())) {
populateL3RulestoDifferentNode(vmIp, vni, d.id(), getHostIpfromOpenstackPort(openstackPort));
if (!d.equals(device) && !d.equals(getGatewayNode())) {
populateL3RulestoDifferentNode(vmIp, vni, d.id(),
getHostIpfromOpenstackPort(openstackPort).getIp4Address());
}
});
......@@ -654,7 +698,7 @@ public class OpenstackRoutingRulePopulator {
OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
deviceService.getAvailableDevices().forEach(d -> {
if (!checkGatewayNode(d.id())) {
if (isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE)) {
routerInterfaces.forEach(routerInterface -> {
String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
long vni = getVni(networkId);
......
......@@ -26,6 +26,7 @@ import org.onosproject.net.Host;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.openstacknetworking.Constants;
import org.slf4j.Logger;
import java.util.Objects;
......@@ -36,7 +37,7 @@ import java.util.stream.Collectors;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.openstacknetworking.switching.Constants.*;
import static org.onosproject.openstacknetworking.Constants.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
......
......@@ -48,7 +48,7 @@ import java.util.Dictionary;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.openstacknetworking.switching.Constants.*;
import static org.onosproject.openstacknetworking.Constants.*;
/**
* Handles ARP packet from VMs.
......
......@@ -50,7 +50,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.onosproject.openstacknetworking.switching.Constants.*;
import static org.onosproject.openstacknetworking.Constants.*;
/**
* Populates flows rules for Security Groups of VMs.
......
......@@ -16,7 +16,6 @@
package org.onosproject.openstacknetworking.switching;
import com.google.common.base.Strings;
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;
......@@ -27,7 +26,6 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.onlab.util.Tools;
import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DhcpService;
import org.onosproject.dhcp.IpAssignment;
......@@ -54,8 +52,6 @@ import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackNetwork;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackSubnet;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.openstacknode.OpenstackNode;
import org.onosproject.openstacknode.OpenstackNodeEvent;
import org.onosproject.openstacknode.OpenstackNodeListener;
......@@ -64,7 +60,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
......@@ -74,7 +69,7 @@ import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNot
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
import static org.onosproject.openstacknetworking.switching.Constants.*;
import static org.onosproject.openstacknetworking.Constants.*;
@Service
@Component(immediate = true)
......@@ -82,7 +77,7 @@ import static org.onosproject.openstacknetworking.switching.Constants.*;
* Populates forwarding rules for VMs created by Openstack.
*/
public final class OpenstackSwitchingManager extends AbstractProvider
implements OpenstackSwitchingService, HostProvider {
implements HostProvider {
private final Logger log = LoggerFactory.getLogger(getClass());
......@@ -153,41 +148,6 @@ public final class OpenstackSwitchingManager extends AbstractProvider
// no probe is required
}
@Override
// TODO remove this and openstackPortInfo
public Map<String, OpenstackPortInfo> openstackPortInfo() {
Map<String, OpenstackPortInfo> portInfoMap = Maps.newHashMap();
Tools.stream(hostService.getHosts()).filter(this::isValidHost).forEach(host -> {
Port port = deviceService.getPort(
host.location().deviceId(),
host.location().port());
OpenstackPortInfo portInfo = OpenstackPortInfo.builder()
.setDeviceId(host.location().deviceId())
.setHostMac(host.mac())
.setNetworkId(host.annotations().value(NETWORK_ID))
.setGatewayIP(Ip4Address.valueOf(host.annotations().value(GATEWAY_IP)))
.setVni(Long.valueOf(host.annotations().value(VXLAN_ID)))
.setHostIp(host.ipAddresses().stream().findFirst().get().getIp4Address())
.build();
portInfoMap.put(port.annotations().value(PORT_NAME), portInfo);
});
return portInfoMap;
}
// TODO remove this and openstackPortInfo
private boolean isValidHost(Host host) {
return !host.ipAddresses().isEmpty() &&
host.annotations().value(VXLAN_ID) != null &&
host.annotations().value(NETWORK_ID) != null &&
host.annotations().value(TENANT_ID) != null &&
host.annotations().value(GATEWAY_IP) != null &&
host.annotations().value(PORT_ID) != null;
}
private void processPortAdded(Port port) {
// TODO check the node state is COMPLETE
OpenstackPort osPort = openstackService.port(port);
......
......@@ -47,7 +47,7 @@ import java.util.Objects;
import java.util.Optional;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.onosproject.openstacknetworking.switching.Constants.*;
import static org.onosproject.openstacknetworking.Constants.*;
/**
* Populates switching flow rules.
......
......@@ -50,6 +50,7 @@ import org.onosproject.scalablegateway.api.GatewayNodeConfig;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import java.util.List;
import java.util.Optional;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
......@@ -128,7 +129,6 @@ public class ScalableGatewayManager implements ScalableGatewayService {
deviceService.addListener(internalDeviceListener);
selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
readConfiguration();
gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
.withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
......@@ -165,13 +165,17 @@ public class ScalableGatewayManager implements ScalableGatewayService {
}
private PortNumber findPortNumFromPortName(DeviceId gatewayDeviceId, String name) {
Port port = deviceService.getPorts(gatewayDeviceId)
Optional<Port> port = deviceService.getPorts(gatewayDeviceId)
.stream()
.filter(p -> p.annotations().value(PORT_NAME).equals(name))
.iterator()
.next();
return checkNotNull(port, PORT_CAN_NOT_BE_NULL).number();
.findFirst();
if (!port.isPresent()) {
log.error("Cannot find port {} in gateway device {}", name, gatewayDeviceId);
return null;
}
return port.get().number();
}
@Override
......