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.util.ArrayList;
13 import java.util.List;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
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;
44 public class TenantNetworkManager implements ITenantNetworkManager {
45 static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
46 private ConcurrentMap<String, NodeConfiguration> nodeConfigurationCache = new ConcurrentHashMap<>();
48 // The implementation for each of these services is resolved by the OSGi Service Manager
49 private volatile IProviderNetworkManager providerNetworkManager;
51 private boolean enableContainer = false;
52 public TenantNetworkManager() {
53 String isTenantContainer = System.getProperty("TenantIsContainer");
54 if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
55 enableContainer = true;
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);
67 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
69 if (nodeConfiguration == null) {
70 nodeConfiguration = addNodeConfigurationToCache(node);
72 Integer vlan = nodeConfiguration.getInternalVlan(networkId);
73 if (vlan == null) return 0;
74 return vlan.intValue();
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);
84 this.nodeConfigurationCache.put(nodeUuid, nodeConfiguration);
85 return nodeConfigurationCache.get(nodeUuid);
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);
96 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
99 if (nodeConfiguration == null)
101 logger.error("Configuration data unavailable for Node {} ", node);
105 int vlan = nodeConfiguration.reclaimInternalVlan(network.getID());
107 logger.error("Unable to get an internalVlan for Network {}", network);
110 logger.debug("Removed Vlan {} on {}", vlan, portUUID);
114 public void networkCreated (String networkId) {
115 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
116 List<Node> nodes = connectionService.getNodes();
118 for (Node node : nodes) {
119 this.networkCreated(node, networkId);
124 private String getNodeUUID(Node node) {
125 String nodeUuid = new String();
126 OvsdbConfigService ovsdbConfigService = (OvsdbConfigService)ServiceHelper.getGlobalInstance(OvsdbConfigService.class, this);
128 Map<String, Row> ovsTable = ovsdbConfigService.getRows(node, ovsdbConfigService.getTableName(node, OpenVSwitch.class));
129 nodeUuid = (String)ovsTable.keySet().toArray()[0];
131 catch (Exception e) {
132 logger.error("Unable to get the Open_vSwitch table for Node {}: {}", node, e);
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);
146 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
149 if (nodeConfiguration == null)
151 nodeConfiguration = addNodeConfigurationToCache(node);
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);
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());
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);
177 * Are there any TenantNetwork VM present on this Node ?
178 * This method uses Interface Table's external-id field to locate the VM.
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);
187 if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
188 String nodeUuid = getNodeUUID(node);
189 if (nodeUuid == null) {
190 logger.debug("Unable to get UUID for Node {}", node);
194 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
197 if (nodeConfiguration == null)
199 logger.error("Configuration data unavailable for Node {} ", node);
203 int internalVlan = nodeConfiguration.getInternalVlan(networkId);
204 if (internalVlan == 0) {
205 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
209 OvsdbConfigService ovsdbTable = (OvsdbConfigService)ServiceHelper.getGlobalInstance(OvsdbConfigService.class, this);
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);
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);
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);
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);
248 } catch (Exception e) {
249 logger.error("Error while trying to determine if network is present on node", e);
253 logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
254 networkId, segmentationId, node);
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();
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;
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;
296 public void programTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
298 String nodeUuid = getNodeUUID(node);
299 if (nodeUuid == null) {
300 logger.error("Unable to get UUID for Node {}", node);
304 NodeConfiguration nodeConfiguration = nodeConfigurationCache.get(nodeUuid);
307 if (nodeConfiguration == null)
309 logger.error("Configuration data unavailable for Node {} ", node);
313 int vlan = nodeConfiguration.getInternalVlan(network.getID());
314 logger.debug("Programming Vlan {} on {}", vlan, portUUID);
316 logger.error("Unable to get an internalVlan for Network {}", network);
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));
324 ovsdbTable.updateRow(node, port.getSchema().getName(), null, portUUID, port.getRow());
325 if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
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");
334 OvsdbConfigService ovsdbTable = (OvsdbConfigService)ServiceHelper.getGlobalInstance(OvsdbConfigService.class, this);
336 Row portRow = ovsdbTable.getRow(node, ovsdbTable.getTableName(node, Port.class), portUUID);
337 Port port = ovsdbTable.getTypedRow(node, Port.class, portRow);
339 logger.trace("Unable to identify Port with UUID {}", portUUID);
342 Set<UUID> interfaces = port.getInterfacesColumn().getData();
343 if (interfaces == null) {
344 logger.trace("No interfaces available to fetch the OF Port");
347 Bridge bridge = this.getBridgeIdForPort(node, portUUID);
348 if (bridge == null) {
349 logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
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]));
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()+"",
370 ncList.add(nc.toString());
371 config.addNodeConnectors(ncList);
373 Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
375 if (!status.isSuccess()) {
376 logger.error(" Failed {} : to add port {} to container - {}",
377 status, nc, network.getID());
379 logger.error(" Successfully added port {} to container - {}",
380 nc, network.getID());
384 } catch (Exception e) {
385 logger.error("Exception in addPortToTenantNetworkContainer", e);
389 private Bridge getBridgeIdForPort (Node node, String uuid) {
390 OvsdbConfigService ovsdbTable = (OvsdbConfigService)ServiceHelper.getGlobalInstance(OvsdbConfigService.class, this);
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);
405 } catch (Exception e) {
406 logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
412 public void networkDeleted(String id) {
413 if (!enableContainer) return;
415 IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
416 if (containerManager == null) {
417 logger.error("ContainerManager is not accessible");
421 String networkID = BaseHandler.convertNeutronIDToKey(id);
422 ContainerConfig config = new ContainerConfig();
423 config.setContainer(networkID);
424 containerManager.removeContainer(config);