2 * Copyright (C) 2013 Red Hat, Inc.
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
10 package org.opendaylight.ovsdb.neutron;
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;
18 import java.util.Queue;
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;
43 public class TenantNetworkManager {
44 static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
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++) {
58 String isTenantContainer = System.getProperty("TenantIsContainer");
59 if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
60 enableContainer = true;
64 public static TenantNetworkManager getManager() {
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);
76 public void internalVlanInUse (int vlan) {
77 internalVlans.remove(vlan);
80 public int getInternalVlan (String networkId) {
81 Integer vlan = tenantVlanMap.get(networkId);
82 if (vlan == null) return 0;
83 return vlan.intValue();
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);
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());
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);
110 * Are there any TenantNetwork VM present on this Node ?
111 * This method uses Interface Table's external-id field to locate the VM.
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);
119 int internalVlan = this.getInternalVlan(networkId);
120 if (internalVlan == 0) {
121 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
124 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
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);
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);
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);
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);
163 } catch (Exception e) {
164 logger.error("Error while trying to determine if network is present on node", e);
168 logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
169 networkId, segmentationId, node);
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();
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;
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;
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);
212 logger.error("Unable to get an internalVlan for Network {}", network);
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));
220 ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
221 if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
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");
230 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
232 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
234 logger.trace("Unable to identify Port with UUID {}", portUUID);
237 Set<UUID> interfaces = port.getInterfaces();
238 if (interfaces == null) {
239 logger.trace("No interfaces available to fetch the OF Port");
242 Bridge bridge = this.getBridgeIdForPort(node, portUUID);
243 if (bridge == null) {
244 logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
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]));
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()+"",
265 ncList.add(nc.toString());
266 config.addNodeConnectors(ncList);
268 Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
270 if (!status.isSuccess()) {
271 logger.error(" Failed {} : to add port {} to container - {}",
272 status, nc, network.getID());
274 logger.error(" Successfully added port {} to container - {}",
275 nc, network.getID());
279 } catch (Exception e) {
280 logger.error("Exception in addPortToTenantNetworkContainer", e);
284 private Bridge getBridgeIdForPort (Node node, String uuid) {
285 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
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);
300 } catch (Exception e) {
301 logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
306 public void networkDeleted(String id) {
307 if (!enableContainer) return;
309 IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
310 if (containerManager == null) {
311 logger.error("ContainerManager is not accessible");
315 String networkID = BaseHandler.convertNeutronIDToKey(id);
316 ContainerConfig config = new ContainerConfig();
317 config.setContainer(networkID);
318 containerManager.removeContainer(config);