Merge "Adding Pax-Exam infra with a basic IT for plugin"
[netvirt.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / TenantNetworkManager.java
1 /*
2  * Copyright (C) 2013 Red Hat, Inc. and others...
3  *
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
7  *
8  * Authors : Madhu Venugopal, Brent Salisbury, Dave Tucker
9  */
10 package org.opendaylight.ovsdb.neutron;
11
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19
20 import org.opendaylight.controller.containermanager.ContainerConfig;
21 import org.opendaylight.controller.containermanager.ContainerFlowConfig;
22 import org.opendaylight.controller.containermanager.IContainerManager;
23 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
24 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
25 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
26 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.utils.HexEncode;
30 import org.opendaylight.controller.sal.utils.ServiceHelper;
31 import org.opendaylight.controller.sal.utils.Status;
32 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
33 import org.opendaylight.ovsdb.lib.notation.UUID;
34 import org.opendaylight.ovsdb.lib.table.Bridge;
35 import org.opendaylight.ovsdb.lib.table.Interface;
36 import org.opendaylight.ovsdb.lib.table.Open_vSwitch;
37 import org.opendaylight.ovsdb.lib.table.Port;
38 import org.opendaylight.ovsdb.lib.table.internal.Table;
39 import org.opendaylight.ovsdb.neutron.provider.IProviderNetworkManager;
40 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
41 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class TenantNetworkManager implements ITenantNetworkManager {
46     static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
47     private ConcurrentMap<String, NodeConfiguration> nodeConfigurationCache = new ConcurrentHashMap<>();
48
49     // The implementation for each of these services is resolved by the OSGi Service Manager
50     private volatile IProviderNetworkManager providerNetworkManager;
51
52     private boolean enableContainer = false;
53     public TenantNetworkManager() {
54         String isTenantContainer = System.getProperty("TenantIsContainer");
55         if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
56             enableContainer =  true;
57         }
58     }
59
60     public int getInternalVlan(Node node, String networkId) {
61         String nodeUuid = getNodeUUID(node);
62         if (nodeUuid == null) {
63             logger.error("Unable to get UUID for Node {}", node);
64             return 0;
65         }
66
67         NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
68
69         if (nodeConfiguration == null) {
70             nodeConfiguration = addNodeConfigurationToCache(node);
71         }
72         Integer vlan = nodeConfiguration.getInternalVlan(networkId);
73         if (vlan == null) return 0;
74         return vlan.intValue();
75     }
76
77     private NodeConfiguration addNodeConfigurationToCache(Node node) {
78         NodeConfiguration nodeConfiguration = new NodeConfiguration(node, this);
79         String nodeUuid = getNodeUUID(node);
80         if (nodeUuid == null) {
81             logger.error("Cannot get Node UUID for Node {}", node);
82             return null;
83         }
84         this.nodeConfigurationCache.put(nodeUuid, nodeConfiguration);
85         return nodeConfigurationCache.get(nodeUuid);
86     }
87
88     public void reclaimTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
89         String nodeUuid = getNodeUUID(node);
90         if (nodeUuid == null) {
91             logger.error("Unable to get UUID for Node {}", node);
92             return;
93         }
94
95         NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
96
97         // Cache miss
98         if (nodeConfiguration == null)
99         {
100             logger.error("Configuration data unavailable for Node {} ", node);
101             return;
102         }
103
104         int vlan = nodeConfiguration.reclaimInternalVlan(network.getID());
105         if (vlan <= 0) {
106             logger.error("Unable to get an internalVlan for Network {}", network);
107             return;
108         }
109         logger.debug("Removed Vlan {} on {}", vlan, portUUID);
110     }
111
112     public void networkCreated (String networkId) {
113         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
114         List<Node> nodes = connectionService.getNodes();
115
116         for (Node node : nodes) {
117             this.networkCreated(node, networkId);
118         }
119
120     }
121
122     private String getNodeUUID(Node node) {
123         String nodeUuid = new String();
124         OVSDBConfigService ovsdbConfigService = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
125         try {
126             Map<String, Table<?>> ovsTable = ovsdbConfigService.getRows(node, Open_vSwitch.NAME.getName());
127             nodeUuid = (String)ovsTable.keySet().toArray()[0];
128         }
129         catch (Exception e) {
130             logger.error("Unable to get the Open_vSwitch table for Node {}: {}", node, e);
131         }
132
133         return nodeUuid;
134     }
135
136     public int networkCreated (Node node, String networkId) {
137         String nodeUuid = getNodeUUID(node);
138         if (nodeUuid == null) {
139             logger.error("Unable to get UUID for Node {}", node);
140             return 0;
141         }
142
143         NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
144
145         // Cache miss
146         if (nodeConfiguration == null)
147         {
148             nodeConfiguration = addNodeConfigurationToCache(node);
149         }
150
151         int internalVlan = nodeConfiguration.assignInternalVlan(networkId);
152         if (enableContainer && internalVlan != 0) {
153             IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
154             if (containerManager == null) {
155                 logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
156                 return 0;
157             }
158
159             ContainerConfig config = new ContainerConfig();
160             config.setContainer(BaseHandler.convertNeutronIDToKey(networkId));
161             Status status = containerManager.addContainer(config);
162             logger.debug("Container Creation Status for {} : {}", networkId, status.toString());
163
164             ContainerFlowConfig flowConfig = new ContainerFlowConfig("InternalVlan", internalVlan+"",
165                     null, null, null, null, null);
166             List<ContainerFlowConfig> containerFlowConfigs = new ArrayList<ContainerFlowConfig>();
167             containerFlowConfigs.add(flowConfig);
168             containerManager.addContainerFlows(BaseHandler.convertNeutronIDToKey(networkId), containerFlowConfigs);
169         }
170         return internalVlan;
171     }
172
173     /**
174      * Are there any TenantNetwork VM present on this Node ?
175      * This method uses Interface Table's external-id field to locate the VM.
176      */
177     public boolean isTenantNetworkPresentInNode(Node node, String segmentationId) {
178         String networkId = this.getNetworkIdForSegmentationId(segmentationId);
179         if (networkId == null) {
180             logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
181             return false;
182         }
183         if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
184             String nodeUuid = getNodeUUID(node);
185             if (nodeUuid == null) {
186                 logger.debug("Unable to get UUID for Node {}", node);
187                 return false;
188             }
189
190             NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
191
192             // Cache miss
193             if (nodeConfiguration == null)
194             {
195                 logger.error("Configuration data unavailable for Node {} ", node);
196                 return false;
197             }
198
199             int internalVlan = nodeConfiguration.getInternalVlan(networkId);
200             if (internalVlan == 0) {
201                 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
202                 return false;
203             }
204         }
205         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
206         try {
207             /*
208             // Vlan Tag based identification
209             Map<String, Table<?>> portTable = ovsdbTable.getRows(node, Port.NAME.getName());
210             if (portTable == null) {
211                 logger.debug("Port table is null for Node {} ", node);
212                 return false;
213             }
214
215             for (Table<?> row : portTable.values()) {
216                 Port port = (Port)row;
217                 Set<BigInteger> tags = port.getTag();
218                 if (tags.contains(internalVlan)) {
219                     logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Port {}",
220                                   networkId, segmentationId, node, port);
221                     return true;
222                 }
223             }
224              */
225             // External-id based more accurate VM Location identification
226             Map<String, Table<?>> ifTable = ovsdbTable.getRows(node, Interface.NAME.getName());
227             if (ifTable == null) {
228                 logger.debug("Interface table is null for Node {} ", node);
229                 return false;
230             }
231
232             for (Table<?> row : ifTable.values()) {
233                 Interface intf = (Interface)row;
234                 Map<String, String> externalIds = intf.getExternal_ids();
235                 if (externalIds != null && externalIds.get(EXTERNAL_ID_INTERFACE_ID) != null) {
236                     if (this.isInterfacePresentInTenantNetwork(externalIds.get(EXTERNAL_ID_INTERFACE_ID), networkId)) {
237                         logger.debug("Tenant Network {} with Segmentation-id {} is present in Node {} / Interface {}",
238                                       networkId, segmentationId, node, intf);
239                         return true;
240                     }
241                 }
242             }
243
244         } catch (Exception e) {
245             logger.error("Error while trying to determine if network is present on node", e);
246             return false;
247         }
248
249         logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
250                 networkId, segmentationId, node);
251
252         return false;
253     }
254
255     public String getNetworkIdForSegmentationId (String segmentationId) {
256         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
257         List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
258         for (NeutronNetwork network : networks) {
259             if (network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) return network.getNetworkUUID();
260         }
261         return null;
262     }
263
264     private boolean isInterfacePresentInTenantNetwork (String portId, String networkId) {
265         INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
266         NeutronPort neutronPort = neutronPortService.getPort(portId);
267         if (neutronPort != null && neutronPort.getNetworkUUID().equalsIgnoreCase(networkId)) return true;
268         return false;
269     }
270
271     public NeutronNetwork getTenantNetworkForInterface (Interface intf) {
272         logger.trace("getTenantNetworkForInterface for {}", intf);
273         if (intf == null) return null;
274         Map<String, String> externalIds = intf.getExternal_ids();
275         logger.trace("externalIds {}", externalIds);
276         if (externalIds == null) return null;
277         String neutronPortId = externalIds.get(EXTERNAL_ID_INTERFACE_ID);
278         if (neutronPortId == null) return null;
279         INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
280         NeutronPort neutronPort = neutronPortService.getPort(neutronPortId);
281         logger.trace("neutronPort {}", neutronPort);
282         if (neutronPort == null) return null;
283         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
284         NeutronNetwork neutronNetwork = neutronNetworkService.getNetwork(neutronPort.getNetworkUUID());
285         logger.debug("{} mappped to {}", intf, neutronNetwork);
286         return neutronNetwork;
287     }
288
289     public void programTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
290
291         String nodeUuid = getNodeUUID(node);
292         if (nodeUuid == null) {
293             logger.error("Unable to get UUID for Node {}", node);
294             return;
295         }
296
297         NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
298
299         // Cache miss
300         if (nodeConfiguration == null)
301         {
302             logger.error("Configuration data unavailable for Node {} ", node);
303             return;
304         }
305
306         int vlan = nodeConfiguration.getInternalVlan(network.getID());
307         logger.debug("Programming Vlan {} on {}", vlan, portUUID);
308         if (vlan <= 0) {
309             logger.error("Unable to get an internalVlan for Network {}", network);
310             return;
311         }
312         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
313         Port port = new Port();
314         OvsDBSet<BigInteger> tags = new OvsDBSet<BigInteger>();
315         tags.add(BigInteger.valueOf(vlan));
316         port.setTag(tags);
317         ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
318         if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
319     }
320
321     private void addPortToTenantNetworkContainer(Node node, String portUUID, NeutronNetwork network) {
322         IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
323         if (containerManager == null) {
324             logger.error("ContainerManager is not accessible");
325             return;
326         }
327         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
328         try {
329             Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
330             if (port == null) {
331                 logger.trace("Unable to identify Port with UUID {}", portUUID);
332                 return;
333             }
334             Set<UUID> interfaces = port.getInterfaces();
335             if (interfaces == null) {
336                 logger.trace("No interfaces available to fetch the OF Port");
337                 return;
338             }
339             Bridge bridge = this.getBridgeIdForPort(node, portUUID);
340             if (bridge == null) {
341                 logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
342                 return;
343             }
344             Set<String> dpids = bridge.getDatapath_id();
345             if (dpids == null || dpids.size() ==  0) return;
346             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
347
348             for (UUID intfUUID : interfaces) {
349                 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), intfUUID.toString());
350                 if (intf == null) continue;
351                 Set<BigInteger> of_ports = intf.getOfport();
352                 if (of_ports == null) continue;
353                 for (BigInteger of_port : of_ports) {
354                     ContainerConfig config = new ContainerConfig();
355                     config.setContainer(BaseHandler.convertNeutronIDToKey(network.getID()));
356                     logger.debug("Adding Port {} to Container : {}", port.toString(), config.getContainer());
357                     List<String> ncList = new ArrayList<String>();
358                     Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
359                     NodeConnector nc = NodeConnector.fromStringNoNode(Node.NodeIDType.OPENFLOW.toString(),
360                                                                       Long.valueOf(of_port.longValue()).intValue()+"",
361                                                                       ofNode);
362                     ncList.add(nc.toString());
363                     config.addNodeConnectors(ncList);
364
365                     Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
366
367                     if (!status.isSuccess()) {
368                         logger.error(" Failed {} : to add port {} to container - {}",
369                                 status, nc, network.getID());
370                     } else {
371                         logger.error(" Successfully added port {} to container - {}",
372                                        nc, network.getID());
373                     }
374                 }
375             }
376         } catch (Exception e) {
377             logger.error("Exception in addPortToTenantNetworkContainer", e);
378         }
379     }
380
381     private Bridge getBridgeIdForPort (Node node, String uuid) {
382         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
383         try {
384             Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
385             if (bridges == null) return null;
386             for (String bridgeUUID : bridges.keySet()) {
387                 Bridge bridge = (Bridge)bridges.get(bridgeUUID);
388                 Set<UUID> portUUIDs = bridge.getPorts();
389                 logger.trace("Scanning Bridge {} to identify Port : {} ",bridge, uuid);
390                 for (UUID portUUID : portUUIDs) {
391                     if (portUUID.toString().equalsIgnoreCase(uuid)) {
392                         logger.trace("Found Port {} -> ", uuid, bridgeUUID);
393                         return bridge;
394                     }
395                 }
396             }
397         } catch (Exception e) {
398             logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
399         }
400         return null;
401     }
402
403     public void networkDeleted(String id) {
404         if (!enableContainer) return;
405
406         IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
407         if (containerManager == null) {
408             logger.error("ContainerManager is not accessible");
409             return;
410         }
411
412         String networkID = BaseHandler.convertNeutronIDToKey(id);
413         ContainerConfig config = new ContainerConfig();
414         config.setContainer(networkID);
415         containerManager.removeContainer(config);
416     }
417 }