Merge "Added Mockito and PowerMock to the neutron pom.xml Unit test coverage for...
[ovsdb.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / TenantNetworkManager.java
1 /*
2  * Copyright (C) 2013 Red Hat, Inc.
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
9  */
10 package org.opendaylight.ovsdb.neutron;
11
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.LinkedList;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Queue;
19 import java.util.Set;
20
21 import org.opendaylight.controller.containermanager.ContainerConfig;
22 import org.opendaylight.controller.containermanager.ContainerFlowConfig;
23 import org.opendaylight.controller.containermanager.IContainerManager;
24 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
25 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
26 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
27 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
28 import org.opendaylight.controller.sal.core.Node;
29 import org.opendaylight.controller.sal.core.NodeConnector;
30 import org.opendaylight.controller.sal.utils.HexEncode;
31 import org.opendaylight.controller.sal.utils.ServiceHelper;
32 import org.opendaylight.controller.sal.utils.Status;
33 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
34 import org.opendaylight.ovsdb.lib.notation.UUID;
35 import org.opendaylight.ovsdb.lib.table.Bridge;
36 import org.opendaylight.ovsdb.lib.table.Interface;
37 import org.opendaylight.ovsdb.lib.table.Port;
38 import org.opendaylight.ovsdb.lib.table.internal.Table;
39 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public class TenantNetworkManager {
44     static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
45
46     private static final int MAX_VLAN = 4096;
47     public static final String EXTERNAL_ID_VM_ID = "vm-id";
48     public static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
49     public static final String EXTERNAL_ID_VM_MAC = "attached-mac";
50     private static TenantNetworkManager tenantHelper = new TenantNetworkManager();
51     private Queue<Integer> internalVlans = new LinkedList<Integer>();
52     private Map<String, Integer> tenantVlanMap = new HashMap<String, Integer>();
53     private boolean enableContainer = false;
54     private TenantNetworkManager() {
55         for (int i = 1; i < MAX_VLAN ; i++) {
56             internalVlans.add(i);
57         }
58         String isTenantContainer = System.getProperty("TenantIsContainer");
59         if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
60             enableContainer =  true;
61         }
62     }
63
64     public static TenantNetworkManager getManager() {
65         return tenantHelper;
66     }
67
68     private int assignInternalVlan (String networkId) {
69         Integer mappedVlan = tenantVlanMap.get(networkId);
70         if (mappedVlan != null) return mappedVlan;
71         mappedVlan = internalVlans.poll();
72         if (mappedVlan != null) tenantVlanMap.put(networkId, mappedVlan);
73         return mappedVlan;
74     }
75
76     public void internalVlanInUse (int vlan) {
77         internalVlans.remove(vlan);
78     }
79
80     public int getInternalVlan (String networkId) {
81         Integer vlan = tenantVlanMap.get(networkId);
82         if (vlan == null) return 0;
83         return vlan.intValue();
84     }
85
86     public int networkCreated (String networkId) {
87         int internalVlan = this.assignInternalVlan(networkId);
88         if (enableContainer && internalVlan != 0) {
89             IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
90             if (containerManager == null) {
91                 logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
92                 return 0;
93             }
94
95             ContainerConfig config = new ContainerConfig();
96             config.setContainer(BaseHandler.convertNeutronIDToKey(networkId));
97             Status status = containerManager.addContainer(config);
98             logger.debug("Container Creation Status for {} : {}", networkId, status.toString());
99
100             ContainerFlowConfig flowConfig = new ContainerFlowConfig("InternalVlan", internalVlan+"",
101                     null, null, null, null, null);
102             List<ContainerFlowConfig> containerFlowConfigs = new ArrayList<ContainerFlowConfig>();
103             containerFlowConfigs.add(flowConfig);
104             containerManager.addContainerFlows(BaseHandler.convertNeutronIDToKey(networkId), containerFlowConfigs);
105         }
106         return internalVlan;
107     }
108
109     /**
110      * Are there any TenantNetwork VM present on this Node ?
111      * This method uses Interface Table's external-id field to locate the VM.
112      */
113     public boolean isTenantNetworkPresentInNode(Node node, String segmentationId) {
114         String networkId = this.getNetworkIdForSegmentationId(segmentationId);
115         if (networkId == null) {
116             logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
117             return false;
118         }
119         int internalVlan = this.getInternalVlan(networkId);
120         if (internalVlan == 0) {
121             logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
122             return false;
123         }
124         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
125         try {
126             /*
127             // Vlan Tag based identification
128             Map<String, Table<?>> portTable = ovsdbTable.getRows(node, Port.NAME.getName());
129             if (portTable == null) {
130                 logger.debug("Port table is null for Node {} ", node);
131                 return false;
132             }
133
134             for (Table<?> row : portTable.values()) {
135                 Port port = (Port)row;
136                 Set<BigInteger> tags = port.getTag();
137                 if (tags.contains(internalVlan)) {
138                     logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Port {}",
139                                   networkId, segmentationId, node, port);
140                     return true;
141                 }
142             }
143              */
144             // External-id based more accurate VM Location identification
145             Map<String, Table<?>> ifTable = ovsdbTable.getRows(node, Interface.NAME.getName());
146             if (ifTable == null) {
147                 logger.debug("Interface table is null for Node {} ", node);
148                 return false;
149             }
150
151             for (Table<?> row : ifTable.values()) {
152                 Interface intf = (Interface)row;
153                 Map<String, String> externalIds = intf.getExternal_ids();
154                 if (externalIds != null && externalIds.get(EXTERNAL_ID_INTERFACE_ID) != null) {
155                     if (this.isInterfacePresentInTenantNetwork(externalIds.get(EXTERNAL_ID_INTERFACE_ID), networkId)) {
156                         logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Interface {}",
157                                       networkId, segmentationId, node, intf);
158                         return true;
159                     }
160                 }
161             }
162
163         } catch (Exception e) {
164             logger.error("Error while trying to determine if network is present on node", e);
165             return false;
166         }
167
168         logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
169                 networkId, segmentationId, node);
170
171         return false;
172     }
173
174     public String getNetworkIdForSegmentationId (String segmentationId) {
175         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
176         List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
177         for (NeutronNetwork network : networks) {
178             if (network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) return network.getNetworkUUID();
179         }
180         return null;
181     }
182
183     private boolean isInterfacePresentInTenantNetwork (String portId, String networkId) {
184         INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
185         NeutronPort neutronPort = neutronPortService.getPort(portId);
186         if (neutronPort != null && neutronPort.getNetworkUUID().equalsIgnoreCase(networkId)) return true;
187         return false;
188     }
189
190     public NeutronNetwork getTenantNetworkForInterface (Interface intf) {
191         logger.trace("getTenantNetworkForInterface for {}", intf);
192         if (intf == null) return null;
193         Map<String, String> externalIds = intf.getExternal_ids();
194         logger.trace("externalIds {}", externalIds);
195         if (externalIds == null) return null;
196         String neutronPortId = externalIds.get(EXTERNAL_ID_INTERFACE_ID);
197         if (neutronPortId == null) return null;
198         INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
199         NeutronPort neutronPort = neutronPortService.getPort(neutronPortId);
200         logger.trace("neutronPort {}", neutronPort);
201         if (neutronPort == null) return null;
202         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
203         NeutronNetwork neutronNetwork = neutronNetworkService.getNetwork(neutronPort.getNetworkUUID());
204         logger.debug("{} mappped to {}", intf, neutronNetwork);
205         return neutronNetwork;
206     }
207
208     public void programTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
209         int vlan = this.getInternalVlan(network.getID());
210         logger.debug("Programming Vlan {} on {}", vlan, portUUID);
211         if (vlan <= 0) {
212             logger.error("Unable to get an internalVlan for Network {}", network);
213             return;
214         }
215         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
216         Port port = new Port();
217         OvsDBSet<BigInteger> tags = new OvsDBSet<BigInteger>();
218         tags.add(BigInteger.valueOf(vlan));
219         port.setTag(tags);
220         ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
221         if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
222     }
223
224     private void addPortToTenantNetworkContainer(Node node, String portUUID, NeutronNetwork network) {
225         IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
226         if (containerManager == null) {
227             logger.error("ContainerManager is not accessible");
228             return;
229         }
230         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
231         try {
232             Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
233             if (port == null) {
234                 logger.trace("Unable to identify Port with UUID {}", portUUID);
235                 return;
236             }
237             Set<UUID> interfaces = port.getInterfaces();
238             if (interfaces == null) {
239                 logger.trace("No interfaces available to fetch the OF Port");
240                 return;
241             }
242             Bridge bridge = this.getBridgeIdForPort(node, portUUID);
243             if (bridge == null) {
244                 logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
245                 return;
246             }
247             Set<String> dpids = bridge.getDatapath_id();
248             if (dpids == null || dpids.size() ==  0) return;
249             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
250
251             for (UUID intfUUID : interfaces) {
252                 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), intfUUID.toString());
253                 if (intf == null) continue;
254                 Set<BigInteger> of_ports = intf.getOfport();
255                 if (of_ports == null) continue;
256                 for (BigInteger of_port : of_ports) {
257                     ContainerConfig config = new ContainerConfig();
258                     config.setContainer(BaseHandler.convertNeutronIDToKey(network.getID()));
259                     logger.debug("Adding Port {} to Container : {}", port.toString(), config.getContainer());
260                     List<String> ncList = new ArrayList<String>();
261                     Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
262                     NodeConnector nc = NodeConnector.fromStringNoNode(Node.NodeIDType.OPENFLOW.toString(),
263                                                                       Long.valueOf(of_port.longValue()).intValue()+"",
264                                                                       ofNode);
265                     ncList.add(nc.toString());
266                     config.addNodeConnectors(ncList);
267
268                     Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
269
270                     if (!status.isSuccess()) {
271                         logger.error(" Failed {} : to add port {} to container - {}",
272                                 status, nc, network.getID());
273                     } else {
274                         logger.error(" Successfully added port {} to container - {}",
275                                        nc, network.getID());
276                     }
277                 }
278             }
279         } catch (Exception e) {
280             logger.error("Exception in addPortToTenantNetworkContainer", e);
281         }
282     }
283
284     private Bridge getBridgeIdForPort (Node node, String uuid) {
285         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
286         try {
287             Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
288             if (bridges == null) return null;
289             for (String bridgeUUID : bridges.keySet()) {
290                 Bridge bridge = (Bridge)bridges.get(bridgeUUID);
291                 Set<UUID> portUUIDs = bridge.getPorts();
292                 logger.trace("Scanning Bridge {} to identify Port : {} ",bridge, uuid);
293                 for (UUID portUUID : portUUIDs) {
294                     if (portUUID.toString().equalsIgnoreCase(uuid)) {
295                         logger.trace("Found Port {} -> ", uuid, bridgeUUID);
296                         return bridge;
297                     }
298                 }
299             }
300         } catch (Exception e) {
301             logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
302         }
303         return null;
304     }
305
306     public void networkDeleted(String id) {
307         if (!enableContainer) return;
308
309         IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
310         if (containerManager == null) {
311             logger.error("ContainerManager is not accessible");
312             return;
313         }
314
315         String networkID = BaseHandler.convertNeutronIDToKey(id);
316         ContainerConfig config = new ContainerConfig();
317         config.setContainer(networkID);
318         containerManager.removeContainer(config);
319     }
320
321 }