package edu.wisc.cs.sdn.apps.loadbalancer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.wisc.cs.sdn.apps.l3routing.IL3Routing;
import edu.wisc.cs.sdn.apps.util.ArpServer;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.ImmutablePort;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.util.MACAddress;
public class LoadBalancer implements IFloodlightModule, IOFSwitchListener,
IOFMessageListener
public static final String MODULE_NAME = LoadBalancer.class.getSimpleName();
private static final byte TCP_FLAG_SYN = 0x02;
private static final short IDLE_TIMEOUT = 20;
// Interface to the logging system
private static Logger log = LoggerFactory.getLogger(MODULE_NAME);
// Interface to Floodlight core for interacting with connected switches
private IFloodlightProviderService floodlightProv;
// Interface to device manager service
private IDeviceService deviceProv;
// Interface to L3Routing application
private IL3Routing l3RoutingApp;
// Switch table in which rules should be installed
private byte table;
// Set of virtual IPs and the load balancer instances they correspond with
private Map
* Loads dependencies and initializes data structures.
public void init(FloodlightModuleContext context)
throws FloodlightModuleException
log.info(String.format(“Initializing %s…”, MODULE_NAME));
// Obtain table number from config
Map
this.table = Byte.parseByte(config.get(“table”));
// Create instances from config
this.instances = new HashMap
String[] instanceConfigs = config.get(“instances”).split(“;”);
for (String instanceConfig : instanceConfigs)
String[] configItems = instanceConfig.split(” “);
if (configItems.length != 3)
log.error(“Ignoring bad instance config: ” + instanceConfig);
LoadBalancerInstance instance = new LoadBalancerInstance(
configItems[0], configItems[1], configItems[2].split(“,”));
this.instances.put(instance.getVirtualIP(), instance);
log.info(“Added load balancer instance: ” + instance);
this.floodlightProv = context.getServiceImpl(
IFloodlightProviderService.class);
this.deviceProv = context.getServiceImpl(IDeviceService.class);
this.l3RoutingApp = context.getServiceImpl(IL3Routing.class);
/*********************************************************************/
/* TODO: Initialize other class variables, if necessary */
/*********************************************************************/
* Subscribes to events and performs other startup tasks.
public void startUp(FloodlightModuleContext context)
throws FloodlightModuleException
log.info(String.format(“Starting %s…”, MODULE_NAME));
this.floodlightProv.addOFSwitchListener(this);
this.floodlightProv.addOFMessageListener(OFType.PACKET_IN, this);
/*********************************************************************/
/* TODO: Perform other tasks, if necessary */
/*********************************************************************/
* Event handler called when a switch joins the network.
* @param DPID for the switch
public void switchAdded(long switchId)
IOFSwitch sw = this.floodlightProv.getSwitch(switchId);
log.info(String.format(“Switch s%d added”, switchId));
/*********************************************************************/
/* TODO: Install rules to send: */
/* (1) packets from new connections to each virtual load */
/* balancer IP to the controller */
/* (2) ARP packets to the controller, and */
/* (3) all other packets to the next rule table in the switch */
/*********************************************************************/
* Handle incoming packets sent from switches.
* @param sw switch on which the packet was received
* @param msg message from the switch
* @param cntx the Floodlight context in which the message should be handled
* @return indication whether another module should also process the packet
public net.floodlightcontroller.core.IListener.Command receive(
IOFSwitch sw, OFMessage msg, FloodlightContext cntx)
// We’re only interested in packet-in messages
if (msg.getType() != OFType.PACKET_IN)
{ return Command.CONTINUE; }
OFPacketIn pktIn = (OFPacketIn)msg;
// Handle the packet
Ethernet ethPkt = new Ethernet();
ethPkt.deserialize(pktIn.getPacketData(), 0,
pktIn.getPacketData().length);
/*********************************************************************/
/* TODO: Send an ARP reply for ARP requests for virtual IPs; for TCP */
/* SYNs sent to a virtual IP, select a host and install */
/* connection-specific rules to rewrite IP and MAC addresses; */
/* for all other TCP packets sent to a virtual IP, send a TCP */
/* reset; ignore all other packets */
/*********************************************************************/
return Command.CONTINUE;
* Returns the MAC address for a host, given the host’s IP address.
* @param hostIPAddress the host’s IP address
* @return the hosts’s MAC address, null if unknown
private byte[] getHostMACAddress(int hostIPAddress)
Iterator extends IDevice> iterator = this.deviceProv.queryDevices(
null, null, hostIPAddress, null, null);
if (!iterator.hasNext())
{ return null; }
IDevice device = iterator.next();
return MACAddress.valueOf(device.getMACAddress()).toBytes();
* Event handler called when a switch leaves the network.
* @param DPID for the switch
public void switchRemoved(long switchId)
{ /* Nothing we need to do, since the switch is no longer active */ }
* Event handler called when the controller becomes the master for a switch.
* @param DPID for the switch
public void switchActivated(long switchId)
{ /* Nothing we need to do, since we’re not switching controller roles */ }
* Event handler called when a port on a switch goes up or down, or is
* added or removed.
* @param DPID for the switch
* @param port the port on the switch whose status changed
* @param type the type of status change (up, down, add, remove)
public void switchPortChanged(long switchId, ImmutablePort port,
PortChangeType type)
{ /* Nothing we need to do, since load balancer rules are port-agnostic */}
* Event handler called when some attribute of a switch changes.
* @param DPID for the switch
public void switchChanged(long switchId)
{ /* Nothing we need to do */ }
* Tell the module system which services we provide.
public Collection
{ return null; }
* Tell the module system which services we implement.
public Map
getServiceImpls()
{ return null; }
* Tell the module system which modules we depend on.
public Collection
getModuleDependencies()
Collection
new ArrayList
floodlightService.add(IFloodlightProviderService.class);
floodlightService.add(IDeviceService.class);
return floodlightService;
* Gets a name for this module.
* @return name for this module
public String getName()
{ return MODULE_NAME; }
* Check if events must be passed to another module before this module is
* notified of the event.
public boolean isCallbackOrderingPrereq(OFType type, String name)
return (OFType.PACKET_IN == type
&& (name.equals(ArpServer.MODULE_NAME)
|| name.equals(DeviceManagerImpl.MODULE_NAME)));
* Check if events must be passed to another module after this module has
* been notified of the event.
public boolean isCallbackOrderingPostreq(OFType type, String name)
{ return false; }