Kyuhwi Choi
Committed by Gerrit Code Review

[ONOS-3952] Implement FloatingIP Handler for OpenstackRoutingService

 - Implements floatingIp REST interfaces & event handler
 - Implements rulePopulate method for floatingIp handler
 - Fixes minor logics
 - Changes app structure
 - exports configuration
 - Implements case issue.
   when openstack deletes vm w/o deassociating floatingIp,
   openstack doesn`t send floatingIp deassociation event.

Change-Id: If4d8ac3fecfed1957d84139f94ae31f593a9097b
......@@ -80,5 +80,11 @@ public interface OpenstackRoutingService {
*/
void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
/**
* Checks floatingIp deassociation when corresponding deleted vm.
*
* @param portId Deleted vm
* @param portInfo
*/
void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo);
}
......
......@@ -15,20 +15,34 @@
*/
package org.onosproject.openstacknetworking.routing;
import org.onosproject.event.AbstractEvent;
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 {
volatile AbstractEvent event;
OpenstackFloatingIPHandler(AbstractEvent event) {
this.event = event;
private final OpenstackFloatingIP floatingIP;
private final OpenstackRoutingRulePopulator rulePopulator;
private boolean associate;
private final OpenstackPortInfo portInfo;
OpenstackFloatingIPHandler(OpenstackRoutingRulePopulator rulePopulator,
OpenstackFloatingIP openstackFloatingIP, boolean associate, OpenstackPortInfo portInfo) {
this.floatingIP = openstackFloatingIP;
this.rulePopulator = rulePopulator;
this.associate = associate;
this.portInfo = portInfo;
}
@Override
public void run() {
if (associate) {
rulePopulator.populateFloatingIpRules(floatingIP);
} else {
rulePopulator.removeFloatingIpRules(floatingIP, portInfo);
}
}
}
......
......@@ -56,19 +56,18 @@ public class OpenstackPnatHandler implements Runnable {
private final int portNum;
private final OpenstackPort openstackPort;
private final Port port;
private OpenstackRoutingConfig config;
private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
// TODO: This will be replaced to get the information from openstacknetworkingservice.
private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
private static final MacAddress EXTERNAL_INTERFACE_MAC = MacAddress.valueOf("00:00:00:00:00:11");
OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
int portNum, OpenstackPort openstackPort, Port port) {
int portNum, OpenstackPort openstackPort, Port port, OpenstackRoutingConfig config) {
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
......@@ -85,7 +84,8 @@ public class OpenstackPnatHandler implements Runnable {
OpenstackRouter router = getOpenstackRouter(openstackPort);
rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
getExternalIp(router), getExternalInterfaceMacAddress(), getExternalRouterMacAddress());
getExternalIp(router), MacAddress.valueOf(config.gatewayExternalInterfaceMac()),
MacAddress.valueOf(config.physicalRouterMac()));
packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
}
......@@ -144,8 +144,9 @@ public class OpenstackPnatHandler implements Runnable {
iPacket.setSourceAddress(getExternalIp(router).toString());
iPacket.resetChecksum();
iPacket.setParent(ethernet);
ethernet.setSourceMACAddress(getExternalInterfaceMacAddress())
.setDestinationMACAddress(getExternalRouterMacAddress());
ethernet.setPayload(iPacket);
ethernet.setSourceMACAddress(config.gatewayExternalInterfaceMac())
.setDestinationMACAddress(config.physicalRouterMac());
ethernet.resetChecksum();
treatment.setOutput(port.number());
......@@ -153,11 +154,4 @@ public class OpenstackPnatHandler implements Runnable {
packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
ByteBuffer.wrap(ethernet.serialize())));
}
private MacAddress getExternalInterfaceMacAddress() {
return EXTERNAL_INTERFACE_MAC;
}
private MacAddress getExternalRouterMacAddress() {
return GATEWAYMAC;
}
}
\ No newline at end of file
......
......@@ -16,7 +16,6 @@
package org.onosproject.openstacknetworking.routing;
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;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -28,6 +27,7 @@ import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
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.net.DeviceId;
......@@ -50,14 +50,18 @@ import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.OpenstackRoutingService;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
......@@ -101,14 +105,21 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry configRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
private ApplicationId appId;
private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
private Map<Integer, String> portNumMap = initPortNumMap();
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>
private static final String APP_ID = "org.onosproject.openstackrouting";
private static final String PORT_NAME = "portName";
private static final String PORTNAME_PREFIX_VM = "tap";
private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
private static final String TP_PORT_MAP_NAME = "openstackrouting-portnum";
private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
private static final int TP_PORT_MINIMUM_NUM = 1024;
private static final int TP_PORT_MAXIMUM_NUM = 65535;
private final ConfigFactory configFactory =
new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackRoutingConfig.class, "openstackrouting") {
@Override
......@@ -119,16 +130,19 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
private final NetworkConfigListener configListener = new InternalConfigListener();
private OpenstackRoutingConfig config;
private static final int PNAT_PORT_NUM_START = 1024;
private static final int PNAT_PORT_NUM_END = 65535;
private Map<Integer, String> initPortNumMap() {
Map<Integer, String> map = Maps.newHashMap();
for (int i = PNAT_PORT_NUM_START; i < PNAT_PORT_NUM_END; i++) {
map.put(i, "");
}
return map;
}
private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(KryoNamespaces.MISC)
.register(OpenstackFloatingIP.FloatingIpStatus.class)
.register(OpenstackFloatingIP.class)
.register(Ip4Address.class)
.register(String.class);
private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(KryoNamespaces.MISC)
.register(Integer.class)
.register(String.class);
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
private ExecutorService l3EventExecutorService =
......@@ -139,6 +153,7 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
private OpenstackIcmpHandler openstackIcmpHandler;
private OpenstackRoutingArpHandler openstackArpHandler;
private OpenstackRoutingRulePopulator rulePopulator;
@Activate
protected void activate() {
......@@ -149,6 +164,17 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
readConfiguration();
floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
.withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
.withName(FLOATING_IP_MAP_NAME)
.withApplicationId(appId)
.build();
tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
.withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
.withName(TP_PORT_MAP_NAME)
.withApplicationId(appId)
.build();
log.info("onos-openstackrouting started");
}
......@@ -159,43 +185,92 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
icmpEventExecutorService.shutdown();
arpEventExecutorService.shutdown();
floatingIpMap.clear();
tpPortNumMap.clear();
log.info("onos-openstackrouting stopped");
}
@Override
public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
}
@Override
public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
if (!floatingIpMap.containsKey(openstackFloatingIP.id())) {
log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIP.id());
return;
}
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());
return;
}
l3EventExecutorService.execute(
new OpenstackFloatingIPHandler(rulePopulator, floatingIP, false, portInfo));
floatingIpMap.replace(floatingIP.id(), openstackFloatingIP);
} else {
floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
l3EventExecutorService.execute(
new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIP, true, null));
}
}
@Override
public void deleteFloatingIP(String id) {
floatingIpMap.remove(id);
}
@Override
public void createRouter(OpenstackRouter openstackRouter) {
checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
}
@Override
public void updateRouter(OpenstackRouter openstackRouter) {
checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
Ip4Address externalIp = openstackRouter.gatewayExternalInfo().externalFixedIps()
.values().stream().findFirst().orElse(null);
OpenstackRouter router = getRouterfromExternalIp(externalIp);
checkExternalConnection(router, getOpenstackRouterInterface(router));
} else {
unsetExternalConnection();
}
}
private void unsetExternalConnection() {
Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
internalRouters.forEach(r ->
getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
}
private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
List<OpenstackRouter> routers;
if (externalConnection) {
routers = openstackService.routers()
.stream()
.filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
.collect(Collectors.toList());
} else {
routers = openstackService.routers()
.stream()
.filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
.collect(Collectors.toList());
}
return routers;
}
@Override
public void deleteRouter(String id) {
//TODO
//TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
}
@Override
public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
routerInterfaceMap.putIfAbsent(routerInterface.id(), routerInterface);
List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
routerInterfaces.add(routerInterface);
checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
......@@ -203,20 +278,55 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
@Override
public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
openstackService, flowObjectiveService, deviceService, driverService, config);
rulePopulator.removeExternalRules(routerInterface);
routerInterfaceMap.remove(routerInterface.portId());
}
private void reloadInitL3Rules() {
openstackService.ports()
@Override
public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
if (floatingIpMap.size() < 1) {
log.info("No information in FloatingIpMap");
return;
}
OpenstackFloatingIP floatingIp = associatedFloatingIps()
.stream()
.filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
.forEach(p -> {
OpenstackRouterInterface routerInterface = portToRouterInterface(p);
updateRouterInterface(routerInterface);
});
.filter(fIp -> fIp.portId().equals(portId))
.findAny()
.orElse(null);
if (floatingIp != null && portInfo != null) {
l3EventExecutorService.execute(
new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
.floatingIpAddress(floatingIp.floatingIpAddress())
.id(floatingIp.id())
.networkId(floatingIp.networkId())
.status(floatingIp.status())
.tenantId(floatingIp.tenantId());
floatingIpMap.replace(floatingIp.id(), fBuilder.build());
} else if (portInfo == null) {
log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
}
}
private Collection<OpenstackFloatingIP> associatedFloatingIps() {
List<OpenstackFloatingIP> fIps = Lists.newArrayList();
floatingIpMap.values()
.stream()
.filter(fIp -> fIp.value().portId() != null)
.forEach(fIp -> fIps.add(fIp.value()));
return fIps;
}
private void reloadInitL3Rules() {
l3EventExecutorService.submit(() ->
openstackService.ports()
.stream()
.filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
.forEach(p -> {
OpenstackRouterInterface routerInterface = portToRouterInterface(p);
updateRouterInterface(routerInterface);
})
);
}
private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
......@@ -249,8 +359,6 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
return;
} else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
IPv4 iPacket = (IPv4) ethernet.getPayload();
OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
openstackService, flowObjectiveService, deviceService, driverService, config);
switch (iPacket.getProtocol()) {
case IPv4.PROTOCOL_ICMP:
......@@ -275,7 +383,7 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
Ip4Address.valueOf(iPacket.getSourceAddress()));
l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
portNum, openstackPort, port));
portNum, openstackPort, port, config));
break;
}
} else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
......@@ -285,11 +393,32 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
}
private int getPortNum(MacAddress sourceMac, int destinationAddress) {
int portNum = portNumMap.keySet().stream()
.filter(k -> portNumMap.get(k).equals("")).findFirst().orElse(0);
portNumMap.replace(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
int portNum = findUnusedPortNum();
if (portNum == 0) {
clearPortNumMap();
portNum = findUnusedPortNum();
}
tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
return portNum;
}
private int findUnusedPortNum() {
for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
if (!tpPortNumMap.containsKey(i)) {
return i;
}
}
return 0;
}
}
private void clearPortNumMap() {
tpPortNumMap.entrySet().forEach(e -> {
if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
tpPortNumMap.remove(e.getKey());
}
});
}
private Port getExternalPort(DeviceId deviceId, String interfaceName) {
......@@ -301,29 +430,55 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
}
private void checkExternalConnection(OpenstackRouter router,
Collection<OpenstackRouterInterface> routerInterfaces) {
Collection<OpenstackRouterInterface> interfaces) {
checkNotNull(router, "Router can not be null");
checkNotNull(routerInterfaces, "routerInterfaces can not be null");
checkNotNull(interfaces, "routerInterfaces can not be null");
Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
.values().stream().findFirst().orElse(null);
if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
log.debug("Not satisfied to set pnat configuration");
return;
}
routerInterfaces.forEach(routerInterface -> initiateL3Rule(router, routerInterface));
if (router.id() == null) {
interfaces.forEach(i -> initiateL3Rule(getRouterfromExternalIp(externalIp), i));
} else {
interfaces.forEach(i -> initiateL3Rule(router, i));
}
}
private OpenstackRouter getRouterfromExternalIp(Ip4Address externalIp) {
OpenstackRouter router = getExternalRouter(true)
.stream()
.filter(r -> r.gatewayExternalInfo()
.externalFixedIps()
.values()
.stream()
.findFirst()
.orElse(null)
.equals(externalIp))
.findAny()
.orElse(null);
return checkNotNull(router);
}
private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
long vni = Long.parseLong(openstackService.network(openstackService
.port(routerInterface.portId()).networkId()).segmentId());
OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
openstackService, flowObjectiveService, deviceService, driverService, config);
rulePopulator.populateExternalRules(vni, router, routerInterface);
}
private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
return routerInterfaceMap.values().stream().filter(i -> i.id().equals(router.id()))
.collect(Collectors.toList());
List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
openstackService.ports()
.stream()
.filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
.filter(p -> p.deviceId().equals(router.id()))
.forEach(p -> {
OpenstackRouterInterface routerInterface = portToRouterInterface(p);
interfaces.add(routerInterface);
});
return interfaces;
}
private OpenstackRouter getOpenstackRouter(String id) {
......@@ -334,8 +489,8 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
OpenstackPort openstackPort = openstackService.ports().stream()
.filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
return checkNotNull(openstackPort.fixedIps().values().stream().findFirst().orElse(null))
.equals(ip4Address) ? openstackPort : null;
return openstackPort.fixedIps().values().stream().filter(ip ->
ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
}
private void readConfiguration() {
......@@ -353,7 +508,8 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
reloadInitL3Rules();
rulePopulator = new OpenstackRoutingRulePopulator(appId,
openstackService, flowObjectiveService, deviceService, driverService, config);
openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
openstackService, config, openstackSwitchingService);
......@@ -361,7 +517,7 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
openstackIcmpHandler.requestPacket(appId);
openstackArpHandler.requestPacket(appId);
reloadInitL3Rules();
log.info("OpenstackRouting configured");
}
......@@ -373,14 +529,12 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
return;
}
switch (event.type()) {
case CONFIG_ADDED:
case CONFIG_UPDATED:
l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
break;
default:
log.debug("Unsupported event type {}", event.type().toString());
break;
if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
rulePopulator = new OpenstackRoutingRulePopulator(appId,
openstackService, flowObjectiveService, deviceService, driverService, config);
}
}
}
......
......@@ -52,6 +52,8 @@ import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
import org.onosproject.openstackinterface.OpenstackSubnet;
import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -73,16 +75,17 @@ public class OpenstackRoutingRulePopulator {
private final DriverService driverService;
private final OpenstackRoutingConfig config;
private static final String PORTNAME_PREFIX_VM = "tap";
private static final String PORTNAME_PREFIX_ROUTER = "qr";
private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
private static final String PORTNAME = "portName";
private static final String PORTNAME_PREFIX_VM = "tap";
private static final String PORTNOTNULL = "Port can not be null";
private static final String DEVICENOTNULL = "Device can not be null";
private static final String TUNNEL_DESTINATION = "tunnelDst";
private static final String DEVICE_ANNOTATION_CHANNELID = "channelId";
private static final int ROUTING_RULE_PRIORITY = 25000;
private static final int PNAT_RULE_PRIORITY = 24000;
private static final int FLOATING_RULE_PRIORITY = 42000;
private static final int PNAT_RULE_PRIORITY = 26000;
private static final int PNAT_TIMEOUT = 120;
private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
......@@ -134,7 +137,7 @@ public class OpenstackRoutingRulePopulator {
this.externalInterface = externalInterfaceMacAddress;
this.externalRouter = externalRouterMacAddress;
long vni = getVni(openstackPort);
long vni = getVni(openstackPort.networkId());
populatePnatIncomingFlowRules(vni, externalIp);
populatePnatOutgoingFlowRules(vni, externalIp);
......@@ -173,7 +176,7 @@ public class OpenstackRoutingRulePopulator {
break;
}
Port port = checkNotNull(getPortNumOfExternalInterface(), PORTNOTNULL);
Port port = checkNotNull(getPortOfExternalInterface(), PORTNOTNULL);
tBuilder.setOutput(port.number());
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -188,8 +191,8 @@ public class OpenstackRoutingRulePopulator {
flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
}
private Port getPortNumOfExternalInterface() {
return deviceService.getPorts(inboundPacket.receivedFrom().deviceId()).stream()
private Port getPortOfExternalInterface() {
return deviceService.getPorts(getGatewayNode().id()).stream()
.filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
.findAny().orElse(null);
}
......@@ -207,6 +210,7 @@ public class OpenstackRoutingRulePopulator {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setTunnelId(vni)
.setEthDst(inboundPacket.parsed().getSourceMAC())
.setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
switch (iPacket.getProtocol()) {
......@@ -226,7 +230,7 @@ public class OpenstackRoutingRulePopulator {
break;
}
tBuilder.extension(buildNiciraExtenstion(deviceId, Ip4Address.valueOf(iPacket.getSourceAddress())), deviceId)
tBuilder.extension(buildNiciraExtenstion(deviceId, getHostIpfromOpenstackPort(openstackPort)), deviceId)
.setOutput(getTunnelPort(deviceId));
ForwardingObjective fo = DefaultForwardingObjective.builder()
......@@ -241,14 +245,37 @@ public class OpenstackRoutingRulePopulator {
flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
}
private Ip4Address getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
Device device = getDevicefromOpenstackPort(openstackPort);
return getIPAddressforDevice(device);
}
private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
.filter(d -> findPortinDevice(d, openstackPortName))
.findAny()
.orElse(null);
checkNotNull(device, DEVICENOTNULL);
return device;
}
private boolean findPortinDevice(Device d, String openstackPortName) {
Port port = deviceService.getPorts(d.id())
.stream()
.filter(p -> p.isEnabled() && p.annotations().value(PORTNAME).equals(openstackPortName))
.findAny()
.orElse(null);
return port != null ? true : false;
}
/**
* Returns NiciraExtension treatment.
* Builds NiciraExtension for tagging remoteIp of vxlan.
*
* @param id device id
* @param hostIp host ip
* @return NiciraExtension treatment
* @param id Device Id of vxlan source device
* @param hostIp Remote Ip of vxlan destination device
* @return NiciraExtension Treatment
*/
public ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
Driver driver = driverService.getDriver(id);
DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
......@@ -270,8 +297,8 @@ public class OpenstackRoutingRulePopulator {
/**
* Returns port number of vxlan tunnel.
*
* @param deviceId device id
* @return port number of vxlan tunnel
* @param deviceId Target Device Id
* @return PortNumber
*/
public PortNumber getTunnelPort(DeviceId deviceId) {
Port port = deviceService.getPorts(deviceId).stream()
......@@ -328,7 +355,7 @@ public class OpenstackRoutingRulePopulator {
private void populateComputeNodeRules(long vni) {
Device gatewayDevice = getGatewayNode();
StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
StreamSupport.stream(deviceService.getDevices().spliterator(), false)
.filter(d -> !checkGatewayNode(d.id()))
.forEach(d -> populateRuleToGateway(d, gatewayDevice, vni));
}
......@@ -366,12 +393,8 @@ public class OpenstackRoutingRulePopulator {
return deviceId.toString().equals(config.gatewayBridgeId());
}
private long getVni(OpenstackPort openstackPort) {
return Long.parseLong(openstackService.network(openstackPort.networkId()).segmentId());
}
private long getVni(OpenstackSubnet openstackSubnet) {
return Long.parseLong(openstackService.network(openstackSubnet.networkId()).segmentId());
private long getVni(String netId) {
return Long.parseLong(openstackService.network(netId).segmentId());
}
/**
......@@ -383,32 +406,122 @@ public class OpenstackRoutingRulePopulator {
OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(getVni(openstackSubnet))
.matchTunnelId(getVni(openstackSubnet.networkId()))
.matchEthDst(GATEWAYMAC);
StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
StreamSupport.stream(deviceService.getDevices().spliterator(), false)
.forEach(d -> {
if (checkGatewayNode(d.id())) {
removeExternalRule(d.id(), sBuilder, ForwardingObjective.Flag.VERSATILE);
removeRule(d.id(), sBuilder, ForwardingObjective.Flag.VERSATILE, ROUTING_RULE_PRIORITY);
} else {
removeExternalRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC);
removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
}
});
}
private void removeExternalRule(DeviceId id, TrafficSelector.Builder sBuilder, ForwardingObjective.Flag flag) {
private void removeRule(DeviceId id, TrafficSelector.Builder sBuilder,
ForwardingObjective.Flag flag, int priority) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withFlag(flag)
.withPriority(ROUTING_RULE_PRIORITY)
.withPriority(priority)
.fromApp(appId)
.remove();
flowObjectiveService.forward(id, fo);
}
/**
* Populates flow rules for floatingIp configuration.
*
* @param floatingIP Corresponding floating ip information
*/
public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
OpenstackPort port = openstackService.port(floatingIP.portId());
//1. incoming rules
populateFloatingIpIncomingRules(floatingIP, port);
//2. outgoing rules
populateFloatingIpOutgoingRules(floatingIP, port);
}
private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
DeviceId portDeviceId = getDevicefromOpenstackPort(port).id();
Device gatewayNode = getGatewayNode();
Device portNode = deviceService.getDevice(portDeviceId);
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), 32));
tBuilder.setEthSrc(MacAddress.valueOf(config.gatewayExternalInterfaceMac()))
.setEthDst(port.macAddress())
.setIpDst(floatingIP.fixedIpAddress())
.setTunnelId(getVni(port.networkId()))
.extension(buildNiciraExtenstion(gatewayNode.id(), getIPAddressforDevice(portNode)), gatewayNode.id())
.setOutput(getTunnelPort(gatewayNode.id()));
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(FLOATING_RULE_PRIORITY)
.fromApp(appId)
.add();
flowObjectiveService.forward(getGatewayNode().id(), fo);
}
private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Port outputPort = checkNotNull(getPortOfExternalInterface(), PORTNOTNULL);
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(getVni(port.networkId()))
.matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
tBuilder.setIpSrc(floatingIP.floatingIpAddress())
.setEthSrc(MacAddress.valueOf(config.gatewayExternalInterfaceMac()))
.setEthDst(MacAddress.valueOf(config.physicalRouterMac()))
.setOutput(outputPort.number());
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(FLOATING_RULE_PRIORITY)
.fromApp(appId)
.add();
flowObjectiveService.forward(getGatewayNode().id(), fo);
}
/**
* Removes flow rules for floating ip configuration.
*
* @param floatingIP Corresponding floating ip information
*/
public void removeFloatingIpRules(OpenstackFloatingIP floatingIP, OpenstackPortInfo portInfo) {
TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(portInfo.vni())
.matchIPSrc(IpPrefix.valueOf(portInfo.ip(), 32));
sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), 32));
removeRule(getGatewayNode().id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
removeRule(getGatewayNode().id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
}
}
......
......@@ -19,6 +19,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.web.OpenstackPortCodec;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.onosproject.openstacknetworking.OpenstackRoutingService;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
......@@ -42,7 +44,7 @@ import java.io.InputStream;
public class OpenstackPortWebResource extends AbstractWebResource {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String PORTNAME_PREFIX_VM = "tap";
private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec();
@POST
......@@ -75,7 +77,14 @@ public class OpenstackPortWebResource extends AbstractWebResource {
public Response deletePorts(@PathParam("portUUID") String id) {
OpenstackSwitchingService switchingService =
getService(OpenstackSwitchingService.class);
OpenstackPortInfo portInfo = switchingService.openstackPortInfo()
.get(PORTNAME_PREFIX_VM.concat(id.substring(0, 11)));
OpenstackRoutingService routingService =
getService(OpenstackRoutingService.class);
routingService.checkDisassociatedFloatingIp(id, portInfo);
switchingService.removePort(id);
return Response.status(Response.Status.OK).build();
}
......