2 * Copyright (C) 2014 SDN Hub, LLC.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 * Authors : Srini Seetharaman
11 package org.opendaylight.ovsdb.openstack.netvirt;
13 import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
14 import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolAware;
15 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
16 import org.opendaylight.neutron.spi.INeutronPortCRUD;
17 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
18 import org.opendaylight.neutron.spi.NeutronLoadBalancer;
19 import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
20 import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.common.base.Preconditions;
30 import com.google.common.collect.Lists;
32 import java.net.HttpURLConnection;
33 import java.util.List;
37 * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for
38 * /v2.0/pools . It is possible that each pool spans multiple subnets.
39 * In that case, the user should be creating a separate VIP for each subnet.
42 public class LBaaSPoolHandler extends AbstractHandler
43 implements INeutronLoadBalancerPoolAware {
45 private static final Logger logger = LoggerFactory.getLogger(LBaaSPoolHandler.class);
47 // The implementation for each of these services is resolved by the OSGi Service Manager
48 private volatile INeutronLoadBalancerCRUD neutronLBCache;
49 private volatile INeutronPortCRUD neutronPortsCache;
50 private volatile INeutronNetworkCRUD neutronNetworkCache;
51 private volatile INeutronSubnetCRUD neutronSubnetCache;
52 private volatile LoadBalancerProvider loadBalancerProvider;
53 private volatile NodeCacheManager nodeCacheManager;
56 public int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLBPool) {
57 String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
58 if (poolProtocol == null) {
59 return HttpURLConnection.HTTP_BAD_REQUEST;
60 } else if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
61 poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
62 poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
63 return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
65 return HttpURLConnection.HTTP_OK;
70 public void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool neutronLBPool) {
71 logger.debug("Neutron LB Pool Creation : {}", neutronLBPool.toString());
72 enqueueEvent(new NorthboundEvent(neutronLBPool, Action.ADD));
76 * Assuming that the pool information is fully populated before this call is made,
77 * we go with creating the LoadBalancerConfiguration object for this call with
78 * all information that is necessary to insert flow_mods
80 private void doNeutronLoadBalancerPoolCreate(NeutronLoadBalancerPool neutronLBPool) {
81 Preconditions.checkNotNull(loadBalancerProvider);
82 List<LoadBalancerConfiguration> lbConfigList = extractLBConfiguration(neutronLBPool);
83 final List<Node> nodes = nodeCacheManager.getNodes();
84 if (lbConfigList == null) {
85 logger.debug("Neutron LB configuration invalid for pool {} ", neutronLBPool.getLoadBalancerPoolID());
86 } else if (lbConfigList.size() == 0) {
87 logger.debug("No Neutron LB VIP not created yet for pool {} ", neutronLBPool.getLoadBalancerPoolID());
88 } else if (nodes.isEmpty()) {
89 logger.debug("Noop with LB pool {} creation because no nodes available.", neutronLBPool.getLoadBalancerPoolID());
91 for (LoadBalancerConfiguration lbConfig: lbConfigList) {
92 if (!lbConfig.isValid()) {
93 logger.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
96 for (Node node : nodes) {
97 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
105 public int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original) {
106 return HttpURLConnection.HTTP_NOT_IMPLEMENTED;
110 public void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool neutronLBPool) {
111 logger.debug("Neutron LB Pool Update : {}", neutronLBPool.toString());
112 enqueueEvent(new NorthboundEvent(neutronLBPool, Action.UPDATE));
116 public int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool neutronLBPool) {
117 String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
118 if (poolProtocol == null) {
119 return HttpURLConnection.HTTP_BAD_REQUEST;
120 } else if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
121 poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
122 poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
123 return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
125 return HttpURLConnection.HTTP_OK;
130 public void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool neutronLBPool) {
131 logger.debug("Neutron LB Pool Deletion : {}", neutronLBPool.toString());
132 enqueueEvent(new NorthboundEvent(neutronLBPool, Action.DELETE));
135 private void doNeutronLoadBalancerPoolDelete(NeutronLoadBalancerPool neutronLBPool) {
136 Preconditions.checkNotNull(loadBalancerProvider);
138 List<LoadBalancerConfiguration> lbConfigList = extractLBConfiguration(neutronLBPool);
139 final List<Node> nodes = nodeCacheManager.getNodes();
140 if (lbConfigList == null) {
141 logger.debug("Neutron LB configuration invalid for pool {} ", neutronLBPool.getLoadBalancerPoolID());
142 } else if (lbConfigList.size() == 0) {
143 logger.debug("No Neutron LB VIP not created yet for pool {} ", neutronLBPool.getLoadBalancerPoolID());
144 } else if (nodes.isEmpty()) {
145 logger.debug("Noop with LB pool {} deletion because no nodes available.", neutronLBPool.getLoadBalancerPoolID());
147 for (LoadBalancerConfiguration lbConfig: lbConfigList) {
148 if (!lbConfig.isValid()) {
149 logger.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
152 for (Node node : nodes) {
153 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
163 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
164 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
167 public void processEvent(AbstractEvent abstractEvent) {
168 logger.debug("Processing Loadbalancer Pool event " + abstractEvent);
169 if (!(abstractEvent instanceof NorthboundEvent)) {
170 logger.error("Unable to process abstract event " + abstractEvent);
173 NorthboundEvent ev = (NorthboundEvent) abstractEvent;
174 switch (ev.getAction()) {
176 doNeutronLoadBalancerPoolCreate(ev.getLoadBalancerPool());
179 doNeutronLoadBalancerPoolDelete(ev.getLoadBalancerPool());
183 * Typical upgrade involves changing algorithm. Right now
184 * we do not support this flexibility. TODO
186 logger.warn("Load balancer pool update is not supported");
189 logger.warn("Unable to process event action " + ev.getAction());
195 * Useful utility for extracting the loadbalancer instance. With
196 * each LB pool, we allow multiple VIP and LB to be instantiated.
198 public List<LoadBalancerConfiguration> extractLBConfiguration(NeutronLoadBalancerPool neutronLBPool) {
199 String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
200 if (poolProtocol == null) {
203 if (!(poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
204 poolProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
208 List<NeutronLoadBalancerPoolMember> poolMembers = neutronLBPool.getLoadBalancerPoolMembers();
209 if (poolMembers.size() == 0) {
210 logger.debug("Neutron LB pool is empty: {}", neutronLBPool);
214 List<LoadBalancerConfiguration> lbConfigList = Lists.newLinkedList();
216 /* Iterate over all the Loadbalancers created so far and identify VIP
218 String loadBalancerSubnetID, loadBalancerVip=null, loadBalancerName=null;
219 for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
220 loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
221 loadBalancerName = neutronLB.getLoadBalancerName();
222 loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
224 LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
225 Map.Entry<String,String> providerInfo = NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, loadBalancerSubnetID);
226 if (providerInfo != null) {
227 lbConfig.setProviderNetworkType(providerInfo.getKey());
228 lbConfig.setProviderSegmentationId(providerInfo.getValue());
230 lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortsCache, loadBalancerSubnetID, loadBalancerVip));
232 /* Iterate over all the members in this pool and find those in same
233 * subnet as the VIP. Those will be included in the lbConfigList
235 String memberSubnetID, memberIP, memberID, memberMAC;
237 Boolean memberAdminStateIsUp;
238 for (NeutronLoadBalancerPoolMember neutronLBPoolMember: neutronLBPool.getLoadBalancerPoolMembers()) {
239 memberAdminStateIsUp = neutronLBPoolMember.getPoolMemberAdminStateIsUp();
240 memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
241 if (memberSubnetID == null || memberAdminStateIsUp == null) {
243 } else if (memberSubnetID.equals(loadBalancerSubnetID) && memberAdminStateIsUp.booleanValue()) {
244 memberID = neutronLBPoolMember.getPoolMemberID();
245 memberIP = neutronLBPoolMember.getPoolMemberAddress();
246 memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
247 if (memberSubnetID == null || memberID == null || memberIP == null || memberPort == null) {
248 logger.debug("Neutron LB pool member details incomplete: {}", neutronLBPoolMember);
251 memberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, memberSubnetID, memberIP);
252 if (memberMAC == null) {
255 lbConfig.addMember(memberID, memberIP, memberMAC, poolProtocol, memberPort);
259 if (lbConfig.getMembers().size() > 0)
260 lbConfigList.add(lbConfig);