initial impl of proxy arp
Change-Id: I131667e8051e88c27f5fa020b580be57fee358ea
diff --git a/core/api/src/main/java/org/onlab/onos/net/proxyarp/ProxyArpService.java b/core/api/src/main/java/org/onlab/onos/net/proxyarp/ProxyArpService.java
new file mode 100644
index 0000000..e6fe43b
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/proxyarp/ProxyArpService.java
@@ -0,0 +1,29 @@
+package org.onlab.onos.net.proxyarp;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Service for processing arp requests on behalf of applications.
+ */
+public interface ProxyArpService {
+
+ /**
+ * Returns whether this particular ip address is known to the system.
+ *
+ * @param addr
+ * a ip address
+ * @return true if know, false otherwise
+ */
+ boolean known(IpPrefix addr);
+
+ /**
+ * Sends a reply for a given request. If the host is not known then the arp
+ * will be flooded at all edge ports.
+ *
+ * @param request
+ * an arp request
+ */
+ void reply(Ethernet request);
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/proxyarp/package-info.java b/core/api/src/main/java/org/onlab/onos/net/proxyarp/package-info.java
new file mode 100644
index 0000000..4917c6e
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/proxyarp/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Base abstractions related to the proxy arp service.
+ */
+package org.onlab.onos.net.proxyarp;
\ No newline at end of file
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index fe146aa..1d90fd3 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -45,9 +45,9 @@
*/
@Component(immediate = true)
@Service
-public class DeviceManager
-extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
-implements DeviceService, DeviceAdminService, DeviceProviderRegistry {
+public class DeviceManager extends
+ AbstractProviderRegistry<DeviceProvider, DeviceProviderService> implements
+ DeviceService, DeviceAdminService, DeviceProviderRegistry {
private static final String DEVICE_ID_NULL = "Device ID cannot be null";
private static final String PORT_NUMBER_NULL = "Port number cannot be null";
@@ -57,8 +57,7 @@
private final Logger log = getLogger(getClass());
- protected final AbstractListenerRegistry<DeviceEvent, DeviceListener>
- listenerRegistry = new AbstractListenerRegistry<>();
+ protected final AbstractListenerRegistry<DeviceEvent, DeviceListener> listenerRegistry = new AbstractListenerRegistry<>();
private final DeviceStoreDelegate delegate = new InternalStoreDelegate();
@@ -169,28 +168,31 @@
}
@Override
- protected DeviceProviderService createProviderService(DeviceProvider provider) {
+ protected DeviceProviderService createProviderService(
+ DeviceProvider provider) {
return new InternalDeviceProviderService(provider);
}
// Personalized device provider service issued to the supplied provider.
- private class InternalDeviceProviderService
- extends AbstractProviderService<DeviceProvider>
- implements DeviceProviderService {
+ private class InternalDeviceProviderService extends
+ AbstractProviderService<DeviceProvider> implements
+ DeviceProviderService {
InternalDeviceProviderService(DeviceProvider provider) {
super(provider);
}
@Override
- public void deviceConnected(DeviceId deviceId, DeviceDescription deviceDescription) {
+ public void deviceConnected(DeviceId deviceId,
+ DeviceDescription deviceDescription) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL);
checkValidity();
DeviceEvent event = store.createOrUpdateDevice(provider().id(),
deviceId, deviceDescription);
- // If there was a change of any kind, trigger role selection process.
+ // If there was a change of any kind, trigger role selection
+ // process.
if (event != null) {
log.info("Device {} connected", deviceId);
mastershipService.requestRoleFor(deviceId);
@@ -212,25 +214,30 @@
}
@Override
- public void updatePorts(DeviceId deviceId, List<PortDescription> portDescriptions) {
+ public void updatePorts(DeviceId deviceId,
+ List<PortDescription> portDescriptions) {
checkNotNull(deviceId, DEVICE_ID_NULL);
- checkNotNull(portDescriptions, "Port descriptions list cannot be null");
+ checkNotNull(portDescriptions,
+ "Port descriptions list cannot be null");
checkValidity();
- List<DeviceEvent> events = store.updatePorts(deviceId, portDescriptions);
+ List<DeviceEvent> events = store.updatePorts(deviceId,
+ portDescriptions);
for (DeviceEvent event : events) {
post(event);
}
}
@Override
- public void portStatusChanged(DeviceId deviceId, PortDescription portDescription) {
+ public void portStatusChanged(DeviceId deviceId,
+ PortDescription portDescription) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(portDescription, PORT_DESCRIPTION_NULL);
checkValidity();
- DeviceEvent event = store.updatePortStatus(deviceId, portDescription);
+ DeviceEvent event = store.updatePortStatus(deviceId,
+ portDescription);
if (event != null) {
- log.info("Device {} port {} status changed", deviceId,
- event.port().number());
+ log.info("Device {} port {} status changed", deviceId, event
+ .port().number());
post(event);
}
}
@@ -238,8 +245,8 @@
@Override
public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
// FIXME: implement response to this notification
- log.warn("Failed to assert role [{}] onto Device {}",
- role, deviceId);
+ log.warn("Failed to assert role [{}] onto Device {}", role,
+ deviceId);
}
}
@@ -255,7 +262,8 @@
@Override
public void event(MastershipEvent event) {
if (event.master().equals(clusterService.getLocalNode().id())) {
- MastershipTerm term = mastershipService.requestTermService().getMastershipTerm(event.subject());
+ MastershipTerm term = mastershipService.requestTermService()
+ .getMastershipTerm(event.subject());
clockService.setMastershipTerm(event.subject(), term);
applyRole(event.subject(), MastershipRole.MASTER);
} else {
diff --git a/core/net/src/main/java/org/onlab/onos/proxyarp/impl/ProxyArpManager.java b/core/net/src/main/java/org/onlab/onos/proxyarp/impl/ProxyArpManager.java
new file mode 100644
index 0000000..f267f68
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/proxyarp/impl/ProxyArpManager.java
@@ -0,0 +1,100 @@
+package org.onlab.onos.proxyarp.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.nio.ByteBuffer;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.Host;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.packet.DefaultOutboundPacket;
+import org.onlab.onos.net.packet.PacketService;
+import org.onlab.onos.net.proxyarp.ProxyArpService;
+import org.onlab.onos.net.topology.TopologyService;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+
+public class ProxyArpManager implements ProxyArpService {
+
+ private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
+ private static final String REQUEST_NULL = "Arp request cannot be null.";
+ private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
+ private static final String NOT_ARP_REQUEST = "ARP is not a request.";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TopologyService topologyService;
+
+ @Override
+ public boolean known(IpPrefix addr) {
+ checkNotNull(MAC_ADDR_NULL, addr);
+ Set<Host> hosts = hostService.getHostsByIp(addr);
+ return !hosts.isEmpty();
+ }
+
+ @Override
+ public void reply(Ethernet request) {
+ checkNotNull(REQUEST_NULL, request);
+ checkArgument(request.getEtherType() == Ethernet.TYPE_ARP,
+ REQUEST_NOT_ARP);
+ ARP arp = (ARP) request.getPayload();
+ checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
+
+ VlanId vlan = VlanId.vlanId(request.getVlanID());
+ Set<Host> hosts = hostService.getHostsByIp(IpPrefix.valueOf(arp
+ .getTargetProtocolAddress()));
+
+ Host h = null;
+ for (Host host : hosts) {
+ if (host.vlan().equals(vlan)) {
+ h = host;
+ break;
+ }
+ }
+
+ if (h == null) {
+ flood(request);
+ return;
+ }
+
+ Ethernet arpReply = buildArpReply(h, request);
+ // TODO: check send status with host service.
+ TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder();
+ builder.setOutput(h.location().port());
+ packetService.emit(new DefaultOutboundPacket(h.location().deviceId(),
+ builder.build(), ByteBuffer.wrap(arpReply.serialize())));
+ }
+
+ private void flood(Ethernet request) {
+ // TODO: flood on all edge ports.
+ }
+
+ private Ethernet buildArpReply(Host h, Ethernet request) {
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(request.getSourceMACAddress());
+ eth.setSourceMACAddress(h.mac().getAddress());
+ eth.setEtherType(Ethernet.TYPE_ARP);
+ ARP arp = new ARP();
+ arp.setOpCode(ARP.OP_REPLY);
+ arp.setSenderHardwareAddress(h.mac().getAddress());
+ arp.setTargetHardwareAddress(request.getSourceMACAddress());
+
+ arp.setTargetProtocolAddress(((ARP) request.getPayload())
+ .getSenderProtocolAddress());
+ arp.setSenderProtocolAddress(h.ipAddresses().iterator().next().toInt());
+ eth.setPayload(arp);
+ return eth;
+ }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/proxyarp/impl/package-info.java b/core/net/src/main/java/org/onlab/onos/proxyarp/impl/package-info.java
new file mode 100644
index 0000000..a9ad72a
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/proxyarp/impl/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Core subsystem for responding to arp requests.
+ */
+package org.onlab.onos.proxyarp.impl;
\ No newline at end of file
diff --git a/tools/test/bin/onos-start-network b/tools/test/bin/onos-start-network
new file mode 100755
index 0000000..c8245ab
--- /dev/null
+++ b/tools/test/bin/onos-start-network
@@ -0,0 +1,17 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Verifies connectivity to each node in ONOS cell.
+#-------------------------------------------------------------------------------
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+SSHCMD="ssh -o PasswordAuthentication=no"
+SCPCMD="scp -q -o PasswordAuthentication=no"
+
+echo "Copying topology files to mininet vm."
+$SSHCMD -n $ONOS_USER@$OCN mkdir -p topos
+$SCPCMD $ONOS_ROOT/tools/test/topos/* $ONOS_USER@$OCN:topos/
+
+echo "Starting Network."
+$SSHCMD -t $ONOS_USER@$OCN sudo python topos/sol.py $(env | sort | egrep "OC[0-9]+" | cut -d= -f2)