From 65723ae236821e71f12ba1a23c3ed1d47ab44e7f Mon Sep 17 00:00:00 2001 From: sanghoshin Date: Tue, 17 Nov 2015 22:07:21 +0900 Subject: [PATCH] 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 --- .../OpenstackSwitchingService.java | 5 +- apps/openstackswitching/app/pom.xml | 3 + .../OpenstackSwitchingManager.java | 157 +++++++++++++----- .../OpenstackSwitchingRulePopulator.java | 58 ++++++- .../web/OpenstackPortWebResource.java | 9 +- apps/openstackswitching/network-cfg.json | 12 ++ 6 files changed, 194 insertions(+), 50 deletions(-) diff --git a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java index 59b8db0c67..be566f0754 100644 --- a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java +++ b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java @@ -35,13 +35,14 @@ public interface OpenstackSwitchingService { * 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. * + * @param openstackPort */ - void updatePorts(); + void updatePort(OpenstackPort openstackPort); /** * Stores the network information created by openstack. diff --git a/apps/openstackswitching/app/pom.xml b/apps/openstackswitching/app/pom.xml index 7d26f8f2d0..719b049782 100644 --- a/apps/openstackswitching/app/pom.xml +++ b/apps/openstackswitching/app/pom.xml @@ -40,6 +40,9 @@ org.onosproject.openstackswitching.web SKT, Inc. + + org.onosproject.dhcp + diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java index 5a19ed0b7f..b5e0df3d02 100644 --- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java +++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java @@ -25,11 +25,14 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.packet.Ethernet; import org.onlab.packet.Ip4Address; +import org.onlab.packet.IpAddress; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.dhcp.DhcpService; +import org.onosproject.event.AbstractEvent; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; import org.onosproject.net.Port; import org.onosproject.net.config.ConfigFactory; import org.onosproject.net.config.NetworkConfigEvent; @@ -39,7 +42,16 @@ 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.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.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.PacketContext; import org.onosproject.net.packet.PacketProcessor; @@ -48,6 +60,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Collection; +import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -75,6 +88,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected DeviceService deviceService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected FlowObjectiveService flowObjectiveService; @@ -87,6 +103,8 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected DriverService driverService; + protected FlowRuleService flowRuleService; + private ApplicationId appId; private boolean doNotPushFlows; private Ip4Address neutronServer; @@ -101,6 +119,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor(); private InternalDeviceListener internalDeviceListener = new InternalDeviceListener(); private InternalConfigListener internalConfigListener = new InternalConfigListener(); + private InternalHostListener internalHostListener = new InternalHostListener(); private final Set factories = ImmutableSet.of( new ConfigFactory(APP_SUBJECT_FACTORY, OpenstackSwitchingConfig.class, @@ -120,6 +139,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { factories.forEach(cfgService::registerConfigFactory); packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1)); deviceService.addListener(internalDeviceListener); + hostService.addListener(internalHostListener); cfgService.addListener(internalConfigListener); internalConfigListener.configureNetwork(); @@ -132,6 +152,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { packetService.removeProcessor(internalPacketProcessor); deviceService.removeListener(internalDeviceListener); cfgService.removeListener(internalConfigListener); + factories.forEach(cfgService::unregisterConfigFactory); deviceEventExcutorService.shutdown(); @@ -144,13 +165,12 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { } @Override - public void deletePorts() { + public void deletePort(String uuid) { } @Override - public void updatePorts() { - + public void updatePort(OpenstackPort openstackPort) { } @Override @@ -201,7 +221,8 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { } 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 = new OpenstackSwitchingRulePopulator(appId, flowObjectiveService, deviceService, restHandler, driverService); @@ -210,7 +231,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { } private void processPortRemoved(Device device, Port port) { - // TODO: Remove flow rules for the VM removed 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) { Ip4Address ip4Address; 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 { @Override @@ -311,46 +383,56 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { private class InternalEventHandler implements Runnable { - volatile DeviceEvent deviceEvent; + volatile AbstractEvent event; - InternalEventHandler(DeviceEvent deviceEvent) { - this.deviceEvent = deviceEvent; + InternalEventHandler(AbstractEvent event) { + this.event = event; } @Override public void run() { - if (doNotPushFlows) { - return; - } + if (event instanceof DeviceEvent) { + DeviceEvent deviceEvent = (DeviceEvent) event; - switch (deviceEvent.type()) { - case DEVICE_ADDED: - processDeviceAdded((Device) deviceEvent.subject()); - break; - case DEVICE_UPDATED: - Port port = (Port) deviceEvent.subject(); - if (port.isEnabled()) { + switch (deviceEvent.type()) { + case DEVICE_ADDED: + processDeviceAdded((Device) deviceEvent.subject()); + break; + case DEVICE_UPDATED: + Port port = (Port) deviceEvent.subject(); + if (port.isEnabled()) { + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + } + break; + case DEVICE_AVAILABILITY_CHANGED: + Device device = (Device) deviceEvent.subject(); + if (deviceService.isAvailable(device.id())) { + processDeviceAdded(device); + } + break; + case PORT_ADDED: processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); - } - break; - case DEVICE_AVAILABILITY_CHANGED: - Device device = (Device) deviceEvent.subject(); - if (deviceService.isAvailable(device.id())) { - processDeviceAdded(device); - } - break; - case PORT_ADDED: - processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); - break; - case PORT_UPDATED: - processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); - break; - case PORT_REMOVED: - processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port()); - break; - default: - break; + break; + case PORT_UPDATED: + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + break; + case PORT_REMOVED: + processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port()); + break; + default: + 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; } } - } \ No newline at end of file diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java index ed89479fbe..8d5c780b3f 100644 --- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java +++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java @@ -130,6 +130,21 @@ public class OpenstackSwitchingRulePopulator { .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. * @@ -170,9 +185,10 @@ public class OpenstackSwitchingRulePopulator { Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]); MacAddress vmMacx = getVmMacAddressForPort(pName); Ip4Address fixedIpx = getFixedIpAddressForPort(pName); - - setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx); - setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac); + if (port.isEnabled()) { + setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx); + setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac); + } } }); } @@ -246,7 +262,7 @@ public class OpenstackSwitchingRulePopulator { .findFirst().orElse(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; } @@ -341,6 +357,40 @@ public class OpenstackSwitchingRulePopulator { 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) { Driver driver = driverService.getDriver(id); DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id)); diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java index faffa732c6..261128da43 100644 --- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java +++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java @@ -28,6 +28,7 @@ import javax.ws.rs.DELETE; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -68,12 +69,9 @@ public class OpenstackPortWebResource extends AbstractWebResource { } } + @Path("{portUUID}") @DELETE - @Path("{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response deletesPorts(InputStream input) { - log.debug("REST API ports is called with {}", input.toString()); + public Response deletePorts(@PathParam("portUUID") String id) { return Response.status(Response.Status.OK).build(); } @@ -82,7 +80,6 @@ public class OpenstackPortWebResource extends AbstractWebResource { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response updatePorts(InputStream input) { - log.info("REST API ports is called with {}", input.toString()); return Response.status(Response.Status.OK).build(); } } diff --git a/apps/openstackswitching/network-cfg.json b/apps/openstackswitching/network-cfg.json index abcd2d15a8..c185d55cbe 100644 --- a/apps/openstackswitching/network-cfg.json +++ b/apps/openstackswitching/network-cfg.json @@ -32,19 +32,31 @@ "nodes" : [ { "hostname" : "compute-01", +<<<<<<< HEAD "ovsdbIp" : "10.40.101.208", +======= + "ovsdbIp" : "127.0.0.1", +>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows "ovsdbPort" : "6640", "bridgeId" : "of:0000000000000001" }, { "hostname" : "compute-02", +<<<<<<< HEAD "ovsdbIp" : "10.40.101.227", +======= + "ovsdbIp" : "127.0.0.1", +>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows "ovsdbPort" : "6640", "bridgeId" : "of:0000000000000002" }, { "hostname" : "network", +<<<<<<< HEAD "ovsdbIp" : "10.40.101.209", +======= + "ovsdbIp" : "127.0.0.1", +>>>>>>> 6a78e2e... SONA: OpenstackSwitching - remove flows "ovsdbPort" : "6640", "bridgeId" : "of:0000000000000003" }