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