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
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 59b8db0..be566f0 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 @@
* 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 7d26f8f..719b049 100644
--- a/apps/openstackswitching/app/pom.xml
+++ b/apps/openstackswitching/app/pom.xml
@@ -40,6 +40,9 @@
</api.description>
<api.package>org.onosproject.openstackswitching.web</api.package>
<onos.app.origin>SKT, Inc.</onos.app.origin>
+ <onos.app.requires>
+ org.onosproject.dhcp
+ </onos.app.requires>
</properties>
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 5a19ed0..b5e0df3 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.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.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.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;
@@ -76,6 +89,9 @@
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -87,6 +103,8 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
+ protected FlowRuleService flowRuleService;
+
private ApplicationId appId;
private boolean doNotPushFlows;
private Ip4Address neutronServer;
@@ -101,6 +119,7 @@
private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
private InternalConfigListener internalConfigListener = new InternalConfigListener();
+ private InternalHostListener internalHostListener = new InternalHostListener();
private final Set<ConfigFactory> factories = ImmutableSet.of(
new ConfigFactory<ApplicationId, OpenstackSwitchingConfig>(APP_SUBJECT_FACTORY,
OpenstackSwitchingConfig.class,
@@ -120,6 +139,7 @@
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 @@
packetService.removeProcessor(internalPacketProcessor);
deviceService.removeListener(internalDeviceListener);
cfgService.removeListener(internalConfigListener);
+ factories.forEach(cfgService::unregisterConfigFactory);
deviceEventExcutorService.shutdown();
@@ -144,13 +165,12 @@
}
@Override
- public void deletePorts() {
+ public void deletePort(String uuid) {
}
@Override
- public void updatePorts() {
-
+ public void updatePort(OpenstackPort openstackPort) {
}
@Override
@@ -201,7 +221,8 @@
}
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 @@
}
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 @@
);
}
+ 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 @@
}
}
+ 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 @@
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 @@
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 ed89479..8d5c780 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
@@ -131,6 +131,21 @@
}
/**
+ * 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.
*
* @param device device to put the rules
@@ -170,9 +185,10 @@
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 @@
.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 @@
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 faffa73..261128d 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.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 @@
}
}
+ @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 @@
@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 abcd2d1..c185d55 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"
}