import org.slf4j.LoggerFactory;
/**
- * This class is the main class that represents the load balancer service.
- * This is a sample load balancer application that balances traffic to backend servers
- * based on the source address and source port on each incoming packet. The service
+ * This class is the main class that represents the load balancer service.
+ * This is a sample load balancer application that balances traffic to backend servers
+ * based on the source address and source port on each incoming packet. The service
* reactively installs OpenFlow rules to direct all packets with a specific source address
- * and source port to one of the appropriate backend servers. The servers may be chosen
- * using a round robin policy or a random policy. This service can be configured via a
+ * and source port to one of the appropriate backend servers. The servers may be chosen
+ * using a round robin policy or a random policy. This service can be configured via a
* REST APIs which are similar to the OpenStack Quantum LBaaS (Load-balancer-as-a-Service)
* v1.0 API proposal (http://wiki.openstack.org/Quantum/LBaaS)
- *
+ *
* To use this service, a virtual IP (or VIP) should be exposed to the clients of this service
* and used as the destination address. A VIP is a entity that comprises of a virtual IP, port
* and protocol (TCP or UDP).
* Assumptions:
* 1. One or more VIPs may be mapped to the same server pool. All VIPs that share the same
* pool must also share the same load balancing policy (random or round robin).
- *
+ *
* 2. Only one server pool can be be assigned to a VIP.
- *
+ *
* 3. All flow rules are installed with an idle timeout of 5 seconds.
- *
+ *
* 4. Packets to a VIP must leave the OpenFlow cluster from the same switch from where
* it entered it.
- *
+ *
* 5. When you delete a VIP or a server pool or a server from a pool, the service does not
* delete the flow rules it has already installed. The flow rules should automatically
- * time out after the idle timeout of 5 seconds.
+ * time out after the idle timeout of 5 seconds.
*
*/
public class LoadBalancerService implements IListenDataPacket, IConfigManager{
-
+
/*
* Logger instance
*/
private static Logger lbsLogger = LoggerFactory.getLogger(LoadBalancerService.class);
-
+
/*
* Single instance of the configuration manager. Application passes this reference to all
* the new policies implemented for load balancing.
*/
private static ConfigManager configManager = new ConfigManager();
-
+
/*
* Round robing policy instance. Need to implement factory patterns to get
* policy instance.
*/
private static RoundRobinLBPolicy rrLBMethod= new RoundRobinLBPolicy(configManager);
-
+
/*
* Random policy instance.
*/
private static RandomLBPolicy ranLBMethod= new RandomLBPolicy(configManager);
-
+
/*
* Reference to the data packet service
*/
private IDataPacketService dataPacketService = null;
-
+
/*
* Reference to the host tracker service
*/
private IfIptoHost hostTracker;
-
+
/*
* Reference to the forwarding manager
*/
private IForwardingRulesManager ruleManager;
-
+
/*
* Reference to the routing service
*/
private IRouting routing;
-
+
/*
* Load balancer application installs all flows with priority 2.
*/
private String containerName = null;
/*
- * Set/unset methods for the service instance that load balancer
+ * Set/unset methods for the service instance that load balancer
* service requires
*/
public String getContainerName() {
return GlobalConstants.DEFAULT.toString();
return containerName;
}
-
+
void setDataPacketService(IDataPacketService s) {
this.dataPacketService = s;
}
this.dataPacketService = null;
}
}
-
+
public void setRouting(IRouting routing) {
this.routing = routing;
}
}
public void setHostTracker(IfIptoHost hostTracker) {
- lbsLogger.debug("Setting HostTracker");
+ lbsLogger.debug("Setting HostTracker");
this.hostTracker = hostTracker;
}
public void setForwardingRulesManager(
IForwardingRulesManager forwardingRulesManager) {
- lbsLogger.debug("Setting ForwardingRulesManager");
+ lbsLogger.debug("Setting ForwardingRulesManager");
this.ruleManager = forwardingRulesManager;
}
/**
* This method receives first packet of flows for which there is no
- * matching flow rule installed on the switch. IP addresses used for VIPs
+ * matching flow rule installed on the switch. IP addresses used for VIPs
* are not supposed to be used by any real/virtual host in the network.
* Hence, any forwarding/routing service will not install any flows rules matching
* these VIPs. This ensures that all the flows destined for VIPs will not find a match
* in the switch and will be forwarded to the load balancing service.
- * Service will decide where to route this traffic based on the load balancing
- * policy of the VIP's attached pool and will install appropriate flow rules
- * in a reactive manner.
+ * Service will decide where to route this traffic based on the load balancing
+ * policy of the VIP's attached pool and will install appropriate flow rules
+ * in a reactive manner.
*/
@Override
public PacketResult receiveDataPacket(RawPacket inPkt){
-
+
if (inPkt == null) {
return PacketResult.IGNORED;
}
-
+
Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
-
+
if (formattedPak instanceof Ethernet) {
byte[] vipMacAddr = ((Ethernet) formattedPak).getDestinationMACAddress();
Object ipPkt = formattedPak.getPayload();
-
+
if (ipPkt instanceof IPv4) {
-
+
lbsLogger.debug("Packet recieved from switch : {}",inPkt.getIncomingNodeConnector().getNode().toString());
IPv4 ipv4Pkt = (IPv4)ipPkt;
if(IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.TCP.toString())
|| IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.UDP.toString())){
-
+
lbsLogger.debug("Packet protocol : {}",IPProtocols.getProtocolName(ipv4Pkt.getProtocol()));
Client client = new LBUtil().getClientFromPacket(ipv4Pkt);
VIP vip = new LBUtil().getVIPFromPacket(ipv4Pkt);
-
+
if(configManager.vipExists(vip)){
VIP vipWithPoolName = configManager.getVIPWithPoolName(vip);
String poolMemberIp = null;
if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.ROUND_ROBIN_LB_METHOD)){
-
+
poolMemberIp = rrLBMethod.getPoolMemberForClient(client,vipWithPoolName);
}
-
+
if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.RANDOM_LB_METHOD)){
poolMemberIp = ranLBMethod.getPoolMemberForClient(client,vipWithPoolName);
}
-
+
try {
-
+
Node clientNode = inPkt.getIncomingNodeConnector().getNode();
HostNodeConnector hnConnector = this.hostTracker.hostFind(InetAddress.getByName(poolMemberIp));
-
+
Node destNode = hnConnector.getnodeconnectorNode();
-
+
lbsLogger.debug("Client is connected to switch : {}",clientNode.toString());
lbsLogger.debug("Destination pool machine is connected to switch : {}",destNode.toString());
-
+
//Get path between both the nodes
Path route = this.routing.getRoute(clientNode, destNode);
-
+
lbsLogger.info("Path between source (client) and destination switch nodes : {}",route.toString());
-
+
NodeConnector forwardPort = route.getEdges().get(0).getTailNodeConnector();
-
+
if(installLoadBalancerFlow(client,
vip,
clientNode,
}else{
lbsLogger.error("Not able to route traffic from client : {}",client );
}
-
+
if(installLoadBalancerFlow(client,
vip,
clientNode,
}
return PacketResult.IGNORED;
}
-
+
/*
* This method installs the flow rule for routing the traffic between two hosts.
* @param source Traffic is sent by this source
* @param destMachineMac MAC address of the pool member where traffic needs to be routed
* @param outport Use this port to send out traffic
* @param flowDirection FORWARD_DIRECTION_LB_FLOW or REVERSE_DIRECTION_LB_FLOW
- * @return true If flow installation was successful
- * false else
+ * @return true If flow installation was successful
+ * false else
* @throws UnknownHostException
*/
private boolean installLoadBalancerFlow(Client source,
VIP dest,
Node sourceSwitch,
String destMachineIp,
- byte[] destMachineMac,
+ byte[] destMachineMac,
NodeConnector outport,
int flowDirection) throws UnknownHostException{
-
+
Match match = new Match();
List<Action> actions = new ArrayList<Action>();
-
+
if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){
match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
match.setField(MatchType.NW_SRC, InetAddress.getByName(source.getIp()));
match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(dest.getProtocol()));
match.setField(MatchType.TP_SRC, source.getPort());
match.setField(MatchType.TP_DST, dest.getPort());
-
+
actions.add(new SetNwDst(InetAddress.getByName(destMachineIp)));
actions.add(new SetDlDst(destMachineMac));
}
-
+
if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){
match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
match.setField(MatchType.NW_SRC, InetAddress.getByName(destMachineIp));
match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(source.getProtocol()));
match.setField(MatchType.TP_SRC, dest.getPort());
match.setField(MatchType.TP_DST,source.getPort());
-
+
actions.add(new SetNwSrc(InetAddress.getByName(dest.getIp())));
actions.add(new SetDlSrc(destMachineMac));
}
-
+
actions.add(new Output(outport));
-
+
// Make sure the priority for IP switch entries is
// set to a level just above default drop entries
-
+
Flow flow = new Flow(match, actions);
flow.setIdleTimeout((short) 5);
flow.setHardTimeout((short) 0);
flow.setPriority(LB_IPSWITCH_PRIORITY);
-
+
String policyName = source.getIp()+":"+source.getProtocol()+":"+source.getPort();
String flowName =null;
-
+
if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){
flowName = "["+policyName+":"+source.getIp() + ":"+dest.getIp()+"]";
}
-
+
if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){
-
+
flowName = "["+policyName+":"+dest.getIp() + ":"+source.getIp()+"]";
}
-
+
FlowEntry fEntry = new FlowEntry(policyName, flowName, flow, sourceSwitch);
-
+
lbsLogger.info("Install flow entry {} on node {}",fEntry.toString(),sourceSwitch.toString());
-
+
if(!this.ruleManager.checkFlowEntryConflict(fEntry)){
if(this.ruleManager.installFlowEntry(fEntry).isSuccess()){
return true;
}
return false;
}
-
+
/**
* Function called by the dependency manager when all the required
* dependencies are satisfied
Dictionary<?, ?> props = c.getServiceProperties();
if (props != null) {
this.containerName = (String) props.get("containerName");
-
+
lbsLogger.info("Running container name:" + this.containerName);
}else {
-
+
// In the Global instance case the containerName is empty
this.containerName = "";
}
lbsLogger.info(configManager.toString());
}
-
+
/**
* Function called by the dependency manager when at least one
* dependency become unsatisfied or when the component is shutting
/*
* All the methods below are just proxy methods to direct the REST API requests to configuration
- * manager. We need this redirection as currently, opendaylight supports only one
- * implementation of the service.
+ * manager. We need this redirection as currently, opendaylight supports only one
+ * implementation of the service.
*/
@Override
public Set<VIP> getAllVIPs() {
return configManager.getAllVIPs();
}
-
+
@Override
public boolean vipExists(String name, String ip, String protocol,
short protocolPort, String poolName) {
return configManager.vipExists(name, ip, protocol, protocolPort, poolName);
}
-
+
@Override
public boolean vipExists(VIP vip) {
return configManager.vipExists(vip);
}
-
+
@Override
public VIP createVIP(String name, String ip, String protocol,
short protocolPort, String poolName) {
return configManager.createVIP(name, ip, protocol, protocolPort, poolName);
}
-
+
@Override
public VIP updateVIP(String name, String poolName) {
return configManager.updateVIP(name, poolName);
}
-
+
@Override
public VIP deleteVIP(String name) {
return configManager.deleteVIP(name);
}
-
+
@Override
public boolean memberExists(String name, String memberIP, String poolName) {
return configManager.memberExists(name, memberIP, poolName);
}
-
+
@Override
public Set<PoolMember> getAllPoolMembers(String poolName) {
-
+
return configManager.getAllPoolMembers(poolName);
}
-
+
@Override
- public PoolMember addPoolMember(String name,
+ public PoolMember addPoolMember(String name,
String memberIP,
String poolName) {
return configManager.addPoolMember(name, memberIP, poolName);
}
-
+
@Override
public PoolMember removePoolMember(String name, String poolName) {
-
+
return configManager.removePoolMember(name, poolName);
}
-
+
@Override
public Set<Pool> getAllPools() {
-
+
return configManager.getAllPools();
}
-
+
@Override
public Pool getPool(String poolName) {
return configManager.getPool(poolName);
}
-
+
@Override
public boolean poolExists(String name, String lbMethod) {
return configManager.poolExists(name, lbMethod);
}
-
+
@Override
public Pool createPool(String name, String lbMethod) {
return configManager.createPool(name, lbMethod);
}
-
+
@Override
public Pool deletePool(String poolName) {
return configManager.deletePool(poolName);
}
-
+
@Override
public boolean vipExists(String name) {
return configManager.vipExists(name);
}
-
+
@Override
public boolean memberExists(String name, String poolName) {
return configManager.memberExists(name, poolName);
}
-
+
@Override
public boolean poolExists(String name) {
return configManager.poolExists(name);
}
-
+
@Override
public String getVIPAttachedPool(String name) {
return configManager.getVIPAttachedPool(name);