package org.opendaylight.ovsdb.openstack.netvirt;
import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerAware;
-import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolAware;
-import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
-
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
+import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.Maps;
+
import java.net.HttpURLConnection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
/**
- * Handle requests for OpenStack Neutron v2.0 LBaaS API calls.
+ * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
*/
-//TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware
+//TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
public class LBaaSHandler extends AbstractHandler
- implements INeutronLoadBalancerAware, INeutronLoadBalancerPoolAware,
- INeutronLoadBalancerPoolMemberAware {
+ implements INeutronLoadBalancerAware {
+
+ private static final Logger logger = LoggerFactory.getLogger(LBaaSHandler.class);
- static final Logger logger = LoggerFactory.getLogger(LBaaSHandler.class);
+ // The implementation for each of these services is resolved by the OSGi Service Manager
+ private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
+ private volatile INeutronLoadBalancerPoolMemberCRUD neutronLBPoolMemberCache;
+ private volatile INeutronPortCRUD neutronPortsCache;
+ private Map<String, LoadBalancerConfiguration> loadbalancersCache = Maps.newHashMap();
@Override
public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
- return HttpURLConnection.HTTP_CREATED;
+ if (loadbalancersCache.containsKey(neutronLoadBalancer.getLoadBalancerID()))
+ return HttpURLConnection.HTTP_CONFLICT;
+ return HttpURLConnection.HTTP_OK;
}
+ /**
+ * Assuming that the pool information is fully populated before this call is made,
+ * we go with creating the LoadBalancerConfiguration object for this call with
+ * all information that is necessary to insert flow_mods
+ */
@Override
public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLoadBalancer) {
logger.debug("Neutron LB Creation : {}", neutronLoadBalancer.toString());
- //TODO: Trigger flowmod addition
- int result = HttpURLConnection.HTTP_BAD_REQUEST;
+ enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.ADD));
+ }
- result = canCreateNeutronLoadBalancer(neutronLoadBalancer);
- if (result != HttpURLConnection.HTTP_CREATED) {
+ private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLoadBalancer) {
+ int result = canCreateNeutronLoadBalancer(neutronLoadBalancer);
+ if (result != HttpURLConnection.HTTP_OK) {
logger.debug("Neutron Load Balancer creation failed {} ", result);
return;
}
+
+ String loadBalancerID = neutronLoadBalancer.getLoadBalancerID();
+ String loadBalancerName = neutronLoadBalancer.getLoadBalancerName();
+ String loadBalancerVip = neutronLoadBalancer.getLoadBalancerVipAddress();
+ String loadBalancerSubnetID = neutronLoadBalancer.getLoadBalancerVipSubnetID();
+ LoadBalancerConfiguration newLB = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
+
+ String memberID, memberIP, memberMAC, memberProtocol;
+ Integer memberPort;
+
+ for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
+ List<? extends NeutronLoadBalancerPoolMember> members =
+ (List<? extends NeutronLoadBalancerPoolMember>)neutronLBPool.getLoadBalancerPoolMembers();
+ memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+ /*
+ * Only HTTP and HTTPS are supported as of this version
+ * TODO: Support all TCP load-balancers
+ */
+ if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+ memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS)))
+ continue;
+ for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
+ if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID)) {
+ memberID = neutronLBPoolMember.getPoolMemberID();
+ memberIP = neutronLBPoolMember.getPoolMemberAddress();
+ memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
+ memberMAC = this.getMacAddress(memberIP);
+ if (memberMAC == null)
+ continue;
+ newLB.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
+ }
+ }
+ }
+ if (newLB.isValid()) {
+ logger.trace("Neutron LB pool configuration invalid for {} ", loadBalancerName);
+ return;
+ } else {
+ loadbalancersCache.put(loadBalancerID, newLB);
+ //TODO: Trigger flowmod addition
+ }
}
@Override
@Override
public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLoadBalancer) {
+ enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.UPDATE));
return;
}
@Override
public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
+ if (!loadbalancersCache.containsKey(neutronLoadBalancer.getLoadBalancerID()))
+ return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
return HttpURLConnection.HTTP_OK;
}
@Override
public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLoadBalancer) {
logger.debug("Neutron LB Deletion : {}", neutronLoadBalancer.toString());
- //TODO: Trigger flowmod removals
- int result = canDeleteNeutronLoadBalancer(neutronLoadBalancer);
- if (result != HttpURLConnection.HTTP_OK) {
- logger.error(" delete Neutron NeutronLoadBalancer Pool validation failed for result - {} ", result);
- return;
- }
- }
-
- /**
- * Invoked when a NeutronLoadBalancer Pools creation is requested
- * to indicate if the specified Rule can be created.
- *
- * @param neutronLoadBalancerPool An instance of proposed new Neutron LoadBalancer Pool object.
- * @return A HTTP status code to the creation request.
- */
-
- @Override
- public int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLoadBalancerPool) {
- return HttpURLConnection.HTTP_CREATED;
- }
-
- @Override
- public void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool neutronLoadBalancerPool) {
- logger.debug("Neutron LB Pool Creation : {}", neutronLoadBalancerPool.toString());
- int result = HttpURLConnection.HTTP_BAD_REQUEST;
-
- result = canCreateNeutronLoadBalancerPool(neutronLoadBalancerPool);
- if (result != HttpURLConnection.HTTP_CREATED) {
- logger.debug("Neutron Load Balancer creation failed {} ", result);
- return;
- }
- }
-
- @Override
- public int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original) {
- return HttpURLConnection.HTTP_OK;
- }
-
- @Override
- public void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool neutronLoadBalancerPool) {
- logger.debug("Neutron LB Pool updated : {}", neutronLoadBalancerPool.toString());
- return;
- }
-
- @Override
- public int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLoadBalancerPool) {
- return HttpURLConnection.HTTP_OK;
+ enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.DELETE));
}
- @Override
- public void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool neutronLoadBalancerPool) {
- logger.debug("Neutron LB Pool Deletion : {}", neutronLoadBalancerPool.toString());
-
- int result = canDeleteNeutronLoadBalancerPool(neutronLoadBalancerPool);
+ private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLoadBalancer) {
+ int result = canDeleteNeutronLoadBalancer(neutronLoadBalancer);
if (result != HttpURLConnection.HTTP_OK) {
logger.error(" delete Neutron NeutronLoadBalancer Pool validation failed for result - {} ", result);
return;
}
- }
- /**
- * Invoked when a NeutronLoadBalancer Pool Members creation is requested
- * to indicate if the specified Rule can be created.
- *
- * @param neutronLoadBalancerPoolMember An instance of proposed new Neutron LoadBalancer Pool Member object.
- * @return A HTTP status code to the creation request.
- */
-
- @Override
- public int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLoadBalancerPoolMember) {
- return HttpURLConnection.HTTP_CREATED;
- }
-
- @Override
- public void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember neutronLoadBalancerPoolMember) {
- logger.debug("Neutron LB Pool Member Creation : {}", neutronLoadBalancerPoolMember.toString());
-
- int result = HttpURLConnection.HTTP_BAD_REQUEST;
-
- result = canCreateNeutronLoadBalancerPoolMember(neutronLoadBalancerPoolMember);
- if (result != HttpURLConnection.HTTP_CREATED) {
- logger.debug("Neutron Load Balancer creation failed {} ", result);
- return;
- }
- }
-
- @Override
- public int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta, NeutronLoadBalancerPoolMember original) {
- return HttpURLConnection.HTTP_OK;
- }
-
- @Override
- public void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember neutronLoadBalancerPoolMember) {
- logger.debug("Neutron LB Pool Member updated : {}", neutronLoadBalancerPoolMember.toString());
- return;
- }
-
- @Override
- public int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLoadBalancerPoolMember) {
- return HttpURLConnection.HTTP_OK;
- }
-
- @Override
- public void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember neutronLoadBalancerPoolMember) {
- logger.debug("Neutron LB Pool Member Deletion : {}", neutronLoadBalancerPoolMember.toString());
-
- int result = canDeleteNeutronLoadBalancerPoolMember(neutronLoadBalancerPoolMember);
- if (result != HttpURLConnection.HTTP_OK) {
- logger.error(" delete Neutron NeutronLoadBalancer Pool Member validation failed for result - {} ", result);
- return;
- }
+ loadbalancersCache.remove(neutronLoadBalancer.getLoadBalancerID());
+ //TODO: Trigger flowmod removals
}
/**
}
NorthboundEvent ev = (NorthboundEvent) abstractEvent;
switch (ev.getAction()) {
- // TODO: add handling of events here, once callbacks do something
- // other than logging.
+ case ADD:
+ doNeutronLoadBalancerCreate(ev.getLoadBalancer());
+ case DELETE:
+ doNeutronLoadBalancerDelete(ev.getLoadBalancer());
+ // fall through
+ case UPDATE:
+ doNeutronLoadBalancerDelete(ev.getLoadBalancer());
+ doNeutronLoadBalancerCreate(ev.getLoadBalancer());
+ break;
default:
logger.warn("Unable to process event action " + ev.getAction());
break;
}
}
-}
+ /**
+ * Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
+ * @param ipAddr IP address of a member or VM
+ * @return MAC address registered with that IP address
+ */
+ private String getMacAddress(String ipAddr) {
+ List<Neutron_IPs> fixedIPs;
+ Iterator<Neutron_IPs> fixedIPIterator;
+ Neutron_IPs ip;
+
+ List<NeutronPort> allPorts = neutronPortsCache.getAllPorts();
+ Iterator<NeutronPort> i = allPorts.iterator();
+ while (i.hasNext()) {
+ NeutronPort port = i.next();
+ fixedIPs = port.getFixedIPs();
+ if (fixedIPs != null && fixedIPs.size() > 0) {
+ fixedIPIterator = fixedIPs.iterator();
+ while (fixedIPIterator.hasNext()) {
+ ip = fixedIPIterator.next();
+ if (ip.getIpAddress().equals(ipAddr))
+ return port.getMacAddress();
+ }
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 SDN Hub, LLC.
+ *
+ * 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
+ *
+ * Authors : Srini Seetharaman
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.api;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Store configuration for each load balancer instance created.
+ */
+
+public class LoadBalancerConfiguration {
+ public static final String PROTOCOL_HTTP = "HTTP";
+ public static final String PROTOCOL_HTTPS = "HTTPS";
+ public static final Integer PROTOCOL_HTTP_PORT = 80;
+ public static final Integer PROTOCOL_HTTPS_PORT = 443;
+
+ public class LoadBalancerPoolMember {
+ String ipAddr;
+ String macAddr;
+ String protocol;
+ Integer port;
+ int index;
+
+ public LoadBalancerPoolMember(String ipAddr, String macAddr, String protocol, Integer port) {
+ this.ipAddr = ipAddr;
+ this.macAddr = macAddr;
+ this.protocol = protocol;
+ this.port = port;
+ this.index = -1;
+ }
+ public LoadBalancerPoolMember(String ipAddr, String macAddr, String protocol, Integer port, int index) {
+ this.ipAddr = ipAddr;
+ this.macAddr = macAddr;
+ this.protocol = protocol;
+ this.port = port;
+ this.index = index;
+ }
+ public String getIP() {
+ return ipAddr;
+ }
+ public String getMAC() {
+ return macAddr;
+ }
+ public String getProtocol() {
+ return protocol;
+ }
+ public Integer getPort() {
+ return port;
+ }
+ public int getIndex() {
+ return index;
+ }
+ public void setIndex(int index) {
+ this.index = index;
+ }
+ public boolean equals(LoadBalancerPoolMember other) {
+ if (other.ipAddr != ipAddr)
+ return false;
+ else if (other.macAddr != macAddr)
+ return false;
+ else if (other.protocol != protocol)
+ return false;
+ else if (other.port != port)
+ return false;
+ //Ignore Index
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "LoadBalancerPoolMember [ip=" + ipAddr + ", mac=" + macAddr +
+ ", protocol=" + protocol + ", port=" + port + ", index=" + index + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((ipAddr == null) ? 0 : ipAddr.hashCode());
+ result = prime * result + ((macAddr == null) ? 0 : macAddr.hashCode());
+ result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
+ result = prime * result + ((port == null) ? 0 : port.hashCode());
+ result = prime * result + index;
+ return result;
+ }
+ }
+
+ private String name;
+ private String vip;
+ private Map <String, LoadBalancerPoolMember> members;
+
+ public LoadBalancerConfiguration() {
+ this.members = Maps.newHashMap();
+ }
+
+ public LoadBalancerConfiguration(String name, String vip) {
+ this.members = Maps.newHashMap();
+ this.name = name;
+ this.vip = vip;
+ }
+
+ public Map<String, LoadBalancerPoolMember> getMembers() {
+ return this.members;
+ }
+
+ public Map<String, LoadBalancerPoolMember> addMember(String uuid, LoadBalancerPoolMember member) {
+ //If index is not set for this object, update it before inserting
+ if (member.getIndex() == -1)
+ member.setIndex(members.size());
+ this.members.put(uuid, member);
+ return this.members;
+ }
+ public Map<String, LoadBalancerPoolMember> addMember(String uuid, String ipAddr, String macAddr, String protocol, Integer port) {
+ this.members.put(uuid,
+ new LoadBalancerPoolMember(ipAddr, macAddr, protocol, port, members.size()));
+ return this.members;
+ }
+ public Map<String, LoadBalancerPoolMember> removeMember(String uuid) {
+ this.members.remove(uuid);
+ return this.members;
+ }
+
+ public boolean isValid() {
+ if (members.size() == 0)
+ return false;
+ return true;
+ }
+ public void setVip(String vip) {
+ this.vip = vip;
+ }
+
+ public String getVip() {
+ return this.vip;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}