<!-- Samples -->
<module>../../samples/simpleforwarding</module>
+ <module>../../samples/loadbalancer</module>
+ <module>../../samples/northbound/loadbalancer</module>
</modules>
<build>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.loadbalancer</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.6</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.controller.samples.loadbalancer,
+ org.opendaylight.controller.samples.loadbalancer.entities,
+ org.opendaylight.controller.samples.loadbalancer.internal,
+ org.opendaylight.controller.samples.loadbalancer.policies
+ </Export-Package>
+ <Import-Package>
+ org.opendaylight.controller.sal.core,
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.controller.sal.action,
+ org.opendaylight.controller.sal.match,
+ org.opendaylight.controller.sal.packet,
+ org.opendaylight.controller.sal.routing,
+ org.opendaylight.controller.sal.flowprogrammer,
+ org.opendaylight.controller.sal.packet.address,
+ org.opendaylight.controller.hosttracker,
+ org.opendaylight.controller.hosttracker.hostAware,
+ org.opendaylight.controller.samples.loadbalancer,
+ org.opendaylight.controller.samples.loadbalancer.entities,
+ org.opendaylight.controller.samples.loadbalancer.internal,
+ org.opendaylight.controller.samples.loadbalancer.policies,
+ org.opendaylight.controller.topologymanager,
+ org.opendaylight.controller.forwardingrulesmanager,
+ org.opendaylight.controller.switchmanager,
+ org.opendaylight.controller.clustering.services,
+ javax.xml.bind.annotation,
+ javax.xml.bind,
+ org.apache.felix.dm,
+ org.apache.commons.lang3.builder,
+ org.osgi.service.component,
+ org.slf4j,
+ org.eclipse.osgi.framework.console,
+ org.osgi.framework
+ </Import-Package>
+ <Bundle-Activator>
+ org.opendaylight.controller.samples.loadbalancer.internal.Activator
+ </Bundle-Activator>
+ <Service-Component>
+ </Service-Component>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topologymanager</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwardingrulesmanager</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents a configuration manager for the Load Balancer service.
+ * This class is responsible for managing(store/update/delete) the load balancer
+ * configuration that it receives through REST APIs or from any other applications
+ * present in the controller.
+ *
+ */
+public class ConfigManager implements IConfigManager{
+
+ /*
+ * Logger instance
+ */
+ private static final Logger cmLogger = LoggerFactory.getLogger(ConfigManager.class);
+
+ /*
+ * All the available VIPs
+ */
+ private HashMap<String,VIP> vips = new HashMap<String,VIP>();
+
+ /*
+ * All the available Pools
+ */
+ private HashMap<String,Pool> pools = new HashMap<String,Pool>();
+
+ public ConfigManager(){
+ }
+
+ @Override
+ public boolean vipExists(String name) {
+ return this.vips.containsKey(name);
+ }
+
+ @Override
+ public boolean vipExists(VIP vip){
+ if(vip.getName()==null){
+ if(!vips.containsValue(vip)){
+ return false;
+ }
+ }else{
+ if(!vips.containsKey(vip.getName())){
+ if(!vips.containsValue(vip)){
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean vipExists(String name,String ip,String protocol,short protocolPort,String poolName){
+
+ VIP vip = new VIP(name,ip,protocol,protocolPort,poolName);
+
+ //Check VIP with the same name
+
+ if(!vips.containsKey(name)){
+ //Check VIP with the same ip, protocol and protocolPort
+ if(!vips.containsValue(vip)){
+
+ //if you reach here, means this VIP don't exist
+ return false;
+ }
+ }
+
+ //Yeah, i have it.
+ return true;
+ }
+
+ @Override
+ public Set<VIP> getAllVIPs(){
+ return new HashSet<VIP>(this.vips.values());
+ }
+
+ public VIP getVIPWithPoolName(VIP vip){
+ cmLogger.info("Search a VIP with name:{}",vip);
+ for(VIP vipTemp: this.vips.values()){
+ if(vipTemp.equals(vip)){
+
+ cmLogger.info("Found VIP with pool detail : {}",vipTemp);
+ return vipTemp;
+ }
+ }
+
+ cmLogger.info("VIP with pool detail not found ");
+ return null;
+ }
+
+ @Override
+ public VIP createVIP(String name,String ip,String protocol,short protocolPort,String poolName){
+
+ cmLogger.info("Create VIP with the following details :[ name : "+name
+ +" ip : "+ip
+ +" protocol : "+protocol
+ +" protocol_port : "+protocolPort
+ +" pool name : "+poolName);
+
+ VIP vip = new VIP(name,ip,protocol,protocolPort,poolName);
+
+ if(poolName !=null && !poolName.isEmpty()){
+ if(pools.containsKey(poolName)){
+ pools.get(poolName).addVIP(vip);
+ }
+ }
+
+ vip.setStatus(LBConst.STATUS_ACTIVE);
+ this.vips.put(name, vip);
+
+ cmLogger.info("New VIP created : "+vip.toString());
+ return vip;
+ }
+
+ @Override
+ public String getVIPAttachedPool(String name) {
+ return this.vips.get(name).getPoolName();
+ }
+
+ @Override
+ public VIP updateVIP(String name, String poolName){
+
+ cmLogger.info("Updating VIP : "+name+" pool name to "+poolName);
+
+ if(vips.containsKey(name)){
+ VIP vip = vips.get(name);
+ if(vip.getPoolName() == null){
+ vip.setPoolName(poolName);
+ cmLogger.error("VIP is now attached to the pool : {}",vip.toString());
+ return vip;
+ }
+ cmLogger.error("VIP is already attached to one pool : {}",vip.toString());
+ }
+ cmLogger.error("VIP with name: "+name+" does not exist");
+ return null;
+ }
+
+ @Override
+ public VIP deleteVIP(String name){
+
+ cmLogger.info("Deleting VIP : "+name);
+
+ VIP vip = vips.get(name);
+
+ String poolName = vip.getPoolName();
+
+ if(poolName != null){
+ if(pools.containsKey(poolName)){
+ Pool pool = pools.get(poolName);
+ pool.removeVIP(vip.getName());
+ }
+ }
+
+ cmLogger.info("VIP removed : "+vip.toString());
+
+ vips.remove(vip.getName());
+
+ return vip;
+ }
+
+ @Override
+ public boolean memberExists(String name, String poolName) {
+ if(this.pools.containsKey(poolName)){
+ if(this.pools.get(poolName).getMember(name) != null )
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean memberExists(String name, String memberIP,String poolName){
+ if(!this.pools.containsKey(poolName))
+ return false;
+
+ return this.pools.get(poolName).poolMemberExists(new PoolMember(name, memberIP, poolName));
+ }
+
+ @Override
+ public PoolMember addPoolMember(String name, String memberIP, String poolName){
+
+ PoolMember pm = new PoolMember(name,memberIP,poolName);
+
+ cmLogger.info("Adding pool member : "+pm.toString());
+
+ pools.get(poolName).addMember(pm);
+
+ return pm;
+ }
+
+ @Override
+ public PoolMember removePoolMember(String name, String poolName){
+
+ cmLogger.info("Removing pool member : {} from pool {}",name, poolName);
+
+ Pool pool = pools.get(poolName);
+
+ PoolMember pm = pool.getMember(name);
+
+ pool.removeMember(name);
+
+ cmLogger.info("Pool member {} removed from {} ",name,poolName);
+
+ return pm;
+ }
+
+ @Override
+ public Set<Pool> getAllPools(){
+ return new HashSet<Pool>(this.pools.values());
+ }
+
+ @Override
+ public boolean poolExists(String name) {
+ return this.pools.containsKey(name);
+ }
+
+ @Override
+ public boolean poolExists(String name, String lbMethod){
+
+ return pools.containsValue(new Pool(name,lbMethod));
+ }
+
+ @Override
+ public Pool createPool(String name, String lbMethod){
+
+ Pool newPool = new Pool(name,lbMethod);
+
+ cmLogger.info("New pool created : " + newPool.toString());
+
+ pools.put(name, newPool);
+
+ return newPool;
+ }
+
+ @Override
+ public Pool deletePool(String poolName){
+
+ Pool pool = pools.get(poolName);
+
+ for(VIP vip:pool.getAllVip()){
+
+ vip.setPoolName(null);
+
+ }
+
+ cmLogger.info("Pool removed : "+pool.toString());
+
+ pools.remove(poolName);
+
+ return pool;
+ }
+
+ @Override
+ public Pool getPool( String poolName){
+ if(pools.containsKey(poolName)){
+ return pools.get(poolName);
+ }
+ return null;
+ }
+
+ @Override
+ public Set<PoolMember> getAllPoolMembers(String poolName) {
+
+ if(pools.containsKey(poolName)){
+ return new HashSet<PoolMember>(pools.get(poolName).getAllMembers());
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "ConfigManager [vips=" + vips + ", pools=" + pools + "]";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer;
+
+import java.util.Set;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * Interface implemented by the configuration manager.
+ *
+ */
+public interface IConfigManager {
+
+ /**
+ * Return all existing VIPs
+ * @return Set of VIP's
+ * if there is no VIP, it will return empty set.
+ */
+ public Set<VIP> getAllVIPs();
+
+ /**
+ * Check if VIP with the 'name' exists
+ * @param name Name of the VIP
+ * @return true if exists
+ * false else
+ */
+ public boolean vipExists(String name);
+
+ /**
+ * Check if VIP exists with the details 'VIP'
+ * @param vip Search for this VIP
+ * @return true if exists
+ * false else
+ */
+ public boolean vipExists(VIP vip);
+
+ /**
+ * Check if VIP with the provided details exists
+ * @param name Name of the VIP
+ * @param ip IP of the VIP
+ * @param protocol IP Protocol of the VIP (TCP/UDP)
+ * @param protocolPort Transport port of the VIP (e.g 5550)
+ * @param poolName Name of the pool attached with the VIP
+ * @return true if exists
+ * false else
+ */
+ public boolean vipExists(String name,String ip,String protocol,short protocolPort,String poolName);
+
+ /**
+ * Add VIP to the configuration
+ * @param name Name of the VIP
+ * @param ip IP of the VIP
+ * @param protocol IP Protocol of the VIP (TCP/UDP)
+ * @param protocolPort Transport port of the VIP
+ * @param poolName Name of the pool that VIP will use for load balancing its traffic
+ * @return Newly created VIP
+ */
+ public VIP createVIP(String name,String ip,String protocol,short protocolPort,String poolName);
+
+ /**
+ * Return pool attached to VIP
+ * @param name Name of the VIP
+ * @return Name of the pool attached to VIP
+ * else null
+ */
+ public String getVIPAttachedPool(String name);
+ /**
+ * Update pool name of the VIP.
+ * @param name Name of the VIP
+ * @param poolName Attach this pool to VIP
+ * @return Updated VIP If successful
+ * null If this VIP is already attached to any existing pool.
+ */
+ public VIP updateVIP(String name, String poolName);
+
+ /**
+ * Delete the VIP
+ * @param name Delete VIP with this name
+ * @return Details of the deleted VIP
+ */
+ public VIP deleteVIP(String name);
+
+ /**
+ * Check if pool member with the 'name' present in the pool with name 'poolName'
+ * @param name Name of the pool member
+ * @param poolName Name of the pool, you want to search for pool member
+ * @return true If exist
+ * false else
+ */
+ public boolean memberExists(String name, String poolName);
+
+ /**
+ * Check if pool member with name 'name' and IP 'memberIP' exist in the pool 'poolName'
+ * @param name Name of the pool member
+ * @param memberIP IP of the pool member
+ * @param poolName Name of the pool member you want to search
+ * @return true If Exist
+ * false else
+ */
+ public boolean memberExists(String name, String memberIP,String poolName);
+
+ /**
+ * Return all pool members of the pool 'poolName'
+ * @param poolName Name of the pool
+ * @return Set of all the pool members if pool with the name present in the configuration
+ * null else
+ *
+ */
+ public Set<PoolMember> getAllPoolMembers(String poolName);
+
+ /**
+ * Add new pool member to the configuration
+ * @param name Name of the pool
+ * @param memberIP IP of the pool
+ * @param poolName Attach pool member to this pool
+ * @return Newly created pool member
+ */
+ public PoolMember addPoolMember(String name, String memberIP, String poolName);
+
+ /**
+ * Remove pool member from the pool
+ * @param name Name of the pool member
+ * @param poolName Name of the pool
+ * @return Details of the removed pool member
+ */
+ public PoolMember removePoolMember(String name, String poolName);
+
+ /**
+ * Return all the existing pools
+ * @return Set of Pools
+ */
+ public Set<Pool> getAllPools();
+
+ /**
+ * Return pool with input name
+ * @param poolName Name of the pool
+ * @return Details of the pool if pool exist
+ * null else
+ */
+ public Pool getPool(String poolName);
+
+ /**
+ * Check if pool exists with the input name
+ * @param name Name of the pool
+ * @return true If exists
+ * false else
+ */
+ public boolean poolExists(String name);
+
+ /**
+ * Check if pool exists with the input name and loadbalancing method.
+ * @param name Name of the pool
+ * @param lbMethod Load balancing method name
+ * @return true If exists
+ * false else
+ */
+ public boolean poolExists(String name, String lbMethod);
+
+ /**
+ * Create new pool with the provided details
+ * @param name Name of the pool
+ * @param lbMethod Load balancing method this pool will use
+ * @return Details of the newly created pool
+ */
+ public Pool createPool(String name, String lbMethod);
+
+ /**
+ * Delete pool with the provided name
+ * @param poolName Name of the pool
+ * @return Details of the deleted pool
+ */
+ public Pool deletePool(String poolName);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer;
+
+/**
+ * Class defines all the constants used by load balancer service
+ *
+ */
+public class LBConst {
+
+ public static final int FORWARD_DIRECTION_LB_FLOW = 0;
+
+ public static final int REVERSE_DIRECTION_LB_FLOW = 1;
+
+ public static final String ROUND_ROBIN_LB_METHOD = "roundrobin";
+
+ public static final String RANDOM_LB_METHOD = "random";
+
+ public static final String STATUS_ACTIVE="active";
+
+ public static final String STATUS_INACTIVE="inactive";
+
+ public static final String STATUS_PENDING="pending";
+
+ public static final String STATUS_ERROR="error";
+
+}
+
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer;
+
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.TCP;
+import org.opendaylight.controller.sal.packet.UDP;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class defines utilty methods that will be used by different components
+ * of the load balancer service
+ *
+ */
+public class LBUtil {
+
+ private static final Logger lbuLogger = LoggerFactory.getLogger(LBUtil.class);
+
+ public LBUtil(){}
+
+ /**
+ * Extract the details of the source machine that sent this packet 'inPkt'
+ * @param inPkt Packet that is received by the controller
+ * @return Details of the source machine in Client object.
+ */
+ public Client getClientFromPacket(IPv4 inPkt){
+ lbuLogger.info("Find client information from packet : {}",inPkt.toString());
+
+ String ip = NetUtils.getInetAddress(inPkt.getSourceAddress()).getHostAddress();
+
+ String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+
+ lbuLogger.info("client ip {} and protocl {}",ip,protocol);
+
+ Packet tpFrame= inPkt.getPayload();
+
+ lbuLogger.info("Get protocol layer {}",tpFrame.toString());
+
+ short port = 0;
+
+ if(protocol.equals(IPProtocols.TCP.toString())){
+ TCP tcpFrame = (TCP)tpFrame;
+ port = tcpFrame.getSourcePort();
+ }else{
+ UDP udpFrame = (UDP)tpFrame;
+ port = udpFrame.getSourcePort();
+ }
+
+ lbuLogger.info("Found port {}",port);
+
+ Client source = new Client(ip, protocol,port);
+
+ lbuLogger.info("Client information : {}",source.toString());
+
+ return source;
+ }
+
+ /**
+ * Extract the details of the destination machine where this packet 'inPkt' need
+ * to be delivered
+ * @param inPkt Packet that is received by controller for forwarding
+ * @return Details of the destination machine packet in VIP
+ */
+ public VIP getVIPFromPacket(IPv4 inPkt){
+
+ lbuLogger.info("Find VIP information from packet : {}",inPkt.toString());
+
+ String ip = NetUtils.getInetAddress(inPkt.getDestinationAddress()).getHostAddress();
+
+ String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+
+ Packet tpFrame= inPkt.getPayload();
+
+ short port = 0;
+
+ if(protocol.equals(IPProtocols.TCP.toString())){
+ TCP tcpFrame = (TCP)tpFrame;
+ port = tcpFrame.getDestinationPort();
+ }else{
+
+ UDP udpFrame = (UDP)tpFrame;
+ port = udpFrame.getDestinationPort();
+ }
+
+ VIP dest = new VIP(null,ip, protocol,port,null);
+
+ lbuLogger.info("VIP information : {}",dest.toString());
+
+ return dest;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.entities;
+
+/**
+ * This class represents the source host that sends any traffic to any existing virtual IP (VIP).
+ * This source host is referred to as a 'Client'. Clients will be differentiated from each other
+ * based on the following three properties:
+ * 1. IP address of the client.
+ * 2. Protocol of the traffic it is using for sending traffic
+ * 3. Source port from which it is sending traffic.
+ * e.g TCP traffic from two different ports from the same host to a given VIP will be considered
+ * as two different clients by this service. Similarly, traffic using two different protocols
+ * (TCP, UDP) from the same host will be considered as two different clients.
+ *
+ */
+public class Client {
+
+ /*
+ * IP address of the client (source address)
+ */
+ private String ip;
+
+ /*
+ * Network protocol of the traffic sent by client
+ */
+ private String protocol;
+
+ /*
+ * Port used to send network traffic (source port)
+ */
+ private short port;
+
+ public Client(String ip, String protocol, short port){
+ this.ip = ip;
+ this.protocol = protocol;
+ this.port = port;
+ }
+
+ /**
+ * @return the client IP
+ */
+ public String getIp() {
+ return ip;
+ }
+
+ /**
+ * @param ip the IP to set
+ */
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ /**
+ * @return the client network protocol
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * @param protocol the protocol to set
+ */
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ /**
+ * @return the client port
+ */
+ public short getPort() {
+ return port;
+ }
+
+ /**
+ * @param port the port to set
+ */
+ public void setPort(short port) {
+ this.port = port;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+ result = prime * result + port;
+ result = prime * result+ ((protocol == null) ? 0 : protocol.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Client)) {
+ return false;
+ }
+ Client other = (Client) obj;
+ if (ip == null) {
+ if (other.ip != null) {
+ return false;
+ }
+ }else if (!ip.equals(other.ip)) {
+ return false;
+ }
+ if (port != other.port) {
+ return false;
+ }
+ if (protocol == null) {
+ if (other.protocol != null) {
+ return false;
+ }
+ }else if (!protocol.equals(other.protocol)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Client [ip=" + ip + ", protocol=" + protocol + ", port=" + port+ "]";
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.entities;
+
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the pool of hosts among which incoming traffic
+ * will be load balanced. Each pool will load balance the traffic among its pool members
+ * based on the loadbalancing policy set for the pool.
+ * Currently, the pool supports two load balancing policies:
+ * 1. Round Robin Policy{@link org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy}
+ * 2. Random Policy {@link org.opendaylight.controller.samples.loadbalancer.policies.RandomLBPolicy}
+ *
+ * NOTE: After creation of the pool, user can't update (change) its load balancing policy.
+ * NOTE: Each Pool should have a unique name.
+ */
+
+@XmlRootElement(name="pool")
+@XmlAccessorType(XmlAccessType.NONE)
+public class Pool {
+
+ /*
+ * Unique name of the pool
+ */
+ @XmlElement
+ private String name;
+
+ /*
+ * Associated load balancing policy
+ */
+ @XmlElement(name="lbmethod")
+ private String lbMethod;
+
+ /*
+ * Status of the pool (active/inactive)
+ */
+ @XmlElement
+ private String status;
+
+ /*
+ * List of all the VIPs using this pool for load balancing their traffic - more than
+ * one VIP can be mapped to each pool.
+ */
+ @XmlElement
+ private ArrayList<VIP> vips = new ArrayList<VIP>();
+
+ /*
+ * List of all the pool members used for load balancing the traffic
+ */
+ @XmlElement
+ private ArrayList<PoolMember> members = new ArrayList<PoolMember>();
+
+ /*
+ * Private constructor used for JAXB mapping
+ */
+ @SuppressWarnings("unused")
+ private Pool() {}
+
+ /**
+ * Getter/ Setter methods
+ */
+
+ public Pool(String name,
+ String lbMethod) {
+ this.name = name;
+ this.lbMethod = lbMethod;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the lbMethod
+ */
+ public String getLbMethod() {
+ return lbMethod;
+ }
+
+ /**
+ * @param lbMethod the lbMethod to set
+ */
+ public void setLbMethod(String lbMethod) {
+ this.lbMethod = lbMethod;
+ }
+
+ /**
+ * @return the status
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * @param status the status to set
+ */
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ /**
+ * @return the vip
+ */
+ public ArrayList<VIP> getAllVip() {
+ return vips;
+ }
+
+ /**
+ * @param vip the vip to set
+ */
+ public void setVips(ArrayList<VIP> vips) {
+ this.vips = vips;
+ }
+
+ /**
+ * @return the members
+ */
+ public ArrayList<PoolMember> getAllMembers() {
+ return members;
+ }
+
+ /**
+ * @param members the members to set
+ */
+ public void setMembers(ArrayList<PoolMember> members) {
+ this.members = members;
+ }
+
+ /**
+ * Add new VIP to the VIP list
+ * @param vip new VIP to add
+ */
+ public void addVIP(VIP vip){
+ this.vips.add(vip);
+ }
+
+ /**
+ * Remove VIP with given name from the VIP list of the pool
+ * @param name Name of the VIP
+ * @return true If VIP was using this pool and removed
+ * false IF VIP is not using this pool
+ */
+ public boolean removeVIP(String name){
+ for(VIP vip: this.vips){
+ if(vip.getName().equals(name)){
+ this.members.remove(vip);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the given pool member is part of this pool
+ * @param pm Search for this pool member
+ * @return true If pool member is attached to this pool
+ * false else
+ */
+ public boolean poolMemberExists(PoolMember pm){
+ return this.members.contains(pm);
+ }
+
+ /**
+ * Returns the pool member with the given name
+ * @param name Search for this pool member
+ * @return PoolMember If pool member is attached to this pool
+ * null else
+ */
+ public PoolMember getMember(String name){
+
+ for(PoolMember pm: this.members){
+ if(pm.getName().equals(name)){
+ return pm;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add new pool member to the pool
+ * @param pm Add this new pool
+ */
+ public void addMember(PoolMember pm){
+ this.members.add(pm);
+ }
+
+ /**
+ * Remove pool member from the pool list
+ * @param name Remove this pool member
+ * @return true If pool member was attached to this pool and successfully removed
+ * false If pool member is not attached to this pool
+ */
+ public boolean removeMember(String name){
+ for(PoolMember pm: this.members){
+ if(pm.getName().equals(name)){
+ this.members.remove(pm);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result+ ((lbMethod == null) ? 0 : lbMethod.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Pool)) {
+ return false;
+ }
+ Pool other = (Pool) obj;
+ if (lbMethod == null) {
+ if (other.lbMethod != null) {
+ return false;
+ }
+ }else if (!lbMethod.equals(other.lbMethod)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ }else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Pool [name=" + name + ", lbMethod=" + lbMethod + ", status="
+ + status + ", vips=" + vips + ", members=" + members + "]";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.entities;
+
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the host where load balancing service will
+ * redirect VIP traffic for load balancing. All these hosts have to
+ * register with a pool to be a part of traffic load balancing.
+ * This entity is referred to as a 'PoolMember'.
+ * Load balancer service differentiates each pool member based on its
+ * two properties { ip address, attached pool }.
+ * A host (IP) can be attached to two different pools through creation of two
+ * different pool member objects.
+ *
+ * NOTE: Each pool member should have a unique name.
+ *
+ */
+@XmlRootElement(name="poolmember")
+@XmlAccessorType(XmlAccessType.NONE)
+public class PoolMember {
+
+ /*
+ * Unique name of the pool member
+ */
+ @XmlElement
+ private String name;
+
+ /*
+ * IP address of the pool member
+ */
+ @XmlElement
+ private String ip;
+
+ /*
+ * Name of the pool this member is attached to.
+ */
+ @XmlElement(name="poolname")
+ private String poolName;
+
+ /*
+ * Status (active/inactive)
+ */
+ @XmlElement
+ private String status;
+
+ /**
+ * Private constructor used for JAXB mapping
+ */
+ @SuppressWarnings("unused")
+ private PoolMember() {}
+
+ public PoolMember(String name, String memberIP, String poolName){
+ this.name = name;
+ this.ip = memberIP;
+ this.poolName = poolName;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the ip
+ */
+ public String getIp() {
+ return ip;
+ }
+
+ /**
+ * @param ip the ip to set
+ */
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ /**
+ * @return the poolName
+ */
+ public String getPoolName() {
+ return poolName;
+ }
+
+ /**
+ * @param poolName the poolName to set
+ */
+ public void setPoolName(String poolName) {
+ this.poolName = poolName;
+ }
+
+ /**
+ * @return the status
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * @param status the status to set
+ */
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+ result = prime * result
+ + ((poolName == null) ? 0 : poolName.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof PoolMember)) {
+ return false;
+ }
+ PoolMember other = (PoolMember) obj;
+ if (ip == null) {
+ if (other.ip != null) {
+ return false;
+ }
+ }else if (!ip.equals(other.ip)) {
+ return false;
+ }
+ if (poolName == null) {
+ if (other.poolName != null) {
+ return false;
+ }
+ }else if (!poolName.equals(other.poolName)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "PoolMember [name=" + name + ", ip=" + ip + ", poolName="
+ + poolName + ", status=" + status + "]";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.entities;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the Virtual IP (VIP) address exposed by the load balancer application.
+ * Load balancer service differentiates one VIP from the other, using the following three properties:
+ * 1. IP address of the VIP exposed by the application
+ * 2. Protocol of the network traffic (TCP/UDP)
+ * 3. Port to which incoming traffic is destined
+ *
+ * User is allowed to create mutliple VIPs with the same IP, but all such VIPs (with the same IP)
+ * should differ at least in the protocol or port or both.
+ *
+ * NOTE: Each VIP should have a unique name.
+ */
+@XmlRootElement(name="vip")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class VIP {
+
+ /*
+ * Unique name of the VIP
+ */
+ @XmlElement
+ private String name;
+
+ /*
+ * Virtual IP address of the VIP
+ */
+ @XmlElement
+ private String ip;
+
+ /*
+ * Network traffic protocol
+ */
+ @XmlElement
+ private String protocol;
+
+ /*
+ * Port where network traffic is destined (destination port)
+ */
+ @XmlElement
+ private short port;
+
+ /*
+ * Name of the pool attached to the VIP for load balancing its traffic
+ */
+ @XmlElement(name="poolname")
+ private String poolName;
+
+ /*
+ * Status (Active/inactive)
+ */
+ @XmlElement
+ private String status;
+
+ /**
+ * Private constructor used for JAXB mapping
+ */
+ @SuppressWarnings("unused")
+ private VIP() {}
+
+ public VIP(String name,
+ String ip,
+ String protocol,
+ short port,
+ String poolName){
+ this.name = name;
+ this.ip=ip;
+ this.protocol=protocol;
+ this.port = port;
+ this.poolName = poolName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public short getPort() {
+ return port;
+ }
+
+ public void setPort(short port) {
+ this.port = port;
+ }
+
+ public String getPoolName() {
+ return poolName;
+ }
+
+ public void setPoolName(String poolName) {
+ this.poolName = poolName;
+ }
+
+ /**
+ * @return the status
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * @param status the status to set
+ */
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+ result = prime * result + port;
+ result = prime * result
+ + ((protocol == null) ? 0 : protocol.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof VIP)) {
+ return false;
+ }
+
+ VIP other = (VIP) obj;
+ if (ip == null) {
+ if (other.ip != null) {
+ return false;
+ }
+ }else if (!ip.equals(other.ip)) {
+ return false;
+ }
+ if (port != other.port) {
+ return false;
+ }
+ if (protocol == null) {
+ if (other.protocol != null) {
+ return false;
+ }
+ }else if (!protocol.equalsIgnoreCase(other.protocol)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "VIP [name=" + name + ", ip=" + ip + ", protocol=" + protocol
+ + ", port=" + port + ", poolName=" + poolName + ", status="
+ + status + "]";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+
+/**
+ * Main application activator class for registering the dependencies and
+ * initialising the load balancer application.
+ *
+ */
+
+public class Activator extends ComponentActivatorAbstractBase {
+
+ /*
+ * Logger instance
+ */
+ protected static final Logger logger = LoggerFactory.getLogger(Activator.class);
+
+ /**
+ * Function called when the activator starts just after some
+ * initializations are done by the
+ * ComponentActivatorAbstractBase.
+ *
+ */
+ public void init() {
+ }
+
+ /**
+ * Function called when the activator stops just before the
+ * cleanup done by ComponentActivatorAbstractBase
+ *
+ */
+ public void destroy() {
+ }
+
+ /**
+ * Function that is used to communicate to dependency manager the
+ * list of known implementations for services inside a container
+ *
+ *
+ * @return An array containing all the CLASS objects that will be
+ * instantiated in order to get an fully working implementation
+ * Object
+ */
+ public Object[] getImplementations() {
+ Object[] res = { LoadBalancerService.class };
+ return res;
+ }
+
+ /**
+ * Function that is called when configuration of the dependencies
+ * is required.
+ *
+ * @param c dependency manager Component object, used for
+ * configuring the dependencies exported and imported
+ * @param imp Implementation class that is being configured,
+ * needed as long as the same routine can configure multiple
+ * implementations
+ * @param containerName The containerName being configured, this allow
+ * also optional per-container different behavior if needed, usually
+ * should not be the case though.
+ */
+ public void configureInstance(Component c, Object imp, String containerName) {
+ if (imp.equals(LoadBalancerService.class)) {
+ // export the service
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put("salListenerName", "loadbalancer");
+
+ c.setInterface(new String[] { IListenDataPacket.class.getName(),
+ IConfigManager.class.getName()}, props);
+
+ c.add(createContainerServiceDependency(containerName).setService(
+ IDataPacketService.class).setCallbacks(
+ "setDataPacketService", "unsetDataPacketService")
+ .setRequired(true));
+
+ c.add(createContainerServiceDependency(containerName).setService(
+ IRouting.class).setCallbacks("setRouting", "unsetRouting")
+ .setRequired(false));
+
+ c.add(createContainerServiceDependency(containerName).setService(
+ IfIptoHost.class).setCallbacks("setHostTracker",
+ "unsetHostTracker").setRequired(true));
+
+ c.add(createContainerServiceDependency(containerName).setService(
+ IForwardingRulesManager.class).setCallbacks(
+ "setForwardingRulesManager", "unsetForwardingRulesManager")
+ .setRequired(true));
+ }
+ }
+
+ /**
+ * Method which tells how many Global implementations are
+ * supported by the bundle. This way we can tune the number of
+ * components created. This components will be created ONLY at the
+ * time of bundle startup and will be destroyed only at time of
+ * bundle destruction, this is the major difference with the
+ * implementation retrieved via getImplementations where all of
+ * them are assumed to be in a container !
+ *
+ *
+ * @return The list of implementations the bundle will support,
+ * in Global version
+ */
+ protected Object[] getGlobalImplementations() {
+ return null;
+ }
+
+ /**
+ * Configure the dependency for a given instance Global
+ *
+ * @param c Component assigned for this instance, this will be
+ * what will be used for configuration
+ * @param imp implementation to be configured
+ * @param containerName container on which the configuration happens
+ */
+ protected void configureGlobalInstance(Component c, Object imp) {
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.internal;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Path;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.LBConst;
+import org.opendaylight.controller.samples.loadbalancer.LBUtil;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.opendaylight.controller.samples.loadbalancer.policies.RandomLBPolicy;
+import org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy;
+import org.slf4j.Logger;
+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
+ * 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
+ * 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.
+ *
+ */
+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 static short LB_IPSWITCH_PRIORITY = 2;
+
+ /*
+ * Name of the container where this application will register.
+ */
+ private String containerName = null;
+
+ /*
+ * Set/unset methods for the service instance that load balancer
+ * service requires
+ */
+ public String getContainerName() {
+ if (containerName == null)
+ return GlobalConstants.DEFAULT.toString();
+ return containerName;
+ }
+
+ void setDataPacketService(IDataPacketService s) {
+ this.dataPacketService = s;
+ }
+
+ void unsetDataPacketService(IDataPacketService s) {
+ if (this.dataPacketService == s) {
+ this.dataPacketService = null;
+ }
+ }
+
+ public void setRouting(IRouting routing) {
+ this.routing = routing;
+ }
+
+ public void unsetRouting(IRouting routing) {
+ if (this.routing == routing) {
+ this.routing = null;
+ }
+ }
+
+ public void setHostTracker(IfIptoHost hostTracker) {
+ lbsLogger.debug("Setting HostTracker");
+ this.hostTracker = hostTracker;
+ }
+
+ public void unsetHostTracker(IfIptoHost hostTracker) {
+ if (this.hostTracker == hostTracker) {
+ this.hostTracker = null;
+ }
+ }
+
+ public void setForwardingRulesManager(
+ IForwardingRulesManager forwardingRulesManager) {
+ lbsLogger.debug("Setting ForwardingRulesManager");
+ this.ruleManager = forwardingRulesManager;
+ }
+
+ public void unsetForwardingRulesManager(
+ IForwardingRulesManager forwardingRulesManager) {
+ if (this.ruleManager == forwardingRulesManager) {
+ this.ruleManager = null;
+ }
+ }
+
+ /**
+ * This method receives first packet of flows for which there is no
+ * 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.
+ */
+ @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.TCP.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,
+ poolMemberIp,
+ hnConnector.getDataLayerAddressBytes(),
+ forwardPort,
+ LBConst.FORWARD_DIRECTION_LB_FLOW)){
+ lbsLogger.info("Traffic from client : {} will be routed " +
+ "to pool machine : {}",client,poolMemberIp);
+ }else{
+ lbsLogger.error("Not able to route traffic from client : {}",client );
+ }
+
+ if(installLoadBalancerFlow(client,
+ vip,
+ clientNode,
+ poolMemberIp,
+ vipMacAddr,
+ inPkt.getIncomingNodeConnector(),
+ LBConst.REVERSE_DIRECTION_LB_FLOW)){
+ lbsLogger.info("Flow rule installed to change the source ip/mac from " +
+ "pool machine ip {} to VIP {} for traffic coming pool machine",poolMemberIp,vip);
+ }else{
+ lbsLogger.error("Not able to route traffic from client : {}",client );
+ }
+ }catch (UnknownHostException e) {
+ lbsLogger.error("Pool member not found in the network : {}",e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ 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 dest Traffic is destined to this destination (VIP)
+ * @param sourceSwitch Switch from where controller received the packet
+ * @param destMachineIp IP address of the pool member where traffic needs to be routed
+ * @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
+ * @throws UnknownHostException
+ */
+ private boolean installLoadBalancerFlow(Client source,
+ VIP dest,
+ Node sourceSwitch,
+ String destMachineIp,
+ 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_DST, InetAddress.getByName(dest.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_DST, InetAddress.getByName(source.getIp()));
+ 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;
+ }else{
+ lbsLogger.error("Error in installing flow entry to node : {}",sourceSwitch);
+ }
+ }else{
+ lbsLogger.error("Conflicting flow entry exists : {}",fEntry.toString());
+ }
+ return false;
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ *
+ */
+ void init(Component c) {
+ 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
+ * down because for example bundle is being stopped.
+ *
+ */
+ void destroy() {
+ }
+
+ /**
+ * Function called by dependency manager after "init ()" is called
+ * and after the services provided by the class are registered in
+ * the service registry
+ *
+ */
+ void start() {
+ }
+
+ /**
+ * Function called by the dependency manager before the services
+ * exported by the component are unregistered, this will be
+ * followed by a "destroy ()" calls
+ *
+ */
+ void stop() {
+ }
+
+ /*
+ * 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.
+ */
+ @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,
+ 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);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.policies;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * All new load balancer policies must implement this interface.
+ */
+public interface ILoadBalancingPolicy {
+
+ /**
+ * Returns IP address of the next pool member from the pool
+ * to which the load balancer service can direct incoming packets.
+ * @param source source on the packet
+ * @param dest virtual IP (VIP) that is used as destination on the packet
+ * @return IP address of the next pool member which will serve
+ * all incoming traffic destined for the given VIP and with the given source
+ * information
+ */
+ public String getPoolMemberForClient(Client source, VIP dest);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.policies;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements the random load balancing policy.
+ *
+ */
+public class RandomLBPolicy implements ILoadBalancingPolicy {
+
+ /*
+ * Instance logger
+ */
+ private static final Logger rLogger = LoggerFactory.getLogger(RandomLBPolicy.class);
+
+ /*
+ * Reference to the configuration manager. This reference is passed from load balancer
+ * class.
+ */
+ private ConfigManager cmgr;
+
+ /*
+ * Mapping between the client and the pool member that serves all traffic for that client.
+ */
+ private HashMap<Client, PoolMember> clientMemberMap;
+
+ /*
+ * Random generator
+ */
+ Random randomGenerator = null;
+
+ @SuppressWarnings("unused")
+ private RandomLBPolicy(){}
+
+ public RandomLBPolicy(ConfigManager cmgr){
+ this.cmgr = cmgr;
+ this.clientMemberMap = new HashMap<Client, PoolMember>();
+ randomGenerator = new Random();
+ }
+ @Override
+ public String getPoolMemberForClient(Client source, VIP dest){
+
+ rLogger.info("Received traffic from client : {} for VIP : {} ",source, dest);
+
+ syncWithLoadBalancerData();
+
+ PoolMember pm= null;
+
+ if(this.clientMemberMap.containsKey(source)){
+ pm= this.clientMemberMap.get(source);
+ rLogger.info("Client {} had sent traffic before,new traffic will be routed to the same pool member {}",source,pm);
+ }else{
+ Pool pool = null;
+ pool = this.cmgr.getPool(dest.getPoolName());
+ int memberNum = this.randomGenerator.nextInt(pool.getAllMembers().size()-1);
+ pm = pool.getAllMembers().get(memberNum);
+ this.clientMemberMap.put(source, pm );
+ rLogger.info("Network traffic from client {} will be directed to pool member {}",pm);
+ }
+ return pm.getIp();
+ }
+
+ /*
+ * This method does the clean up. Whenever a new client packet arrives with a given VIP,
+ * this method checks the current configuration to see if any pool members have been deleted and
+ * cleans up the metadata stored by this loadbalancing algorithm.
+ */
+ private void syncWithLoadBalancerData(){
+ rLogger.debug("[Client - PoolMember] table before cleanup : {}",this.clientMemberMap.toString());
+
+ ArrayList<Client> removeClient = new ArrayList<Client>();
+
+ if(this.clientMemberMap.size() != 0){
+ for(Client client : this.clientMemberMap.keySet()){
+
+ if(!this.cmgr.memberExists(this.clientMemberMap.get(client).getName(),
+ this.clientMemberMap.get(client).getPoolName())){
+ removeClient.add(client);
+ }
+ }
+ }
+
+ for(Client client : removeClient){
+ this.clientMemberMap.remove(client);
+
+ rLogger.debug("Removed client : {} ",client);
+ }
+ rLogger.debug("[Client - PoolMember] table after cleanup : {}",this.clientMemberMap.toString());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.policies;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements the round robin load balancing policy.
+ *
+ */
+public class RoundRobinLBPolicy implements ILoadBalancingPolicy{
+
+ /*
+ * Logger instance
+ */
+ private static final Logger rrLogger = LoggerFactory.getLogger(RoundRobinLBPolicy.class);
+
+ /*
+ * Reference to the configuration manager. This reference is passed from load balancer
+ * class.
+ */
+ private ConfigManager cmgr;
+
+ /*
+ * Mapping between the client and the pool member that serves all traffic for that client.
+ */
+ private HashMap<Client, PoolMember> clientMemberMap;
+
+ /*
+ * Maintains the next pool member counter for the VIPs.
+ * More than one VIP can be attached to one pool, so each VIP
+ * will have its own counter for the next pool member from
+ * the same pool.
+ */
+ private HashMap<VIP,Integer> nextItemFromPool;
+
+ @SuppressWarnings("unused")
+ private RoundRobinLBPolicy(){}
+
+ public RoundRobinLBPolicy(ConfigManager cmgr){
+ this.cmgr = cmgr;
+ this.clientMemberMap = new HashMap<Client, PoolMember>();
+ this.nextItemFromPool = new HashMap<VIP, Integer>();
+ }
+
+ @Override
+ public String getPoolMemberForClient(Client source, VIP dest){
+
+ rrLogger.info("Received traffic from client : {} for VIP : {} ",source, dest);
+
+ syncWithLoadBalancerData();
+
+ PoolMember pm= null;
+
+ if(this.clientMemberMap.containsKey(source)){
+
+ pm= this.clientMemberMap.get(source);
+ rrLogger.info("Client {} had sent traffic before,new traffic will be routed to the same pool member {}",source,pm);
+ }else{
+
+ Pool pool = null;
+ if(nextItemFromPool.containsKey(dest)){
+
+ int memberNum = nextItemFromPool.get(dest).intValue();
+ rrLogger.debug("Packet is from new client for VIP {}",dest);
+ pool = this.cmgr.getPool(dest.getPoolName());
+ pm = pool.getAllMembers().get(memberNum);
+ this.clientMemberMap.put(source, pm );
+ rrLogger.info("New client's packet will be directed to pool member {}",pm);
+ memberNum++;
+
+ if(memberNum > pool.getAllMembers().size()-1){
+ memberNum = 0;
+ }
+ rrLogger.debug("Next pool member for new client of VIP is set to {}",pool.getAllMembers().get(memberNum));
+
+ this.nextItemFromPool.put(dest, new Integer(memberNum));
+ }else{
+ rrLogger.debug("Network traffic for VIP : {} has appeared first time from client {}",dest,source);
+ pool = this.cmgr.getPool(dest.getPoolName());
+ pm = pool.getAllMembers().get(0);
+ this.clientMemberMap.put(source, pm);
+
+ rrLogger.info("Network traffic from client {} will be directed to pool member {}",pm);
+ this.nextItemFromPool.put(dest, new Integer(1));
+ rrLogger.debug("Next pool member for new client of VIP is set to {}",pool.getAllMembers().get(1));
+ }
+ }
+ return pm.getIp();
+ }
+
+ /*
+ * This method does the clean up. Whenever a new client packet arrives with a given VIP,
+ * this method checks the current configuration to see if any pool members have been deleted and
+ * cleans up the metadata stored by this loadbalancing algorithm.
+ */
+ private void syncWithLoadBalancerData(){
+ rrLogger.debug("[Client - PoolMember] table before cleanup : {}",this.clientMemberMap.toString());
+ ArrayList<Client> removeClient = new ArrayList<Client>();
+
+ if(this.clientMemberMap.size() != 0){
+ for(Client client : this.clientMemberMap.keySet()){
+ if(!this.cmgr.memberExists(this.clientMemberMap.get(client).getName(),
+ this.clientMemberMap.get(client).getPoolName())){
+
+ removeClient.add(client);
+ }
+ }
+ }
+
+ for(Client client : removeClient){
+ this.clientMemberMap.remove(client);
+
+ rrLogger.debug("Removed client : {} ",client);
+ }
+ rrLogger.debug("[Client - PoolMember] table after cleanup : {}",this.clientMemberMap.toString());
+
+ rrLogger.debug("[VIP- NextMember] table before cleanup : {}",this.nextItemFromPool.toString());
+
+ ArrayList<VIP> resetVIPPoolMemberCount= new ArrayList<VIP>();
+
+ if(this.nextItemFromPool.size() != 0){
+
+ for(VIP vip:this.nextItemFromPool.keySet()){
+ if(this.nextItemFromPool.get(vip).intValue() > this.cmgr.getPool(vip.getPoolName()).getAllMembers().size()-1){
+
+ resetVIPPoolMemberCount.add(vip);
+ }
+ }
+ }
+
+ for(VIP vip:resetVIPPoolMemberCount){
+ rrLogger.debug("VIP next pool member counter reset to 0");
+ this.nextItemFromPool.put(vip, new Integer(0));
+ }
+
+ rrLogger.debug("[VIP- NextMember] table after cleanup : {}",this.nextItemFromPool.toString());
+ }
+}
--- /dev/null
+/*\r
+ * Copyright IBM Corporation, 2013. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.samples.loadbalancer.internal;\r
+\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;\r
+import org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy;\r
+\r
+import junit.framework.TestCase;\r
+\r
+/**\r
+ * \r
+ * Class to unit test the load balancing policies.\r
+ *\r
+ */\r
+public class LoadBalancerTest extends TestCase {\r
+ @Test\r
+ public void testRoundRobinPolicy() {\r
+ ConfigManager cm = null;\r
+ cm = new ConfigManager();\r
+ Assert.assertFalse(cm== null);\r
+ \r
+ Pool pool = cm.createPool("TestPool","roundrobin");\r
+ VIP vip = cm.createVIP("TestVIP","10.0.0.9","TCP",(short)5550,"TestPool");\r
+ PoolMember host1 = new PoolMember("host1","10.0.0.1","TestPool");\r
+ PoolMember host2 = new PoolMember("host2","10.0.0.2","TestPool");\r
+ PoolMember host3 = new PoolMember("host3","10.0.0.3","TestPool");\r
+ PoolMember host4 = new PoolMember("host4","10.0.0.4","TestPool");\r
+ PoolMember host5 = new PoolMember("host5","10.0.0.5","TestPool");\r
+ PoolMember host6 = new PoolMember("host6","10.0.0.6","TestPool");\r
+ PoolMember host7 = new PoolMember("host7","10.0.0.7","TestPool");\r
+ \r
+ pool.addMember(host1);\r
+ pool.addMember(host2);\r
+ pool.addMember(host3);\r
+ pool.addMember(host4);\r
+ pool.addMember(host5);\r
+ pool.addMember(host6);\r
+ pool.addMember(host7);\r
+ pool.addVIP(vip);\r
+ \r
+ Assert.assertTrue(cm.getAllPoolMembers("TestPool").size() == pool.getAllMembers().size());\r
+ \r
+ RoundRobinLBPolicy rrp = new RoundRobinLBPolicy(cm);\r
+ \r
+ Client c1 = new Client("10.0.0.1","TCP",(short)5000);\r
+ Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host1.getIp()));\r
+ \r
+ c1 = new Client("10.0.0.1","TCP",(short)5001);\r
+ Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host2.getIp()));\r
+ \r
+ c1 = new Client("10.0.0.1","TCP",(short)5002);\r
+ Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host3.getIp()));\r
+ \r
+ c1 = new Client("10.0.0.1","TCP",(short)5003);\r
+ Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host4.getIp()));\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+ <services>
+ <rest defaultRestSubcontext="/one/nb/v2/lb"/>
+ </services>
+
+ <modules>
+ <docs docsDir="rest" title="Load Balancer REST API" includeExampleXml="true" includeExampleJson="true"/>
+ </modules>
+</enunciate>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../../../commons/opendaylight</relativePath>
+ </parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.loadbalancer.northbound</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>maven-enunciate-plugin</artifactId>
+ <version>${enunciate.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.6</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ org.opendaylight.controller.samples.loadbalancer,
+ org.opendaylight.controller.samples.loadbalancer.entities,
+ org.opendaylight.controller.samples.loadbalancer.internal,
+ org.opendaylight.controller.samples.loadbalancer.policies,
+ org.opendaylight.controller.hosttracker,
+ org.opendaylight.controller.sal.core,
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.controller.containermanager,
+ org.opendaylight.controller.switchmanager,
+ org.apache.commons.logging,
+ com.sun.jersey.spi.container.servlet,
+ org.opendaylight.controller.northbound.commons,
+ org.opendaylight.controller.northbound.commons.exception,
+ com.sun.jersey.spi.spring.container.servlet,
+ org.springframework.web.context,
+ org.springframework.web,
+ org.springframework.web.servlet,
+ org.springframework.web.filter,
+ org.springframework.security.config,
+ org.springframework.security.web.authentication,
+ org.springframework.security.web.authentication.www,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.xml.bind.annotation,
+ javax.xml.bind,
+ org.slf4j,
+ !org.codehaus.enunciate.jaxrs
+ </Import-Package>
+ <Web-ContextPath>/one/nb/v2/lb</Web-ContextPath>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+ <version>1.17-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.loadbalancer</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>enunciate-core-annotations</artifactId>
+ <version>${enunciate.version}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBElement;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+
+/**
+ * This class exposes North bound REST APIs for the Load Balancer Service.
+ * Following APIs are exposed by the Load Balancer Service:
+ *
+ * Data retrieval REST APIs::
+ * 1. Get details of all existing pools
+ * Type : GET
+ * URI : /one/nb/v2/lb/{container-name}/
+ * NOTE: Current implementation of the opendaylight usage 'default' as a container-name
+ * e.g : http://localhost:8080/one/nb/v2/lb/default will give you list of all the pools
+ *
+ * 2. Get details of all the existing VIPs
+ * Type : GET
+ * URI: /one/nb/v2/lb/{container-name}/vips
+ *
+ * Pool related REST APIs::
+ * 1. Create Pool :
+ * Type : POST
+ * URI : /one/nb/v2/lb/{container-name}/create/pool
+ * Request body :
+ * {
+ * "name":"",
+ * "lbmethod":""
+ * }
+ * Currently, two load balancing policies are allowed {"roundrobin" and "random" }
+ *
+ * 2. Delete Pool :
+ * Type : DELETE
+ * URI : /one/nb/v2/lb/{container-name}/delete/pool/{pool-name}
+ *
+ * VIP related REST APIs::
+ * 1. Create VIP:
+ * Type : POST
+ * URI : /one/nb/v2/lb/{container-name}/create/vip
+ * Request body :
+ * {
+ * "name":"",
+ * "ip":"ip in (xxx.xxx.xxx.xxx) format",
+ * "protocol":"TCP/UDP",
+ * "port":"any valid port number",
+ * "poolname":"" (optional)
+ * }
+ * The pool name is optional and can be set up at a later stage (using the REST API given below).
+ *
+ * 2. Update VIP: Update pool name of the VIP
+ * Type : PUT
+ * URI : /one/nb/v2/lb/{container-name}/update/vip
+ * Request body :
+ * {
+ * "name":"",
+ * "poolname":""
+ * }
+ * Currently, we only allow update of the VIP pool name (if a VIP does not have an attached pool)
+ * and not of the VIP name itself.
+ * The specified pool name must already exist. If the specified VIP is already attached to a pool, the update
+ * will fail.
+ *
+ * 3. Delete VIP :
+ * Type : DELETE
+ * URI : /one/nb/v2/lb/{container-name}/delete/vip/{vip-name}
+ *
+ * Pool member related REST APIs::
+ * 1. Create pool member:
+ * Type : POST
+ * URI : /one/nb/v2/lb/default/create/poolmember
+ * Request body :
+ * {
+ * "name":"",
+ * "ip":"ip in (xxx.xxx.xxx.xxx) format",
+ * "poolname":"existing pool name"
+ * }
+ *
+ * 2. Delete pool member:
+ * Type : DELETE
+ * URI : /one/nb/v2/lb/{container-name}/delete/poolmember/{pool-member-name}/{pool-name}
+ *
+ * NOTE: Property "name" of each individual entity must be unique.
+ * All the above REST APIs throw appropriate response codes in case of error/success.
+ * Please consult the respective methods to get details of various response codes.
+ */
+
+@Path("/")
+public class LoadBalancerNorthbound {
+
+ /*
+ * Method returns the Load balancer service instance running within
+ * 'default' container.
+ */
+ private IConfigManager getConfigManagerService(String containerName) {
+ IContainerManager containerManager = (IContainerManager) ServiceHelper
+ .getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ throw new ServiceUnavailableException("Container "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ boolean found = false;
+ List<String> containerNames = containerManager.getContainerNames();
+ for (String cName : containerNames) {
+ if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+ found = true;
+ }
+ }
+
+ if (found == false) {
+ throw new ResourceNotFoundException(containerName + " "
+ + RestMessages.NOCONTAINER.toString());
+ }
+
+ IConfigManager configManager = (IConfigManager) ServiceHelper.getInstance(
+ IConfigManager.class, containerName, this);
+
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer"
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ return configManager;
+ }
+
+ @Path("/{containerName}")
+ @GET
+ @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(Pools.class)
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Operation successful"),
+ @ResponseCode(code = 404, condition = "The containerName is not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
+ public Pools getAllPools(
+ @PathParam("containerName") String containerName) {
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ return new Pools(configManager.getAllPools());
+ }
+
+ @Path("/{containerName}/vips")
+ @GET
+ @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(VIPs.class)
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Operation successful"),
+ @ResponseCode(code = 404, condition = "The containerName is not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
+ public VIPs getAllVIPs(
+ @PathParam("containerName") String containerName) {
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ return new VIPs(configManager.getAllVIPs());
+ }
+
+ @Path("/{containerName}/create/vip")
+ @POST
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 201, condition = "VIP created successfully"),
+ @ResponseCode(code = 404, condition = "The Container Name not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 409, condition = "VIP already exist"),
+ @ResponseCode(code = 415, condition = "Invalid input data")})
+ public Response addVIP(@PathParam("containerName") String containerName,
+ @TypeHint(VIP.class) JAXBElement<VIP> inVIP){
+
+ VIP vipInput = inVIP.getValue();
+ String name = vipInput.getName();
+ String ip = vipInput.getIp();
+ String protocol = vipInput.getProtocol();
+ short protocolPort = vipInput.getPort();
+ String poolName = vipInput.getPoolName();
+ if(name.isEmpty() ||
+ ip.isEmpty()||
+ protocol.isEmpty()||
+ protocolPort < 0 ){
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+ }
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.vipExists(name, ip, protocol, protocolPort, poolName)){
+
+ VIP vip = configManager.createVIP(name, ip, protocol, protocolPort, poolName);
+ if ( vip != null){
+ return Response.status(Response.Status.CREATED).build();
+ }
+ }else{
+ throw new ResourceConflictException(NBConst.RES_VIP_ALREADY_EXIST);
+ }
+ throw new InternalServerErrorException(NBConst.RES_VIP_CREATION_FAILED);
+ }
+
+ @Path("/{containerName}/update/vip")
+ @PUT
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 201, condition = "VIP updated successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "VIP not found"),
+ @ResponseCode(code = 404, condition = "Pool not found"),
+ @ResponseCode(code = 405, condition = "Pool already attached to the VIP"),
+ @ResponseCode(code = 415, condition = "Invalid input name")})
+ public Response updateVIP(@PathParam("containerName") String containerName,
+ @TypeHint(VIP.class) JAXBElement<VIP> inVIP) {
+
+ VIP vipInput = inVIP.getValue();
+ String name = vipInput.getName();
+ String poolName = vipInput.getPoolName();
+ if(name.isEmpty() ||
+ poolName.isEmpty()){
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+ }
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.poolExists(poolName))
+ throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+ if(configManager.getVIPAttachedPool(name)!=null)
+ throw new MethodNotAllowedException(NBConst.RES_VIP_POOL_EXIST);
+
+ if(configManager.updateVIP(name, poolName)!= null)
+ return Response.status(Response.Status.ACCEPTED).build();
+
+ throw new InternalServerErrorException(NBConst.RES_VIP_UPDATE_FAILED);
+ }
+
+ @Path("/{containerName}/delete/vip/{vipName}")
+ @DELETE
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "VIP deleted successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 404, condition = "VIP not found"),
+ @ResponseCode(code = 500, condition = "Failed to delete VIP")})
+ public Response deleteVIP(
+ @PathParam(value = "containerName") String containerName,
+ @PathParam(value = "vipName") String vipName) {
+
+ if(vipName.isEmpty())
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer"
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.vipExists(vipName))
+ throw new ResourceNotFoundException(NBConst.RES_VIP_NOT_FOUND);
+
+ for(VIP vip : configManager.getAllVIPs()){
+ if(vip.getName().equals(vipName)){
+ configManager.deleteVIP(vipName);
+ return Response.ok().build();
+ }
+ }
+ throw new InternalServerErrorException(NBConst.RES_VIP_DELETION_FAILED);
+ }
+
+ @Path("/{containerName}/create/pool")
+ @POST
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 201, condition = "Pool created successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 409, condition = "Pool already exist"),
+ @ResponseCode(code = 415, condition = "Invalid input data")})
+ public Response addPool(@PathParam("containerName") String containerName,
+ @TypeHint(Pool.class) JAXBElement<Pool> inPool) {
+
+ Pool poolInput = inPool.getValue();
+ String name = poolInput.getName();
+ String lbMethod =poolInput.getLbMethod();
+ if(name.isEmpty() ||
+ lbMethod.isEmpty()){
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+ }
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.poolExists(name)){
+
+ Pool pool = configManager.createPool(name, lbMethod);
+ if ( pool != null){
+ return Response.status(Response.Status.CREATED).build();
+ }
+ }else{
+ throw new ResourceConflictException(NBConst.RES_POOL_ALREADY_EXIST);
+ }
+ throw new InternalServerErrorException(NBConst.RES_POOL_CREATION_FAILED);
+ }
+
+ @Path("/{containerName}/delete/pool/{poolName}")
+ @DELETE
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Pool deleted successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 404, condition = "Pool not found"),
+ @ResponseCode(code = 500, condition = "Failed to delete Pool")})
+ public Response deletePool(
+ @PathParam(value = "containerName") String containerName,
+ @PathParam(value = "poolName") String poolName) {
+
+ if(poolName.isEmpty())
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer"
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.poolExists(poolName))
+ throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+ for(Pool pool:configManager.getAllPools()){
+ if(pool.getName().equals(poolName)){
+ configManager.deletePool(poolName);
+ return Response.ok().build();
+ }
+ }
+ throw new InternalServerErrorException(NBConst.RES_POOL_DELETION_FAILED);
+ }
+
+ @Path("/{containerName}/create/poolmember")
+ @POST
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 201, condition = "Pool member created successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 404, condition = "Pool not found"),
+ @ResponseCode(code = 409, condition = "Pool member already exist"),
+ @ResponseCode(code = 415, condition = "Invalid input data")})
+ public Response addPoolMember(@PathParam("containerName") String containerName,
+ @TypeHint(PoolMember.class) JAXBElement<PoolMember> inPoolMember){
+
+ PoolMember pmInput = inPoolMember.getValue();
+ String name = pmInput.getName();
+ String memberIP = pmInput.getIp();
+ String poolName = pmInput.getPoolName();
+
+ if(name.isEmpty() ||
+ memberIP.isEmpty()||
+ poolName.isEmpty()){
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+ }
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.poolExists(poolName))
+ throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+ if(!configManager.memberExists(name, memberIP, poolName)){
+
+ PoolMember poolMember = configManager.addPoolMember(name, memberIP, poolName);
+ if ( poolMember != null){
+ return Response.status(Response.Status.CREATED).build();
+ }
+ }else{
+ throw new ResourceConflictException(NBConst.RES_POOLMEMBER_ALREADY_EXIST);
+ }
+ throw new InternalServerErrorException(NBConst.RES_POOLMEMBER_CREATION_FAILED);
+ }
+
+ @Path("/{containerName}/delete/poolmember/{poolMemberName}/{poolName}")
+ @DELETE
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Pool member deleted successfully"),
+ @ResponseCode(code = 404, condition = "The containerName not found"),
+ @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+ @ResponseCode(code = 404, condition = "Pool member not found"),
+ @ResponseCode(code = 404, condition = "Pool not found")})
+ public Response deletePoolMember(
+ @PathParam(value = "containerName") String containerName,
+ @PathParam(value = "poolMemberName") String poolMemberName,
+ @PathParam(value = "poolName") String poolName) {
+
+ if(poolMemberName.isEmpty()||
+ poolName.isEmpty())
+ throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+ IConfigManager configManager = getConfigManagerService(containerName);
+
+ if (configManager == null) {
+ throw new ServiceUnavailableException("Load Balancer"
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if(!configManager.poolExists(poolName))
+ throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+ if(configManager.memberExists(poolMemberName, poolName)){
+
+ configManager.removePoolMember(poolMemberName, poolName);
+
+ return Response.ok().build();
+ }
+ throw new ResourceNotFoundException(NBConst.RES_POOLMEMBER_NOT_FOUND);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.ws.rs.core.Application;
+
+/**
+ * This class is an instance of javax.ws.rs.core.Application and is used to return the classes
+ * that will be instantiated for JAXRS processing. This is necessary
+ * because package scanning in jersey doesn't yet work in OSGi environment.
+ *
+ */
+public class LoadBalancerNorthboundRSApplication extends Application {
+ @Override
+ public Set<Class<?>> getClasses() {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ classes.add(LoadBalancerNorthbound.class);
+ return classes;
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+/**
+ * This class defines all the constants used by the load balancer north bound service
+ *
+ */
+public class NBConst {
+
+ public static final String RES_VIP_ALREADY_EXIST= " VIP already exists";
+
+ public static final String RES_VIP_NOT_FOUND= " VIP not found";
+
+ public static final String RES_VIP_CREATION_FAILED = " Creation of VIP failed";
+
+ public static final String RES_VIP_DELETION_FAILED = " Deletion of VIP failed";
+
+ public static final String RES_VIP_UPDATE_FAILED = " Update of VIP failed";
+
+ public static final String RES_POOL_ALREADY_EXIST= " Pool already exists";
+
+ public static final String RES_POOL_NOT_FOUND= " Pool not found";
+
+ public static final String RES_POOL_CREATION_FAILED = " Creation of pool failed";
+
+ public static final String RES_POOL_DELETION_FAILED = " Deletion of pool failed";
+
+ public static final String RES_POOLMEMBER_ALREADY_EXIST= " Pool member already exists";
+
+ public static final String RES_POOLMEMBER_NOT_FOUND= " Pool member not found";
+
+ public static final String RES_POOLMEMBER_CREATION_FAILED = " Creation of pool member failed";
+
+ public static final String RES_POOLMEMBER_DELETION_FAILED = " Deletion of pool member failed";
+
+ public static final String RES_VIP_POOL_EXIST = "Pool already attached to a VIP";
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+/**
+ * JAX-RS resource for handling details of all the available pools
+ * in response to respective REST API requests.
+ */
+
+public class Pools {
+
+ @XmlElement (name="pool")
+ Set<Pool> loadBalancerPools;
+
+ public Pools() {
+ }
+
+ public Pools (Set<Pool> loadBalancerPools) {
+ this.loadBalancerPools = loadBalancerPools;
+ }
+
+ /**
+ * @return the loadBalancerPools
+ */
+ public Set<Pool> getLoadBalancerPools() {
+ return loadBalancerPools;
+ }
+
+ /**
+ * @param loadBalancerPools the loadBalancerPools to set
+ */
+ public void setLoadBalancerPools(Set<Pool> loadBalancerPools) {
+ this.loadBalancerPools = loadBalancerPools;
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * JAX-RS resource for handling details of all the available VIPs
+ * in response to respective REST API requests.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class VIPs {
+
+ @XmlElement (name="vip")
+ Set<VIP> loadBalancerVIPs;
+
+ public VIPs() {}
+
+
+ public VIPs (Set<VIP> loadBalancerVIPs) {
+ this.loadBalancerVIPs = loadBalancerVIPs;
+ }
+
+ /**
+ * @return the loadBalancerVIPs
+ */
+ public Set<VIP> getLoadBalancerVIPs() {
+ return loadBalancerVIPs;
+ }
+
+ /**
+ * @param loadBalancerVIPs the loadBalancerVIPs to set
+ */
+
+ public void setLoadBalancerVIPs(Set<VIP> loadBalancerVIPs) {
+ this.loadBalancerVIPs = loadBalancerVIPs;
+ }
+}
\ No newline at end of file
--- /dev/null
+org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
--- /dev/null
+http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
+http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
+http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
+http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
+http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
+http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
+http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
+http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
+http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
+http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
--- /dev/null
+http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
+http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
+http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
+http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd
+http\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
+http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd
+http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
+http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd
+http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd
+http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/security/spring-security-3.1.xsd=org/springframework/security/config/spring-security-3.1.xsd
+http\://www.springframework.org/schema/security/spring-security-3.2.xsd=org/springframework/security/config/spring-security-3.2.xsd
+
--- /dev/null
+# Tooling related information for the beans namespace
+http\://www.springframework.org/schema/beans@name=beans Namespace
+http\://www.springframework.org/schema/beans@prefix=beans
+http\://www.springframework.org/schema/beans@icon=org/springframework/beans/factory/xml/spring-beans.gif
+
+# Tooling related information for the util namespace
+http\://www.springframework.org/schema/util@name=util Namespace
+http\://www.springframework.org/schema/util@prefix=util
+http\://www.springframework.org/schema/util@icon=org/springframework/beans/factory/xml/spring-util.gif
+
+# Tooling related information for the context namespace
+http\://www.springframework.org/schema/context@name=context Namespace
+http\://www.springframework.org/schema/context@prefix=context
+http\://www.springframework.org/schema/context@icon=org/springframework/context/config/spring-context.gif
+
+# Tooling related information for the jee namespace
+http\://www.springframework.org/schema/jee@name=jee Namespace
+http\://www.springframework.org/schema/jee@prefix=jee
+http\://www.springframework.org/schema/jee@icon=org/springframework/ejb/config/spring-jee.gif
+
+# Tooling related information for the scheduling namespace
+http\://www.springframework.org/schema/task@name=task Namespace
+http\://www.springframework.org/schema/task@prefix=task
+http\://www.springframework.org/schema/task@icon=org/springframework/scheduling/config/spring-task.gif
+
+# Tooling related information for the lang namespace
+http\://www.springframework.org/schema/lang@name=lang Namespace
+http\://www.springframework.org/schema/lang@prefix=lang
+http\://www.springframework.org/schema/lang@icon=org/springframework/scripting/config/spring-lang.gif
+
+# Tooling related information for the cache namespace
+http\://www.springframework.org/schema/cache@name=cache Namespace
+http\://www.springframework.org/schema/cache@prefix=cache
+http\://www.springframework.org/schema/cache@icon=org/springframework/cache/config/spring-cache.gif
+
+# Tooling related information for the mvc namespace
+http\://www.springframework.org/schema/mvc@name=mvc Namespace
+http\://www.springframework.org/schema/mvc@prefix=mvc
+http\://www.springframework.org/schema/mvc@icon=org/springframework/web/servlet/config/spring-mvc.gif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <import resource="servlet/security.xml"/>
+
+</beans>
--- /dev/null
+<beans:beans xmlns="http://www.springframework.org/schema/security"
+ xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/security
+ http://www.springframework.org/schema/security/spring-security-3.1.xsd">
+
+ <http auto-config="false" authentication-manager-ref="authenticationManager"
+ security-context-repository-ref="securityContextRepo" entry-point-ref="authenticationEntryPoint">
+ <intercept-url pattern="/**"
+ access="ROLE_SYSTEM-ADMIN, ROLE_NETWORK-ADMIN, ROLE_NETWORK-OPERATOR, ROLE_CONTAINER-USER" />
+ <custom-filter ref="restAuthenticationFilter" position="BASIC_AUTH_FILTER" />
+ </http>
+
+ <authentication-manager id="authenticationManager">
+ <authentication-provider ref="AuthenticationProviderWrapper" />
+ </authentication-manager>
+
+ <beans:bean id="restAuthenticationFilter"
+ class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
+ <beans:property name="authenticationManager" ref="authenticationManager"/>
+ <beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
+ </beans:bean>
+
+ <beans:bean id="authenticationEntryPoint"
+ class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
+ <beans:property name="realmName" value="opendaylight"/>
+ </beans:bean>
+
+ <beans:bean id="securityContextRepo"
+ class="org.opendaylight.controller.northbound.commons.WebSecurityContextRepository" />
+
+ <beans:bean id="AuthenticationProviderWrapper"
+ class="org.opendaylight.controller.northbound.commons.AuthenticationProviderWrapper" />
+
+</beans:beans>
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="2.4">
+ <servlet>
+ <servlet-name>JAXRSLoadBalancer</servlet-name>
+ <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.opendaylight.controller.samples.loadbalancer.northbound.LoadBalancerNorthboundRSApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAXRSLoadBalancer</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+<!-- Spring Security related -->
+
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>/WEB-INF/spring/*.xml</param-value>
+ </context-param>
+
+ <filter>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <filter-class>
+ org.springframework.web.filter.DelegatingFilterProxy
+ </filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+</web-app>
one.main.page = {
load : function(page) {
+ if (one.f !== undefined && one.f.cleanUp !== undefined) {
+ one.f.cleanUp();
+ }
// clear page related
delete one.f;
$('.dashlet', '#main').empty();