Skip to content
Snippets Groups Projects
Commit bf51f820 authored by Rob Adams's avatar Rob Adams
Browse files

Add device service rest API

parent 53ba1577
No related branches found
No related tags found
No related merge requests found
......@@ -25,9 +25,11 @@ import java.util.EnumSet;
import java.util.Iterator;
import java.util.TreeSet;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.openflow.util.HexString;
import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField;
import net.floodlightcontroller.devicemanager.web.DeviceSerializer;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IEntityClass;
import net.floodlightcontroller.devicemanager.SwitchPort;
......@@ -37,6 +39,7 @@ import net.floodlightcontroller.topology.ITopologyService;
* Concrete implementation of {@link IDevice}
* @author readams
*/
@JsonSerialize(using=DeviceSerializer.class)
public class Device implements IDevice {
protected Long deviceKey;
protected DeviceManagerImpl deviceManager;
......
......@@ -41,7 +41,6 @@ import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IInfoProvider;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
......@@ -51,15 +50,16 @@ import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.devicemanager.IEntityClass;
import net.floodlightcontroller.devicemanager.IEntityClassifier;
import net.floodlightcontroller.devicemanager.IDeviceListener;
import net.floodlightcontroller.devicemanager.web.DeviceRoutable;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.DHCP;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.packet.UDP;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.storage.IStorageSourceService;
import net.floodlightcontroller.storage.IStorageSourceListener;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.topology.ITopologyListener;
import net.floodlightcontroller.util.MultiIterator;
import static net.floodlightcontroller.devicemanager.internal.
DeviceManagerImpl.DeviceUpdate.Change.*;
......@@ -67,7 +67,6 @@ import static net.floodlightcontroller.devicemanager.internal.
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPhysicalPort;
import org.openflow.protocol.OFPortStatus;
import org.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -80,7 +79,6 @@ import org.slf4j.LoggerFactory;
*/
public class DeviceManagerImpl implements
IDeviceService, IOFMessageListener,
IOFSwitchListener, ITopologyListener,
IStorageSourceListener, IFloodlightModule,
IInfoProvider {
protected static Logger logger =
......@@ -89,6 +87,7 @@ public class DeviceManagerImpl implements
protected IFloodlightProviderService floodlightProvider;
protected ITopologyService topology;
protected IStorageSourceService storageSource;
protected IRestApiService restApi;
/**
* Time in milliseconds before entities will expire
......@@ -436,9 +435,6 @@ public class DeviceManagerImpl implements
case PACKET_IN:
return this.processPacketInMessage(sw,
(OFPacketIn) msg, cntx);
case PORT_STATUS:
return this.processPortStatusMessage(sw,
(OFPortStatus) msg);
}
logger.error("received an unexpected message {} from switch {}",
......@@ -462,31 +458,6 @@ public class DeviceManagerImpl implements
}
// *****************
// ITopologyListener
// *****************
@Override
public void toplogyChanged() {
// TODO Auto-generated method stub
}
// *****************
// IOFSwitchListener
// *****************
@Override
public void addedSwitch(IOFSwitch sw) {
// TODO Auto-generated method stub
}
@Override
public void removedSwitch(IOFSwitch sw) {
// TODO Auto-generated method stub
}
// *****************
// IFloodlightModule
// *****************
......@@ -518,6 +489,7 @@ public class DeviceManagerImpl implements
l.add(IFloodlightProviderService.class);
l.add(IStorageSourceService.class);
l.add(ITopologyService.class);
l.add(IRestApiService.class);
return l;
}
......@@ -535,6 +507,8 @@ public class DeviceManagerImpl implements
fmc.getServiceImpl(IStorageSourceService.class);
this.topology =
fmc.getServiceImpl(ITopologyService.class);
this.restApi = fmc.getServiceImpl(IRestApiService.class);
}
@Override
......@@ -580,17 +554,8 @@ public class DeviceManagerImpl implements
return r;
}
};
if (topology != null) {
// Register to get updates from topology
topology.addListener(this);
} else {
logger.error("Could not add topology listener");
}
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
floodlightProvider.addOFSwitchListener(this);
Runnable ecr = new Runnable() {
@Override
......@@ -605,16 +570,17 @@ public class DeviceManagerImpl implements
entityCleanupTask = new SingletonTask(ses, ecr);
entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL,
TimeUnit.SECONDS);
if (restApi != null) {
restApi.addRestletRoutable(new DeviceRoutable());
} else {
logger.error("Could not instantiate REST API");
}
}
// ****************
// Internal methods
// ****************
protected Command processPortStatusMessage(IOFSwitch sw, OFPortStatus ps) {
// XXX - TODO
return null;
}
/**
* This method is called for every packet-in and should be optimized for
......@@ -1045,6 +1011,7 @@ public class DeviceManagerImpl implements
break;
case DELETE:
listener.deviceRemoved(update.device);
break;
case CHANGE:
for (DeviceField field : update.fieldsChanged) {
switch (field) {
......
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.devicemanager.web;
import java.util.Iterator;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.packet.IPv4;
import org.openflow.util.HexString;
import org.restlet.data.Form;
import org.restlet.data.Status;
import org.restlet.resource.ServerResource;
/**
* Resource for querying and displaying devices that exist in the system
*/
public abstract class AbstractDeviceResource extends ServerResource {
public static final String MAC_ERROR =
"Invalid MAC address: must be a 48-bit quantity, " +
"expressed in hex as AA:BB:CC:DD:EE:FF";
public static final String VLAN_ERROR =
"Invalid VLAN: must be an integer in the range 0-4095";
public static final String IPV4_ERROR =
"Invalid IPv4 address: must be in dotted decimal format, " +
"234.0.59.1";
public static final String DPID_ERROR =
"Invalid Switch DPID: must be a 64-bit quantity, expressed in " +
"hex as AA:BB:CC:DD:EE:FF:00:11";
public static final String PORT_ERROR =
"Invalid Port: must be a positive integer";
public Iterator<? extends IDevice> getDevices() {
IDeviceService deviceManager =
(IDeviceService)getContext().getAttributes().
get(IDeviceService.class.getCanonicalName());
Long macAddress = null;
Short vlan = null;
Integer ipv4Address = null;
Long switchDPID = null;
Integer switchPort = null;
Form form = getQuery();
String macAddrStr = form.getFirstValue("mac", true);
String vlanStr = form.getFirstValue("vlan", true);
String ipv4Str = form.getFirstValue("ipv4", true);
String dpid = form.getFirstValue("dpid", true);
String port = form.getFirstValue("port", true);
if (macAddrStr != null) {
try {
macAddress = HexString.toLong(macAddrStr);
} catch (Exception e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, MAC_ERROR);
return null;
}
}
if (vlanStr != null) {
try {
vlan = Short.parseShort(vlanStr);
if (vlan > 4095 || vlan < 0) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR);
return null;
}
} catch (Exception e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR);
return null;
}
}
if (ipv4Str != null) {
try {
ipv4Address = IPv4.toIPv4Address(ipv4Str);
} catch (Exception e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, IPV4_ERROR);
return null;
}
}
if (dpid != null) {
try {
switchDPID = HexString.toLong(dpid);
} catch (Exception e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR);
return null;
}
}
if (port != null) {
try {
switchPort = Integer.parseInt(port);
if (switchPort < 0) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR);
return null;
}
} catch (Exception e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR);
return null;
}
}
Iterator<? extends IDevice> diter =
deviceManager.queryDevices(macAddress,
vlan,
ipv4Address,
switchDPID,
switchPort);
return diter;
}
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.devicemanager.web;
import java.util.Iterator;
import net.floodlightcontroller.devicemanager.IDevice;
import org.restlet.resource.Get;
/**
* Resource for querying and displaying devices that exist in the system
*/
public class DeviceResource extends AbstractDeviceResource {
public static final String MAC_ERROR =
"Invalid MAC address: must be a 48-bit quantity, " +
"expressed in hex as AA:BB:CC:DD:EE:FF";
public static final String VLAN_ERROR =
"Invalid VLAN: must be an integer in the range 0-4095";
public static final String IPV4_ERROR =
"Invalid IPv4 address: must be in dotted decimal format, " +
"234.0.59.1";
public static final String DPID_ERROR =
"Invalid Switch DPID: must be a 64-bit quantity, expressed in " +
"hex as AA:BB:CC:DD:EE:FF:00:11";
public static final String PORT_ERROR =
"Invalid Port: must be a positive integer";
@Get("json")
public Iterator<? extends IDevice> getDevices() {
return super.getDevices();
}
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.devicemanager.web;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import net.floodlightcontroller.restserver.RestletRoutable;
/**
* Routable for device rest api
*/
public class DeviceRoutable implements RestletRoutable {
@Override
public String basePath() {
return "/wm/device";
}
@Override
public Restlet getRestlet(Context context) {
Router router = new Router(context);
router.attach("/", DeviceResource.class);
return router;
}
}
/**
* Copyright 2012 Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.devicemanager.web;
import java.io.IOException;
import net.floodlightcontroller.devicemanager.SwitchPort;
import net.floodlightcontroller.devicemanager.internal.Device;
import net.floodlightcontroller.packet.IPv4;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.openflow.util.HexString;
/**
* Serialize a device object
*/
public class DeviceSerializer extends JsonSerializer<Device> {
@Override
public void serialize(Device device, JsonGenerator jGen,
SerializerProvider serializer) throws IOException,
JsonProcessingException {
jGen.writeStartObject();
jGen.writeArrayFieldStart("mac");
jGen.writeString(HexString.toHexString(device.getMACAddress(), 6));
jGen.writeEndArray();
jGen.writeArrayFieldStart("ipv4");
for (Integer ip : device.getIPv4Addresses())
jGen.writeString(IPv4.fromIPv4Address(ip));
jGen.writeEndArray();
jGen.writeArrayFieldStart("vlan");
for (Short ip : device.getVlanId())
if (ip >= 0)
jGen.writeNumber(ip);
jGen.writeEndArray();
jGen.writeArrayFieldStart("attachmentPoint");
for (SwitchPort ap : device.getAttachmentPoints()) {
jGen.writeStartObject();
jGen.writeStringField("dpid",
HexString.toHexString(ap.getSwitchDPID(), 8));
jGen.writeNumberField("port", ap.getPort());
jGen.writeEndObject();
}
jGen.writeEndArray();
jGen.writeEndObject();
}
}
......@@ -14,9 +14,13 @@ import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.ext.jackson.JacksonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.routing.Filter;
import org.restlet.routing.Router;
import org.restlet.routing.Template;
import org.restlet.service.StatusService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -73,6 +77,15 @@ public class RestApiServer
}
public void run(FloodlightModuleContext fmlContext, int restPort) {
setStatusService(new StatusService() {
@Override
public Representation getRepresentation(Status status,
Request request,
Response response) {
return new JacksonRepresentation<Status>(status);
}
});
// Add everything in the module context to the rest
for (Class<? extends IFloodlightService> s : fmlContext.getAllServices()) {
context.getAttributes().put(s.getCanonicalName(),
......
......@@ -632,62 +632,4 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
deviceManager.readPortChannelConfigFromStorage();
}
*/
/**
* The same test as testAttachmentPointFlapping except for port-channel
* @throws Exception
*/
@Test
public void testPortChannel() throws Exception {
fail();
/*
OFPhysicalPort port1 = new OFPhysicalPort();
OFPhysicalPort port2 = new OFPhysicalPort();
port1.setName("port1");
port2.setName("port2");
setupPortChannel();
byte[] dataLayerSource = ((Ethernet)this.testPacket).getSourceMACAddress();
// Mock up our expected behavior
IOFSwitch mockSwitch = createMock(IOFSwitch.class);
expect(mockSwitch.getPort((short)1)).andReturn(port1).anyTimes();
expect(mockSwitch.getPort((short)2)).andReturn(port2).anyTimes();
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
expect(mockSwitch.getStringId()).andReturn("00:00:00:00:00:00:00:01").anyTimes();
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isInternal(1L, (short)1))
.andReturn(false).atLeastOnce();
expect(mockTopology.isInternal(1L, (short)2))
.andReturn(false).atLeastOnce();
deviceManager.setTopology(mockTopology);
// Start recording the replay on the mocks
replay(mockSwitch, mockTopology);
// Get the listener and trigger the packet in
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn);
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn.setInPort((short)2));
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn.setInPort((short)1));
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn.setInPort((short)2));
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn.setInPort((short)1));
mockFloodlightProvider.dispatchMessage(mockSwitch, this.packetIn.setInPort((short)2));
Device device = deviceManager.getDeviceByDataLayerAddress(dataLayerSource);
// Verify the replay matched our expectations
verify(mockSwitch, mockTopology);
// Verify the device
assertEquals(device.getAttachmentPoints().size(), 1);
assertEquals(device.getOldAttachmentPoints().size(), 1);
for (DeviceAttachmentPoint ap : device.getOldAttachmentPoints()) {
assertFalse(ap.isBlocked());
}
// Reset the device cache
deviceManager.clearAllDeviceStateFromMemory();
teardownPortChannel();
*/
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment