2 * Copyright (C) 2013 Red Hat, Inc. and others...
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 : Madhu Venugopal, Brent Salisbury, Dave Tucker
10 package org.opendaylight.ovsdb.neutron;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
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.ProviderNetworkManager;
40 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
41 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 public class TenantNetworkManager {
46 static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
48 public static final String EXTERNAL_ID_VM_ID = "vm-id";
49 public static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
50 public static final String EXTERNAL_ID_VM_MAC = "attached-mac";
51 private static TenantNetworkManager tenantHelper = new TenantNetworkManager();
52 private ConcurrentMap<String, NodeConfiguration> nodeConfigurationCache = new ConcurrentHashMap<>();
54 private boolean enableContainer = false;
55 private TenantNetworkManager() {
56 String isTenantContainer = System.getProperty("TenantIsContainer");
57 if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
58 enableContainer = true;
62 public static TenantNetworkManager getManager() {
66 public int getInternalVlan(Node node, String networkId) {
67 String nodeUuid = getNodeUUID(node);
68 if (nodeUuid == null) {
69 logger.error("Unable to get UUID for Node {}", node);
73 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
75 if (nodeConfiguration == null) {
76 nodeConfiguration = addNodeConfigurationToCache(node);
78 Integer vlan = nodeConfiguration.getInternalVlan(networkId);
79 if (vlan == null) return 0;
80 return vlan.intValue();
83 private NodeConfiguration addNodeConfigurationToCache(Node node) {
84 NodeConfiguration nodeConfiguration = new NodeConfiguration(node);
85 String nodeUuid = getNodeUUID(node);
86 if (nodeUuid == null) {
87 logger.error("Cannot get Node UUID for Node {}", node);
90 this.nodeConfigurationCache.put(nodeUuid, nodeConfiguration);
91 return nodeConfigurationCache.get(nodeUuid);
94 public void reclaimTennantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
95 String nodeUuid = getNodeUUID(node);
96 if (nodeUuid == null) {
97 logger.error("Unable to get UUID for Node {}", node);
101 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
104 if (nodeConfiguration == null)
106 logger.error("Configuration data unavailable for Node {} ", node);
110 int vlan = nodeConfiguration.reclaimInternalVlan(network.getID());
112 logger.error("Unable to get an internalVlan for Network {}", network);
115 logger.debug("Removed Vlan {} on {}", vlan, portUUID);
118 public void networkCreated (String networkId) {
119 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
120 List<Node> nodes = connectionService.getNodes();
122 for (Node node : nodes) {
123 this.networkCreated(node, networkId);
128 private String getNodeUUID(Node node) {
129 String nodeUuid = new String();
130 OVSDBConfigService ovsdbConfigService = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
132 Map<String, Table<?>> ovsTable = ovsdbConfigService.getRows(node, Open_vSwitch.NAME.getName());
133 nodeUuid = (String)ovsTable.keySet().toArray()[0];
135 catch (Exception e) {
136 logger.error("Unable to get the Open_vSwitch table for Node {}: {}", node, e);
142 public int networkCreated (Node node, String networkId) {
143 String nodeUuid = getNodeUUID(node);
144 if (nodeUuid == null) {
145 logger.error("Unable to get UUID for Node {}", node);
149 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
152 if (nodeConfiguration == null)
154 nodeConfiguration = addNodeConfigurationToCache(node);
157 int internalVlan = nodeConfiguration.assignInternalVlan(networkId);
158 if (enableContainer && internalVlan != 0) {
159 IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
160 if (containerManager == null) {
161 logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
165 ContainerConfig config = new ContainerConfig();
166 config.setContainer(BaseHandler.convertNeutronIDToKey(networkId));
167 Status status = containerManager.addContainer(config);
168 logger.debug("Container Creation Status for {} : {}", networkId, status.toString());
170 ContainerFlowConfig flowConfig = new ContainerFlowConfig("InternalVlan", internalVlan+"",
171 null, null, null, null, null);
172 List<ContainerFlowConfig> containerFlowConfigs = new ArrayList<ContainerFlowConfig>();
173 containerFlowConfigs.add(flowConfig);
174 containerManager.addContainerFlows(BaseHandler.convertNeutronIDToKey(networkId), containerFlowConfigs);
180 * Are there any TenantNetwork VM present on this Node ?
181 * This method uses Interface Table's external-id field to locate the VM.
183 public boolean isTenantNetworkPresentInNode(Node node, String segmentationId) {
184 String networkId = this.getNetworkIdForSegmentationId(segmentationId);
185 if (networkId == null) {
186 logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
189 if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
190 String nodeUuid = getNodeUUID(node);
191 if (nodeUuid == null) {
192 logger.debug("Unable to get UUID for Node {}", node);
196 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
199 if (nodeConfiguration == null)
201 logger.error("Configuration data unavailable for Node {} ", node);
205 int internalVlan = nodeConfiguration.getInternalVlan(networkId);
206 if (internalVlan == 0) {
207 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
211 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
214 // Vlan Tag based identification
215 Map<String, Table<?>> portTable = ovsdbTable.getRows(node, Port.NAME.getName());
216 if (portTable == null) {
217 logger.debug("Port table is null for Node {} ", node);
221 for (Table<?> row : portTable.values()) {
222 Port port = (Port)row;
223 Set<BigInteger> tags = port.getTag();
224 if (tags.contains(internalVlan)) {
225 logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Port {}",
226 networkId, segmentationId, node, port);
231 // External-id based more accurate VM Location identification
232 Map<String, Table<?>> ifTable = ovsdbTable.getRows(node, Interface.NAME.getName());
233 if (ifTable == null) {
234 logger.debug("Interface table is null for Node {} ", node);
238 for (Table<?> row : ifTable.values()) {
239 Interface intf = (Interface)row;
240 Map<String, String> externalIds = intf.getExternal_ids();
241 if (externalIds != null && externalIds.get(EXTERNAL_ID_INTERFACE_ID) != null) {
242 if (this.isInterfacePresentInTenantNetwork(externalIds.get(EXTERNAL_ID_INTERFACE_ID), networkId)) {
243 logger.debug("Tenant Network {} with Segmentation-id {} is present in Node {} / Interface {}",
244 networkId, segmentationId, node, intf);
250 } catch (Exception e) {
251 logger.error("Error while trying to determine if network is present on node", e);
255 logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
256 networkId, segmentationId, node);
261 public String getNetworkIdForSegmentationId (String segmentationId) {
262 INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
263 List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
264 for (NeutronNetwork network : networks) {
265 if (network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) return network.getNetworkUUID();
270 private boolean isInterfacePresentInTenantNetwork (String portId, String networkId) {
271 INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
272 NeutronPort neutronPort = neutronPortService.getPort(portId);
273 if (neutronPort != null && neutronPort.getNetworkUUID().equalsIgnoreCase(networkId)) return true;
277 public NeutronNetwork getTenantNetworkForInterface (Interface intf) {
278 logger.trace("getTenantNetworkForInterface for {}", intf);
279 if (intf == null) return null;
280 Map<String, String> externalIds = intf.getExternal_ids();
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;
295 public void programTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
297 String nodeUuid = getNodeUUID(node);
298 if (nodeUuid == null) {
299 logger.error("Unable to get UUID for Node {}", node);
303 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
306 if (nodeConfiguration == null)
308 logger.error("Configuration data unavailable for Node {} ", node);
312 int vlan = nodeConfiguration.getInternalVlan(network.getID());
313 logger.debug("Programming Vlan {} on {}", vlan, portUUID);
315 logger.error("Unable to get an internalVlan for Network {}", network);
318 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
319 Port port = new Port();
320 OvsDBSet<BigInteger> tags = new OvsDBSet<BigInteger>();
321 tags.add(BigInteger.valueOf(vlan));
323 ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
324 if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
327 private void addPortToTenantNetworkContainer(Node node, String portUUID, NeutronNetwork network) {
328 IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
329 if (containerManager == null) {
330 logger.error("ContainerManager is not accessible");
333 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
335 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
337 logger.trace("Unable to identify Port with UUID {}", portUUID);
340 Set<UUID> interfaces = port.getInterfaces();
341 if (interfaces == null) {
342 logger.trace("No interfaces available to fetch the OF Port");
345 Bridge bridge = this.getBridgeIdForPort(node, portUUID);
346 if (bridge == null) {
347 logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
350 Set<String> dpids = bridge.getDatapath_id();
351 if (dpids == null || dpids.size() == 0) return;
352 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
354 for (UUID intfUUID : interfaces) {
355 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), intfUUID.toString());
356 if (intf == null) continue;
357 Set<BigInteger> of_ports = intf.getOfport();
358 if (of_ports == null) continue;
359 for (BigInteger of_port : of_ports) {
360 ContainerConfig config = new ContainerConfig();
361 config.setContainer(BaseHandler.convertNeutronIDToKey(network.getID()));
362 logger.debug("Adding Port {} to Container : {}", port.toString(), config.getContainer());
363 List<String> ncList = new ArrayList<String>();
364 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
365 NodeConnector nc = NodeConnector.fromStringNoNode(Node.NodeIDType.OPENFLOW.toString(),
366 Long.valueOf(of_port.longValue()).intValue()+"",
368 ncList.add(nc.toString());
369 config.addNodeConnectors(ncList);
371 Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
373 if (!status.isSuccess()) {
374 logger.error(" Failed {} : to add port {} to container - {}",
375 status, nc, network.getID());
377 logger.error(" Successfully added port {} to container - {}",
378 nc, network.getID());
382 } catch (Exception e) {
383 logger.error("Exception in addPortToTenantNetworkContainer", e);
387 private Bridge getBridgeIdForPort (Node node, String uuid) {
388 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
390 Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
391 if (bridges == null) return null;
392 for (String bridgeUUID : bridges.keySet()) {
393 Bridge bridge = (Bridge)bridges.get(bridgeUUID);
394 Set<UUID> portUUIDs = bridge.getPorts();
395 logger.trace("Scanning Bridge {} to identify Port : {} ",bridge, uuid);
396 for (UUID portUUID : portUUIDs) {
397 if (portUUID.toString().equalsIgnoreCase(uuid)) {
398 logger.trace("Found Port {} -> ", uuid, bridgeUUID);
403 } catch (Exception e) {
404 logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
409 public void networkDeleted(String id) {
410 if (!enableContainer) return;
412 IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
413 if (containerManager == null) {
414 logger.error("ContainerManager is not accessible");
418 String networkID = BaseHandler.convertNeutronIDToKey(id);
419 ContainerConfig config = new ContainerConfig();
420 config.setContainer(networkID);
421 containerManager.removeContainer(config);