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