SONA: OpenstackSwitching - remove flows

- Remove the corresponding flows when VMs are removed.
 - Remove the IP mapping of the VM removed from the DHCP service (even when doNotPushFlows is true)
 - Updated the network config json file to reflect the change of cordvtn
Change-Id: I4c359d456422ece37b93e6366f2fd4daaf081a37
This commit is contained in:
sanghoshin 2015-11-17 22:07:21 +09:00
parent 00e4ee2714
commit 65723ae236
6 changed files with 194 additions and 50 deletions

View File

@ -35,13 +35,14 @@ public interface OpenstackSwitchingService {
* Removes flow rules corresponding to the port removed by Openstack. * Removes flow rules corresponding to the port removed by Openstack.
* *
*/ */
void deletePorts(); void deletePort(String uuid);
/** /**
* Updates flow rules corresponding to the port information updated by Openstack. * Updates flow rules corresponding to the port information updated by Openstack.
* *
* @param openstackPort
*/ */
void updatePorts(); void updatePort(OpenstackPort openstackPort);
/** /**
* Stores the network information created by openstack. * Stores the network information created by openstack.

View File

@ -40,6 +40,9 @@
</api.description> </api.description>
<api.package>org.onosproject.openstackswitching.web</api.package> <api.package>org.onosproject.openstackswitching.web</api.package>
<onos.app.origin>SKT, Inc.</onos.app.origin> <onos.app.origin>SKT, Inc.</onos.app.origin>
<onos.app.requires>
org.onosproject.dhcp
</onos.app.requires>
</properties> </properties>

View File

@ -25,11 +25,14 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service; import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet; import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId; import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService; import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DhcpService; import org.onosproject.dhcp.DhcpService;
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.Device; import org.onosproject.net.Device;
import org.onosproject.net.DeviceId; import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port; import org.onosproject.net.Port;
import org.onosproject.net.config.ConfigFactory; import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent; import org.onosproject.net.config.NetworkConfigEvent;
@ -39,7 +42,16 @@ import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService; import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverService; import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.net.packet.InboundPacket; import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketProcessor;
@ -48,6 +60,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
import java.util.Collection; import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -75,6 +88,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService; protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService; protected FlowObjectiveService flowObjectiveService;
@ -87,6 +103,8 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService; protected DriverService driverService;
protected FlowRuleService flowRuleService;
private ApplicationId appId; private ApplicationId appId;
private boolean doNotPushFlows; private boolean doNotPushFlows;
private Ip4Address neutronServer; private Ip4Address neutronServer;
@ -101,6 +119,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor(); private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
private InternalDeviceListener internalDeviceListener = new InternalDeviceListener(); private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
private InternalConfigListener internalConfigListener = new InternalConfigListener(); private InternalConfigListener internalConfigListener = new InternalConfigListener();
private InternalHostListener internalHostListener = new InternalHostListener();
private final Set<ConfigFactory> factories = ImmutableSet.of( private final Set<ConfigFactory> factories = ImmutableSet.of(
new ConfigFactory<ApplicationId, OpenstackSwitchingConfig>(APP_SUBJECT_FACTORY, new ConfigFactory<ApplicationId, OpenstackSwitchingConfig>(APP_SUBJECT_FACTORY,
OpenstackSwitchingConfig.class, OpenstackSwitchingConfig.class,
@ -120,6 +139,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
factories.forEach(cfgService::registerConfigFactory); factories.forEach(cfgService::registerConfigFactory);
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1)); packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
deviceService.addListener(internalDeviceListener); deviceService.addListener(internalDeviceListener);
hostService.addListener(internalHostListener);
cfgService.addListener(internalConfigListener); cfgService.addListener(internalConfigListener);
internalConfigListener.configureNetwork(); internalConfigListener.configureNetwork();
@ -132,6 +152,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
packetService.removeProcessor(internalPacketProcessor); packetService.removeProcessor(internalPacketProcessor);
deviceService.removeListener(internalDeviceListener); deviceService.removeListener(internalDeviceListener);
cfgService.removeListener(internalConfigListener); cfgService.removeListener(internalConfigListener);
factories.forEach(cfgService::unregisterConfigFactory);
deviceEventExcutorService.shutdown(); deviceEventExcutorService.shutdown();
@ -144,13 +165,12 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
} }
@Override @Override
public void deletePorts() { public void deletePort(String uuid) {
} }
@Override @Override
public void updatePorts() { public void updatePort(OpenstackPort openstackPort) {
} }
@Override @Override
@ -201,7 +221,8 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
} }
private void processPortAdded(Device device, Port port) { private void processPortAdded(Device device, Port port) {
if (!port.annotations().value("portName").equals("vxlan")) { if (!port.annotations().value("portName").equals("vxlan")
&& port.isEnabled() && !doNotPushFlows) {
OpenstackSwitchingRulePopulator rulePopulator = OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService, new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, restHandler, driverService); deviceService, restHandler, driverService);
@ -210,7 +231,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
} }
private void processPortRemoved(Device device, Port port) { private void processPortRemoved(Device device, Port port) {
// TODO: Remove flow rules for the VM removed
log.debug("port {} is removed", port.toString()); log.debug("port {} is removed", port.toString());
} }
@ -238,6 +258,50 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
); );
} }
private void processHostRemoved(Host host) {
log.debug("host {} was removed", host.toString());
try {
if (!doNotPushFlows) {
IpAddress hostIp = host.ipAddresses().stream().
filter(ip -> ip.isIp4()).findAny().orElse(null);
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, restHandler, driverService);
rulePopulator.removeSwitchingRules(host.location().deviceId(),
hostIp.getIp4Address());
}
dhcpService.removeStaticMapping(host.mac());
} catch (NoSuchElementException e) {
log.error("No IP address is assigned.");
}
}
private long getVniFromFlowRules(DeviceId deviceId, Ip4Address hostIp) {
for (FlowEntry flowEntry: flowRuleService.getFlowEntries(deviceId)) {
Criterion c = flowEntry.selector().getCriterion(Criterion.Type.IPV4_DST);
if (c != null) {
IPCriterion destIpCriterion = (IPCriterion) c;
if (destIpCriterion.ip().getIp4Prefix().address().equals(hostIp)) {
for (Instruction i : flowEntry.treatment().immediate()) {
if (i.type().equals(Instruction.Type.L2MODIFICATION)) {
L2ModificationInstruction l2m = (L2ModificationInstruction) i;
if (l2m.subtype().equals(L2ModificationInstruction.L2SubType.TUNNEL_ID)) {
L2ModificationInstruction.ModTunnelIdInstruction setTunnelInstr =
(L2ModificationInstruction.ModTunnelIdInstruction) l2m;
return setTunnelInstr.tunnelId();
}
}
}
}
}
}
return 0;
}
private void registerDhcpInfo(OpenstackPort openstackPort) { private void registerDhcpInfo(OpenstackPort openstackPort) {
Ip4Address ip4Address; Ip4Address ip4Address;
Ip4Address subnetMask; Ip4Address subnetMask;
@ -301,6 +365,14 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
} }
} }
private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent hostEvent) {
deviceEventExcutorService.execute(new InternalEventHandler(hostEvent));
}
}
private class InternalDeviceListener implements DeviceListener { private class InternalDeviceListener implements DeviceListener {
@Override @Override
@ -311,18 +383,17 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
private class InternalEventHandler implements Runnable { private class InternalEventHandler implements Runnable {
volatile DeviceEvent deviceEvent; volatile AbstractEvent event;
InternalEventHandler(DeviceEvent deviceEvent) { InternalEventHandler(AbstractEvent event) {
this.deviceEvent = deviceEvent; this.event = event;
} }
@Override @Override
public void run() { public void run() {
if (doNotPushFlows) { if (event instanceof DeviceEvent) {
return; DeviceEvent deviceEvent = (DeviceEvent) event;
}
switch (deviceEvent.type()) { switch (deviceEvent.type()) {
case DEVICE_ADDED: case DEVICE_ADDED:
@ -352,6 +423,17 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
default: default:
break; break;
} }
} else if (event instanceof HostEvent) {
HostEvent hostEvent = (HostEvent) event;
switch (hostEvent.type()) {
case HOST_REMOVED:
processHostRemoved((Host) hostEvent.subject());
break;
default:
break;
}
}
} }
} }
@ -395,5 +477,4 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
this.hostIp = hostIp; this.hostIp = hostIp;
} }
} }
} }

View File

@ -130,6 +130,21 @@ public class OpenstackSwitchingRulePopulator {
.findAny().orElse(null); .findAny().orElse(null);
} }
/**
* Remove flows rules for the VM removed.
*
* @param deviceId device to remove rules
* @param vmIp IP address of the VM removed
*/
public void removeSwitchingRules(DeviceId deviceId, Ip4Address vmIp) {
removeFlowRuleForVMsInSameCnode(deviceId, vmIp);
deviceService.getAvailableDevices().forEach(device -> {
if (!device.id().equals(deviceId)) {
removeVxLanFlowRule(device.id(), vmIp);
}
});
}
/** /**
* Populates the flow rules for traffic to VMs in the same Cnode as the sender. * Populates the flow rules for traffic to VMs in the same Cnode as the sender.
* *
@ -170,10 +185,11 @@ public class OpenstackSwitchingRulePopulator {
Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]); Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]);
MacAddress vmMacx = getVmMacAddressForPort(pName); MacAddress vmMacx = getVmMacAddressForPort(pName);
Ip4Address fixedIpx = getFixedIpAddressForPort(pName); Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
if (port.isEnabled()) {
setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx); setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx);
setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac); setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac);
} }
}
}); });
} }
}); });
@ -246,7 +262,7 @@ public class OpenstackSwitchingRulePopulator {
.findFirst().orElse(null); .findFirst().orElse(null);
if (port == null) { if (port == null) {
log.error("There is port information for port name {}", portName); log.error("There is no port information for port name {}", portName);
return null; return null;
} }
@ -341,6 +357,40 @@ public class OpenstackSwitchingRulePopulator {
flowObjectiveService.forward(id, fo); flowObjectiveService.forward(id, fo);
} }
private void removeFlowRuleForVMsInSameCnode(DeviceId id, Ip4Address vmIp) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(vmIp.toIpPrefix());
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(DefaultTrafficTreatment.builder().build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(SWITCHING_RULE_PRIORITY)
.fromApp(appId)
.remove();
flowObjectiveService.forward(id, fo);
}
private void removeVxLanFlowRule(DeviceId id, Ip4Address vmIp) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
// XXX: Later, more matches will be added when multiple table is implemented.
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(vmIp.toIpPrefix());
ForwardingObjective fo = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(DefaultTrafficTreatment.builder().build())
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(SWITCHING_RULE_PRIORITY)
.fromApp(appId)
.remove();
flowObjectiveService.forward(id, fo);
}
private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) { private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
Driver driver = driverService.getDriver(id); Driver driver = driverService.getDriver(id);
DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id)); DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));

View File

@ -28,6 +28,7 @@ import javax.ws.rs.DELETE;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -68,12 +69,9 @@ public class OpenstackPortWebResource extends AbstractWebResource {
} }
} }
@Path("{portUUID}")
@DELETE @DELETE
@Path("{id}") public Response deletePorts(@PathParam("portUUID") String id) {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deletesPorts(InputStream input) {
log.debug("REST API ports is called with {}", input.toString());
return Response.status(Response.Status.OK).build(); return Response.status(Response.Status.OK).build();
} }
@ -82,7 +80,6 @@ public class OpenstackPortWebResource extends AbstractWebResource {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response updatePorts(InputStream input) { public Response updatePorts(InputStream input) {
log.info("REST API ports is called with {}", input.toString());
return Response.status(Response.Status.OK).build(); return Response.status(Response.Status.OK).build();
} }
} }

View File

@ -32,19 +32,31 @@
"nodes" : [ "nodes" : [
{ {
"hostname" : "compute-01", "hostname" : "compute-01",
<<<<<<< HEAD
"ovsdbIp" : "10.40.101.208", "ovsdbIp" : "10.40.101.208",
=======
"ovsdbIp" : "127.0.0.1",
>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows
"ovsdbPort" : "6640", "ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000001" "bridgeId" : "of:0000000000000001"
}, },
{ {
"hostname" : "compute-02", "hostname" : "compute-02",
<<<<<<< HEAD
"ovsdbIp" : "10.40.101.227", "ovsdbIp" : "10.40.101.227",
=======
"ovsdbIp" : "127.0.0.1",
>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows
"ovsdbPort" : "6640", "ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000002" "bridgeId" : "of:0000000000000002"
}, },
{ {
"hostname" : "network", "hostname" : "network",
<<<<<<< HEAD
"ovsdbIp" : "10.40.101.209", "ovsdbIp" : "10.40.101.209",
=======
"ovsdbIp" : "127.0.0.1",
>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows
"ovsdbPort" : "6640", "ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000003" "bridgeId" : "of:0000000000000003"
} }