Added a REST API to the Proxy ARP module to inspect the ARP cache
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index c70a2ea..a698fd5 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -40,6 +40,7 @@
import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
+import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
import net.onrc.onos.ofcontroller.routing.TopoRouteService;
import net.onrc.onos.ofcontroller.util.DataPath;
@@ -76,7 +77,8 @@
public class BgpRoute implements IFloodlightModule, IBgpRouteService,
ITopologyListener, IArpRequester,
- IOFSwitchListener, ILayer3InfoService {
+ IOFSwitchListener, ILayer3InfoService,
+ IProxyArpService {
protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
@@ -232,6 +234,7 @@
Map<Class<? extends IFloodlightService>, IFloodlightService> m
= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
m.put(IBgpRouteService.class, this);
+ m.put(IProxyArpService.class, this);
return m;
}
@@ -262,7 +265,7 @@
//TODO We'll initialise this here for now, but it should really be done as
//part of the controller core
- proxyArp = new ProxyArpManager(floodlightProvider, topology, this);
+ proxyArp = new ProxyArpManager(floodlightProvider, topology, this, restApi);
linkUpdates = new ArrayList<LDUpdate>();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -1298,4 +1301,27 @@
public MACAddress getRouterMacAddress() {
return bgpdMacAddress;
}
+
+ /*
+ * TODO This is a hack to get the REST API to work for ProxyArpManager.
+ * The REST API is currently tied to the Floodlight module system and we
+ * need to separate it to allow ONOS modules to use it. For now we will
+ * proxy calls through to the ProxyArpManager (which is not a Floodlight
+ * module) through this class which is a module.
+ */
+ @Override
+ public MACAddress getMacAddress(InetAddress ipAddress) {
+ return proxyArp.getMacAddress(ipAddress);
+ }
+
+ @Override
+ public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
+ boolean retry) {
+ proxyArp.sendArpRequest(ipAddress, requester, retry);
+ }
+
+ @Override
+ public List<String> getMappings() {
+ return proxyArp.getMappings();
+ }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java
index 4af4b05..83a3b55 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCache.java
@@ -1,7 +1,9 @@
package net.onrc.onos.ofcontroller.proxyarp;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import net.floodlightcontroller.util.MACAddress;
@@ -20,10 +22,10 @@
* don't do this which means the cache memory size will never decrease. We already
* have a periodic thread that can be used to do this in ProxyArpManager.
*/
-public class ArpCache {
+class ArpCache {
private final static Logger log = LoggerFactory.getLogger(ArpCache.class);
- private final long ARP_ENTRY_TIMEOUT = 60000; //ms (1 min)
+ private final static long ARP_ENTRY_TIMEOUT = 60000; //ms (1 min)
//Protected by locking on the ArpCache object
private final Map<InetAddress, ArpCacheEntry> arpCache;
@@ -40,29 +42,28 @@
public MACAddress getMacAddress() {
return macAddress;
}
-
- public long getTimeLastSeen() {
- return timeLastSeen;
- }
public void setTimeLastSeen(long time){
timeLastSeen = time;
}
+
+ public boolean isExpired() {
+ return System.currentTimeMillis() - timeLastSeen > ARP_ENTRY_TIMEOUT;
+ }
}
- public ArpCache() {
+ ArpCache() {
arpCache = new HashMap<InetAddress, ArpCacheEntry>();
}
- public synchronized MACAddress lookup(InetAddress ipAddress){
+ synchronized MACAddress lookup(InetAddress ipAddress){
ArpCacheEntry arpEntry = arpCache.get(ipAddress);
if (arpEntry == null){
return null;
}
- if (System.currentTimeMillis() - arpEntry.getTimeLastSeen()
- > ARP_ENTRY_TIMEOUT){
+ if (arpEntry.isExpired()) {
//Entry has timed out so we'll remove it and return null
log.trace("Removing expired ARP entry for {}", ipAddress.getHostAddress());
@@ -73,7 +74,7 @@
return arpEntry.getMacAddress();
}
- public synchronized void update(InetAddress ipAddress, MACAddress macAddress){
+ synchronized void update(InetAddress ipAddress, MACAddress macAddress){
ArpCacheEntry arpEntry = arpCache.get(ipAddress);
if (arpEntry != null && arpEntry.getMacAddress().equals(macAddress)){
@@ -83,4 +84,16 @@
arpCache.put(ipAddress, new ArpCacheEntry(macAddress));
}
}
+
+ synchronized List<String> getMappings() {
+ List<String> result = new ArrayList<String>(arpCache.size());
+
+ for (Map.Entry<InetAddress, ArpCacheEntry> entry : arpCache.entrySet()) {
+ result.add(entry.getKey().getHostAddress() + " => " +
+ entry.getValue().getMacAddress().toString() +
+ (entry.getValue().isExpired()?" : EXPIRED":" : VALID"));
+ }
+
+ return result;
+ }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java
new file mode 100644
index 0000000..252e66e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpCacheResource.java
@@ -0,0 +1,18 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import java.util.List;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+public class ArpCacheResource extends ServerResource {
+
+ @Get("json")
+ public List<String> getArpCache() {
+ IProxyArpService arp = (IProxyArpService) getContext().getAttributes().
+ get(IProxyArpService.class.getCanonicalName());
+
+ return arp.getMappings();
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java
new file mode 100644
index 0000000..eefa2db
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpWebRoutable.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+public class ArpWebRoutable implements RestletRoutable {
+
+ @Override
+ public Restlet getRestlet(Context context) {
+ Router router = new Router(context);
+ router.attach("/cache/json", ArpCacheResource.class);
+ return router;
+ }
+
+ @Override
+ public String basePath() {
+ return "/wm/arp";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
index 2c5dd72..97844d3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
@@ -1,10 +1,13 @@
package net.onrc.onos.ofcontroller.proxyarp;
import java.net.InetAddress;
+import java.util.List;
+import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.util.MACAddress;
-public interface IProxyArpService {
+//Extends IFloodlightService so we can access it from REST API resources
+public interface IProxyArpService extends IFloodlightService{
/**
* Returns the MAC address if there is a valid entry in the cache.
* Otherwise returns null.
@@ -22,4 +25,10 @@
*/
public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
boolean retry);
+
+ /**
+ * Returns a snapshot of the entire ARP cache.
+ * @return
+ */
+ public List<String> getMappings();
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 10aa87a..31cc4fc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -19,6 +19,7 @@
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.ofcontroller.bgproute.ILayer3InfoService;
@@ -39,7 +40,6 @@
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
-//TODO REST API to inspect ARP table
public class ProxyArpManager implements IProxyArpService, IOFMessageListener {
private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
@@ -50,6 +50,7 @@
private final IFloodlightProviderService floodlightProvider;
private final ITopologyService topology;
private final ILayer3InfoService layer3;
+ private final IRestApiService restApi;
private final ArpCache arpCache;
@@ -103,10 +104,12 @@
}
public ProxyArpManager(IFloodlightProviderService floodlightProvider,
- ITopologyService topology, ILayer3InfoService layer3){
+ ITopologyService topology, ILayer3InfoService layer3,
+ IRestApiService restApi){
this.floodlightProvider = floodlightProvider;
this.topology = topology;
this.layer3 = layer3;
+ this.restApi = restApi;
arpCache = new ArpCache();
@@ -115,6 +118,8 @@
}
public void startUp() {
+ restApi.addRestletRoutable(new ArpWebRoutable());
+
Timer arpTimer = new Timer("arp-processing");
arpTimer.scheduleAtFixedRate(new TimerTask() {
@Override
@@ -552,4 +557,9 @@
sendArpRequestForAddress(ipAddress);
}
}
+
+ @Override
+ public List<String> getMappings() {
+ return arpCache.getMappings();
+ }
}