ONOS-5182 Refactored SONA to cache network states
Change-Id: Ib316fa5fa5d36e9da370a1578ac55de4a8dd9b04
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index b4ae36c..2a980d3 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -25,64 +25,97 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
+import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.util.Tools;
-import org.onosproject.net.Host;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+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.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortService;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+import org.openstack4j.model.network.Subnet;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import java.nio.ByteBuffer;
import java.util.Dictionary;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.openstacknetworking.api.Constants.*;
+import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
+import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
/**
* Handles ARP packet from VMs.
*/
@Component(immediate = true)
-public final class OpenstackSwitchingArpHandler extends AbstractVmHandler {
+public final class OpenstackSwitchingArpHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String GATEWAY_MAC = "gatewayMac";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackInterfaceService openstackService;
+ protected ComponentConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected InstancePortService instancePortService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNetworkService osNetworkService;
@Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
label = "Fake MAC address for virtual network subnet gateway")
private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
- private final Set<Ip4Address> gateways = Sets.newConcurrentHashSet();
+ private final InternalOpenstackNetworkListener osNetworkListener =
+ new InternalOpenstackNetworkListener();
+ private final Set<IpAddress> gateways = Sets.newConcurrentHashSet();
+
+ private ApplicationId appId;
@Activate
protected void activate() {
+ appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
+ configService.registerProperties(getClass());
+ osNetworkService.addListener(osNetworkListener);
packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
- super.activate();
+ osNetworkService.subnets().forEach(this::addSubnetGateway);
+ requestPacket();
+
+ log.info("Started");
}
@Deactivate
protected void deactivate() {
packetService.removeProcessor(packetProcessor);
- super.deactivate();
+ osNetworkService.removeListener(osNetworkListener);
+ configService.unregisterProperties(getClass(), false);
+
+ log.info("Stopped");
}
@Modified
@@ -98,12 +131,41 @@
log.info("Modified");
}
+ private void requestPacket() {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+ .build();
+
+ packetService.requestPackets(
+ selector,
+ PacketPriority.CONTROL,
+ appId);
+ }
+
+ private void addSubnetGateway(Subnet osSubnet) {
+ if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
+ return;
+ }
+ IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
+ gateways.add(gatewayIp);
+ log.debug("Added ARP proxy entry IP:{}", gatewayIp);
+ }
+
+ private void removeSubnetGateway(Subnet osSubnet) {
+ if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
+ return;
+ }
+ IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
+ gateways.remove(gatewayIp);
+ log.debug("Removed ARP proxy entry IP:{}", gatewayIp);
+ }
+
/**
* Processes ARP request packets.
* It checks if the target IP is owned by a known host first and then ask to
* OpenStack if it's not. This ARP proxy does not support overlapping IP.
*
- * @param context packet context
+ * @param context packet context
* @param ethPacket ethernet packet
*/
private void processPacketIn(PacketContext context, Ethernet ethPacket) {
@@ -112,15 +174,18 @@
return;
}
- Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
- MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
- getMacFromHostService(targetIp);
- if (replyMac.equals(MacAddress.NONE)) {
- replyMac = getMacFromOpenstack(targetIp);
+ InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
+ if (srcInstPort == null) {
+ log.trace("Failed to find source instance port(MAC:{})",
+ ethPacket.getSourceMAC());
+ return;
}
+ IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
+ MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
+ getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
if (replyMac == MacAddress.NONE) {
- log.debug("Failed to find MAC address for {}", targetIp.toString());
+ log.trace("Failed to find MAC address for {}", targetIp);
return;
}
@@ -141,66 +206,24 @@
/**
* Returns MAC address of a host with a given target IP address by asking to
- * OpenStack. It does not support overlapping IP.
- *
- * @param targetIp target ip address
- * @return mac address, or null if it fails to fetch the mac
- */
- private MacAddress getMacFromOpenstack(IpAddress targetIp) {
- checkNotNull(targetIp);
-
- OpenstackPort openstackPort = openstackService.ports()
- .stream()
- .filter(port -> port.fixedIps().containsValue(targetIp.getIp4Address()))
- .findFirst()
- .orElse(null);
-
- if (openstackPort != null) {
- log.debug("Found MAC from OpenStack for {}", targetIp.toString());
- return openstackPort.macAddress();
- } else {
- return MacAddress.NONE;
- }
- }
-
- /**
- * Returns MAC address of a host with a given target IP address by asking to
- * host service. It does not support overlapping IP.
+ * instance port service.
*
* @param targetIp target ip
- * @return mac address, or null if it fails to find the mac
+ * @param osNetId openstack network id of the source instance port
+ * @return mac address, or none mac address if it fails to find the mac
*/
- private MacAddress getMacFromHostService(IpAddress targetIp) {
+ private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
checkNotNull(targetIp);
- Host host = hostService.getHostsByIp(targetIp)
- .stream()
- .findFirst()
- .orElse(null);
-
- if (host != null) {
- log.debug("Found MAC from host service for {}", targetIp.toString());
- return host.mac();
+ InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
+ if (instPort != null) {
+ log.trace("Found MAC from host service for {}", targetIp);
+ return instPort.macAddress();
} else {
return MacAddress.NONE;
}
}
- @Override
- protected void hostDetected(Host host) {
- OpenstackNetwork osNet = openstackService.network(host.annotations().value(NETWORK_ID));
- if (osNet == null) {
- log.warn("Failed to get OpenStack network for {}", host);
- return;
- }
- osNet.subnets().forEach(subnet -> gateways.add(Ip4Address.valueOf(subnet.gatewayIp())));
- }
-
- @Override
- protected void hostRemoved(Host host) {
- // TODO remove subnet gateway from gateways if no hosts exists on that subnet
- }
-
private class InternalPacketProcessor implements PacketProcessor {
@Override
@@ -216,4 +239,38 @@
processPacketIn(context, ethPacket);
}
}
+
+ private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
+
+ @Override
+ public boolean isRelevant(OpenstackNetworkEvent event) {
+ Subnet osSubnet = event.subnet();
+ if (osSubnet == null) {
+ return false;
+ }
+ return !Strings.isNullOrEmpty(osSubnet.getGateway());
+ }
+
+ @Override
+ public void event(OpenstackNetworkEvent event) {
+ switch (event.type()) {
+ case OPENSTACK_SUBNET_CREATED:
+ case OPENSTACK_SUBNET_UPDATED:
+ addSubnetGateway(event.subnet());
+ break;
+ case OPENSTACK_SUBNET_REMOVED:
+ removeSubnetGateway(event.subnet());
+ break;
+ case OPENSTACK_NETWORK_CREATED:
+ case OPENSTACK_NETWORK_UPDATED:
+ case OPENSTACK_NETWORK_REMOVED:
+ case OPENSTACK_PORT_CREATED:
+ case OPENSTACK_PORT_UPDATED:
+ case OPENSTACK_PORT_REMOVED:
+ default:
+ // do nothing for the other events
+ break;
+ }
+ }
+ }
}